头图

image

Preface

Four articles have been written in the " WonderTrader Architecture Detailed Explanation" series. For a lazy person like the author, it is really a big project. This is not the first time being introduced architecture, the article will introduce you about how WonderTrader written on a arbitrage strategies across species , aims to show you what WonderTrader general pattern of the underlying strategy of multi, also introduced I look at wtpy latest version v0.6.3 in the latest release of performance analysis module .

List of WonderTrader architecture articles:

Introduction to arbitrage strategy

I believe that everyone who does quantification has studied arbitrage strategies. Arbitrage strategy is favored by most people because of its relatively simple logic and relatively stable returns. At the same time, the arbitrage strategy and the trend strategy are highly complementary, which means that if they are properly coordinated, they can greatly promote the smoothing of the yield curve, reduce the fluctuation of performance, and improve the Sharpe.
There are many classifications of arbitrage strategies. The author once quoted Dr. Ding Peng's " Quantitative Investment-Strategies and Technology " in the WonderTrader Architecture Detailed 4-Talking about Platform Support There are many kinds of arbitrage models mentioned in the classification of arbitrage, such as: cash-in-period, inter-period, cross-variety, pair trading, etc.
In order to develop this strategy, the author saw a point of view when looking up the information, and was deeply : 1609b51ae27a20 No matter how complicated the classification of arbitrage strategies, the essence of arbitrage strategy is to find trading opportunities fluctuation of the spread between different contracts.

Arbitrage strategy implementation

Strategy design

In view of the fact that the author’s skill tree for quantitative strategies has not been illuminated yet, the strategy examples in this article are learned from the Internet. The author would like to sincerely thank the sharers of this strategy. The basic design of the strategy is as follows:

  • The contract pair chooses the main continuous contract of rebar SHFE.rb.HOT and the main continuous contract of iron ore DCE.i.HOT
  • The back-test data is the main continuous data, which has been re-weighted to prevent the spread change caused when the main contract is not synchronized.
  • Based . 1 minute data , past N minutes closing price two sequences linear regression to obtain a coefficient beta , a constant c and a residual sequence
  • ADF test on the residual sequence. If the residual sequence is a stationary sequence, enter the signal calculation logic
  • Calculate the new residual based on the obtained coefficient beta and constant c , and the latest price
  • When the new residuals exceed a threshold , admission signal is triggered when then spread back to within the threshold is triggered exit signals

Strategy implementation

  • Parameter design
    According to the above introduction, the core parameters of the strategy are as follows:

    • code1 : Arbitrage contract 1, set to SHFE.rb.HOT
    • code2 : Arbitrage contract 2, set to DCE.i.HOT
    • period : data period, set to m1 this example, that is, one minute line
    • threshold : threshold, set to 0.9
    • N : The number of K lines counted. In this example 360 , which is the one-minute line of a trading day
    • bar_cnt : The number of K lines read by the strategy, which is greater than N , and the main consideration is to reserve space for scrolling calculations
    def __init__(self, name:str, code1:str, code2:str, bar_cnt:int, 
                            period:str, N:int, threshold:float=1):
        BaseCtaStrategy.__init__(self, name)
    
        self.__n__ = N
        self.__threshold__ = threshold
    
        self.__period__ = period
        self.__bar_cnt__ = bar_cnt
        self.__code_1__ = code1
        self.__code_2__ = code2
  • Cointegration test
    The core logic of the strategy lies in the co-integration test and . Only when the co-integration test passes can the signal trigger.

    # 协整检验函数
    def cointegration_check(series01, series02):
        # 对两个序列分别进行ADF检验
        urt_1 = ts.adfuller(np.array(series01), 1)[1]
        urt_2 = ts.adfuller(np.array(series02), 1)[1]
    
        # 同时平稳或不平稳则差分再次检验
        if (urt_1 > 0.1 and urt_2 > 0.1) or (urt_1 < 0.1 and urt_2 < 0.1):
            urt_diff_1 = ts.adfuller(np.diff(np.array(series01)), 1)[1]
            urt_diff_2 = ts.adfuller(np.diff(np.array(series02), 1))[1]
    
            # 同时差分平稳进行OLS回归的残差平稳检验
            if urt_diff_1 < 0.1 and urt_diff_2 < 0.1:
                matrix = np.vstack([series02, np.ones(len(series02))]).T
                beta, c = np.linalg.lstsq(matrix, series01, rcond=None)[0]
                resid = series01 - beta * series02 - c
                # 最后对残差序列再进行ADF检验
                if ts.adfuller(np.array(resid), 1)[1] > 0.1:
                    result = False
                else:
                    result = True
                return beta, c, resid, result
            else:
                result = False
                return 0.0, 0.0, 0.0, result
    
        else:
            result = False
            return 0.0, 0.0, 0.0, result
  • Signal
    When the residual exceeds the upper boundary, it means that the residual is positively expanded . According to the characteristics of the residual mean regression, then is required to short the spread ; on the contrary, when the residual exceeds the lower boundary, it means that the residual is reversed expansion , then we need do more spread ; when to participate in the upper and lower boundaries of the range, then cleared away the existing position, waiting for the next opportunity.

    # 计算新残差
    resid_new = close_ay1[-1] - self.beta * close_ay2[-1] - self.c
    
    if resid_new > self.up and curPos1 != 1:
        context.stra_log_text("[%d.%04d]残差正向扩大,做空价差" % (curDate, curTime))
        context.stra_enter_short(self.__code_1__, 1, 'OpenSA')
        context.stra_enter_long(self.__code_2__, 1, 'OpenLB')
    
    elif resid_new < self.down and curPos1 != -1:
        context.stra_log_text("[%d.%04d]残差反向扩大,做多价差" % (curDate, curTime))
        context.stra_enter_long(self.__code_1__, 1, 'OpenLA')
        context.stra_enter_short(self.__code_2__, 1, 'OpenSB')
    
    elif curPos1 != 0 and self.down  <= resid_new and resid_new <= self.up:
        context.stra_log_text("[%d.%04d]残差回归,清掉头寸" % (curDate, curTime))
        context.stra_set_position(self.__code_1__, 0, 'CutA')
        context.stra_set_position(self.__code_2__, 0, 'CutB')

