0%

【Quantaxis】QAStrategy回测

回测中使用的模块

  • QAStrategy

示例

Quantaxis 版本为 1.10.19。仍以 MACD_JCSC 策略进行回测。

创建 Strategy 类回测

在原 QAStrategy 回测文档中,多使用在 on_bar 函数中处理每一条 bar 数据,生成指标或回测信号。如下例代码所示的回测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from QAStrategy.qastockbase import QAStrategyStockBase
import QUANTAXIS as QA
from Risk_util import QA_Risk_Abstract
from collections import deque
import pandas as pd
import datetime
from rich import print


class MACD_JCSC(QAStrategyStockBase):
def on_bar(self, bar):
res = self.macd_jcsc()
print(res)
print(res.iloc[-1])

if res.iloc[-1].CROSS_JC == 1:
print("[%s] %s 出现买入信号!!!" % bar.name)
if self.get_positions(bar.name[1]).volume_long == 0:
self.send_order("BUY", "OPEN", code=bar.name[1], price=bar.close, volume=1000)
print("交易:以%.2f价格买入!!!" % bar.close)
elif res.iloc[-1].CROSS_SC == 1:
print("[%s] %s 出现卖出信号!!!" % bar.name)
if self.get_positions(bar.name[1]).volume_long > 0:
self.send_order("SELL", "CLOSE",code=bar.name[1], price=bar.close, volume=1000)
print("交易:以%.2f价格卖出!!!" % bar.close)

def macd_jcsc(self, SHORT=12, LONG=26, M=9):
"""
1.DIF向上突破DEA,买入信号参考。
2.DIF向下跌破DEA,卖出信号参考。
"""
CLOSE = self.market_data.close
DIFF = QA.EMA(CLOSE, SHORT) - QA.EMA(CLOSE, LONG)
DEA = QA.EMA(DIFF, M)
MACD = 2*(DIFF-DEA)

CROSS_JC = QA.CROSS(DIFF, DEA)
CROSS_SC = QA.CROSS(DEA, DIFF)
ZERO = 0
return pd.DataFrame({'DIFF': DIFF, 'DEA': DEA, 'MACD': MACD, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC, 'ZERO': ZERO})

st1=datetime.datetime.now()
print('开始回测 -- {}'.format(datetime.datetime.now()))
code_list = ['000001']
#code_list = QA.QA_fetch_stock_list_adv().code.tolist()

s = MACD_JCSC(
code = code_list,
frequence = 'day',
start = '2019-01-01',
end = '2024-06-27',
strategy_id = 's-without_unit_init',
)


#s.debug() //不保存进数据库
#s._debug_sim() //模拟盘测试
s.run_backtest()
r = QA_Risk_Abstract(QA.QA_Risk(s.acc))
print('[bold magenta][风险指标][/bold magenta]')
print(r.message)
p = QA.QA_Performance(s.acc)
print('[bold magenta][绩效指标][/bold magenta]')
print(p.base_message(p.pnl))
print('回测耗时 -- {}'.format(datetime.datetime.now()-st1))

但对于像MACD这类指标,会使用前N天(比如26天)的数据进行计算,在生成market_data时,该数据在回测时即提取的历史数据源,在模拟/实盘时为行情数据。根据它的定义

1
2
3
4
5
6
7
@property
def market_data(self):

if self.running_mode == 'sim':
return self._market_data
elif self.running_mode == 'backtest':
return pd.concat(self._market_data[-100:], axis=1, sort=False).T
会使用最后100条记录生成 DataFrame。所以在计算MACD时,指标会随着数据的更新发生一些变化。

  • 但数据不足100条时的计算情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
                        DIFF       DEA      MACD  CROSS_JC  CROSS_SC  ZERO
