Backtesting FX Systre with Python (1) It is a continuation of.
The only systems that can be backtested in (1) are those that market buy and sell at the opening price of the next bar for the signal generated from the fixed closing price. This time, we expanded from limit trading and open position profit / loss to profit taking and loss cut systems.
The overall flow is the same as (1). Since the common parts are briefly written, please refer to the article (1) for details.
Create EUR / USD, 1-hour 4-value data for 2015 as ʻohlc`.
import numpy as np
import pandas as pd
import indicators as ind #indicators.Import of 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 hour offset
ohlc = ind.TF_ohlc(dataM1, 'H') #Creation of 1-hour data
Create a buy / sell signal for the system to be backtested. This time, the entry is the intersection of the moving average and the exit is the intersection of the moving average and the closing price.
The technical indicators used are two moving averages for entry and one moving average for exit.
FastMA = ind.iMA(ohlc, 10) #Short-term moving average for entry
SlowMA = ind.iMA(ohlc, 30) #Long-term moving average for entry
ExitMA = ind.iMA(ohlc, 5) #Moving average for exit
Create a buy / sell signal using these index values.
#Buy entry signal
BuyEntry = ((FastMA > SlowMA) & (FastMA.shift() <= SlowMA.shift())).values
#Sell entry signal
SellEntry = ((FastMA < SlowMA) & (FastMA.shift() >= SlowMA.shift())).values
#Buy exit signal
BuyExit = ((ohlc.Close < ExitMA) & (ohlc.Close.shift() >= ExitMA.shift())).values
#Sell exit signal
SellExit = ((ohlc.Close > ExitMA) & (ohlc.Close.shift() <= ExitMA.shift())).values
These signals are generated at all positions that meet the conditions of intersection, but some are not actually adopted depending on the presence or absence of positions. The control around that is done by the following backtest function.
This time, the following two points have been added as extensions of the trading rules of the system.
Therefore, I increased the argument of the function as follows.
def Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit, lots=0.1, spread=2, TP=0, SL=0, Limit=0, Expiration=10):
Substituting a positive value for Limit in this will indicate a limit price that is Limitpips cheaper for buying and a limit price that is Limitpips higher for selling, without buying or selling immediately at the entry signal. .. ʻExpiration` is the validity period of the limit price and is specified by the number of bars.
TP and SL represent profit (pips) for profit taking and loss (pips) for loss cut, respectively. It works by substituting a positive value.
The whole function looks like this:
def Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit, lots=0.1, spread=2, TP=0, SL=0, Limit=0, Expiration=10):
    Open = ohlc.Open.values #Open price
    Low = ohlc.Low.values #Low price
    High = ohlc.High.values #High price
    Point = 0.0001 #Value of 1pip
    if(Open[0] > 50): Point = 0.01 #1 pip value of cross circle
    Spread = spread*Point #Spread
    Lots = lots*100000 #Actual trading volume
    N = len(ohlc) #FX data size
    
    LongTrade = np.zeros(N) #Buy trade information
    ShortTrade = np.zeros(N) #Sell trade information
    #Buy entry price
    BuyEntryS = np.hstack((False, BuyEntry[:-1])) #Buy entry signal shift
    if Limit == 0: LongTrade[BuyEntryS] = Open[BuyEntryS]+Spread #Market buying
    else: #Limit buy
        for i in range(N-Expiration):
            if BuyEntryS[i]:
                BuyLimit = Open[i]-Limit*Point #Limit price
                for j in range(Expiration):
                    if Low[i+j] <= BuyLimit: #Contract conditions
                        LongTrade[i+j] = BuyLimit+Spread
                        break
    #Buy exit price
    BuyExitS = np.hstack((False, BuyExit[:-2], True)) #Buy exit signal shift
    LongTrade[BuyExitS] = -Open[BuyExitS]
    
    #Sell entry price
    SellEntryS = np.hstack((False, SellEntry[:-1])) #Sell entry signal shift
    if Limit == 0: ShortTrade[SellEntryS] = Open[SellEntryS] #Market sale
    else: #Limit selling
        for i in range(N-Expiration):
            if SellEntryS[i]:
                SellLimit = Open[i]+Limit*Point #Limit price
                for j in range(Expiration):
                    if High[i+j] >= SellLimit: #Contract conditions
                        ShortTrade[i+j] = SellLimit
                        break
    #Sell exit price
    SellExitS = np.hstack((False, SellExit[:-2], True)) #Sell exit signal shift
    ShortTrade[SellExitS] = -(Open[SellExitS]+Spread)
    
    LongPL = np.zeros(N) #Profit and Loss of Buy Position
    ShortPL = np.zeros(N) #Sell position profit or loss
    BuyPrice = SellPrice = 0.0 #Selling price
    
    for i in range(1,N):
        if LongTrade[i] > 0: #Buy entry signal
            if BuyPrice == 0:
                BuyPrice = LongTrade[i]
                ShortTrade[i] = -BuyPrice #Sell exit
            else: LongTrade[i] = 0
        if ShortTrade[i] > 0: #Sell entry signal
            if SellPrice == 0:
                SellPrice = ShortTrade[i]
                LongTrade[i] = -SellPrice #Buy exit
            else: ShortTrade[i] = 0
        if LongTrade[i] < 0: #Buy exit signal
            if BuyPrice != 0:
                LongPL[i] = -(BuyPrice+LongTrade[i])*Lots #Profit and loss settlement
                BuyPrice = 0
            else: LongTrade[i] = 0
                
        if ShortTrade[i] < 0: #Sell exit signal
            if SellPrice != 0:
                ShortPL[i] = (SellPrice+ShortTrade[i])*Lots #Profit and loss settlement
                SellPrice = 0
            else: ShortTrade[i] = 0
        if BuyPrice != 0 and SL > 0: #Settlement of buy position by SL
            StopPrice = BuyPrice-SL*Point
            if Low[i] <= StopPrice:
                LongTrade[i] = -StopPrice
                LongPL[i] = -(BuyPrice+LongTrade[i])*Lots #Profit and loss settlement
                BuyPrice = 0
        if BuyPrice != 0 and TP > 0: #Settlement of buy position by TP
            LimitPrice = BuyPrice+TP*Point
            if High[i] >= LimitPrice:
                LongTrade[i] = -LimitPrice
                LongPL[i] = -(BuyPrice+LongTrade[i])*Lots #Profit and loss settlement
                BuyPrice = 0
                
        if SellPrice != 0 and SL > 0: #Settlement of sell position by SL
            StopPrice = SellPrice+SL*Point
            if High[i]+Spread >= StopPrice:
                ShortTrade[i] = -StopPrice
                ShortPL[i] = (SellPrice+ShortTrade[i])*Lots #Profit and loss settlement
                SellPrice = 0
        if SellPrice != 0 and TP > 0: #Settlement of sell position by TP
            LimitPrice = SellPrice-TP*Point
            if Low[i]+Spread <= LimitPrice:
                ShortTrade[i] = -LimitPrice
                ShortPL[i] = (SellPrice+ShortTrade[i])*Lots #Profit and loss settlement
                SellPrice = 0
                
    return pd.DataFrame({'Long':LongTrade, 'Short':ShortTrade}, index=ohlc.index),\
            pd.DataFrame({'Long':LongPL, 'Short':ShortPL}, index=ohlc.index)
