仓位管理大杀器:凯利公式你用对了吗?
今天我们介绍一个神奇的人,和他神奇的公式。目前网络上传播较广的一篇讲凯利公式前世今生的文章,个人认为深度不够当然,而且思路是有问题的。大家不要看多了走偏路。最近也花了一些力气做梳理,把这篇分享出来,尽量做到讲对,讲透,也是提醒各位,低头挖矿,不要搞错了挖矿的初衷。_
一、故事背景
市场不好的时候,我们总是会犹豫,满仓?半仓?还是空仓?有没有一个科学的办法给出一个标准答案呢?下面来看看仓位管理神器——凯利公式。
投资(ji)就是一场赌博。像索普、香农等很多投资大师早期都对研究赌博业的秘密情有独钟,科学家们总是希望从理论上找到赌博游戏的必胜策略,使得一场游戏中赢的概率远远高过输的概率。
凯利就是这样一个大师。他是香农(信息论创始人)在贝尔实验室的同事,这个来自德克萨斯州、爱摆弄手枪、喜欢一根接一根抽烟的狂野硬汉,干过很多恶作剧,特别喜欢将填满塑料的子弹射进他客厅的墙壁里来戏弄家里暂住的客人。他的研究领域从量子物理学到电视信号解码,发明了能够准确模拟人类声音的电脑设备。最广为人知的研究贡献,便是将香农的信息论运用到了赛马赌博中。
凯利用这样一个精巧简洁的公式,将信息论与赌博之间的本质联系揭露出来,告诉我们在有限了解的信息下,如何下注能使得资本增值的速度最大化。
二、赌博怎么用凯利公式?
最早的凯利公式是运用在赌博游戏中的,我们先看看赌博情形下凯利公式的特殊形式:
f:下注比例
Pwin:赌赢的概率
Ploss:赌输的概率(=1-Pwin)
b:赔率,押1赔b(这个赌球的朋友们是不陌生啦)
举个简单的例子
假想一个游戏。赢的概率是60%,输的概率40%。入场费随意交。如果赢了获得2倍的入场费金额(1赔1),输则输掉入场费。小米有100元做本金,请问小米每次给多少入场费,理论上4次游戏后几何期望收益能最大?
然后我拿凯利公式算了一下,最佳的策略是每次投剩余本金的20%。
f = (1×0.6-0.4)/1 = 0.2。
基于上述的例子,做个简单的蒙特卡洛模拟实验(进行200次游戏):
**In[1]:**
from pandas import DataFrame
base = 100
pwin = 0.6
ploss = 1-pwin
b = 1
c = 1
rnd_position = 0.25
rnd_position2 = 0.15
kelly_position = (pwin*b - ploss)/b
stopline = 1
print 'kelly position is %s'%kelly_position
port_A = DataFrame()
port_B = DataFrame()
port_C = DataFrame()
port_D = DataFrame()
# 重复模拟次数
for i in range(1000):
port1 = [base]
port2 = [base]
port3 = [base]
port4 = [base]
# 游戏进行次数
for step in range(200):
rnd = random.random()
if rnd base*(1-stopline):
port1.append(port1[-1]*(1+next_step))
else:
port1.append(port1[-1])
if port2[-1] > base*(1-stopline):
port2.append(port2[-1]*(1+next_step*kelly_position))
else:
port2.append(port2[-1])
if port3[-1] > base*(1-stopline):
port3.append(port3[-1]*(1+next_step*rnd_position))
else:
port3.append(port3[-1])
if port4[-1] > base*(1-stopline):
port4.append(port4[-1]*(1+next_step*rnd_position2))
else:
port4.append(port4[-1])
port_A[i] = port1
port_B[i] = port2
port_C[i] = port3
port_D[i] = port4
plt.figure(figsize = (8,5))
plt.plot(exp(log(port_A.T).sum()/1000),label = 'port1:full')
plt.plot(exp(log(port_B.T).sum()/1000),'*',label = 'port2:kelly')
plt.plot(exp(log(port_C.T).sum()/1000),label = 'port3:0.25')
plt.plot(exp(log(port_D.T).sum()/1000),label = 'port4:0.15')
plt.legend(loc = 0)
print '\n不同组合的几何期望收益'
print 'full position %s'%exp(log(port_A.T).sum()/1000).iloc[-1]
print 'kelly position %s'%exp(log(port_B.T).sum()/1000).iloc[-1]
print 'position = 0.25 %s'%exp(log(port_C.T).sum()/1000).iloc[-1]
print 'position = 0.15 %s'%exp(log(port_D.T).sum()/1000).iloc[-1]
**Out[1]:**
观察四种操作方式:满仓下注、按凯利公式下注20%、按25%下注、按15%下注
图为进行200次游戏之后几何期望资金曲线的情况
凯利无疑是增长最快的!
从另一个角度,我们来理解一下
不同赔率下,赢的概率多大我们会选择入场参与游戏?
还是上面的游戏,如果赢的概率40%,输的概率60%,那么,期望净收益就是(1×0.4-0.6)=0)
zero = 0
fig = plt.figure(figsize = (10,6))
ax = fig.gca(projection = '3d')
surf = ax.plot_surface(b,pwin,kelly,rstride=1, cstride=1,cmap = plt.cm.coolwarm)
ax.plot_surface((1-pwin)/pwin,pwin,0)
ax.set_xlabel('b 赔率')
ax.set_ylabel('pwin 赢概率')
ax.set_zlabel('kelly 下注比例')
fig.colorbar(surf,shrink = 0.6,aspect = 10)
Out[2]:
上图说明两个问题:
1. 如果一次赌博赔率越大,在赢的概率较小的情况下,凯利公式就开始提示要下注啦。(如图赔率为20时,只需要10%的赢率就可以入场玩啦)
2. 同一赔率下,凯利公式只有在稳赢(赢概率=100%)时才会支持押下全部本金,否则都是本金的一定比例。也即永远不会输完所有的钱。
三、炒股怎么用凯利公式?
凯利的论文给出的押注策略,神奇之处就在于,当你总是遵循这一准则进行操作,你就能预测接下来发生的事情,你也能清楚的知道你的财富增长速度是在控制住风险情况下最优的结果。
来看看凯利运用他的财富公式,专门成立的hedge fund 的performance~20年15倍,就是辣么厉害。
数据:《财富公式:玩转拉斯维加斯和华尔街的故事》
那么问题来了,我们量化炒股如何引入这么神奇的仓位管理神器?
因为股市的涨跌我们不会一次性赔光本金,所以引入损失率对凯利公式做微调,即更一般性的凯利公式:
f:仓位比例
Pwin:赌赢的概率—股市上涨概率
Ploss:赌输的概率—股市下跌概率
b:赢钱率(资产从1增加到1+b)
c:损失率(资产从1减少到1-c)
仔细想一个问题(挖矿秘籍)
赌博和买股票,赢概率Pwin和输概率Ploss究竟是什么?
赌博的时候,Pwin和Ploss是根据游戏规则算出的概率而定。比如投硬币(Pwin=Ploss=0.5),或者转轮盘,扑克等更为复杂的游戏。
而买股票的过程,是n次离散赌博的过程。当你找到一个有效信号之后进行一次操作(比如有效信号是价格突破5日均线,财务数据好,成交量放大,或者各种金叉死叉等等。。)
假设我们找到了一个有效信号,信号发生时,股价为S。我们提前给定价格S(1+b)和S(1-c)作为信号发生后止盈和止损的边界,这个时候的Pwin和Ploss应该是基于历史这个信号的收益情况做数据统计分析胜率(赢概率)和败率(输概率)来给出,也即价格触碰到S(1+b)止盈的概率是Pwin,触碰到S(1-c)止损的概率是Ploss。
又举一个简单例子
有效信号:当前价突破5日均线
统计样本:100只相似股票,过去三年有效信号发生了1000次
统计包含:假定上涨20%止盈,下跌20%止损。止盈赢钱的次数57次,止损输钱的次数43次
对应公式的参数:Pwin=0.57,Ploss=0.43,b=0.20,c=0.20
此时f=Pwin/c – Ploss/b = 0.57/0.20 – 0.43/0.20= 70%
按照我们对某一个有效信号做历史统计定出来的Pwin,Ploss,b和c来进行模拟的投资组合看看看效果:
In[3]:
from pandas import DataFrame
base = 100
pwin = 0.57
ploss = 1-pwin
b = 0.2
c = 0.2
stopline后文会介绍
stopline = 1
rnd_position = 0.6
rnd_position2 = 0.9
kelly_position = (pwin/c - ploss/b)*stopline
print 'kelly position is %s'%kelly_position
port_A = DataFrame()
port_B = DataFrame()
port_C = DataFrame()
port_D = DataFrame()
重复模拟次数
for i in range(1000):
port1 = [base]
port2 = [base]
port3 = [base]
port4 = [base]
投资次数步长
for step in range(500):
rnd = random.random()
if rnd base*(1-stopline):
port1.append(port1[-1]*(1+next_step))
else:
port1.append(port1[-1])
if port2[-1] > base*(1-stopline):
port2.append(port2[-1]*(1+next_step*kelly_position))
else:
port2.append(port2[-1])
if port3[-1] > base*(1-stopline):
port3.append(port3[-1]*(1+next_step*rnd_position))
else:
port3.append(port3[-1])
if port4[-1] > base*(1-stopline):
port4.append(port4[-1]*(1+next_step*rnd_position2))
else:
port4.append(port4[-1])
port_A[i] = port1
port_B[i] = port2
port_C[i] = port3
port_D[i] = port4
port1 = [base]
port2 = [base]
port3 = [base]
port4 = [base]
投资次数步长
for step in range(500):
rnd = random.random()
if rnd base*(1-stopline):
port1.append(port1[-1]*(1+next_step))
else:
port1.append(port1[-1])
if port2[-1] > base*(1-stopline):
port2.append(port2[-1]*(1+next_step*kelly_position))
else:
port2.append(port2[-1])
if port3[-1] > base*(1-stopline):
port3.append(port3[-1]*(1+next_step*rnd_position))
else:
port3.append(port3[-1])
if port4[-1] > base*(1-stopline):
port4.append(port4[-1]*(1+next_step*rnd_position2))
else:
port4.append(port4[-1])
port_A[i] = port1
port_B[i] = port2
port_C[i] = port3
port_D[i] = port4
port1 = [base]
port2 = [base]
port3 = [base]
port4 = [base]
投资次数步长
for step in range(500):
rnd = random.random()
if rnd base*(1-stopline):
port1.append(port1[-1]*(1+next_step))
else:
port1.append(port1[-1])
if port2[-1] > base*(1-stopline):
port2.append(port2[-1]*(1+next_step*kelly_position))
else:
port2.append(port2[-1])
if port3[-1] > base*(1-stopline):
port3.append(port3[-1]*(1+next_step*rnd_position))
else:
port3.append(port3[-1])
if port4[-1] > base*(1-stopline):
port4.append(port4[-1]*(1+next_step*rnd_position2))
else:
port4.append(port4[-1])
port_A[i] = port1
port_B[i] = port2
port_C[i] = port3
port_D[i] = port4
plt.figure(figsize = (8,5))
plt.plot(exp(log(port_A.T).sum()/1000),label = 'port1:full')
plt.plot(exp(log(port_B.T).sum()/1000),label = 'port2:kelly')
plt.plot(exp(log(port_C.T).sum()/1000),label = 'port3:position = 0.6')
plt.plot(exp(log(port_D.T).sum()/1000),label = 'port3:position = 0.9')
plt.legend(loc = 0)
print '\n不同组合的几何期望收益'
print 'full position %s'%exp(log(port_A.T).sum()/1000).iloc[-1]
print 'kelly position %s'%exp(log(port_B.T).sum()/1000).iloc[-1]
print 'position = 0.6 %s'%exp(log(port_C.T).sum()/1000).iloc[-1]
print 'position = 0.9 %s'%exp(log(port_D.T).sum()/1000).iloc[-1]
Out[3]:
同样四种仓位操作后的资金曲线来进行比较:
1. 凯利公式下资金曲线增长是最快的。
2. 高于或低于凯利公式的比例资金曲线增长都不是最快的。
再思考一个问题:关于杠杆
再多举一个例子:f>1
研究不能止步于此啊。很多知道凯利公式的朋友都有的疑问,是凯利计算出来的仓位容易过大。比如一不小心就提示几倍,几十倍了。这是什么情况呢?
比如我们找到一个信号:Pwin=0.7,Ploss=0.3,b=0.20,c=0.20
来看看实验结果(代码同上,只修改上述参数)
Out[4]:
f>1了,甚至等于4了,什么意思!!凯利公式在告诉你这个信号太好了,值得你做4倍的杠杆来操作~!什么,你说我多加一点好不好,看上图,加到6倍显然就挫了。。。
(想知道凯利公式为何能做到几何期望收益最大化,证明过程戳wiki百科自行科普)
再思考一个止损的问题,stopline不为1
上面杠杆的问题引出其实说明了A股版凯利公式暗含的一个假设:
资金可以随意无摩擦地加杠杆操作,无借贷成本。
什么意思。一个好的信号,凯利会告诉你在已知风险(Pwin,Ploss,b和c)的情况下,最优的杠杆是多少。你可以毫不犹豫的就按这个杠杆去操作,最大化自己的资金曲线。
那么真实情况下呢,我们可能不加杠杆,而且也不能承受全部本金损失掉的风险。也就是,我们stopline会小于1,甚至只到30%或者20%。那这时候凯利公式怎么用?
这里不做实验,仅抛个引子。感兴趣的朋友可以继续深入研究,也欢迎与我探讨。
A. 静态止损:即亏损本金的固定数额后撤出投资
kelly_position = (pwin/c - ploss/b)×stopline
stopline应为此时剩余可承受的损失/本金base。
举例:base=100元,输20元止损。initial_stopline = 0.2。假设损失率c = 0.04
第一次,赔了4块,base=96,stopline = (20-4)/96 = 0.16
第n次,输输赢赢后,base = 250,stopline = (150-4)/250 = 0.584
B. 动态止损:即亏损剩余资金的一定比例后撤出投资
比如动态20%止损。base =100元,赚到200元后,如亏损到160元即止损。
这个具体实验就留给各位自己研究啦~~
Bonus:小结一下
好啦,少年。真正赚钱的是找有效的因子or信号,使得Pwin尽可能大,b尽可能大。无论是以往大家关注的一些技术指标(各种金叉、死叉)还是量价指标(放量、突破等等)又或者是财务指标,都可以作为一个信号。
统计历史信号出现时的一个表现,得到这个信号产生的收益的分布。只要这个信号的收益分布正偏一些些,就是纯纯的Alpha啊。当然这个因子or信号的挖掘,就是作为矿工孜孜不倦追求的终极目标了。当你找到这样一个神奇的信号,配上凯利公式会让你的财富增加更快~
程序化交易, 交易策略
风险提示及免责条款
市场有风险,投资需谨慎。本文不构成个人投资建议,也未考虑到个别用户特殊的投资目标、财务状况或需要。用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!