2019-01-02 000001 NaN NaN NaN 0 0 0
2019-01-03 000001 NaN NaN NaN 0 0 0
2019-01-04 000001 NaN NaN NaN 0 0 0
2019-01-07 000001 NaN NaN NaN 0 0 0
2019-01-08 000001 NaN NaN NaN 0 0 0
2019-01-09 000001 NaN NaN NaN 0 0 0
2019-01-10 000001 NaN NaN NaN 0 0 0
2019-01-11 000001 NaN NaN NaN 0 0 0
2019-01-14 000001 NaN NaN NaN 0 0 0
2019-01-15 000001 NaN NaN NaN 0 0 0
2019-01-16 000001 NaN NaN NaN 0 0 0
2019-01-17 000001 NaN NaN NaN 0 0 0
2019-01-18 000001 NaN NaN NaN 0 0 0
2019-01-21 000001 NaN NaN NaN 0 0 0
2019-01-22 000001 NaN NaN NaN 0 0 0
2019-01-23 000001 NaN NaN NaN 0 0 0
2019-01-24 000001 NaN NaN NaN 0 0 0
2019-01-25 000001 NaN NaN NaN 0 0 0
2019-01-28 000001 NaN NaN NaN 0 0 0
2019-01-29 000001 NaN NaN NaN 0 0 0
2019-01-30 000001 NaN NaN NaN 0 0 0
2019-01-31 000001 NaN NaN NaN 0 0 0
2019-02-01 000001 NaN NaN NaN 0 0 0
2019-02-11 000001 NaN NaN NaN 0 0 0
2019-02-12 000001 0.201445 NaN NaN 0 0 0
2019-02-13 000001 0.213348 NaN NaN 0 0 0
2019-02-14 000001 0.212171 NaN NaN 0 0 0
2019-02-15 000001 0.190256 NaN NaN 0 0 0
2019-02-18 000001 0.196467 NaN NaN 0 0 0
2019-02-19 000001 0.193391 NaN NaN 0 0 0
2019-02-20 000001 0.197590 NaN NaN 0 0 0
2019-02-21 000001 0.195407 0.197895 -0.004975 0 0 0
2019-02-22 000001 0.202954 0.199063 0.007781 1 0 0
  • 数据大于100条后的计算情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
                       DIFF       DEA      MACD  CROSS_JC  CROSS_SC  ZERO
