Author: ABU

All rights reserved

ABU quantization system Github address (welcome +star)

This section ipython notebook

While the previous section looked at sample strategies written based on the characteristics of the Bitcoin market, this section looks at examples of cross-market statistical arbitrage in quantitative trading.

Thomas Peterffy, the father of algorithmatic trading, had some of his greatest success using the fastest computers of the day, renting a proprietary telephone line to keep data flowing, and even using statistical arbitrage to hedge strategies in different markets, ahead of his time with custom counter-rebellion computers.

This is the most guaranteed history of quantitative trading, in which the use of technology in the market can actually be profitable.

However, this strategy is certainly not applicable today, because of the continuous progress of technology, the continuous transparency of technology, the rapid development of the information society, automated trading accounts for more than 60% of the volume of the U.S. stock market. In The United States, many HIGH-FREQUENCY traders build their own communications networks by drilling holes in the bottom of the Pacific Ocean in order to improve communication speed by a few milliseconds. There are also exclusive network providers specializing in dark optical fiber, whose network lease costs tens of millions of dollars a year. In this environment, is there no chance for individual quantitative investors?

1. Metal futures in London futures market and domestic futures market

The examples in this section are low-frequency statistical arbitrage strategies suitable for individual quantitative traders. The target markets are metal futures in London futures market and domestic futures market.

Obtain London metal futures symbol data as follows:

gb = AbuFuturesGB()
metal_gb = gb.futures_gb_df[
                  (gb.futures_gb_df['product'] = ='London lead') |
                  (gb.futures_gb_df['product'] = ='London zinc') |
                  (gb.futures_gb_df['product'] = ='London Aluminium') |
                  (gb.futures_gb_df['product'] = ='London Copper') |
                  (gb.futures_gb_df['product'] = =London Gold) |
                  (gb.futures_gb_df['product'] = =London Silver) 
                 ]
metal_gbCopy the code

Next obtain the domestic metal futures symbol data:

cn = AbuFuturesCn()
metal_cn = cn.futures_cn_df[
                  (cn.futures_cn_df['product'] = ='Shanghai lead') |
                  (cn.futures_cn_df['product'] = ='Shanghai zinc') |
                  (cn.futures_cn_df['product'] = ='Shanghai aluminum') |
                  (cn.futures_cn_df['product'] = ='Shanghai') |
                  (cn.futures_cn_df['product'] = ='gold') |
                  (cn.futures_cn_df['product'] = ='silver') 
                  ]
metal_cnCopy the code

The following is a cross-market pairing of two metal futures. First visualize the trend, and it can be seen that the trend of each pair of futures market follows closely:

from ipywidgets import interact

def do_plot_pair_metal(mt_cn, mt_gb):
    gb_data = ABuSymbolPd.make_kl_df(mt_gb, start='2011-07-28', end='2017-07-26')
    cn_data = ABuSymbolPd.make_kl_df(mt_cn, start='2011-07-28', end='2017-07-26')
    ABuMarketDrawing.plot_simple_two_stock({mt_gb: gb_data, mt_cn: cn_data})
def plot_pair_metal(pairs):
    pair = pairs.split('vs')
    do_plot_pair_metal(pair[0], pair[1])

pairs = ['CADvsCU0'.'XAUvsAU0'.'ZN0vsSND'.'AHDvsAL0'.'XAGvsAG0'.'PBDvsPB0']

_ = interact(plot_pair_metal, pairs=pairs)Copy the code

In case of cross-market high-frequency trading, it needs very good equipment to make trading decisions quickly by staring at the data of the trade position, and also has requirements on the amount of capital. The example in this section is the cross-market low-frequency statistical arbitrage example suitable for individual quantitative traders.

Observe the above each pair of trend curve, such as CAD vs CU0, you can find CU0 sensitive significantly faster than the speed of the CAD of the trend, and is a high frequency of fast, namely the blue line above the trend break down first, trend rises up first, then we can think of CAD in following CU0, not under the high frequency with low frequency statistical arbitrage opportunities.

2. Sensitive rate of trend change

It is impossible to actually observe each one with the naked eye, and it is impossible to quantify the trend-sensitive speed, that is, to determine whether low-frequency statistical arbitrage opportunities really exist.

For quantitative trading, the advantage is to obtain the probability advantage and trade with the advantage of market breadth through the powerful computing power of computers. The following example is how to use the API in ABupy to calculate the sensitive speed of trend change, as shown below:

Note: See calc_pair_speed in the TL module to calculate the trend speed

speed_pair = tl.execute.calc_pair_speed('CU0'.'CAD', 
                                        start='2011-07-28', end='2016-07-26', show=True)
