You are welcome to subscribe to Python In Action: Building a Stock-based Quantitative Trading System. This booklet will include a series of columns that will expand on the topics covered in the booklet and make it easier for readers to access the information. This column is a supplement to the brochure content!!

preface

When we develop a trading strategy, we need to backtest the strategy. Then we need a backtest framework.

There are many mature backtesting frameworks and platforms. Each of these frameworks or platforms has its strengths and weaknesses, and not everyone’s needs. In order to integrate the knowledge points of quantitative trading learned before, better consolidate the learning content, and to build a framework suitable for our own in the future, we will build a simple backtest framework together in this section.

Policy back test process

Completing a strategy backtest generally involves the following steps:

  • Get market data. Taking stock quotation data as an example, we need to obtain at least the closing price, opening price, high price, low price and volume. Usually, we divide the data into two parts according to time sequence: one is the data of strategy training set; A copy of the policy test set data.

  • Generate timing signals. Taking the timing strategy in the course as an example, we generate sequences containing trading signals on the training set data. Some comprehensive strategy, is should be in the timing strategy can be integrated into the stop profit and stop loss mechanism, parameter optimization measures and so on.

  • The policy test report is displayed. The initial capital is first set up for backtesting, and then the stock is bought and sold according to the trading signal. We can choose to buy/sell full positions, or we can use position management. Finally, the effect of the strategy is evaluated by backtesting indicators. The retest index includes the return rate of funds, the comparison with the benchmark return, the maximum retracement of funds, the maximum retracement of ups and downs, etc.. Of course, there are transaction poundage and slippery point situation in actual trade, more close to the actual word is to need to consider these factors.

  • Visual strategy backtest effect. Visualization is very important in the process of data analysis in various fields, which can most intuitively show the meaning behind the data. Here, we can visualize the income curve and the maximum retracement curve to more intuitively evaluate the operation of the strategy.

Function Interface Introduction

1. Get the stock trading data interface GetStockDatApi.

The interfaces are described as follows:

# Data acquisition interface, refer to "Common Stock Trading Data Interface for Differentiation Analysis"
# input parameter
# :param data: code
# :param data: start Start date, default is January 1, 2010
# :param data: start Start date, default is January 1, 2010
# output parameter
# :return data: dF_recon normalized stock data in DataFrame format
# Note: This interface is for stock ex - rights data
Copy the code

The interface use routine is as follows, after the call will return the closing price, open price, high price, low price, volume:

df_stock = GetStockDatApi("000876.SZ".'20170101'.'20200101')
"""
             High    Low   Open  Close     Volume
trade_date                                       
2017-01-03   8.12   8.07   8.07   8.12  179801.01
2017-01-04   8.16   8.09   8.13   8.15  166242.35
2017-01-05   8.23   8.13   8.15   8.17  222902.53
2017-01-06   8.19   8.12   8.18   8.13  128549.96
2017-01-09   8.15   8.08   8.13   8.13  136700.04
.. . . . . 2019-12-25 18.79 18.44 18.59 18.60 207776.34 2019-12-26 18.76 18.46 18.69 18.60 189935.42 2019-12-27 19.43 18.58 18.74 19.28 504214.70 2019-12-30 19.50 18.92 19.24 19.38 379296.95 2019-12-31 20.31 19.55 19.55 19.95 562873.40 [731 rows x 5 columns] """
Copy the code

2. Interface for signal generation of timing policy, CalNdaysSignal is used to calculate n-day breakthrough signal.

The interfaces are described as follows:

# Calculate n-day breakout signal interface, refer to "Turtle Timing Strategy Introduction quantitative Trading"
# input parameter
# :param Data: StockData individual stock price data
# :param data: N1 Policy parameter. The default is 15
# :param data: N2 Policy parameter, default is 5
# output parameter
# :return data: Stock data in DataFrame format to add trading signals
Copy the code

The interface usage routine is as follows:

df_stock = CalNdaysSignal(df_stock, N1=15, N2=5)
Copy the code

The stock data returned after calling the interface looks like this:

""" High Low Open Close Volume N1_High N2_Low Signal trade_date 2017-01-03 8.12 8.07 8.07 8.12 179801.01 8.12 8.12 1.0 2017-01-04 8.16 8.09 8.13 8.15 166242.35 8.15 8.12 1.0 2017-01-05 8.23 8.13 8.15 8.17 222902.53 8.17 8.12 1.0 2017-01-06 8.18 8.13 128549.96 8.17 8.12 1.0 2017-01-09 8.15 8.08 8.13 8.13 136700.04 8.17 8.07 1.0.. . . . . . . . 2019-12-25 18.79 18.44 18.59 18.60 207776.34 21.53 18.36 0.0 2019-12-26 18.76 18.46 18.69 18.60 189935.42 21.53 18.36 0.0 2019-12-27 19.43 18.58 18.74 19.28 504214.70 21.03 18.36 0.0 2019-12-30 19.50 18.92 19.24 19.38 379296.95 20.71 [731 rows x 8 columns] ""

Copy the code

3. Timing strategy is integrated into risk management factors to generate CalNdaysStopSignal.

The interfaces are described as follows:

# N day breakthrough timing strategy based on the introduction of risk management factors, can refer to "Timing Strategy into ATR Risk Management"
# input parameter
# :param Data: StockData individual stock price data
# :param data: N1 Policy parameter. The default is 15
# :param data: N2 Policy parameter, default is 5
# :param data: n_loss stop-loss policy parameter, default is 0.8
# :param data: n_win Stop profit policy parameter, default is 2
# output parameter
# :return data: Stock data in DataFrame format with trading signals added after normalization
# Note: This interface is for stock ex - rights data
Copy the code

The interface usage routine is as follows:

df_stock = CalNdaysStopSignal(df_stock, N1=15, N2=5, n_loss=0.8, n_win=2)
Copy the code

The stop-loss signal generated after calling the interface is as follows:

"" 17-03-09 Buy Price: 8.16 Stop Offer Price: 8.06 17-03-28 Buy price: 8.24 Stop Offer Price: 8.16 17-06-16 Buy price: 8.07 Stop Offer Price: 7.98 17-07-04 Buy Price: 8.31 Stop Selling Price: 8.17 17-11-14 Buy price: 7.74 Stop Selling Price: 7.62 17-11-23 Buy price: 7.95 Stop Selling Price: 7.77 18-02-01 Buy price: 8.32 Stop Selling Price: 8.04 18-05-30 Buy Price: 7.34 Stop Sell Price: 7.02 18-07-19 Buy Price: 6.53 Stop Sell Price: 6.33 18-11-20 Buy Price: 6.83 Stop Sell Price: 6.64 18-12-06 Buy Price: 7.52 Stop Selling Price: 7.27 19-01-08 Buy price: 7.82 Stop Selling Price: 7.6 19-02-28 buy price: 11.18 Stop Selling price: 10.6 19-03-13 Buy price: 14.22 Stop Selling price: 12.8 19-04-11 Buy Price: 14.84 Stop Selling Price: 14.03 19-05-07 Buy Price: 17.31 Stop Selling Price: 16.15 19-06-06 Buy price: 20.6 Stop Selling Price: 18.67 19-07-18 Buy Price: 20.25 Stop Selling Price: 19.1 19-09-06 Buy Price: 19.51 Stop Selling Price: 18.48 19-10-17 Buy price: 18.85 Stop Selling Price: 18.25 19-10-31 Buy price: 23.13 Stop Selling Price: 22.06 ""
Copy the code

The stock data returned after calling the interface looks like this:

""" High Low Open Close ... N1_High N2_Low atr14 signal trade_date ... 2017-01-03 8.12 8.07 8.07 8.12... 2017-01-04 8.16 8.09 8.13 8.15... 2017-01-05 8.23 8.13 8.15 8.17... 2017-01-06 8.19 8.12 8.18 8.13... 2017-01-09 8.15 8.08 8.13 8.13... 8.17 8.12 0.10 0.0.. . . . . . . . . 2019-12-25 18.79 18.44 18.59 18.60... 21.60 18.36 0.72 0.0 2019-12-26 18.76 18.46 18.69 18.60... 21.53 18.36 0.69 0.0 19.43 18.58 18.74 19.28... 21.53 18.36 0.70 0.0 0.0 19.50 18.92 19.24 19.38... 20.31 19.55 19.55 19.95... [731 rows x 9 columns] ""
Copy the code