2019-01-07 000001 NaN NaN NaN 0 0 0
2019-01-08 000001 NaN NaN NaN 0 0 0
2019-01-09 000001 NaN NaN NaN 0 0 0
2019-01-10 000001 NaN NaN NaN 0 0 0
2019-01-11 000001 NaN NaN NaN 0 0 0
2019-01-14 000001 NaN NaN NaN 0 0 0
2019-01-15 000001 NaN NaN NaN 0 0 0
2019-01-16 000001 NaN NaN NaN 0 0 0
2019-01-17 000001 NaN NaN NaN 0 0 0
2019-01-18 000001 NaN NaN NaN 0 0 0
2019-01-21 000001 NaN NaN NaN 0 0 0
2019-01-22 000001 NaN NaN NaN 0 0 0
2019-01-23 000001 NaN NaN NaN 0 0 0
2019-01-24 000001 NaN NaN NaN 0 0 0
2019-01-25 000001 NaN NaN NaN 0 0 0
2019-01-28 000001 NaN NaN NaN 0 0 0
2019-01-29 000001 NaN NaN NaN 0 0 0
2019-01-30 000001 NaN NaN NaN 0 0 0
2019-01-31 000001 NaN NaN NaN 0 0 0
2019-02-01 000001 NaN NaN NaN 0 0 0
2019-02-11 000001 NaN NaN NaN 0 0 0
2019-02-12 000001 NaN NaN NaN 0 0 0
2019-02-13 000001 NaN NaN NaN 0 0 0
2019-02-14 000001 NaN NaN NaN 0 0 0
2019-02-15 000001 0.157022 NaN NaN 0 0 0
2019-02-18 000001 0.164416 NaN NaN 0 0 0
2019-02-19 000001 0.162747 NaN NaN 0 0 0
2019-02-20 000001 0.168194 NaN NaN 0 0 0
2019-02-21 000001 0.167374 NaN NaN 0 0 0
2019-02-22 000001 0.176082 NaN NaN 0 0 0
2019-02-25 000001 0.244633 NaN NaN 0 0 0
2019-02-26 000001 0.273117 0.207987 0.130260 0 0 0
2019-02-27 000001 0.305015 0.230401 0.149227 0 0 0
2019-02-28 000001 0.323862 0.251342 0.145041 0 0 0
2019-03-01 000001 0.360723 0.275274 0.170898 0 0 0
2019-03-04 000001 0.400339 0.302133 0.196413 0 0 0
2019-03-05 000001 0.431294 0.329467 0.203652 0 0 0
2019-03-06 000001 0.451868 0.355074 0.193588 0 0 0
2019-03-07 000001 0.440428 0.372767 0.135322 0 0 0
2019-03-08 000001 0.397392 0.377835 0.039115 0 0 0
2019-03-11 000001 0.360469 0.374282 -0.027626 0 1 0
2019-03-12 000001 0.330084 0.365280 -0.070391 0 0 0
2019-03-13 000001 0.303178 0.352678 -0.098999 0 0 0
2019-03-14 000001 0.282642 0.338507 -0.111731 0 0 0
2019-03-15 000001 0.268008 0.324276 -0.112537 0 0 0
2019-03-18 000001 0.280965 0.315550 -0.069168 0 0 0
2019-03-19 000001 0.279837 0.308365 -0.057055 0 0 0
2019-03-20 000001 0.273061 0.301270 -0.056420 0 0 0
2019-03-21 000001 0.260586 0.293103 -0.065034 0 0 0
2019-03-22 000001 0.241083 0.282667 -0.083168 0 0 0
2019-03-25 000001 0.190592 0.264207 -0.147231 0 0 0
2019-03-26 000001 0.148189 0.240959 -0.185540 0 0 0
2019-03-27 000001 0.132268 0.219187 -0.173838 0 0 0
2019-03-28 000001 0.107424 0.196807 -0.178765 0 0 0
2019-03-29 000001 0.127513 0.182934 -0.110842 0 0 0
2019-04-01 000001 0.166284 0.179601 -0.026636 0 0 0
2019-04-02 000001 0.207012 0.185087 0.043850 1 0 0
2019-04-03 000001 0.242006 0.196477 0.091059 0 0 0
2019-04-04 000001 0.295303 0.216250 0.158106 0 0 0
2019-04-08 000001 0.340510 0.241110 0.198800 0 0 0
2019-04-09 000001 0.361793 0.265253 0.193080 0 0 0
2019-04-10 000001 0.368870 0.285981 0.165778 0 0 0
2019-04-11 000001 0.357212 0.300229 0.113965 0 0 0
2019-04-12 000001 0.335793 0.307343 0.056900 0 0 0
2019-04-15 000001 0.333666 0.312608 0.042116 0 0 0
2019-04-16 000001 0.389150 0.327918 0.122465 0 0 0
2019-04-17 000001 0.412419 0.344819 0.135200 0 0 0
2019-04-18 000001 0.425260 0.360908 0.128703 0 0 0
2019-04-19 000001 0.457213 0.380170 0.154085 0 0 0
2019-04-22 000001 0.437246 0.391586 0.091321 0 0 0
2019-04-23 000001 0.411128 0.395494 0.031268 0 0 0
2019-04-24 000001 0.411374 0.398670 0.025408 0 0 0
2019-04-25 000001 0.385593 0.396055 -0.020923 0 1 0
2019-04-26 000001 0.337650 0.384374 -0.093448 0 0 0
2019-04-29 000001 0.317533 0.371005 -0.106945 0 0 0
2019-04-30 000001 0.280976 0.352999 -0.144047 0 0 0
2019-05-06 000001 0.181789 0.318757 -0.273936 0 0 0
2019-05-07 000001 0.107507 0.276507 -0.338000 0 0 0
2019-05-08 000001 0.024025 0.226010 -0.403970 0 0 0
2019-05-09 000001 -0.071904 0.166427 -0.476663 0 0 0
2019-05-10 000001 -0.110485 0.111045 -0.443058 0 0 0
2019-05-13 000001 -0.165585 0.055719 -0.442606 0 0 0
2019-05-14 000001 -0.193798 0.005815 -0.399226 0 0 0
2019-05-15 000001 -0.184113 -0.032170 -0.303885 0 0 0
2019-05-16 000001 -0.179243 -0.061585 -0.235315 0 0 0
2019-05-17 000001 -0.201593 -0.089587 -0.224013 0 0 0
2019-05-20 000001 -0.220935 -0.115856 -0.210157 0 0 0
2019-05-21 000001 -0.221183 -0.136922 -0.168523 0 0 0
2019-05-22 000001 -0.229868 -0.155511 -0.148714 0 0 0
2019-05-23 000001 -0.241623 -0.172733 -0.137780 0 0 0
2019-05-24 000001 -0.243949 -0.186976 -0.113945 0 0 0
2019-05-27 000001 -0.241615 -0.197904 -0.087421 0 0 0
2019-05-28 000001 -0.228771 -0.204077 -0.049387 0 0 0
2019-05-29 000001 -0.222297 -0.207721 -0.029151 0 0 0
2019-05-30 000001 -0.227083 -0.211594 -0.030979 0 0 0
2019-05-31 000001 -0.230999 -0.215475 -0.031049 0 0 0
2019-06-03 000001 -0.250713 -0.222522 -0.056381 0 0 0
2019-06-04 000001 -0.266744 -0.231367 -0.070754 0 0 0
2019-06-05 000001 -0.268000 -0.238693 -0.058613 0 0 0
2019-06-06 000001 -0.269373 -0.244829 -0.049088 0 0 0