speed_pair[0], speed_pair[1]Copy the code
(0.57260273972602738, 0.52328767123287667)Copy the code

The above calculation result 0.57 is the sensitivity rate of CU0 to trend change, and 0.52 is the sensitivity rate of CAD to trend change, that is, the sensitivity of CU0 to trend change is greater than CAD, and greater than 0.03 has the condition of low-frequency statistical arbitrage. (A value greater than 0.05 is considered as a safe low-frequency statistical arbitrage opportunity, and these thresholds will be explained in the following chapters)

In the case of low-frequency statistical arbitrage, CAD will be used as the trading target, and CU0 will be used as the trend weathervane because of its high sensitivity. A dictionary will be initialized below, where key is the CAD that will be used as the trading target and value is the trend weathervane CU0, as shown below:

pair_dict = {}
pair_dict['CAD'] = 'CU0'Copy the code

The sensitivity rates of Shanghai aluminum (AL0) and London aluminum (AHD) to trend changes are calculated as follows:

speed_pair = tl.execute.calc_pair_speed('AL0'.'AHD', 
                                        start='2011-07-28', end='2016-07-26', show=True)
speed_pair[0], speed_pair[1]Copy the code
(0.61643835616438358, 0.57808219178082187)Copy the code

The above calculation result 0.61 is the sensitivity rate of Shanghai aluminum (AL0) to trend changes, and 0.57 is the sensitivity rate of London aluminum (AHD) to trend changes, that is, the sensitivity of AL0 to trend changes is greater than AHD, and greater than 0.03 has the condition of low-frequency statistical arbitrage.

In the dictionary, key is the low sensitive AHD that will be used as the trading target, and value is the high sensitive AL0 that will be used as the trend indicator, as shown below:

pair_dict['AHD'] = 'AL0'Copy the code

The sensitivity rates of domestic gold (AU0) and London gold (XAU) to trend changes are calculated as follows:

speed_pair = tl.execute.calc_pair_speed('AU0'.'XAU', 
                                        start='2012-07-28', end='2016-07-26', show=True)
speed_pair[0], speed_pair[1]Copy the code
(0.58075601374570451, 0.61512027491408938)Copy the code

According to the above calculation result, 0.58 is the sensitive speed of domestic gold (AU0) to trend change, and 0.61 is the sensitive speed of London gold (XAU) to trend change, that is, the sensitive speed of external disk is faster than that of domestic futures trend change, and the previous two are the sensitive speed of domestic futures trend change is faster than that of external disk.

In the dictionary, key is the low sensitive domestic gold (AU0) that will be used as a trading target, and value is the high sensitive London gold (XAU) that will be used as a trend indicator, as shown below:

pair_dict['AU0'] = 'XAU'Copy the code

The sensitivity of domestic silver (AG0) and London silver (XAG) to trend changes is calculated as follows:

speed_pair = tl.execute.calc_pair_speed('AG0'.'XAG', 
                                        start='2012-07-28', end='2016-07-26', show=True)
speed_pair[0], speed_pair[1]Copy the code
(0.5532646048109966, 0.60137457044673537)Copy the code

The above calculation result 0.55 is the sensitive speed of domestic silver (AG0) to trend changes, and 0.60 is the sensitive speed of London silver (XAG) to trend changes, that is, the sensitive speed of silver’s outer plate is faster than that of domestic futures.

In the dictionary, key is the low sensitive domestic silver (AG0) that will be used as a trading target, and value is the high sensitive London silver (XAG) that will be used as a trend indicator, as shown below:

pair_dict['AG0'] = 'XAG'Copy the code

The sensitivity rates of Shanghai zinc (ZN0) and London zinc (SND) to trend changes are calculated as follows:

speed_pair = tl.execute.calc_pair_speed('ZN0'.'SND', 
                           start='2011-07-28', end='2016-07-26', show=True)
speed_pair[0], speed_pair[1]Copy the code
(0.57260273972602738, 0.53424657534246578)Copy the code

In the dictionary, key is low sensitive London zinc (SND) that will be used as a trading target, and value is high sensitive Shanghai zinc (ZN0) that will be used as a trend indicator, as shown below:

pair_dict['SND'] = 'ZN0'Copy the code

The sensitivity rates of Shanghai lead (PB0) and London lead (PBD) to trend changes are calculated as follows:

speed_pair = tl.execute.calc_pair_speed('PB0'.'PBD', start='2011-07-28', end='2016-07-26', show=True)
speed_pair[0], speed_pair[1]Copy the code
(0.50410958904109593, 0.59999999999999998)Copy the code

In the above calculation, 0.50 is the speed at which Shanghai lead (PB0) is sensitive to trend change, and 0.59 is the speed at which London lead (PBD) is sensitive to trend change. The difference value reaches 0.09, far greater than 0.03, which is a very good low-frequency statistical arbitrage matching.

