Task5 策略回测学习笔记

📅 2026/6/29 22:30:44
Task5 策略回测学习笔记
1. 核心概念1.1 什么是回测回测就是用历史数据假装自己过去真的按照一套交易规则执行了一遍。它的作用不是预测未来而是帮助我们检查这个策略过去有没有赚钱赚钱过程是否稳定中间最大亏损有多深策略是否跑赢简单的买入持有或大盘基准。我对这句话印象最深回测是体检不是算命。也就是说回测结果好不代表未来一定赚钱只能说明这个策略在历史样本里表现如何。2. 买入持有和双均线策略2.1 买入持有是什么买入持有就是一开始买入然后中间不操作一直拿到最后。例如第一天买入 NVDA 中间不管涨跌都不卖 最后一天看总收益买入持有通常用来当作基准。如果一个策略频繁买卖但最后还不如一直拿着那么这个策略就需要重新评估。2.2 双均线策略是什么双均线策略是用两条移动平均线判断趋势。本次代码中使用的是MA5最近5天平均收盘价 MA20最近20天平均收盘价交易规则是MA5 MA20短期趋势强于长期趋势明天持仓 MA5 MA20短期趋势弱于长期趋势明天空仓代码里最关键的一句是df[position]df[signal].shift(1).fillna(0).astype(int)这里使用shift(1)是为了避免“偷看未来”。因为今天的均线信号要等今天收盘后才能知道所以只能从下一个交易日开始执行。3. 关键代码理解3.1 计算每日收益率df[ret]df[Close].pct_change().fillna(0)这行代码计算股票每天的涨跌幅。3.2 计算策略收益df[strategy_ret]df[position]*df[ret]含义是position 1时策略持仓吃到当天涨跌position 0时策略空仓当天收益为 0。3.3 计算累计净值df[nav_strategy](1df[strategy_ret]).cumprod()cumprod()的作用是把每天的收益连续乘起来得到从 1 元钱开始的账户净值变化。4. 最大回撤最大回撤表示账户净值从历史最高点到后面最低点之间最大跌了多少。计算逻辑是peaknav_series.cummax()drawdownnav_series/peak-1最大回撤不是看最后赚没赚钱而是看过程中最痛苦的时候亏了多少。所以一个策略即使最后赚钱如果中间最大回撤太大也可能很难坚持执行。5. 本次作业挑战 1把TICKER改成NVDA截一张策略 vs 大盘净值图写一句话跑赢还是跑输# 第四章通关作业策略回测 importsysimportwarningsfrompathlibimportPathimportmatplotlib.pyplotaspltimportnumpyasnpimportpandasaspdimportyfinanceasyf warnings.filterwarnings(ignore)ifhasattr(sys.stdout,reconfigure):sys.stdout.reconfigure(encodingutf-8)ifhasattr(sys.stderr,reconfigure):sys.stderr.reconfigure(encodingutf-8)plt.rcParams[font.sans-serif][SimHei]plt.rcParams[axes.unicode_minus]FalseTICKERNVDABENCHMARKSPYOUTPUT_DIRPath(__file__).resolve().parentdefmax_drawdown(nav_series):返回最大回撤比例。peaknav_series.cummax()drawdownnav_series/peak-1returndrawdown.min(),drawdowndefrun_backtest(period):运行双均线策略回测并返回带净值和回撤的数据。rawyf.download(TICKER,periodperiod,progressFalse,multi_level_indexFalse)ifraw.empty:raiseRuntimeError(f{TICKER}在{period}周期没有下载到数据)dfraw[[Close]].dropna().copy()df.columns[Close]df[MA5]df[Close].rolling(5).mean()df[MA20]df[Close].rolling(20).mean()df[signal](df[MA5]df[MA20]).astype(int)df[position]df[signal].shift(1).fillna(0).astype(int)df[ret]df[Close].pct_change().fillna(0)df[strategy_ret]df[position]*df[ret]df[buyhold_ret]df[ret]spyyf.download(BENCHMARK,periodperiod,progressFalse,multi_level_indexFalse)[[Close]]ifspy.empty:raiseRuntimeError(f{BENCHMARK}在{period}周期没有下载到数据)spy.columns[SPY_Close]dfdf.join(spy,howinner)df[market_ret]df[SPY_Close].pct_change().fillna(0)df[nav_strategy](1df[strategy_ret]).cumprod()df[nav_buyhold](1df[buyhold_ret]).cumprod()df[nav_market](1df[market_ret]).cumprod()df[mdd_strategy],df[drawdown_strategy]max_drawdown(df[nav_strategy])df[mdd_buyhold],df[drawdown_buyhold]max_drawdown(df[nav_buyhold])returndfdefsave_nav_chart(df,period):保存策略 vs 标的 vs 大盘净值图。fig,axplt.subplots(figsize(14,6))ax.plot(df.index,df[nav_strategy],linewidth2.2,colortab:purple,labelf双均线策略 ({TICKER}))ax.plot(df.index,df[nav_buyhold],linewidth1.8,colortab:blue,alpha0.85,labelf买入持有 ({TICKER}))ax.plot(df.index,df[nav_market],linewidth1.8,colortab:gray,linestyle--,labelf买入持有 ({BENCHMARK}大盘))ax.axhline(1.0,colorblack,linewidth0.6,linestyle:,alpha0.5)ax.set_title(f{TICKER}回测净值曲线策略 vs 标的 vs 大盘{period},fontsize14)ax.set_xlabel(日期)ax.set_ylabel(净值起点1)ax.legend(locupper left)ax.grid(True,alpha0.3)plt.tight_layout()chart_pathOUTPUT_DIR/fhomework_{TICKER}_{period}_nav_comparison.pngplt.savefig(chart_path,dpi150)plt.close(fig)returnchart_pathdefsummarize(period,df):打印单个周期的关键回测结果。total_strategydf[nav_strategy].iloc[-1]-1total_buyholddf[nav_buyhold].iloc[-1]-1total_marketdf[nav_market].iloc[-1]-1mdd_strategydf[mdd_strategy].iloc[-1]mdd_buyholddf[mdd_buyhold].iloc[-1]print(f\n{period}回测结果 )print(f双均线策略 ({TICKER}) 累计收益{total_strategy:.2%})print(f买入持有 ({TICKER}) 累计收益{total_buyhold:.2%})print(f买入持有 ({BENCHMARK}大盘) 累计收益{total_market:.2%})print(f双均线策略最大回撤{mdd_strategy:.2%})print(f买入持有最大回撤{mdd_buyhold:.2%})returnmdd_strategydefmain():print(第四章作业NVDA 双均线策略回测 [OK])df_1yrun_backtest(1y)chart_pathsave_nav_chart(df_1y,1y)print(f\n作业1策略 vs 大盘净值图已保存{chart_path})strategy_enddf_1y[nav_strategy].iloc[-1]market_enddf_1y[nav_market].iloc[-1]race_answer跑赢ifstrategy_endmarket_endelse跑输print(f一句话1y 周期里NVDA 双均线策略相对 SPY 大盘是{race_answer}。)summarize(1y,df_1y)if__name____main__:main()运行结果双均线策略 (NVDA) 累计收益-12.45% 买入持有 (NVDA) 累计收益22.21% 买入持有 (SPY 大盘) 累计收益19.87% 双均线策略最大回撤-28.41% 买入持有最大回撤-20.21%结论1 年周期里NVDA 双均线策略相对 SPY 大盘是跑输的。挑战 2对比PERIOD1y和5y最大回撤哪个更深我更能接受哪种根据运行结果1y 双均线策略最大回撤-28.41% 5y 双均线策略最大回撤-52.50%结论5y 的最大回撤更深。如果只看最大回撤我更能接受1y的结果因为它从历史高点跌下来的幅度更小。5y虽然样本更长但过程中经历过更深的下跌对执行策略的心理压力更大。挑战 3用三句话向朋友解释“回测是什么”回测就是用历史数据假装自己过去真的按照一套规则买入、持仓和卖出。它能帮我们看清策略过去的收益、回撤和风险但不能保证未来还会赚钱。所以回测更像是给策略做体检而不是预测未来。6. 学习理解量化策略不能只看“最后赚了多少”还要看过程中有没有大幅亏损以及是否真的跑赢了简单基准。以后看策略时我应该同时关注收益、最大回撤、基准比较等。