而且每次调用on_bar,都需要对指标进行一次计算。 所以考虑在QAStragety类自带的user_init中先统一根据所有数据计算完并生成信号后,再在on_bar中判断信号出现与否,再完成下单动作。修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from QAStrategy.qastockbase import QAStrategyStockBase
import QUANTAXIS as QA
from Risk_util import QA_Risk_Abstract
from collections import deque
import pandas as pd
import datetime
from rich import print


class MACD_JCSC(QAStrategyStockBase):
def user_init(self):
data = QA.QA_fetch_stock_day_adv(
self.code, self.start, self.end).to_qfq()
self.signal = data.add_func(self.macd_jcsc)

def on_bar(self, bar):
cursor_date = bar.name[0].date().strftime("%Y-%m-%d")
cursor_code = bar.name[1]

if self.signal.loc[cursor_date].loc[cursor_code].CROSS_JC == 1:
print("[%s] %s 出现买入信号!!!" % bar.name)
if self.get_positions(bar.name[1]).volume_long == 0:
self.send_order("BUY", "OPEN", code=bar.name[1], price=bar.close, volume=1000)
print("交易:以%.2f价格买入!!!" % bar.close)
elif self.signal.loc[cursor_date].loc[cursor_code].CROSS_SC == 1:
print("[%s] %s 出现卖出信号!!!" % bar.name)
if self.get_positions(bar.name[1]).volume_long > 0:
self.send_order("SELL", "CLOSE",code=bar.name[1], price=bar.close, volume=1000)
print("交易:以%.2f价格卖出!!!" % bar.close)

def macd_jcsc(self, dataframe, SHORT=12, LONG=26, M=9):
"""
1.DIF向上突破DEA,买入信号参考。
2.DIF向下跌破DEA,卖出信号参考。
"""
CLOSE = dataframe.close
DIFF = QA.EMA(CLOSE, SHORT) - QA.EMA(CLOSE, LONG)
DEA = QA.EMA(DIFF, M)
MACD = 2*(DIFF-DEA)

