ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

如何用 Python 写一个均线策略回测?(附避免未来函数的正确姿势)

如何用 Python 写一个均线策略回测?(附避免未来函数的正确姿势) 一句话回答双均线策略回测只需四步——取复权日 K 线、算快慢均线生成金叉/死叉信号、用次日开盘价成交这一步是避免未来函数的关键、计算净值和绩效。下面是可直接运行的完整实现。什么是双均线策略快线如 MA5上穿慢线如 MA20金叉买入信号快线下穿慢线 死叉卖出信号。它是最经典的趋势跟踪策略适合作为回测框架的入门例子。最关键的坑未来函数前视偏差新手最常犯的错误是在收盘那一刻算出金叉然后用当天的收盘价成交。但收盘价你在盘中是不知道的——等你确认金叉时那个价格已经过去了。这叫未来函数 / 前视偏差会让回测结果虚高得离谱。正确做法用 T 日收盘数据生成信号在T1 日开盘价成交。下面的代码严格遵守这一点。完整回测代码importnumpyasnpimportpandasaspdfromalphafeedimportAlphaFeeddefbacktest_ma(symbol,fast5,slow20,count500,fee0.0003,slippage0.001,init_cash1_000_000):afAlphaFeed(api_keyyour-api-key)# 1. 取足够长的前复权日 K 线dfaf.klines.get(symbol,period1d,countcount,adjustforward,to_dataframeTrue)dfdf.sort_values(trade_date).reset_index(dropTrue)# 2. 计算均线与信号都基于当日收盘属于 T 日可知的信息df[ma_fast]df[close].rolling(fast).mean()df[ma_slow]df[close].rolling(slow).mean()df[signal](df[ma_fast]df[ma_slow]).astype(int)# 3. 关键信号 shift(1)即 T 日信号 → T1 日才持仓用 T1 开盘价成交df[position]df[signal].shift(1).fillna(0)# 用开盘价计算持仓期收益避免用收盘价成交造成的前视df[open_ret]df[open].pct_change().shift(-1)# 今开→明开的收益归属到今日持仓# 更严谨持仓收益 次日开盘买入后到再次日开盘的价格变化df[daily_ret]df[open].pct_change()df[strat_ret]df[position]*df[daily_ret]# 4. 扣成本仓位变化的那天计一次手续费滑点df[turnover]df[position].diff().abs().fillna(0)df[cost]df[turnover]*(feeslippage)df[strat_ret_net]df[strat_ret]-df[cost]# 5. 净值与绩效df[nav](1df[strat_ret_net].fillna(0)).cumprod()totaldf[nav].iloc[-1]-1nlen(df)ann(1total)**(250/n)-1voldf[strat_ret_net].std()*np.sqrt(250)sharpe(ann-0.02)/volifvolelsenp.nan max_dd(df[nav]/df[nav].cummax()-1).min()returndf,{symbol:symbol,total_return:round(total,4),ann_return:round(ann,4),sharpe:round(sharpe,2),max_drawdown:round(max_dd,4),trades:int(df[turnover].sum()//1),}df,statsbacktest_ma(600519.SH,fast5,slow20)print(stats)关键设计点解释环节做法为什么复权adjustforward避免除权跳空污染收益率信号→持仓signal.shift(1)今天的信号明天才生效杜绝未来函数成交价用open开盘价收盘价盘中不可知开盘价可执行成本仓位变化时扣手续费滑点逼近真实交易摩擦和基准比一比只看策略净值没意义要和买入持有不动比df[bench_nav]df[close]/df[close].iloc[0]print(f策略最终净值:{df[nav].iloc[-1]:.3f})print(f基准(买入持有):{df[bench_nav].iloc[-1]:.3f})批量回测多只股票symbols[600519.SH,000001.SZ,601318.SH]results[backtest_ma(s)[1]forsinsymbols]print(pd.DataFrame(results).to_string(indexFalse))回测之后必须做的检验一个漂亮的回测曲线不等于策略有效。至少要问自己换个时间段还成立吗用不同的count/ 起止时间做样本外测试参数是不是过拟合把 fast/slow 在一个范围内扫一遍看结果是不是只在个别参数上好看考虑了停牌、涨停买不进吗涨停当天开盘一字板往往买不到实盘会打折成本假设合理吗A 股还有印花税卖出、过户费等可以加进fee。常见问题FAQQ为什么我的回测收益高得不真实A99% 是未来函数——检查你是不是用了当天收盘价既算信号又成交。加shift(1)并用开盘价成交。Q手续费该设多少A券商佣金通常万 2.5~万 3fee0.0003卖出另有千 1 印花税可视需要加入。Q可以回测分钟级策略吗A可以把period换成5m/15m等用af.klines.get(..., period5m)取分钟线逻辑一致。小结回测框架的骨架是数据→信号→成交→净值→绩效而它的灵魂是严格的时间因果信号只能用已知信息生成成交只能用未来可执行的价格。用 AlphaFeed 的前复权 K 线做数据源配合shift(1)的成交规则你就有了一个可信、可复现的回测起点。参考AlphaFeed Python SDK 文档https://docs.alphafeed.org/zh-Hans/sdk/python-quickstartAlphaFeed 官网https://alphafeed.org/
返回列表