Backtesting FX Systre with Python (2)

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.

Creation of 4-value data

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

Creating trading signals

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.

Creating a backtest function

This time, the following two points have been added as extensions of the trading rules of the system.

  1. Specify a limit price that is a certain pips away from the price at the time of the entry signal, and execute when the price is reached.
  2. Settle when the opened position reaches a certain pips profit or loss.

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.

  1. Shift each signal 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.
  2. Substitute 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.

Backtest execution example

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)

chart.png

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

Recommended Posts

Backtesting FX Systre with Python (2)
Backtesting FX Systre in Python (1)
FX Systre Parameter Optimization in Python
FizzBuzz with Python3
Scraping with Python
Statistics with python
Scraping with Python
Python with Go
Twilio with Python
Integrate with Python
Play with 2016-Python
AES256 with python
Tested with Python
Convert FX 1-minute data to 5-minute data with Python
python starts with ()
with syntax (Python)
Bingo with python
Zundokokiyoshi with python
Excel with Python
Microcomputer with Python
Cast with python
Serial communication with Python
Zip, unzip with python
Django 1.11 started with Python3.6
Primality test with Python
Python with eclipse + PyDev.
Socket communication with Python
Data analysis with python 2
Scraping with Python (preparation)
Learning Python with ChemTHEATER 03
Sequential search with Python
Run Python with VBA
Handling yaml with python
Solve AtCoder 167 with python
Serial communication with python
[Python] Use JSON with Python
Learning Python with ChemTHEATER 05-1
Learn Python with ChemTHEATER
Run prepDE.py with python3
1.1 Getting Started with Python
Collecting tweets with Python
Binarization with OpenCV / Python
3. 3. AI programming with Python
Kernel Method with Python
Non-blocking with Python + uWSGI
Scraping with Python + PhantomJS
Posting tweets with python
Use mecab with Python3
[Python] Redirect with CGIHTTPServer
Operate Kinesis with Python
Getting Started with Python
Use DynamoDB with Python
Zundko getter with python
Handle Excel with python
Ohm's Law with Python
Primality test with python
Run Blender with python
Solve Sudoku with Python
Python starting with Windows 7
Multi-process asynchronously with python
Python programming with Atom