In [1]:
import numpy as np
import pandas as pd
import indicators as ind #indicators.pyのインポート

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時間のオフセット
ohlc = ind.TF_ohlc(dataM1, 'H') #1時間足データの作成
In [2]:
FastMA = ind.iMA(ohlc, 10) #エントリー用短期移動平均
SlowMA = ind.iMA(ohlc, 30) #エントリー用長期移動平均
ExitMA = ind.iMA(ohlc, 5) #エグジット用移動平均
In [3]:
#買いエントリーシグナル
BuyEntry = ((FastMA > SlowMA) & (FastMA.shift() <= SlowMA.shift())).values
#売りエントリーシグナル
SellEntry = ((FastMA < SlowMA) & (FastMA.shift() >= SlowMA.shift())).values
#買いエグジットシグナル
BuyExit = ((ohlc.Close < ExitMA) & (ohlc.Close.shift() >= ExitMA.shift())).values
#売りエグジットシグナル
SellExit = ((ohlc.Close > ExitMA) & (ohlc.Close.shift() <= ExitMA.shift())).values
In [4]:
def Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit, lots=0.1, spread=2, TP=0, SL=0, Limit=0, Expiration=10):
    Open = ohlc.Open.values #始値
    Low = ohlc.Low.values #安値
    High = ohlc.High.values #高値
    Point = 0.0001 #1pipの値
    if(Open[0] > 50): Point = 0.01 #クロス円の1pipの値
    Spread = spread*Point #スプレッド
    Lots = lots*100000 #実際の売買量
    N = len(ohlc) #FXデータのサイズ
    
    LongTrade = np.zeros(N) #買いトレード情報
    ShortTrade = np.zeros(N) #売りトレード情報

    #買いエントリー価格
    BuyEntryS = np.hstack((False, BuyEntry[:-1])) #買いエントリーシグナルのシフト
    if Limit == 0: LongTrade[BuyEntryS] = Open[BuyEntryS]+Spread #成行買い
    else: #指値買い
        for i in range(N-Expiration):
            if BuyEntryS[i]:
                BuyLimit = Open[i]-Limit*Point #指値
                for j in range(Expiration):
                    if Low[i+j] <= BuyLimit: #約定条件
                        LongTrade[i+j] = BuyLimit+Spread
                        break
    #買いエグジット価格
    BuyExitS = np.hstack((False, BuyExit[:-2], True)) #買いエグジットシグナルのシフト
    LongTrade[BuyExitS] = -Open[BuyExitS]
    
    #売りエントリー価格
    SellEntryS = np.hstack((False, SellEntry[:-1])) #売りエントリーシグナルのシフト
    if Limit == 0: ShortTrade[SellEntryS] = Open[SellEntryS] #成行売り
    else: #指値売り
        for i in range(N-Expiration):
            if SellEntryS[i]:
                SellLimit = Open[i]+Limit*Point #指値
                for j in range(Expiration):
                    if High[i+j] >= SellLimit: #約定条件
                        ShortTrade[i+j] = SellLimit
                        break
    #売りエグジット価格
    SellExitS = np.hstack((False, SellExit[:-2], True)) #売りエグジットシグナルのシフト
    ShortTrade[SellExitS] = -(Open[SellExitS]+Spread)
    
    LongPL = np.zeros(N) # 買いポジションの損益
    ShortPL = np.zeros(N) # 売りポジションの損益
    BuyPrice = SellPrice = 0.0 # 売買価格
    
    for i in range(1,N):
        if LongTrade[i] > 0: #買いエントリーシグナル
            if BuyPrice == 0:
                BuyPrice = LongTrade[i]
                ShortTrade[i] = -BuyPrice #売りエグジット
            else: LongTrade[i] = 0

        if ShortTrade[i] > 0: #売りエントリーシグナル
            if SellPrice == 0:
                SellPrice = ShortTrade[i]
                LongTrade[i] = -SellPrice #買いエグジット
            else: ShortTrade[i] = 0

        if LongTrade[i] < 0: #買いエグジットシグナル
            if BuyPrice != 0:
                LongPL[i] = -(BuyPrice+LongTrade[i])*Lots #損益確定
                BuyPrice = 0
            else: LongTrade[i] = 0
                
        if ShortTrade[i] < 0: #売りエグジットシグナル
            if SellPrice != 0:
                ShortPL[i] = (SellPrice+ShortTrade[i])*Lots #損益確定
                SellPrice = 0
            else: ShortTrade[i] = 0

        if BuyPrice != 0 and SL > 0: #SLによる買いポジションの決済
            StopPrice = BuyPrice-SL*Point
            if Low[i] <= StopPrice:
                LongTrade[i] = -StopPrice
                LongPL[i] = -(BuyPrice+LongTrade[i])*Lots #損益確定
                BuyPrice = 0

        if BuyPrice != 0 and TP > 0: #TPによる買いポジションの決済
            LimitPrice = BuyPrice+TP*Point
            if High[i] >= LimitPrice:
                LongTrade[i] = -LimitPrice
                LongPL[i] = -(BuyPrice+LongTrade[i])*Lots #損益確定
                BuyPrice = 0
                
        if SellPrice != 0 and SL > 0: #SLによる売りポジションの決済
            StopPrice = SellPrice+SL*Point
            if High[i] >= StopPrice+Spread:
                ShortTrade[i] = -StopPrice
                ShortPL[i] = (SellPrice+ShortTrade[i])*Lots #損益確定
                SellPrice = 0

        if SellPrice != 0 and TP > 0: #TPによる売りポジションの決済
            LimitPrice = SellPrice-TP*Point
            if Low[i] <= LimitPrice+Spread:
                ShortTrade[i] = -LimitPrice
                ShortPL[i] = (SellPrice+ShortTrade[i])*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, TP=100, SL=50, Limit=20)
In [5]:
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)
買いトレード数 = 51
勝トレード数 = 19
最大勝トレード = 100.0
平均勝トレード = 32.33
負トレード数 = 34
最大負トレード = -50.0
平均負トレード = -17.4
勝率 = 37.25 %

売りトレード数 = 43
勝トレード数 = 22
最大勝トレード = 100.0
平均勝トレード = 33.13
負トレード数 = 23
最大負トレード = -50.0
平均負トレード = -19.92
勝率 = 51.16 %

総トレード数 = 94
勝トレード数 = 41
最大勝トレード = 100.0
平均勝トレード = 32.76
負トレード数 = 57
最大負トレード = -50.0
平均負トレード = -18.42
勝率 = 43.62 %

総利益 = 1343.1
総損失 = -1049.8
総損益 = 293.3
プロフィットファクター = 1.28
平均損益 = 3.12
最大ドローダウン = 192.6
リカバリーファクター = 1.52
In [6]:
from pandas_highcharts.display import display_charts
Initial = 10000 # 初期資産
Equity = (PL.Long+PL.Short).cumsum() #累積損益
display_charts(pd.DataFrame({'Equity':Equity+Initial}), chart_type="stock", title="資産曲線", figsize=(640,480), grid=True)
In [7]:
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'
        if Line[i] < 0: 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)

This website does not host notebooks, it only renders notebooks available on other websites.

Delivered by Fastly, Rendered by Rackspace

nbviewer GitHub repository.

nbviewer version: 07b0e30

nbconvert version: 5.6.0

Rendered (Sun, 15 Dec 2019 13:38:41 UTC)