In the dictionary, key is low sensitive Shanghai lead (PB0) that will be used as a trading target, and value is high sensitive London lead (PBD) that will be used as a trend indicator, as shown below:

pair_dict['PB0'] = 'PBD'Copy the code

The trade matching dictionary of cross-market low-frequency statistical arbitrage is selected above. Key is the low sensitivity of the transaction target, and value is the high sensitivity of the trend target, as follows:

pair_dictCopy the code
{'AG0': 'XAG'.'AHD': 'AL0'.'AU0': 'XAU'.'CAD': 'CU0'.'PB0': 'PBD'.'SND': 'ZN0'}Copy the code

3. Breakthrough strategy based on cross-market low-frequency statistical arbitrage

Timing trading strategies are written to achieve trade pairing of this cross-market low-frequency statistical arbitrage, as shown below:

class AbuFactorBuyPairBreak(AbuFactorBuyXD, BuyCallMixin):
    Example of cross-market low-frequency statistical arbitrage Strategy
    def _init_self(self, **kwargs):
        # Get high-sensitivity targets as trend indicators from the dictionary as low-sensitivity trading targets
        pair_symbol = pair_dict[self.kl_pd.name]
        # Obtain the financial time series of highly sensitive trading targets as trend markers
        self.pair_kl_pd = ABuSymbolPd.make_kl_df(
            pair_symbol, data_mode=EMarketDataSplitMode.E_DATA_SPLIT_UNDO,
            benchmark=self.benchmark)
        # Whether to buy today or lower the frequency and buy tomorrow
        self.td_buy = kwargs.pop('buy_today'.True)
        # set the breakout cycle parameter like trend breakout strategy code, eg: 21,42...
        self.xd = kwargs['xd']

    def fit_day(self, today):
        # Get today's trading data for highly sensitive targets as trend indicators
        pair_today = self.pair_kl_pd.iloc[self.today_ind]
        # High sensitive as trend indicators broke today, buying low sensitive targets
        if pair_today.close == self.pair_kl_pd.close[self.today_ind - 
                                                     self.xd + 1:self.today_ind + 1].max():
            # Generate buy orders, pure low frequency, buy tomorrow, can also buy today, because it is cross-market
            return self.buy_today() if self.td_buy else self.buy_tomorrow()
        return NoneCopy the code

The only difference between AbuFactorBuyPairBreak and the periodic breakout strategy AbuFactorBuyBreak used in previous chapters is that the breakout signal sender is the highly sensitive target of the trend index. Once the high-sensitive target breaks through today, it buys the low-sensitive trading target.

This buying strategy is used for backtesting, and the selling strategy remains the same as before, as shown below:

read_cash = 10000000
# Sell factor continues with the factor used in the previous section
sell_factors = [
    {'stop_loss_n': 1.0.'stop_win_n': 3.0.'class': AbuFactorAtrNStop},
    {'class': AbuFactorPreAtrNStop, 'pre_atr_n': 1.5},
    {'class': AbuFactorCloseAtrNStop, 'close_atr_n': 1.5}]# Buy strategy uses AbuFactorBuyPairBreak
buy_factors = [{'xd': 5.'class': AbuFactorBuyPairBreak},
               {'xd': 10.'class': AbuFactorBuyPairBreak}]

abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
                                                   buy_factors,
                                                   sell_factors,
                                                   start='2016-07-26', 
                                                   end='2017-07-26',
                                                   choice_symbols=pair_dict.keys(),
                                                   n_process_pick=1)
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)Copy the code
Number of trades bought and sold :202 Number of trades bought and not yet sold :28 Win percentage :47.5248% Average Profit Expectation :4.6478% Average Loss Expectation :-3.1876% BREAK-even ratio :1.2979 Strategic Return: 11.2057% Benchmark Return: -2.2138% Strategy annualized Return: 11.5731% Benchmark annualized return: -2.2864% Strategy buy/close Ratio :28.2609% Strategy fund utilization ratio :81.4983% Strategy executed for 244 trading daysCopy the code

The results of back-test are shown above. Compared with the back-test of ordinary breakthrough strategy without statistical arbitrage of internal and external disks, it can be seen that the back-test effect is greatly improved, as shown below:

buy_factors = [{'xd': 5.'class': AbuFactorBuyBreak},
               {'xd': 10.'class': AbuFactorBuyBreak}]

abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
                                                   buy_factors,
                                                   sell_factors,
                                                   start='2016-07-26', 
                                                   end='2017-07-26',
                                                   choice_symbols=pair_dict.keys())
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)Copy the code
Number of trades bought and sold :201 Number of trades bought and not yet sold :26 Win rate :39.3035% Average Profit expectation :4.7833% Average Loss Expectation :-3.2777% BREAK-even Ratio :0.9362 Strategic Return: 3.9885% Benchmark Return: -2.2138% Strategy annualized return: 4.1193% Benchmark annualized return: -2.2864% Strategy buy volume ratio :25.1101% Strategy fund utilization ratio :80.1697% Strategy executed for 244 trading daysCopy the code

And even if the trading frequency is reduced again and the time advantage of cross-market arbitrage is not used and the trading target is bought on another day, namely the following construction factor parameter buy_today=False, it can be seen that the back test result is still better than that of the ordinary breakthrough strategy without the statistical arbitrage of internal and external market.

# Buy strategy uses AbuFactorBuyPairBreak
buy_factors = [{'xd': 5.'class': AbuFactorBuyPairBreak, 'buy_today': False},
               {'xd': 10.'class': AbuFactorBuyPairBreak, 'buy_today': False}]

abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
                                                   buy_factors,
                                                   sell_factors,
                                                   start='2016-07-26', 
                                                   end='2017-07-26',
                                                   choice_symbols=pair_dict.keys(), 
                                                   n_process_pick=1)
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)Copy the code
Number of trades bought and sold :199 Number of trades bought and not yet sold :28 Win Percentage :41.7085% Average Profit Expectation :4.7901% Average Loss Expectation :-3.2208% BREAK-even Ratio :1.0460 Strategic Return: 10.2191% Benchmark Return: -2.2138% Strategy annualized return: 10.5542% Benchmark annualized return: -2.2864% Strategy buy volume ratio :26.8722% Strategy fund utilization ratio :80.0871% Strategy executed for 244 trading daysCopy the code

4. Paired low-frequency statistical arbitrage in other markets

The above paired statistical arbitrage based on the futures market is based on one condition: the futures products of the two markets are highly correlated, which is naturally true for the futures market, but it needs to be verified from the correlation for other markets. As follows, calc_pair_speed is used to calculate the trend change sensitivity speed of bitcoin and Litecoin:

speed_pair = tl.execute.calc_pair_speed('btc'.'ltc', 
                           start='2014-03-19', end='2017-07-26', show=True)
speed_pairCopy the code
(0.59999999999999998, 0.58367346938775511, 0.78994253276843451)Copy the code

The first result 0.599 is the trend-sensitive rate of BTC, 0.583 is the trend-sensitive rate of LTC, and the third value 0.78 is the correlation value of BTC and LTC.

The speed difference between BTC and LTC is calculated as follows:

(0.599 - 0.583) * 0.78Copy the code
0.012480000000000012Copy the code

It can be seen that the results do not meet the conditions of matching low-frequency statistical arbitrage. In fact, the pairing of futures products such as ZN0 and SND in the example above also do not meet the conditions of low-frequency statistical arbitrage, as follows:

speed_pair = tl.execute.calc_pair_speed('ZN0'.'SND', 
                           start='2011-07-28', end='2016-07-26', show=False)
print(speed_pair)
(speed_pair[0] - speed_pair[1]) * speed_pair[2]Copy the code
0.012278534955254709 (0.57260273972602738, 0.53424657534246578, 0.32011894704771243)Copy the code

Poor results shown above, even if the calculation speed, to meet the low frequency of statistical arbitrage conditions, but because of the low correlation, the result is not reliable, namely in the first round of the correlation threshold in practical strategy is filter conditions, meet the above may only be used under the condition of a certain threshold calculation interface, sample after chapter how the change of comprehensive utilization in the stock market trend of speed, Correlation to carry out low frequency matching statistical arbitrage, please pay attention to the tutorial update reminder in the public account

ABU quantization document catalog chapter

  1. Development of timing strategies
  2. Optimization of timing strategies
  3. Slippage strategies and transaction fees
  4. A number of stock timing back test and position management
  5. Development of stock selection strategy
  6. Measurement of back test results
  7. Search for optimal policy parameters and scores
  8. A – share market back test
  9. Hong Kong stock market back test
  10. Bitcoin, litecoin back test
  11. Backtesting of futures markets
  12. Machine learning and Bitcoin examples
  13. Application of quantitative technology analysis
  14. Quantitative correlation analysis is applied
  15. Quantitative trading and search engines
  16. UMP presided over transaction decisions
  17. UMP linesman trade decision
  18. Custom referee decision trades
  19. The data source
  20. A – share market back test
  21. A-share UMP decision
  22. Us stock market back test
  23. United States stock UMP decision

ABU quantization system documentation tutorial continues to update, please pay attention to the update reminder in the public account.

For more information about ABU quantization system, please follow the wechat official account abu_quant