如何用 Python 计算凯利公式仓位(Kelly Criterion)?用胜率与盈亏比定最优下注比例
如何用 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 | 实务常用,降波动 |
| 连续凯利 | 均值/方差 | 连续收益近似 |
关键坑与注意事项
- 凯利为负=不该下注:f* ≤ 0 意味着策略无正期望,答案是”不交易/重做策略”,不是”用很小仓位”。本例 −0.195 就是如此。
- 满凯利极其激进:即便 f* > 0,全凯利的回撤常达 50%+,心态和资金都难承受;实务普遍用半凯利或更低。
- p、b 不稳定:它们是历史估计,样本少(本例仅 43 笔)时噪声极大,未来会漂移;凯利对 b 的估计误差很敏感。
- 假设独立同分布:经典凯利假设每次下注独立、分布不变;实盘有自相关、有肥尾,直接套用会高估最优仓位。
- 单资产 vs 组合:多标的要用”组合凯利”(考虑相关性),单笔公式不能简单相加。
- 前复权必须:否则交易收益被除权缺口污染,p、b 全错。
常见问题(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 不稳定、实务用半凯利。
相关链接:
- AlphaFeed 官网:https://alphafeed.org/
- Python SDK 快速开始:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。