Strategy backtest

回测示意图

Performance Analysis

In this example, wtpy in the v0.6.3 version is used for analysis. The calling method is basically the same as the old version, but the analysis entry has changed.

analyst = WtBtAnalyst()
analyst.add_strategy("t1_rb_i", folder="./outputs_bt/t1_rb_i/", init_capital=350000, rf=0.02, annual_trading_days=240)
# 绩效分析的入口,老版本run的仍然可用
analyst.run_new()

Performance analysis screenshot
绩效分析截图

Summary of Strategic Performance
策略绩效概要

Detailed transaction list
详细交易列表

Overall transaction analysis
总体交易分析

Continuous transaction analysis
连续交易分析

Income distribution
收益分布

Daily performance analysis
日度绩效分析

Other cycle performance
其他周期绩效

Daily performance overview
逐日绩效概览

As can be seen from the foregoing, the new version of the performance analysis module provides more dimensional analysis functions . The new version of the performance analysis module mainly refers to MultiCharts , so the comprehensiveness and practicability of the analysis results should be guaranteed.
Going back to the strategy itself, it can be seen from the previous performance report that the strategy is obviously not very successful. How to optimize this strategy? The author considers whether it can be adding stop-profit and stop-loss logic , or by adjusting the threshold . However, these are beyond the purpose of this article. If you are interested, you can research on your own.

Strategy acquisition

The example strategy in this article has been shared under /demos/cta_arbitrage_bt in the wtpy project on github, and interested friends can download it by themselves. click here to jump

Concluding remarks

This concludes the introduction of using WonderTrader write arbitrage strategies. The author feels uneasy while writing an article today. Although the author has been working with everyone in an excellent quantitative team, because the author is engaged in technical work, the understanding of the strategy is still on the surface after all, so I am afraid that the strategy shared today has made a low-level error. Fortunately, the author finally decided to find a ready-made strategy from the Internet, which slightly alleviated the author's anxiety. Even so, this article and the strategies demonstrated in this article will inevitably have errors and omissions, and I hope that all viewers can include their corrections. Fortunately, the ultimate goal of this article is to cause everyone to find more "beautiful jade" through the "bricks" thrown by the author today. If it can be of benefit to everyone, it would be great.

Finally, Amway WonderTrader
WonderTrader aims to provide better wheels for all quantitative practitioners, encapsulate technology-related things in the platform, create a more efficient underlying framework, and strive to bring better strategy development and trading experience to strategy research and development.

WonderTrader of github address: https://github.com/wondertrader/wondertrader

WonderTrader official website address: https://wondertrader.github.io

wtpy of github address: https://github.com/wondertrader/wtpy


market is risky and investment needs to be cautious. The above statement only serves as a review of historical events, does not represent an opinion on the future, and does not serve as any investment advice.


WonderTrader
31 声望23 粉丝