以下代码对比亚迪2020年1月1日至2022年10月5日进行均线策略回测
策略逻辑是:如果5日均线大于10日均线,那么就持有一手仓位,否则不持有仓位,就这么简单明了,然后换算成净值,看净值图情况,查看回测的效果。
根据净值图,最高净值可达到最初净值的20倍。
ps:现实情况肯定没这么简单,比如核心要解决的问题就是选股先选到比亚迪,其次是坚定不宜的持有这么久,才能得到这么高的收益。

import tushare as ts
ts.set_token('你的token')
# 以比亚迪前复权日线数据为例进行回测
df = ts.pro_bar(ts_code='002594.SZ', adj='qfq', start_date='20200101', end_date='20221004')
df.sort_values(by="trade_date",inplace=True)
df
ts_code trade_date open high low close pre_close change pct_chg vol amount
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 765516.493
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 628361.961
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 822172.472
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 449013.435
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 529249.404
... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 3911414.127
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 2262822.665
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 2293531.516
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 2355802.796
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 5421385.039

668 rows × 11 columns

import talib as ta

# 两条均线的参数
L1=5
L2=10

# 使用talib计算移动均线
df['ma1']=ta.SMA(df.close.values,timeperiod=L1)
df['ma2']=ta.SMA(df.close.values,timeperiod=L2)
df
ts_code trade_date open high low close pre_close change pct_chg vol amount ma1 ma2
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 765516.493 NaN NaN
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 628361.961 NaN NaN
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 822172.472 NaN NaN
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 449013.435 NaN NaN
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 529249.404 47.9029 NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 3911414.127 270.4220 272.107
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 2262822.665 270.3720 271.023
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 2293531.516 269.4960 269.752
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 2355802.796 268.7000 269.259
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 5421385.039 265.8220 267.862

668 rows × 13 columns

# 计算趋势,0代表没有趋势不做操作,空仓,1代表多头趋势,第二日买入
df['trend']=0
con_long=df['ma1']>df['ma2']
con_short=df['ma1']<=df['ma2']
df.loc[con_long,'trend']=1
df.loc[con_short,'trend']=0
df
ts_code trade_date open high low close pre_close change pct_chg vol amount ma1 ma2 trend
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 765516.493 NaN NaN 0
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 628361.961 NaN NaN 0
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 822172.472 NaN NaN 0
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 449013.435 NaN NaN 0
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 529249.404 47.9029 NaN 0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 3911414.127 270.4220 272.107 0
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 2262822.665 270.3720 271.023 0
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 2293531.516 269.4960 269.752 0
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 2355802.796 268.7000 269.259 0
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 5421385.039 265.8220 267.862 0

668 rows × 14 columns

# 假设出现信号后,第二天开盘进行交易,每次开仓1手(即100股)
# 注意pos代表目标仓位,如果trend>1,也就是当5日均线大于10日均线,就持有一手仓位,否则补充持有仓位
# new_pos为当日新增仓位,old_pos为老仓位
# 新旧仓位这里不好理解,可按照表格自己计算梳理下
df['pos']=100*df['trend'].shift(1)
df['pos_shift']=df['pos'].shift(1)
df['new_pos']=df['pos']-df['pos'].shift(1)
df['old_pos']=df['pos']-df['new_pos']
df
ts_code trade_date open high low close pre_close change pct_chg vol amount ma1 ma2 trend pos pos_shift new_pos old_pos
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 765516.493 NaN NaN 0 NaN NaN NaN NaN
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 628361.961 NaN NaN 0 0.0 NaN NaN NaN
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 822172.472 NaN NaN 0 0.0 0.0 0.0 0.0
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 449013.435 NaN NaN 0 0.0 0.0 0.0 0.0
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 529249.404 47.9029 NaN 0 0.0 0.0 0.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 3911414.127 270.4220 272.107 0 0.0 0.0 0.0 0.0
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 2262822.665 270.3720 271.023 0 0.0 0.0 0.0 0.0
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 2293531.516 269.4960 269.752 0 0.0 0.0 0.0 0.0
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 2355802.796 268.7000 269.259 0 0.0 0.0 0.0 0.0
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 5421385.039 265.8220 267.862 0 0.0 0.0 0.0 0.0

668 rows × 18 columns

# 把开盘价作为交易价格
df['entry_p']=df['open']
df
ts_code trade_date open high low close pre_close change pct_chg vol amount ma1 ma2 trend pos pos_shift new_pos old_pos entry_p
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 765516.493 NaN NaN 0 NaN NaN NaN NaN 47.6292
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 628361.961 NaN NaN 0 0.0 NaN NaN NaN 48.1386
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 822172.472 NaN NaN 0 0.0 0.0 0.0 0.0 47.3296
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 449013.435 NaN NaN 0 0.0 0.0 0.0 0.0 48.2484
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 529249.404 47.9029 NaN 0 0.0 0.0 0.0 0.0 47.4894
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 3911414.127 270.4220 272.107 0 0.0 0.0 0.0 0.0 266.4000
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 2262822.665 270.3720 271.023 0 0.0 0.0 0.0 0.0 272.9600
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 2293531.516 269.4960 269.752 0 0.0 0.0 0.0 0.0 273.0000
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 2355802.796 268.7000 269.259 0 0.0 0.0 0.0 0.0 270.0000
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 5421385.039 265.8220 267.862 0 0.0 0.0 0.0 0.0 263.0000

