import numpy as np
import pandas as pd
dataM1 = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
names=('Time','Open','High','Low','Close', ''),
index_col='Time', parse_dates=True)
dataM1.index += pd.offsets.Hour(7) #7時間のオフセット
# dfのデータからtfで指定するタイムフレームの4本足データを作成する関数
def TF_ohlc(df, tf):
x = df.resample(tf).ohlc()
O = x['Open']['open']
H = x['High']['high']
L = x['Low']['low']
C = x['Close']['close']
ret = pd.DataFrame({'Open': O, 'High': H, 'Low': L, 'Close': C},
columns=['Open','High','Low','Close'])
return ret.dropna()
ohlc = TF_ohlc(dataM1, 'H') #1時間足データの作成
import indicators as ind #indicators.pyのインポート
FastMA = ind.iMA(ohlc, 8) #短期移動平均
SlowMA = ind.iMA(ohlc, 27) #長期移動平均
from pandas_highcharts.display import display_charts
df = pd.DataFrame({'Close': ohlc['Close'], 'FastMA': FastMA, 'SlowMA': SlowMA})
display_charts(df, chart_type="stock", title="MA cross", figsize=(640,480), grid=True)
#買いエントリーシグナル
BuyEntry = ((FastMA > SlowMA) & (FastMA.shift() <= SlowMA.shift())).values
#売りエントリーシグナル
SellEntry = ((FastMA < SlowMA) & (FastMA.shift() >= SlowMA.shift())).values
#買いエグジットシグナル
BuyExit = SellEntry.copy()
#売りエグジットシグナル
SellExit = BuyEntry.copy()
from numba import jit
#@jit
def Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit, lots=0.1, spread=2):
Open = ohlc['Open'].values #始値
Point = 0.0001 #1pipの値
if(Open[0] > 50): Point = 0.01 #クロス円の1pipの値
Spread = spread*Point #スプレッド
Lots = lots*100000 #実際の売買量
N = len(ohlc) #FXデータのサイズ
BuyExit[N-2] = SellExit[N-2] = True #最後に強制エグジット
BuyPrice = SellPrice = 0.0 # 売買価格
LongTrade = np.zeros(N) # 買いトレード情報
ShortTrade = np.zeros(N) # 売りトレード情報
LongPL = np.zeros(N) # 買いポジションの損益
ShortPL = np.zeros(N) # 売りポジションの損益
for i in range(1,N):
if BuyEntry[i-1] and BuyPrice == 0: #買いエントリーシグナル
BuyPrice = Open[i]+Spread
LongTrade[i] = BuyPrice #買いポジションオープン
elif BuyExit[i-1] and BuyPrice != 0: #買いエグジットシグナル
ClosePrice = Open[i]
LongTrade[i] = -ClosePrice #買いポジションクローズ
LongPL[i] = (ClosePrice-BuyPrice)*Lots #損益確定
BuyPrice = 0
if SellEntry[i-1] and SellPrice == 0: #売りエントリーシグナル
SellPrice = Open[i]
ShortTrade[i] = SellPrice #売りポジションオープン
elif SellExit[i-1] and SellPrice != 0: #売りエグジットシグナル
ClosePrice = Open[i]+Spread
ShortTrade[i] = -ClosePrice #売りポジションクローズ
ShortPL[i] = (SellPrice-ClosePrice)*Lots #損益確定
SellPrice = 0
return pd.DataFrame({'Long':LongTrade, 'Short':ShortTrade}, index=ohlc.index),\
pd.DataFrame({'Long':LongPL, 'Short':ShortPL}, index=ohlc.index)
Trade, PL = Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit)
def BacktestReport(Trade, PL):
LongPL = PL['Long']
LongTrades = np.count_nonzero(Trade['Long'])//2
LongWinTrades = np.count_nonzero(LongPL.clip_lower(0))
LongLoseTrades = np.count_nonzero(LongPL.clip_upper(0))
print('買いトレード数 =', LongTrades)
print('勝トレード数 =', LongWinTrades)
print('最大勝トレード =', LongPL.max())
print('平均勝トレード =', round(LongPL.clip_lower(0).sum()/LongWinTrades, 2))
print('負トレード数 =', LongLoseTrades)
print('最大負トレード =', LongPL.min())
print('平均負トレード =', round(LongPL.clip_upper(0).sum()/LongLoseTrades, 2))
print('勝率 =', round(LongWinTrades/LongTrades*100, 2), '%\n')
ShortPL = PL['Short']
ShortTrades = np.count_nonzero(Trade['Short'])//2
ShortWinTrades = np.count_nonzero(ShortPL.clip_lower(0))
ShortLoseTrades = np.count_nonzero(ShortPL.clip_upper(0))
print('売りトレード数 =', ShortTrades)
print('勝トレード数 =', ShortWinTrades)
print('最大勝トレード =', ShortPL.max())
print('平均勝トレード =', round(ShortPL.clip_lower(0).sum()/ShortWinTrades, 2))
print('負トレード数 =', ShortLoseTrades)
print('最大負トレード =', ShortPL.min())
print('平均負トレード =', round(ShortPL.clip_upper(0).sum()/ShortLoseTrades, 2))
print('勝率 =', round(ShortWinTrades/ShortTrades*100, 2), '%\n')
Trades = LongTrades + ShortTrades
WinTrades = LongWinTrades+ShortWinTrades
LoseTrades = LongLoseTrades+ShortLoseTrades
print('総トレード数 =', Trades)
print('勝トレード数 =', WinTrades)
print('最大勝トレード =', max(LongPL.max(), ShortPL.max()))
print('平均勝トレード =', round((LongPL.clip_lower(0).sum()+ShortPL.clip_lower(0).sum())/WinTrades, 2))
print('負トレード数 =', LoseTrades)
print('最大負トレード =', min(LongPL.min(), ShortPL.min()))
print('平均負トレード =', round((LongPL.clip_upper(0).sum()+ShortPL.clip_upper(0).sum())/LoseTrades, 2))
print('勝率 =', round(WinTrades/Trades*100, 2), '%\n')
GrossProfit = LongPL.clip_lower(0).sum()+ShortPL.clip_lower(0).sum()
GrossLoss = LongPL.clip_upper(0).sum()+ShortPL.clip_upper(0).sum()
Profit = GrossProfit+GrossLoss
Equity = (LongPL+ShortPL).cumsum()
MDD = (Equity.cummax()-Equity).max()
print('総利益 =', round(GrossProfit, 2))
print('総損失 =', round(GrossLoss, 2))
print('総損益 =', round(Profit, 2))
print('プロフィットファクター =', round(-GrossProfit/GrossLoss, 2))
print('平均損益 =', round(Profit/Trades, 2))
print('最大ドローダウン =', round(MDD, 2))
print('リカバリーファクター =', round(Profit/MDD, 2))
return Equity
Equity = BacktestReport(Trade, PL)
買いトレード数 = 132 勝トレード数 = 53 最大勝トレード = 488.0 平均勝トレード = 72.35 負トレード数 = 79 最大負トレード = -146.1 平均負トレード = -39.51 勝率 = 40.15 % 売りトレード数 = 132 勝トレード数 = 52 最大勝トレード = 320.7 平均勝トレード = 88.32 負トレード数 = 80 最大負トレード = -233.7 平均負トレード = -34.98 勝率 = 39.39 % 総トレード数 = 264 勝トレード数 = 105 最大勝トレード = 488.0 平均勝トレード = 80.26 負トレード数 = 159 最大負トレード = -233.7 平均負トレード = -37.23 勝率 = 39.77 % 総利益 = 8427.1 総損失 = -5920.0 総損益 = 2507.1 プロフィットファクター = 1.42 平均損益 = 9.5 最大ドローダウン = 485.1 リカバリーファクター = 5.17
Initial = 10000 # 初期資産
display_charts(pd.DataFrame({'Equity':Equity+Initial}), chart_type="stock", title="資産曲線", figsize=(640,480), grid=True)
def PositionLine(trade):
PosPeriod = 0 #ポジションの期間
Position = False #ポジションの有無
Line = trade.copy()
for i in range(len(Line)):
if trade[i] > 0: Position = True
elif Position: PosPeriod += 1 # ポジションの期間をカウント
if trade[i] < 0:
if PosPeriod > 0:
Line[i] = -trade[i]
diff = (Line[i]-Line[i-PosPeriod])/PosPeriod
for j in range(i-1, i-PosPeriod, -1):
Line[j] = Line[j+1]-diff # ポジションの期間を補間
PosPeriod = 0
Position = False
if trade[i] == 0 and not Position: Line[i] = 'NaN'
return Line
df = pd.DataFrame({'Open': ohlc['Open'],
'Long': PositionLine(Trade['Long'].values),
'Short': PositionLine(Trade['Short'].values)})
display_charts(df, chart_type="stock", title="トレードチャート", figsize=(640,480), grid=True)