引言

在上一次我们提到了凯利公式,很多人可能会想去套用凯利公式到我们的投资策略里面去,但是实际操作中, 我们会发现,很多量化平台,回测数据并不够,譬如说,掘金量化平台,它提供了胜率,收益情况等,但是 并没有赔率的结果,那么,我们是不是就不能去进行相应的凯利公式计算了呢?

凯利公式的套用

其实换一种思路,我们完全自己在策略中进行运算,笔者这里简单起见,对沪深 300 指数进行买入和平仓 操作,交易策略用的是双均线策略,为了看出策略在交易标的上的胜率与赔率表现,笔者每次都是满仓买入 满仓卖出,同时,简单起见同时为了看到足够多的交易,这里用了 1 分钟数据择时,不再加入 T+1 限制。 策略代码如下所示:

# coding=utf-8"""
双均线策略
"""
from gm.api import *
from datetime import datetime
from datetime import date
from datetime import timedelta
from collections import deque
import numpy as np
import talib# 常用常量设置
DATE_STR = "%Y-%m-%d"
TIME_STR = "%Y-%m-%d %H:%M:%S"
HIST_WINDOW = 50
LIMIT_LISTED_MONTH = 2
SHORT_PERIOD = 5
LONG_PERIOD = 10def init(context):stock = 'SHSE.000300'context.stock_prices = deque(maxlen=HIST_WINDOW)context.risk_ratio = 1.0context.entry_price = 0.context.profit = 0.context.loss = 0.context.win_counter = 0context.loss_counter = 0start_today = datetime.strftime(date.today()-timedelta(days=1), DATE_STR)history_bars = history_n(symbol=stock,frequency='60s',count=HIST_WINDOW,end_time=start_today,adjust=ADJUST_PREV,adjust_end_time=context.backtest_end_time)for bar in history_bars:context.stock_prices.append(bar.close)subscribe(stock, '60s')def on_bar(context, bars):# ----------------------- 策略执行 -----------------------------------------# 数据不足数据滑窗要求,返回if len(context.stock_prices) < HIST_WINDOW:returnpos = context.account().position(symbol=bars[0].symbol, side=PositionSide_Long)open_vol = int(context.account().cash.available * context.risk_ratio /bars[0].close/100)*100# 指标计算closes = np.array(context.stock_prices)ma5 = talib.SMA(closes, SHORT_PERIOD)ma10 = talib.SMA(closes, LONG_PERIOD)if ma5[-2] < ma10[-2] and ma5[-1] >= ma10[-1]:flag_golden_cross = Trueflag_dead_cross = Falseelif ma5[-2] > ma10[-2] and ma5[-1] <= ma10[-1]:flag_dead_cross = Trueflag_golden_cross = Falseelse:flag_dead_cross = Falseflag_golden_cross = Falseif pos is None and flag_golden_cross:order_volume(symbol=bars[0].symbol,volume=open_vol,side=OrderSide_Buy,order_type=OrderType_Limit,position_effect=PositionEffect_Open,price=bars[0].open)context.entry_price = bars[0].openif pos is not None and flag_dead_cross:order_volume(symbol=bars[0].symbol,volume=pos.volume,side=OrderSide_Sell,order_type=OrderType_Limit,position_effect=PositionEffect_Close,price=bars[0].open)if bars[0].open > context.entry_price:context.profit = context.profit + (bars[0].open - context.entry_price)*pos.volumecontext.win_counter += 1else:context.loss = context.loss + (context.entry_price - bars[0].open)*pos.volumecontext.loss_counter += 1# ----------------------- 数据填充 -----------------------------------------context.stock_prices.append(bars[0].close)if datetime.strftime(bars[0].eob, TIME_STR) == context.backtest_end_time:print("总盈利为: ", context.profit, "\n""总亏损为: ", context.loss, "\n","实际盈利为: ", context.profit-context.loss)print("盈利次数为: ", context.win_counter, "\n", "亏损次数为: ", context.loss_counter, "胜率为: ", context.win_counter/(context.win_counter+context.loss_counter))print("平均每次盈利为: ", context.profit/context.win_counter, "\n", "平均每次亏损为: ", context.loss/context.loss_counter, "\n","盈亏比为: ", context.profit*context.loss_counter/context.loss/context.win_counter)if __name__ == '__main__':run(strategy_id='5127bcbb-8da3-11e8-9ce5-f48c50eb367a',filename='main.py',backtest_initial_cash=10000000,mode=2,token='64c33fc82f334e11e1138eefea8ffc241db4a2a0',backtest_start_time='2015-02-01 09:30:00',backtest_end_time='2017-04-05 15:00:00')

运行结果,得到结果如下:

可能有读者会奇怪,为何我们自己计算出来的盈亏结果和掘金量化终端显示有差异,其实这里的差异来自于最后 一笔交易,可能策略仅仅做了买入的操作,而没有卖出,导致的浮动盈亏,实际如果读者去下载回测详细记录, 可以看到,如果将总盈利减去浮动盈亏,得到的结果和我们计算的结果一致。

将策略中的 context.risk_ratio 改为 0.96, 可以看到,回测情况如下所示:

盈利确实有增加,那么,是不是我们就可以按照凯利公式去进行投资了呢?

讨论

实际情况下,一般不会有人去按照凯利公式进行仓位配置的,凯利公式又被称为破产公式, 因为回测行情仅仅 针对于回测区间的行情对策略有效性的判断,当行情切换,或者哪怕行情不变,但是不同时间区间内,行情也不会 完全一样,回测时得到的胜率,盈亏比,仅供参考,给出一个大概区间范围,如果真的去按照凯利公式配置自己的 仓位,因为风险放的很大,往往一个极端行情过来,本金就会亏掉大半。

因此,在我们评估回测绩效的时候, 最大回撤 往往是评估策略风险的极重要指标,因为这表明了在历史行情 中,我们可能承受的最大风险,根据这个风险,我们可以以此来评估配置一个合理的仓位。海龟策略作为一个公开 几十年的策略依然被很多人青睐和使用,就在于其对于仓位的管理,充分考虑了风险在仓位管理中的重要性。

固定分数法

这里,笔者根据 《资金管理方法及其应用》这本书介绍固定分数法的资金配置方案,并通过一个简单的示例,试图 给读者一个比较直观的感受。

固定分数法介绍

固定分数法是股市交易中最常用的一种方法,它有多种表现形式,但他们都建立在同意原则的基础上。实际使用这 种方法的目的是,让交易系统在每次交易中确定好投注的资金比例。 这种交易方式不同于凯利公式,其并不涉及到交易系统的各项参数,但却要考虑投资者的心理素质和可承受的损失 数额。

假设我们可以承受的损失为可用资金的 f%, 用这个可承受损失金额除以我们设定的止损值,就可以得到我们 可以买进的合约数。譬如,我们有 100 万的资金,我们可承受的损失为 10 万,买入的股票我们能承受 50%的亏损,假如股票初始价格为 10 元,那么,我们可以买入股票数目为100000/(10*0.5)=200000 股。

示例

不同的可承受风险,对应的收益曲线可能差异巨大,这充分反映出盈亏同源的理念,可承受风险足够大,那么获取 超额收益的可能性也就相应变大;但是,当风险达到一定程度的时候,当交易数目足够多的时候,我们很可能出 出现本金都被亏损完的窘境,因此,确定好一个合理的,可控的风险度对于资金管理至关重要。

这里,笔者利用双均线,在沪深 300 的成分股上进行简单的交易,代码如下,其中 context.risk_ratio 对应的是可承受的风险,为了避免出现买入股票太多,导致资金不够用的情况,笔者这里简单起见,设定了持仓 股票最多 20 支的限制,同时,由于持仓有不同股票,笔者这里简单采用可承受风险资金除以满足条件股票价格 作为买入股票数目

from gm.api import *
import numpy as np
from collections import deque
import datetime
import talibDATE_STR = '%Y-%m-%d'
TIME_STR = '%Y-%m-%d %H:%M:%S'def init(context):print('starting initialization')# 股票池context.stock_pool = get_constituents('SHSE.000300')# 订阅行情subscribe(context.stock_pool)# 量价信息存储context.dict_vol_price = {}# 开平仓信息context.dict_open_close_signal = {}# 时间窗context.hist_size = 20# 风险暴露context.risk_ratio = 0.1# 技术指标参数context.short_period = 5context.long_period = 10# 持仓股票种类context.set_hold_stock = set()context.hold_stock_limit = 20# 日期设置context.curr_bar_time = context.backtest_start_timecurr_bar_time = datetime.datetime.strptime(context.curr_bar_time, TIME_STR)shift_bar_time = datetime.timedelta(days=1)pre_bar_time = datetime.datetime.strftime(curr_bar_time-shift_bar_time, TIME_STR)# 开平仓信息for stock in context.stock_pool:# 初始化开平仓信息context.dict_open_close_signal.setdefault(stock, False)# 定义存储时间窗内历史信息deque_open = deque(maxlen=context.hist_size)deque_high = deque(maxlen=context.hist_size)deque_low = deque(maxlen=context.hist_size)deque_close = deque(maxlen=context.hist_size)history_bars = history_n(symbol=stock,frequency='1d',count=context.hist_size,end_time=pre_bar_time,adjust=ADJUST_PREV,adjust_end_time=context.backtest_end_time)for bar in history_bars:deque_open.append(bar.open)deque_high.append(bar.high)deque_low.append(bar.low)deque_close.append(bar.close)context.dict_vol_price[stock] = [deque_open, deque_high, deque_low, deque_close]print('end initialization')def on_bar(context, bars):# 判断是否换日if datetime.datetime.strftime(context.now, DATE_STR) != context.curr_bar_time[0:10]:context.curr_bar_time = datetime.datetime.strftime(context.now, DATE_STR) + ' 09:30:00'# 重置开平仓信号for key in context.dict_open_close_signal:context.dict_open_close_signal[key] = Falsefor bar in bars:context.dict_vol_price[bar.symbol][0].append(bar.open)context.dict_vol_price[bar.symbol][1].append(bar.high)context.dict_vol_price[bar.symbol][2].append(bar.low)context.dict_vol_price[bar.symbol][3].append(bar.close)# 如果用于计算的量不够if len(context.dict_vol_price[bar.symbol][0]) < context.hist_size:continueelse:algo(context, bar)def algo(context, bar):# 获取仓位pos = context.account().position(symbol=bar.symbol, side=PositionSide_Long)open_vol = int(context.account().cash.available*context.risk_ratio/bar.close/100)*100# 如果没钱开仓,跳过该股票if open_vol <= 0:return# 计算指标closes = np.asarray(context.dict_vol_price[bar.symbol][3])ma5 = talib.SMA(closes, context.short_period)ma10 = talib.SMA(closes, context.long_period)if ma5[-2] <= ma10[-2] and ma5[-1] > ma10[-1]:flag_golden_cross = Trueflag_dead_cross = Falseelif ma5[-2] >= ma10[-2] and ma5[-1] < ma10[-1]:flag_dead_cross = Trueflag_golden_cross = Falseelse:flag_dead_cross = Falseflag_golden_cross = Falseif pos is None and flag_golden_cross and len(context.set_hold_stock) < context.hold_stock_limit:if context.dict_open_close_signal[bar.symbol] is False:order_volume(symbol=bar.symbol,volume=open_vol,side=OrderSide_Buy,order_type=OrderType_Market,position_effect=PositionEffect_Open,price=0,)context.dict_open_close_signal[bar.symbol] = Truecontext.set_hold_stock.add(bar.symbol)if pos is not None:if flag_dead_cross or pos.fpnl/pos.vwap <= -1.1 or pos.fpnl/pos.vwap > 1.3:if context.dict_open_close_signal[bar.symbol] is False:# print('stock %s at date %s has fpnl %f' %(bar.symbol, context.now, pos.fpnl))order_volume(symbol=bar.symbol,volume=pos.volume,side=OrderSide_Sell,order_type=OrderType_Market,position_effect=PositionEffect_Close,price=0,)context.dict_open_close_signal[bar.symbol] = Truecontext.set_hold_stock.remove(bar.symbol)if __name__ == '__main__':run(strategy_id='e4fa3c86-8cb9-11e8-b011-f48c50eb367a',filename='main.py',mode=2,backtest_initial_cash=10000000,token='64c33fc82f334e11e1138eefea8ffc241db4a2a0',backtest_start_time='2016-06-17 13:00:00',backtest_end_time='2017-08-21 15:00:00')

当设置 context.risk_ratio 为 0.1 和 0.2 的时候,回测绩效差异已然很大,具体见下图:

而当风险设置到 0.4 的时候,回测结果甚至已经为负,说明,一味放大风险并不能带来收益率的提高,甚至会 导致不必要的亏损。

写在最后

篇幅所限,笔者仅介绍了固定分数法的仓位管理方法,其实,还有包括最优 f 值法,安全 f 值法,固定比例法,变动 比例法,不同仓位管理方法对应了不同的风险偏好,但是有一点是共通的,对于风险的控制,在仓位管理中是非常非常重要, 无论如何强调都不会过分。

很多读者在炒股的时候,经常都会有满仓去操作的情况,往往持仓的股票一个细微的波动就给自己的心理带来非常大的影响, 于是,要不就是早早地亏损出场,要不就是明明有一波大行情,但是又会在行情到来之前就出场了,如何去选择一个让自己 心理安定,不至于让短期的行情波动去影响自己的心理,一个合理的仓位管理方法尤为重要。

祝各位读者早日找到一个符合自己的交易逻辑与仓位管理方法出来。

来源:掘金量化 myquant.cn

推荐阅读: | 量化交易  | 期货模拟交易 | python量化交易 | 股票数据  | 量化交易策略 | 机器学习算法  | 多因子选股 |

| 双均线策略 |  网格交易法 |  海龟交易法  |  跨期套利  | 行业轮动  | 指数增强  | 跨品种套利 | 日内交易 |

仓位管理之二: 凯利公式指导投资与多种资金管理方式相关推荐

  1. 凯利公式指导投资示例

    引言 在上一次我们提到了凯利公式,很多人可能会想去套用凯利公式到我们的投资策略里面去,但是实际操作中,我们会发现,很多量化平台,回测数据并不够,譬如说,掘金量化平台,它提供了胜率,收益情况等,但是并没 ...

  2. 通达信 移动平均算法_通达信仓位管理主图指标公式

    作者: 黄老师  发布时间: 06/02 2020 15:00 MA10:MA(C,10)COLORWHITE,LINETHICK2;MA30:MA(C,30)COLOR238E23,LINETHIC ...

  3. python 凯利公式_凯利公式的模拟验证

    凯利公式的模拟验证 场景:一个赌局,你跟庄家.你出 1 元,庄家出 0.96元.赌金数目可随之翻倍. 根据每次抛色子的结果的单双决定胜负. 胜者得到双方所下的赌金,计 1.96 元. 问题:如何下注才 ...

  4. 品种小组2期—凯利公式在RFI策略中的运用

    量化策略开发,高质量社群,交易思路分享等相关内容 大家好,今天我们来聊一聊松鼠2期V2版本的阶段内容--凯利公式在RFI择时框架上的运用. 松鼠品种小组2期第1版策略.讲解视频已完结,该期小组我们分享 ...

  5. 凯利公式仓位控制,投注比例的利器,凯利公式在仓位管理、彩票投注中的应用...

    凯利公式: f* = (bp - q) / b 其中,f* = 投注金额占总资金的比例 p = 获胜的概率 q = 失败的概率,q = 1-p b = 赔率 假设:你输和赢的概率均为是50%,例如抛硬 ...

  6. 凯利公式 - Kelly formula

    欢迎关注沉睡者IT,点上面关注我 ↑ ↑ 凯利公式的概述 凯利公式是一条可应用在投资资金和赌注的公式.应用于多次的随机赌博游戏,资金的期望增长率最高,且永远不会导致完全损失所有资金的后果.它假设赌博可 ...

  7. 凯利公式在期货交易中杠杆比例控制上的应用举例及组合投资策略探讨

    凯利公式下最佳仓位比例f=胜率/每次亏损的净亏损率-(1-胜率)/每次收益的净收益率,也明确从数学上证明了如果仓位管理不当,一个期望值为正的交易系统,是完全可能因为仓位不佳(主要是仓位过重)而实际交易 ...

  8. 倍投技巧 - 凯利公式教你如何用正确的方法投资

    凯利公式志在解决的问题 假设赌局1:你赢的概率是60%,输的概率是40%.赢时的净收益率是100%,输时的亏损率也是100%.也即,如果赢,那么你每赌1元可以赢得1元,如果输,则每赌1元将会输掉1元. ...

  9. 凯利公式介绍、计算公式以及在投资中的运用

    介绍 在概率论中,凯利公式(也称 "凯利方程式")是一个在期望净收益为正的独立重复赌局中,使本金的长期增长率最大化的投注策略.该公式于 1956 年由约翰·拉里·凯利(John L ...

  10. 凯利公式-----应用

    作者:贾元宏 链接:https://www.zhihu.com/question/23534782/answer/108093123 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

最新文章

  1. #Ruby# Introspect (1)
  2. python数字计算公式_Python中数字以及算数运算符的相关使用
  3. ESP8266的一些MicroPython基础实验
  4. springboot 定时任务schedule
  5. 声明和定义结构体需要注意的问题
  6. Django框架(17.Django中的元选项)
  7. 云笔记项目-过滤器与拦截器学习
  8. python傅里叶函数图像_python实现傅里叶级数展开的实现
  9. Flink 有状态计算的状态容错
  10. 《天天数学》连载45:二月十四日
  11. vivo S10系列官方渲染图公布 外壳太好看了!
  12. STM32F1xx系列单片机通过程序获取MCU信息
  13. 阿里云推出首个数据库云上跑分平台,背后是什么逻辑?
  14. win 7-8-10 下 删除我的电脑下多余的设备和驱动器,腾讯视频,酷我音乐,手机
  15. mysql匿名账户登录导致的ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'mysql'错误...
  16. Java SSH框架学习
  17. TDSQL破圈背后:国产数据库加速出击
  18. 第2章:几何方面:六边形面积
  19. python 利用脚本命令压缩加密文件并删除源文件
  20. 傅里叶级数展开的详细推导和部分证明

热门文章

  1. PPT总结篇之字体,图片
  2. ES搜索特殊字符异常Encountered: <EOF> after
  3. 2021东北四省赛J. Transform(空间几何)
  4. 安卓adb push图片到相册后刷新相册(Mac版)
  5. matlab方波响应,对周期方波信号进行滤波matlab的实现
  6. blog在搜索引擎的排名下降与technorati
  7. MMORPG游戏服务器技术选型参考
  8. 树莓派价格暴涨买不起?他们自己做了一块价格还不到1/4的开发板平替树莓派,还火到海外去了
  9. 用python画股票行情图
  10. shell 中 if[X$1 = X];then 什么意思