AlphaFeed Blog

如何用 Python 计算凯利公式仓位(Kelly Criterion)?用胜率与盈亏比定最优下注比例

分析与指标 · 代码验证于 2026-10-18

如何用 Python 计算凯利公式仓位(Kelly Criterion)?

一句话回答: 凯利公式给出”长期资金增长最快”的下注比例:f* = p − (1−p)/b,其中 p = 胜率、b = 盈亏比(平均盈利 ÷ 平均亏损)。用 AlphaFeed 取前复权日线跑一个策略、从真实交易统计出 p 和 b 即可代入——关键结论:当 f* ≤ 0 说明策略没有正期望,凯利告诉你”根本不该下注”;即便 f* > 0,实务也常用「半凯利」降低波动。

为什么会有这个问题 / 传统做法的痛点

“该用多少仓位”是比”买什么”更决定生死的问题:仓位过大,一轮回撤就爆仓;过小,赢了也赚不到。凯利公式从数学上给出使对数财富期望最大的比例。痛点有三:① 很多人不知道 p、b 要从自己策略的真实交易估、而非拍脑袋;② 忽视”凯利为负=无正期望”这一最有用的信号;③ 直接上满凯利,波动大到心态崩溃。本文用真实回测交易演示全过程。

分步骤解决(每步配可运行代码)

第 1 步:取前复权日线,跑一个策略拿到交易序列

from alphafeed import AlphaFeed
import numpy as np, pandas as pd

af = AlphaFeed(api_key="your-api-key")  # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()

df = af.klines.get("600519.SH", period="1d", count=800,
                   adjust="forward", to_dataframe=True).sort_values("trade_date").reset_index(drop=True)

def ma_trades(df, n=20, fee=0.0013):          # 简单 MA20 上/下穿策略,次日开盘成交
    df = df.copy(); df["ma"] = df["close"].rolling(n).mean(); df["open_next"] = df["open"].shift(-1)
    pos, entry, rets = 0, 0.0, []
    for i in range(n, len(df) - 1):
        px = df["open_next"].iloc[i]
        if np.isnan(px) or np.isnan(df["ma"].iloc[i]): continue
        c, cp, m, mp = df["close"].iloc[i], df["close"].iloc[i-1], df["ma"].iloc[i], df["ma"].iloc[i-1]
        if pos == 0 and cp <= mp and c > m:   pos, entry = 1, px
        elif pos == 1 and cp >= mp and c < m: rets.append(px/entry*(1-fee)**2 - 1); pos = 0
    return pd.Series(rets)

rets = ma_trades(df, 20)

第 2 步:从交易统计出胜率 p、盈亏比 b,代入凯利

wins, losses = rets[rets > 0], rets[rets < 0]
p = len(wins) / len(rets)                       # 胜率
b = wins.mean() / (-losses.mean())              # 盈亏比 = 平均盈利 / 平均亏损
kelly = p - (1 - p) / b                          # 凯利比例 f*
print(f"交易{len(rets)}次 胜率{p:.3f} 盈亏比{b:.3f} 凯利f*={kelly:.3f} 半凯利={kelly/2:.3f}")

实测(tools/verify_new_2026-10-18.py,SDK 0.1.4):贵州茅台 MA20 策略近 800 日 43 次交易、胜率 0.186、盈亏比 2.138,代入得 凯利 f* = −0.195(负!)。解读:虽然盈亏比 >2,但胜率只有 18.6%,p−(1−p)/b = 0.186 − 0.814/2.138 ≈ −0.195 < 0 —— 这个策略没有正期望,凯利明确告诉你”别下注”,而不是去算仓位。这正是凯利最有价值的用法之一。

第 3 步:连续型凯利(用收益均值/方差,供参考)

daily = df["close"].pct_change().dropna()
kelly_cont = daily.mean() / daily.var()         # 连续凯利近似:均值/方差
print(f"连续凯利(日)≈{kelly_cont:.2f}")

对连续收益,凯利近似为 均值/方差;本例为负,与上面结论一致(该区间无正向边际)。

参数与字段说明

参数/概念含义备注
adjust="forward"前复权必须,否则交易盈亏失真
p胜率盈利交易数/总交易数
b盈亏比平均盈利/平均亏损
f* = p−(1−p)/b凯利比例≤0 则不下注
半凯利f*/2实务常用,降波动
连续凯利均值/方差连续收益近似

关键坑与注意事项

常见问题(FAQ)

Q:盈亏比大于 1 为什么凯利还是负的? A:因为胜率太低。凯利同时看胜率和盈亏比:f* = p − (1−p)/b。本例 b=2.14 不错,但 p 只有 18.6%,0.814/2.14≈0.38 > 0.186,所以 f* 为负。高盈亏比也救不了过低的胜率。

Q:为什么推荐半凯利? A:全凯利理论增长最快,但波动/回撤巨大,且 p、b 一旦高估就会”过注”导致长期亏损。半凯利牺牲一点增长换取大幅更低的波动,稳健性显著提升,是业界常见折中。

Q:需要付费吗? A:单只股票日线回测在免费额度内即可;若要对全市场/组合估 p、b 做组合凯利,需要 klines.batch(Starter 及以上),详见官网定价页。

小结

凯利公式用胜率 p 与盈亏比 b(f* = p−(1−p)/b)给出长期增长最优仓位。用 AlphaFeed 的前复权日线从真实策略交易估 p、b 即可代入——最关键的是读懂”凯利为负=没有正期望、根本不该下注”(本例 f*=−0.195),以及满凯利太激进、p/b 不稳定、实务用半凯利。

相关链接:


免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。