CROSS_JC = QA.CROSS(DIFF, DEA)
CROSS_SC = QA.CROSS(DEA, DIFF)
ZERO = 0
return pd.DataFrame({'DIFF': DIFF, 'DEA': DEA, 'MACD': MACD, 'CROSS_JC': CROSS_JC, 'CROSS_SC': CROSS_SC, 'ZERO': ZERO})

st1=datetime.datetime.now()
print('开始回测 -- {}'.format(datetime.datetime.now()))
code_list = ['000001']
#code_list = QA.QA_fetch_stock_list_adv().code.tolist()

s = MACD_JCSC(
code = code_list,
frequence = 'day',
start = '2019-01-01',
end = '2024-06-27',
strategy_id = 's-with_unit_init',
)


#s.debug() //不保存进数据库
#s._debug_sim() //模拟盘测试
s.run_backtest()
r = QA_Risk_Abstract(QA.QA_Risk(s.acc))
print('[bold magenta][风险指标][/bold magenta]')
print(r.message)
p = QA.QA_Performance(s.acc)
print('[bold magenta][绩效指标][/bold magenta]')
print(p.base_message(p.pnl))
print('回测耗时 -- {}'.format(datetime.datetime.now()-st1))

修改前完成单只股票5年半的回测需要 33.95秒, 而修改后仅需 25.71秒

回测结果