4. Output policy back test report interface SimpleBackTest.

The interfaces are described as follows:

# Implement simple strategy backtest interface, refer to "Benefit and Risk dimensions measure strategy Effect"
# input parameter
# :param data: stockdata and trading signals
# :param data: code_name Stock name
# : Param data: Cash_hold back test funds
# output parameter
# :return data: Adds stock data in DataFrame format to the result of the backtest
Copy the code

The interface usage routine is as follows:

df_stock = SimpleBackTest(df_stock, "A New Hope".100000)
Copy the code

After calling the interface, the final capital, benchmark rate of return, stock trading records and other back test results can be printed.

""" New Hope retest result Final fund: 132180.0 Benchmark yield: 0.8988989891622865 Strategy yield: 0.046179711142093044 Maximum redraw point: trade_date 2019-10-18 0.58 ""
"" 17-01-03 bought 12,300 shares of New Hope 17-01-13 sold 12,300 shares of New Hope 17-02-10 bought 12,100 shares of New Hope 17-03-10 sold 12,100 shares of New Hope 17-03-24 bought 11,700 shares of New Hope 17-03-31 Sold 11,700 new Hope shares 17-06-13 bought 11,600 New Hope shares 17-07-18 sold 11,600 New Hope shares 17-11-03 Bought 12,500 New Hope shares 17-12-01 sold 12,500 New Hope shares 18-01-08 Buy 12,000 new Hope shares 18-02-02 Sell 12,000 New Hope shares 18-05-17 Buy 13,300 New Hope shares 18-05-31 Buy 13,300 New Hope shares 18-07-16 Buy 14,500 New Hope shares 18-08-02 sell New Hope shares 14,500 shares 18-11-05 New Hope 14,600 shares 18-11-28 New Hope 14,600 shares 18-11-29 New Hope 14,500 shares 18-12-18 New Hope 14,500 shares 19-01-07 New Hope 13,400 shares 19-03-15 Sold 13400 shares of New Hope 19-04-03 Bought 11100 shares of New Hope 19-05-06 bought 9400 shares of New Hope 19-05-09 sold 9400 shares of New Hope 19-05-31 I bought new Hope 7300 shares 19-06-24 sold new Hope 7300 shares 19-07-16 sold New Hope 6500 shares 19-09-02 sold New Hope 6200 shares 19-09-09 sold New Hope 6200 shares 19-10-11 Bought New Hope 6100 shares 19-10-21 sold New Hope 6100 shares 19-10-22 bought New Hope 6000 shares 19-11-18 sold New Hope 6000 shares ""
Copy the code

In addition, the return value of the interface adds dynamic backtest data for each trading day on top of stock data in DataFrame format.

""" total per_total max_total Close max_close trend_profit benchmark_profit trade_date 2017-01-03 99997.0 1.00 99997.0 NaN NaN 2017-01-04 100367.0 1.00 100367.0 8.15 8.15 3.69E-03 3.69E-03 2017-01-05 100613.0 1.00 100613.0 8.17 8.17 2.45E-03 2.45E-03 2017-01-06 100120.0 1.00 100613.0 8.13 8.17-4.91E-03-4.91E-03 2017-01-09 100120.0 1.00 100613.0 8.13 8.17 0.00 0.00 e+00 e+00.. . . . . . . $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$+ 1 $$ 0.00e+00 2019-12-27 146829.0 0.74 198468.0 19.28 29.20 0.00e+00 3.59e-02 146829.0 0.74 198468.0 19.38 23.20 [731 rows x 7 columns] """
Copy the code

5. Visual interface of policy backtest effect DrawBackTest, which outputs the backtest result in the form of chart.

The interfaces are described as follows:

# Implement simple strategy backtest interface, refer to "Benefit and Risk dimensions measure strategy Effect"
# input parameter
# :param data: dF_StockLoad Stock data/trading signals/backtest results data
# :param data: code_name Stock name
Copy the code

The interface usage routine is as follows:

DrawBackTest(df_stock, "A New Hope")
Copy the code

After the interface is called, the result of the back test is displayed in the form of a graph.

6. Account class ST_Account, which provides interfaces such as the remaining funds, number of shares held, total assets and trading operations of the current account.

The constructor looks like this:

# Refer to "Timing Into ATR Dynamic Position Management"
def __init__(
        self,init_hold={},
        init_cash=1000000,
        commission_coeff=0,
        tax_coeff= 0):
    """ :param [dict] init_hold Stock assets for initialization :param [float] init_cash: Funds for initialization :param [float] commission_coeff: Param [float] tax_COeff: Stamp Duty: Default thousand 1.5(float type 0.001) Here routine is set to 0 ""
    self.hold = init_hold
    self.cash = init_cash