It's been quite a long time, but to explain it briefly, first, preprocess the signal as follows.
BuyEntry, SellEntry, BuyExit, SellExit by one sample to make BuyEntryS, SellEntryS, BuyExitS, SellExitS. This is so that the signal will appear in the bar where the actual sale is made.LongTrade, ShortTrade for the price to be bought or sold at the time of the signal. The entry is a positive number, the exit is a negative number, and in the case of limit trading, the trading price is entered at the position of the bar that first reached the limit price during the valid period.After that, the bar is turned from the beginning to the end, and trading and settlement processing is performed while checking the existence of positions and the profit and loss of positions. Returns the actual traded price to LongTrade, ShortTrade and the fixed profit or loss to LongPL, ShortPL.
The following example is a backtest of a system that buys and sells at a limit price 20 pips away from the entry signal price and settles with a profit of 100 pips or a loss of 50 pips separately from the exit signal.
Trade, PL = Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit, TP=100, SL=50, Limit=20)
This time, I will display only the asset curve.
from pandas_highcharts.display import display_charts
Initial = 10000 #Initial assets
Equity = (PL.Long+PL.Short).cumsum() #Cumulative profit and loss
display_charts(pd.DataFrame({'Equity':Equity+Initial}), chart_type="stock", title="Asset curve", figsize=(640,480), grid=True)

The code posted in this article has been uploaded below. MT5IndicatorsPy/EA_sample2.ipynb
Recommended Posts