668 rows × 19 columns

# 计算旧仓位的盈利和新仓位的盈利
# 新仓位当日盈亏为当日收盘价与开盘价之差乘以新仓位
# 旧仓位当日盈亏为当日收盘价与昨日收盘价之差乘以旧仓位
df['p&l_new']=(df['close']-df['entry_p'])*df['new_pos']
df['p&l_old']=(df['close']-df['close'].shift(1))*df['old_pos']
# 交易费用,new_pos为100或者-100表示有交易,交易费用统一为5元
df['fee']=0
df.loc[(df['new_pos']==100) | (df['new_pos']==-100),'fee']=5
# 每日盈亏由三部分组成
df['p&l']=df['p&l_new']+df['p&l_old']-df['fee']
df
ts_code trade_date open high low close pre_close change pct_chg vol ... trend pos pos_shift new_pos old_pos entry_p p&l_new p&l_old fee p&l
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 ... 0 NaN NaN NaN NaN 47.6292 NaN NaN 0 NaN
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 ... 0 0.0 NaN NaN NaN 48.1386 NaN NaN 0 NaN
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 ... 0 0.0 0.0 0.0 0.0 47.3296 0.0 0.0 0 0.0
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 ... 0 0.0 0.0 0.0 0.0 48.2484 -0.0 -0.0 0 0.0
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 ... 0 0.0 0.0 0.0 0.0 47.4894 -0.0 -0.0 0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 ... 0 0.0 0.0 0.0 0.0 266.4000 0.0 0.0 0 0.0
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 ... 0 0.0 0.0 0.0 0.0 272.9600 0.0 0.0 0 0.0
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 ... 0 0.0 0.0 0.0 0.0 273.0000 -0.0 -0.0 0 0.0
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 ... 0 0.0 0.0 0.0 0.0 270.0000 -0.0 -0.0 0 0.0
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 ... 0 0.0 0.0 0.0 0.0 263.0000 -0.0 -0.0 0 0.0

668 rows × 23 columns

# 计算累计盈亏
df['p&l_cum']=df['p&l'].cumsum()

# 计算净值曲线,假设初始资金是1000
ini_cap=1000
df['capital']=df['p&l_cum']+ini_cap
df['net_value']=df['capital']/ini_cap
df['net_value']=df.net_value.apply(lambda x:x if x>=0 else 0)
df
ts_code trade_date open high low close pre_close change pct_chg vol ... new_pos old_pos entry_p p&l_new p&l_old fee p&l p&l_cum capital net_value
667 002594.SZ 20200102 47.6292 48.4082 47.4495 48.1086 47.6093 0.4993 1.0487 159345.70 ... NaN NaN 47.6292 NaN NaN 0 NaN NaN NaN 0.00000
666 002594.SZ 20200103 48.1386 48.9276 47.6192 47.9788 48.1086 -0.1298 -0.2698 129936.07 ... NaN NaN 48.1386 NaN NaN 0 NaN NaN NaN 0.00000
665 002594.SZ 20200106 47.3296 49.1273 47.1299 48.2185 47.9788 0.2397 0.4996 169871.38 ... 0.0 0.0 47.3296 0.0 0.0 0 0.0 0.00 1000.00 1.00000
664 002594.SZ 20200107 48.2484 48.4382 47.7091 47.9888 48.2185 -0.2297 -0.4764 93400.58 ... 0.0 0.0 48.2484 -0.0 -0.0 0 0.0 0.00 1000.00 1.00000
663 002594.SZ 20200108 47.4894 48.2884 47.0899 47.2198 47.9888 -0.7690 -1.6025 110974.45 ... 0.0 0.0 47.4894 -0.0 -0.0 0 0.0 0.00 1000.00 1.00000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 002594.SZ 20220926 266.4000 276.0000 263.5800 272.9500 266.4000 6.5500 2.4587 143606.40 ... 0.0 0.0 266.4000 0.0 0.0 0 0.0 14668.52 15668.52 15.66852
3 002594.SZ 20220927 272.9600 274.8300 270.0600 273.9600 272.9500 1.0100 0.3700 83095.93 ... 0.0 0.0 272.9600 0.0 0.0 0 0.0 14668.52 15668.52 15.66852
2 002594.SZ 20220928 273.0000 273.0000 265.5000 265.6200 273.9600 -8.3400 -3.0442 85620.18 ... 0.0 0.0 273.0000 -0.0 -0.0 0 0.0 14668.52 15668.52 15.66852
1 002594.SZ 20220929 270.0000 271.8000 264.0000 264.5700 265.6200 -1.0500 -0.3953 88356.68 ... 0.0 0.0 270.0000 -0.0 -0.0 0 0.0 14668.52 15668.52 15.66852
0 002594.SZ 20220930 263.0000 263.5500 249.0000 252.0100 264.5700 -12.5600 -4.7473 214035.88 ... 0.0 0.0 263.0000 -0.0 -0.0 0 0.0 14668.52 15668.52 15.66852

668 rows × 26 columns

# 绘制净值曲线
df=df.set_index('trade_date')
df.plot(figsize=(12,6),y=['net_value'])
<AxesSubplot:xlabel='trade_date'>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RxLeXcoi-1664949829950)(output_8_1.png)]
如上图所示,最高净值涨幅近20倍。

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