Copy the code

Create an instance of the account as follows:

account_a = ST_Account(dict(), 100000) Number of shares and initial capital of Account A

account_b = ST_Account(dict(), 100000) # Number of shares and initial capital of Account B

Copy the code

7. ATR position management and dynamic position management interfaces are completed by the draw_graph class and run_ADD_POStion class respectively.

Draw_graph includes methods to calculate daily transactions in an account, draw an account yield curve, and so on.

The run_add_postion class inherits draw_graph and adds dynamic position management methods. To demonstrate the effectiveness of ATR position management and dynamic position management, we observe two money accounts in the draw_graph class by default. One account performs full position buying and selling, and the other account performs position management.

The test routine is as follows:

# Refer to "Timing Into ATR Dynamic Position Management"
test_kind = u"test1"  # test1:ATR position/test2: dynamic position adjustment
fig = plt.figure(figsize=(16.8), dpi=100, facecolor="white") # create a FIG object
if test_kind == u"test1": # the ATR positions
    app_graph_a = draw_graph(fig, df_stock, "600410.SS")
    app_graph_a.draw_config()
else: # Dynamic positioning
    app_graph_b = draw_add_postion(fig, df_stock, "600410.SS")
    app_graph_b.draw_config()
plt.show()
Copy the code

For example, calling an instance of draw_graph will output the results of the back test as a graph.

For example, calling an instance of draw_add_POStion outputs dynamic position adjustments.

17-02-10 Account A buying price: 8.13 Number of shares bought: 12300 17-02-10 Account B buying price: 8.13 Number of shares bought: 11822 720 17-02-15 Account B reducing price: 8.16 Reducing number of shares: 810 17-02-20 Account B reducing price: 8.26 Reducing number of shares: 804 17-02-24 Account B increasing price: 8.19 Increasing number of shares: 551 17-03-03 Account B increasing price: 8.11 Number of Shares Added: 831 17-03-06 Number of Shares Added: 815 Number of Shares Added: 526 17-03-10 Account A Selling Price: 8.06 Number of Shares sold: 12300 17-03-10 Account B Selling Price: 8.06 Number of shares sold: 12836...... 19-10-11 Account B Bought Price: 18.62 Number of Shares Bought: 1368 19-10-18 Account A Sold Price: 18.06 Number of shares Sold: 5267 19-10-18 Account B Sold Price: 18.06 Number of shares sold: 1368 19-10-22 Account A Bought Price: 19.3 Shares Bought: 4929 19-10-22 Account B Bought Price: 19.3 Shares Bought: 1407 19-11-01 Account A Sold Price: 22.09 Shares Sold: 4929 19-11-01 Account B Sold Price: 22.09 Shares Sold: 1407 ""
Copy the code

conclusion

All of these topics are covered in the course, and we provide you with an “index” designed to match them to their location in the course.

Students can use the reference section of the course to test their own, through this process to enable them to have a more comprehensive grasp of quantitative trading backtest.

Only through their own hands-on practice, in order to have a deeper understanding, of course, we have also provided the collated back test framework source code, there is a need for comparative analysis of the students can be in the group of private letters TO me.

The above strategies and the stocks involved are for educational purposes only and do not constitute any investment advice! Investment needs to be cautious, entering the market is risky!!

Subscribe for more quantitative trading contentSmall volumesRead!!!!!

You are also welcome to follow my wechat official account to learn more about Python quantitative trading