import pandas as pd
import datetime
import talib
from backtesting import Strategy
from backtesting.lib import crossover
from backtesting import Backtest
import re
import warnings
warnings.filterwarnings('ignore')

#%matplotlib inline

df = pd.read_csv('C:/Users/xi/MT5/in_dat/common.csv', index_col=0)
use_max = df.iat[0,0]
use = df.iat[0,1]
spread = df.iat[0,2]
use_data = df.iat[0,3]
if  use_data == 'short':
    data = df.iat[0,4]
if  use_data == 'long':
    data = df.iat[0,5]
max_weight = df.iat[0,6]
opt_factor = df.iat[0,7]
flag = 0
path_ohlcv = 'C:/Users/xi/MT5/in_dat/{}/OHLCV_{}_DMI.csv'
path_ohlcv = path_ohlcv.format(use_data,use_data)
path_opt = 'C:/Users/xi/MT5/out_dat/{}/opt/opt_DMI.csv'
path_opt = path_opt.format(use_data)
path_para = 'C:/Users/xi/MT5/out_dat/{}/para/para_DMI.csv'
path_para = path_para.format(use_data)

def DMI(value1,value2, value3,n):
    high = pd.Series(value1)
    low = pd.Series(value2)
    close = pd.Series(value3)
    Adx = talib.ADX(high, low, close, timeperiod=n)
    DIp = talib.PLUS_DI(high, low, close,timeperiod=n)
    DIm = talib.MINUS_DI(high, low, close,timeperiod=n)
    return Adx, DIp, DIm

def ATR(value1,value2,value3,n):
    high = pd.Series(value1)
    low = pd.Series(value2)
    close = pd.Series(value3)
    return talib.ATR(high, low, close, timeperiod=n)


while True:
    try:
        # データの読み込み
        #長期の場合OHLCVのPathだけ短期のPathにする(短期の方はそのまま)
        #最終行を取得---------
        lastRow = sum(1 for line in open(path_ohlcv)) - 2
        #最終行からuse_max行の行数を求める
        pickRow = [lastRow - line for line in range(use_max)]
        pickRow.reverse()
        df = pd.read_csv(path_ohlcv, header=None,skiprows=lambda x: x not in pickRow)
        df.columns = ['time','Open','High','Low','Close','Volume']
        df = df.drop(0)
        # timeの型変換
        # datetime型にする
        df = df.astype({'Open':float,'High':float,'Low':float,'Close':float,'Volume':float})
        df_first = df.tail(1)
        ohlcv_last = df_first.iat[0,0]
        ohlcv_last = pd.to_datetime(ohlcv_last)
        dt_now = datetime.datetime.now()
        dt_now = pd.to_datetime(dt_now)
        td = dt_now - ohlcv_last
        if data == '10S':
            if td.seconds < 30:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        if data == '30S':
            if td.seconds < 90:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        if data == '1T':
            if td.seconds < 180:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        if data == '3T':
            if td.seconds < 540:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        if data == '5T':
            if td.seconds < 900:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        if data == '10T':
            if td.seconds < 1800:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        if data == '15T':
            if td.seconds < 2700:
                flag = 1
                df["time"] = pd.to_datetime(df["time"])
                df = df.set_index('time')
            else:
                flag = 0
        
        if flag == 1:
            #----------------------
            #NaN回避
            nan_count = df.isnull().sum()
            nan_count_sum = 0
            for i in range(len(nan_count)):
                nan_count_sum = nan_count_sum + nan_count[i]
            #OHLCVにNaNが含まれてなかった場合のみ次へ
            if nan_count_sum == 0:
        
                class DMIt(Strategy):
                    n = 26
                    r = 14
                    a = 10
                    w = max_weight

                    def init(self):
                        self.adx, self.dip, self.dim = self.I(DMI, self.data['High'], self.data['Low'], self.data['Close'], self.n)
                        self.atr = self.I(ATR, self.data['High'], self.data['Low'], self.data['Close'], self.r)
                    
                    def next(self):
                        if self.w >= self.atr * self.a >= 0.03:
                            if not self.position:
                                if (self.dim[-2] > self.dip[-2] and self.dim[-1] < self.dip[-1] and self.dim[-1] < self.adx[-1]): 
                                    self.buy(limit=self.data['Close'],tp = self.data['Close'] + (self.atr * self.a) + (spread * 0.01), sl = self.data['Close'] - (self.atr * self.a))
                                if (self.dim[-2] < self.dip[-2] and self.dim[-1] > self.dip[-1] and self.dip[-1] < self.adx[-1]):
                                    self.sell(limit=self.data['Close'], tp = self.data['Close'] - (self.atr * self.a) - (spread * 0.01), sl = self.data['Close'] + (self.atr * self.a))

                df_ = df.tail(use)
                #DMI最適化
                dt_now = datetime.datetime.now()
                print(dt_now)

                print("-----------------DMI-----------------")

                bt = Backtest(df_, DMIt, cash=100000, commission=spread*0.0001, trade_on_close=True)
                n=list(range(8, 20, 2))
                r=list(range(6, 24, 3))
                a=list(range(1, 13, 2))
                stats = bt.optimize(n=n,r=r,a=a,maximize=opt_factor)
                print(stats)

                stats.to_csv(path_opt, index=True, header=True)
                #bt.plot()

                df = pd.read_csv(path_opt, index_col=0)
                result = df.at['Equity Final [$]','0']
                DMIresult = float(result)
                print('Equity Final [$] =',DMIresult)
                saiteki = df.at['_strategy','0']
                num = re.findall('\d+',saiteki)
                DMIvalue = int(num[0])
                ATRvalue = int(num[1])
                ATRweight = int(num[2])
                print('DMI =',DMIvalue)
                print('ATR =',ATRvalue)
                print('ATRweight =',ATRweight)

                cols = ['DMI','ATR','ATRweight']
                dmi_frame = pd.DataFrame(index=[], columns=cols)

                dmi_data = pd.Series( [DMIvalue,ATRvalue,ATRweight], index=dmi_frame.columns )
                dmi_frame = dmi_frame.append(dmi_data, ignore_index=True)
                dmi_frame.to_csv(path_para, index=True, header=True)

    except pd.errors.EmptyDataError:
        print('csvファイルが読み取れませんでした．スキップします．')
        continue

    except ValueError:
        print('ValueError')
        continue

    except AssertionError:
        print('AssertionError')
        continue

    except TypeError:
        print('TypeError')
        continue

    except AttributeError:
        print('AttributeError')
        continue

    except OverflowError:
        print('OverflowError')
        continue
    
    except OSError:
        print('OSError')
        continue
    
    