【Python量化实战入门 #02】宣传页的夏普、最大回撤,用麦蕊K线自己算一遍
2026/8/12 14:31:49 网站建设 项目流程

📚本系列进度:#01 ✅(跑通 SDK 打出实时行情) · #02 ✅(本篇) · #03–#16 ⏳ 规划中
系列定位:面向零基础开发者的「从 0 到 1 量化工具箱」连载,数据源全部锁定麦蕊行情 API。


一、为什么写这篇

你买基金、看策略,是不是常被一串指标砸脸:「年化夏普 2.3」「最大回撤仅 8%」?

这些数字到底是算出来的,还是写出来的?很多人信了一辈子,却从没自己算过一遍。

这一篇,我们拿麦蕊的真实历史 K 线,把累计收益、最大回撤、年化波动、夏普、胜率这五个「宣传页常客」亲手算一遍。算完你就明白:指标不神秘,神秘的是「它用哪段数据算的」。

二、读完你能得到什么

  • stock_history拉取任意股票的历史日 K 线;
  • 手写最大回撤(不用任何「神器」库);
  • 搞懂夏普比率到底在比什么;
  • 一个可复用的main.py,改个代码就能算任意标的。

三、环境准备

接上篇:SDK 已装、证书已在环境变量MAIRUI_LICENCE。本篇只需标准库 +math,不额外装包。

四、核心代码

importos,sys,datetime sys.path.insert(0,"Demo/_common")frommairui_helperimportload_licencefrommairuiimportClientimportmathdefget_close_series(mc,code,days=120):end=datetime.date.today().strftime("%Y%m%d")start=(datetime.date.today()-datetime.timedelta(days=days)).strftime("%Y%m%d")rows=mc.stock_history(code,"d","n",st=start,et=end)# dividend='n' 不复权clean=[rforrinrowsifr.get("c")isnotNoneandr.get("t")]clean.sort(key=lambdar:r["t"])return[r["c"]forrinclean]defmax_drawdown(close):peak=close[0]mdd=0.0forpinclose:ifp>peak:peak=p dd=(p-peak)/peakifdd<mdd:mdd=ddreturnmdddefdaily_returns(close):return[(close[i]-close[i-1])/close[i-1]foriinrange(1,len(close))]defstats(close):rets=daily_returns(close)n=len(rets)cum=(close[-1]-close[0])/close[0]mdd=max_drawdown(close)mean=sum(rets)/n std=math.sqrt(sum((r-mean)**2forrinrets)/n)ann_vol=std*math.sqrt(252)sharpe=(mean*252)/(std*math.sqrt(252))ifstd>0else0.0win=sum(1forrinretsifr>0)/nreturncum,mdd,ann_vol,sharpe,win mc=Client(load_licence())close=get_close_series(mc,"000001",days=120)cum,mdd,ann_vol,sharpe,win=stats(close)print(f"累计收益率{cum*100:.2f}% 最大回撤{mdd*100:.2f}%")print(f"年化波动率{ann_vol*100:.2f}% 夏普(简化){sharpe:.2f}胜率{win*100:.2f}%")

五、跑出来的真实结果

本机当天实跑(非虚构),以平安银行(000001) 近 120 日窗口:

=== 000001 近 82 个交易日 === 首个交易日: 2026-04-08 收盘 11.22 最后交易日: 2026-08-05 收盘 11.25 --- 手算收益风险指标 --- 累计收益率 : 0.27 % 最大回撤 : -12.76 % (从山顶到谷底最狠的一刀) 年化波动率 : 18.04 % 夏普(简化) : 0.14 胜率 : 46.91 % (38/81 个交易日上涨)

六、原理拆解(口语化)

  • 累计收益率:首尾一减一除,最直白。
  • 最大回撤:想象你账户净值画成一条线,从任意「山顶」跌到之后「谷底」最狠的那一刀,就是最大回撤。它不管你最后赚没赚,只记你「最痛的一次」。代码里边走边记历史最高peak,每步算(当前-peak)/peak,取最小。
  • 年化波动率:日收益上下乱跳的幅度 × √252(一年约 252 个交易日)。跳得越凶,波动越大。
  • 夏普比率(简化版)年化收益 ÷ 年化波动。它回答一个问题——你每多冒一份险,多赚了几份钱?这里无风险利率取 0,所以夏普偏低;真实算法要减掉国债收益。
  • 胜率:上涨交易日 ÷ 总交易日。46.91% 说明这只票近 4 个月「涨的日子还没跌的多」,但累计却微涨 0.27%——因为涨的日子平均涨得比跌的日子狠。这就是胜率低不等于亏钱的例子

一句记忆:最大回撤量「最痛」,夏普量「值不值」,胜率量「频率」,三个维度拼起来才看懂一个策略。

七、常见坑

  1. 复权参数填错stock_historydividend'n'(不复权)或'q'(前复权),填'1'会直接返回{'error':'数据不存在'}
  2. 返回是 list 不是 dict:别拿hist['data']去取,直接遍历。
  3. 空行:历史接口偶尔返回cNone的行,计算前务必过滤,否则除零崩。
  4. 夏普别神化:简化版没减无风险利率,且对「用哪段窗口算」极度敏感——换段时间数字能差很远。

八、小结 + 下篇预告

今天你亲手算出了夏普和最大回撤。下次再看到「夏普 2.3」的宣传,你会先问:这段 K 线从哪天到哪天?

下一篇#03:把行情落进SQLite,搭一个本地行情库,让历史 K 线随用随取、还能增量更新(也呼应盯盘系列的落库那篇)。


⚠️ 本文仅为技术实现演示,不构成任何投资建议。指标计算依赖历史数据,不代表未来表现;市场有风险,投资须谨慎。代码示例仅用于学习。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询