学习记录655@python双均线突破量化回测实战-以比亚迪为例

以下代码对比亚迪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_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamount
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70765516.493
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07628361.961
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38822172.472
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58449013.435
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45529249.404
....................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.403911414.127
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.932262822.665
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.182293531.516
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.682355802.796
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.885421385.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_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamountma1ma2
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70765516.493NaNNaN
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07628361.961NaNNaN
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38822172.472NaNNaN
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58449013.435NaNNaN
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45529249.40447.9029NaN
..........................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.403911414.127270.4220272.107
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.932262822.665270.3720271.023
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.182293531.516269.4960269.752
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.682355802.796268.7000269.259
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.885421385.039265.8220267.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_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamountma1ma2trend
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70765516.493NaNNaN0
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07628361.961NaNNaN0
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38822172.472NaNNaN0
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58449013.435NaNNaN0
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45529249.40447.9029NaN0
.............................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.403911414.127270.4220272.1070
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.932262822.665270.3720271.0230
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.182293531.516269.4960269.7520
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.682355802.796268.7000269.2590
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.885421385.039265.8220267.8620

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_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamountma1ma2trendpospos_shiftnew_posold_pos
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70765516.493NaNNaN0NaNNaNNaNNaN
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07628361.961NaNNaN00.0NaNNaNNaN
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38822172.472NaNNaN00.00.00.00.0
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58449013.435NaNNaN00.00.00.00.0
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45529249.40447.9029NaN00.00.00.00.0
.........................................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.403911414.127270.4220272.10700.00.00.00.0
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.932262822.665270.3720271.02300.00.00.00.0
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.182293531.516269.4960269.75200.00.00.00.0
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.682355802.796268.7000269.25900.00.00.00.0
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.885421385.039265.8220267.86200.00.00.00.0

668 rows × 18 columns

# 把开盘价作为交易价格
df['entry_p']=df['open']
df
ts_codetrade_dateopenhighlowclosepre_closechangepct_chgvolamountma1ma2trendpospos_shiftnew_posold_posentry_p
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70765516.493NaNNaN0NaNNaNNaNNaN47.6292
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07628361.961NaNNaN00.0NaNNaNNaN48.1386
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38822172.472NaNNaN00.00.00.00.047.3296
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58449013.435NaNNaN00.00.00.00.048.2484
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45529249.40447.9029NaN00.00.00.00.047.4894
............................................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.403911414.127270.4220272.10700.00.00.00.0266.4000
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.932262822.665270.3720271.02300.00.00.00.0272.9600
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.182293531.516269.4960269.75200.00.00.00.0273.0000
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.682355802.796268.7000269.25900.00.00.00.0270.0000
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.885421385.039265.8220267.86200.00.00.00.0263.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_codetrade_dateopenhighlowclosepre_closechangepct_chgvol...trendpospos_shiftnew_posold_posentry_pp&l_newp&l_oldfeep&l
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70...0NaNNaNNaNNaN47.6292NaNNaN0NaN
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07...00.0NaNNaNNaN48.1386NaNNaN0NaN
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38...00.00.00.00.047.32960.00.000.0
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58...00.00.00.00.048.2484-0.0-0.000.0
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45...00.00.00.00.047.4894-0.0-0.000.0
..................................................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.40...00.00.00.00.0266.40000.00.000.0
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.93...00.00.00.00.0272.96000.00.000.0
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.18...00.00.00.00.0273.0000-0.0-0.000.0
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.68...00.00.00.00.0270.0000-0.0-0.000.0
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.88...00.00.00.00.0263.0000-0.0-0.000.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_codetrade_dateopenhighlowclosepre_closechangepct_chgvol...new_posold_posentry_pp&l_newp&l_oldfeep&lp&l_cumcapitalnet_value
667002594.SZ2020010247.629248.408247.449548.108647.60930.49931.0487159345.70...NaNNaN47.6292NaNNaN0NaNNaNNaN0.00000
666002594.SZ2020010348.138648.927647.619247.978848.1086-0.1298-0.2698129936.07...NaNNaN48.1386NaNNaN0NaNNaNNaN0.00000
665002594.SZ2020010647.329649.127347.129948.218547.97880.23970.4996169871.38...0.00.047.32960.00.000.00.001000.001.00000
664002594.SZ2020010748.248448.438247.709147.988848.2185-0.2297-0.476493400.58...0.00.048.2484-0.0-0.000.00.001000.001.00000
663002594.SZ2020010847.489448.288447.089947.219847.9888-0.7690-1.6025110974.45...0.00.047.4894-0.0-0.000.00.001000.001.00000
..................................................................
4002594.SZ20220926266.4000276.0000263.5800272.9500266.40006.55002.4587143606.40...0.00.0266.40000.00.000.014668.5215668.5215.66852
3002594.SZ20220927272.9600274.8300270.0600273.9600272.95001.01000.370083095.93...0.00.0272.96000.00.000.014668.5215668.5215.66852
2002594.SZ20220928273.0000273.0000265.5000265.6200273.9600-8.3400-3.044285620.18...0.00.0273.0000-0.0-0.000.014668.5215668.5215.66852
1002594.SZ20220929270.0000271.8000264.0000264.5700265.6200-1.0500-0.395388356.68...0.00.0270.0000-0.0-0.000.014668.5215668.5215.66852
0002594.SZ20220930263.0000263.5500249.0000252.0100264.5700-12.5600-4.7473214035.88...0.00.0263.0000-0.0-0.000.014668.5215668.5215.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倍。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
股票回测量化交易中非常重要的一环,它可以通过历史数据对交易策略进行模拟和评估,从而评估策略的可行性和优劣性。在Python中,有很多开源的量化交易框架可以用来进行股票回测,如zipline、backtrader等。 下面是一个使用zipline框架进行简单交易策略回测的例子: 1. 安装zipline ```python pip install zipline ``` 2. 编写交易策略代码 ```python from zipline.api import order_target_percent, record, symbol def initialize(context): context.asset = symbol('AAPL') def handle_data(context, data): # 获取过去10天的收盘价 prices = data.history(context.asset, 'price', 10, '1d') # 计算平均价 mean_price = prices.mean() # 如果当前价格低于平均价,则买入 if data.current(context.asset, 'price') < mean_price: # 调整持仓比例至100% order_target_percent(context.asset, 1.0) # 否则卖出 else: # 调整持仓比例至0% order_target_percent(context.asset, 0.0) # 记录当前持仓比例 record(position=context.portfolio.positions[context.asset].amount) ``` 3. 运行回测 ```python from zipline import run_algorithm from zipline.api import symbol from datetime import datetime start = datetime(2016, 1, 1) end = datetime(2017, 1, 1) result = run_algorithm( start=start, end=end, initialize=initialize, capital_base=10000, handle_data=handle_data, bundle='quandl' ) ``` 在上述代码中,我们定义了一个简单的交易策略,即如果当前价格低于过去10天的平均价,则买入,否则卖出。然后我们使用zipline框架进行回测,设定回测开始和结束时间、初始资本、数据来源等参数,最终得到回测结果。 需要注意的是,这只是一个简单的例子,实际的交易策略可能会更加复杂,需要考虑更多的因素。另外,在进行股票回测时,也需要注意避免过度拟合或过度优化,以免出现回测虚高的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值