回测的结果可以直接在终端上可见,也可以能过 Web 方式(http://127.0.0.1:81/) 查询。

风险分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
{
'account_cookie': 's-with_unit_init',
'annualize_return': 0.0,
'profit': 0.0,
'max_dropback': 0.01,
'time_gap': 1330,
'volatility': 0.43,
'benchmark_code': '000300',
'bm_annualizereturn': 0.03,
'bm_profit': 0.16,
'beta': 0.01,
'alpha': -0.0,
'sharpe': -0.12,
'sortino': -395.75,
'last_assets': '1002633.56',
'total_tax': -644.7,
'total_commission': -481.4,
'profit_money': 2633.56,
'ir': 0.0,
'month_profit': {
'2019-01-31 00:00:00': 0.0,
'2019-02-28 00:00:00': 703.1234393180348,
'2019-03-31 00:00:00': -50.181729689240456,
'2019-04-30 00:00:00': 642.743004972348,
'2019-05-31 00:00:00': 0.0,
'2019-06-30 00:00:00': 1368.4163899420528,
'2019-07-31 00:00:00': -353.5741839206312,
'2019-08-31 00:00:00': -773.1137744144071,
'2019-09-30 00:00:00': 68.32695359084755,
'2019-10-31 00:00:00': 705.2476993447635,
'2019-11-30 00:00:00': 0.0,
'2019-12-31 00:00:00': 684.6625807939563,
'2020-01-31 00:00:00': 250.99576606589835,
'2020-02-29 00:00:00': -764.5018294820329,
'2020-03-31 00:00:00': -639.1336695251521,
'2020-04-30 00:00:00': 986.47938771802,
'2020-05-31 00:00:00': -627.6430917717516,
'2020-06-30 00:00:00': -518.7461710819043,
'2020-07-31 00:00:00': 607.8399459136417,
'2020-08-31 00:00:00': 220.76756709371693,
'2020-09-30 00:00:00': 17.090446144808084,
'2020-10-31 00:00:00': 1495.516639258014,
'2020-11-30 00:00:00': 711.2246544788359,
'2020-12-31 00:00:00': -293.4999780562939,
'2021-01-31 00:00:00': 2069.263243380934,
'2021-02-28 00:00:00': 621.7155406653183,
'2021-03-31 00:00:00': 456.697427464067,
'2021-04-30 00:00:00': 229.10599464632105,
'2021-05-31 00:00:00': -48.13997128745541,
'2021-06-30 00:00:00': -277.31763577868696,
'2021-07-31 00:00:00': 0.0,
'2021-08-31 00:00:00': -626.0138344422448,
'2021-09-30 00:00:00': -1153.6153345350176,
'2021-10-31 00:00:00': 84.48616837000009,
'2021-11-30 00:00:00': -1622.0463032894768,
'2021-12-31 00:00:00': -97.31165447854437,
'2022-01-31 00:00:00': -2169.600942116813,
'2022-02-28 00:00:00': -588.2864658574108,
'2022-03-31 00:00:00': 701.9407301229658,
'2022-04-30 00:00:00': -492.56538836390246,
'2022-05-31 00:00:00': -407.6765322362771,
'2022-06-30 00:00:00': 728.7865806339541,
'2022-07-31 00:00:00': -519.0264483509818,
'2022-08-31 00:00:00': 359.32954159996007,
'2022-09-30 00:00:00': -307.7851737852907,
'2022-10-31 00:00:00': 0.0,
'2022-11-30 00:00:00': 2007.9207173399627,
'2022-12-31 00:00:00': 46.82587729266379,
'2023-01-31 00:00:00': 586.5987326084869,
'2023-02-28 00:00:00': 0.0,
'2023-03-31 00:00:00': -523.4222982611973,
'2023-04-30 00:00:00': -376.4062199871987,
'2023-05-31 00:00:00': -239.97391489637084,
'2023-06-30 00:00:00': -623.9189663539873,
'2023-07-31 00:00:00': 769.7435180819593,
'2023-08-31 00:00:00': -622.6199320594314,
'2023-09-30 00:00:00': -305.4354766883189,
'2023-10-31 00:00:00': -183.30302026984282,
'2023-11-30 00:00:00': -627.8779737370787,
'2023-12-31 00:00:00': 200.35370358801447,
'2024-01-31 00:00:00': 65.3398147780681,
'2024-02-29 00:00:00': 1054.7712957019685,
'2024-03-31 00:00:00': -257.3330304133706,
'2024-04-30 00:00:00': -14.334259253926575,
'2024-05-31 00:00:00': 292.6508590914309,
'2024-06-30 00:00:00': 0.0
}
}

绩效分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
'total_profit': 17887.74,
'total_loss': -14128.09,
'total_pnl': 1.27,
'trading_amounts': 48,
'profit_amounts': 20,
'loss_amounts': 28,
'even_amounts': 0,
'profit_precentage': 0.42,
'loss_precentage': 0.58,
'even_precentage': 0.0,
'average_profit': 894.39,
'average_loss': -504.57,
'average_pnl': 1.77,
'max_profit': 3782.37,
'max_loss': -1342.29,
'max_pnl': 2.82,
'netprofio_maxloss_ratio': 2.8,
'continue_profit_amount': 4,
'continue_loss_amount': 9,
'average_holdgap': '20 days 00:00:00',
'average_profitholdgap': '32 days 15:36:00',
'average_losssholdgap': '10 days 23:08:34.285714285'
}

回测中遇到的问题

回测使用的 pandas 版本为 2.2以上,比 Quantaxis 发布时使用的版本要高得多,所以在回测时会遇到大量用法未来会舍弃的告警。如:

①FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use ser.iloc[pos]
②FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
③Removed deprecated Series.iteritems(), DataFrame.iteritems() and HDFStore.iteritems() use obj.items instead (GH 45321)
④FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
⑤FutureWarning: The 'axis' keyword in DataFrame.groupby is deprecated and will be removed in a future version.

可以有两种办法解决。

  1. 屏蔽告警

    1
    2
    import warnings
    warnings.filterwarnings('ignore')

  2. 根据告警中的提示修改源代码以符合未来版本的要求。 我在所修改的部分,都加注了详细的文档注解,方便以后回溯。具体改动在 [[Quantaxis适配pandas2.x的修改]]。

参考

  1. 投资没有银弹 -- (五连阳回测代码勘误与更快的回测实现)
  2. QUANTAXIS探索(七)量化策略实现类QAStrategy的回测模式