完全的T神公众号, 吕神特约策略翻译. 下面是转载内容, 请多多关注"千千的量化世界" 获取更多策略源码!! 另外也给自己个广告~ 公众号"扁豆子的量化日志" 给大家每日公开处刑在线量化破产~ 更有多项福利更你来拿~
这只是 Demo!! Demo!! Demo阿喂!! 爸爸们!!实盘需谨慎!!
用好波动率,跑赢BTC大盘就这么简单! 原创 吕洋洋 千千的量化世界 3天前 “ 量化策略的研发其实是个两面性,对于刚刚入门的人来说很难很难,难得不光是“术”层面的代码,同样难的也是“略”层面的策略逻辑思维。两者皆为重要,万万不可偏颇。”
各位千千量化的小伙伴们大家好!!!
本篇是特邀稿第二期,千千很荣幸地邀请到吕洋洋大神(微信号LE_CHIFFRE1)为大家介绍:如何利用波动率因子轻松跑赢BTC大盘,实现“降维打击”!
吕神来自传统量投机构,曾经也深度参与过币圈交易所业务,在量化领域有丰富的经验和独特的见解。吕神这期内容涵盖思路启示、编码实现和个人体悟等等,不可谓不是干货满满,千千自己看完也感到获益匪浅,真的是非常佩服和感谢吕神,强烈推荐大家研读细品!
下面掌声有请吕神为大家介绍波动率策略。
01
—
引言
大家好,今天有幸在“千千的量化”公众号推送文章,同时也要感谢T老板(千千的外号之一)的邀请。第一次给T老板写文章,完全的自由发挥,借用工作后的闲余时间,质量和错误也请大家文中指正和包含,谢谢大家。
T老板说写个量化的,又没有给什么范围,着实不知道从哪里写起。那就从自己最喜欢与他人讨论的话题入手吧。量化指标与策略(即可辅助也可自动化),当然了,最后咱们还要加上一句老生常谈的话:“投资有风险,入市需谨慎”,策略只是给大家提供思路和借鉴,盈亏自负。一切使用本策略的盈亏与我本人和“千千的量化世界”公众号主体无任何关系。
免责声明说完了,下面就开始正题。
02
—
一个简单的波动率策略
熟悉我的人其实都知道,从我个人来说,我不是很喜欢阿尔法那种玩法,相对来说我更信贝塔,更多的去研究贝塔。至于为什么,e………mmmmm,不知道咋回答了~~,大家自行脑补吧。如果感兴趣的话大家可以私信、留言给该公众号的作者,逻辑鲜明有特色的,作者本人将发一个小红包给大家。
量化策略的研发其实是个两面性,对于刚刚入门的人来说很难很难,难得不光是“术”层面的代码,同样难的也是“略”层面的策略逻辑思维。两者皆为重要,万万不可偏颇。今天给大家介绍的策略其实是很多年前来自华泰一个研报的启发,大家看仔细只是启发哦~~,之所以这么说是因为该策略逻辑已经完全不是研报中所提及的内容,具体研报大家私聊T大佬。
该策略算法采用对数价格一定周期涨跌幅的滚动收益率波动原理,根据该波动区间计算一定周期滚动最高值与最小值的寻找,最高值作为上管道,最小值作为下管道,突破上管道,开仓。上下管道滚动平均值作为平仓线。(此处敲黑板!)
具体图形可视化界面可参考下面的PPT。该图形是本人用Pyecharts所画,具体代码也请私聊T大佬。
其实该策略是本人之前做宽基ETF所用的策略,当然也用于指数择时进行股票买卖,后来直接挪到币圈,惊愕发现真的降维打击,参数都不用变。
下图所示是当年回测的绩效,具体的部分代码逻辑截图如下:
上面其实就是读取数据后,通过pandas进行指标数据计算。
计算完毕后,可通过pd.to_csv()函数进行数据输出和上面截图中所用到的pyecharts进行可视化输出(注:本人用的是老版本的pyecharts)。
具体所有的策略、可视化、以及绩效指标代码还是私聊T大佬。
03
—
漫谈量化
接下来我主要讲的两点。第一:有人很多疑问或者说你们这些人为什么可以公布实盘的策略,是假的骗子吗?还是说真的普度众生?哈哈~~ 。首先,好的策略是不怕公开的,这又不是什么战争级别对抗的武器开发,会决定生死的东西,所以本人和其他一些机构或者说个人,也不怕所谓的什么策略秘密,因为在我看来CTA没有秘密。只不过是每个人想到的和没想到的点子而已罢了。其次,这个版本是本人最老的版本,在此基础上面做了几个版本的升级,比如说加入了其他的条件判断和止盈止损等等,当然也包括了别的品种别的周期的参数调整等等。
第二:很多人不论是新手还是已经入门甚至包括老玩家,都是需要灵感来源的,包括股票的因子挖掘,择时策略的思路等等,这些往往来源主观经验,研报,圈内的沟通交流等等,不排除现在市面上一些买来的策略然后进行阅读和理解,根据自身的风险承受能力和具体需求在进行改版等。
最后总结一下,量化本来是个舶来品,程序化交易属于量化内的子集,早在本人大学时候(2009年左右)那时候TB 、金字塔等程序化就有人涉猎了,如果持续做到今天,可以说这部分最早先知先觉的人已经有10个年头了,其中还不包括那些从华尔街“带回来”的高频策略和系统的人。因此,量化策略或者说程序化策略在中国已经持续了一段时间,但是在目前市场份额和参与主体,以及政策支持来讲,量化依然是很小众的一部分存在,尽管多因子分析和策略建模的研报满天飞。有的人喜欢无脑的逻辑拿这个跟美国去比较,认为中国量化未来发展大趋势会跟美国一样,爆发式增长等等。但是,这不是瑞幸“咖啡与小罐茶”的商业逻辑,中国有中国的特色,未来的道路依然荆棘与坎坷。因此,我们也聚拢了广大的机构和个人投资者的圈子,希望大家可以共同结识交流与成长,为这个行业做出一份小小的贡献与付出。
最后感谢“千千的量化”公众号对于本人专业的信任以及文章邀请。大家有什么具体代码和策略问题,请私信我本人或T大佬,我也在T大佬的群里。
最后再次感谢吕神的精彩讲解!
还没有加入量化讨论群的朋友们速来加群领取学习资料哦!!!
千千本尊镇楼!
微信扫一扫 关注该公众号
/*backtest start: 2019-04-18 00:00:00 end: 2020-04-17 23:59:00 period: 15m exchanges: [{"eid":"Futures_BitMEX","currency":"XBT_USD"}] */ // 胖友们!! 实盘前请注意!! 此内容仅是吕神翻译demo, 上实盘请自行添加相关内容. // 是Demo!!! 实盘谨慎!!! // 初始化 exchange.SetContractType('XBTUSD') var vix_arr = [] var vix_ma = [] var vix_ma_up = [] var vix_ma_dw = [] var LastBarTime = 0 var isFirst = true function initVix() { records = _C(exchange.GetRecords) Log(records.length) if (records && records.length > 2 * N + 2) { // 初始化前N个vix值 for (var i = -2; i < N - 1; i++) { Bar = records[records.length - N + i] lastNbar = records[records.length - N + i - N] Vix() } } // Log("vix_arr", vix_arr.length, vix_arr) // Log("vix_ma", vix_ma.length, vix_ma) // Log("vix_ma_up", vix_ma_up.length, vix_ma_up) // Log("vix_ma_dw", vix_ma_dw.length, vix_ma_dw) } // 获取交易所信息 function UpdateInfo() { account = _C(exchange.GetAccount) pos = _C(exchange.GetPosition) records = _C(exchange.GetRecords) Bar = records[records.length - 1] lastNbar = records[records.length - N] ticker = _C(exchange.GetTicker) } // 计算波动率及上下轨 function Vix() { // 当每K结束时计算 if (LastBarTime !== Bar.Time) { // 当K达到计算根数开始计算vix_arr if (records && records.length > N) { // 获取vix 当前close自然对数 除以 前90根自然对数 减一 vix = Math.log(Bar.Close) / Math.log(lastNbar.Close) - 1 vix_arr.push(vix) //Log("vix_arr", vix_arr) } // 当vix_arr达到计算根数时开始计算vix_ma if (vix_arr && vix_arr.length > N) { // 获取对应周期vix算其移动平均值 vix_ma = TA.MA(vix_arr, N) // 去除ma中的null值 vix_ma = vix_ma.filter(function(val) { return !(!val || val === ""); }) //Log("vix_ma", vix_ma) // 获取上下通道 vix_up = TA.Highest(vix_arr, N) vix_dw = TA.Lowest(vix_arr, N) vix_ma_up.push(vix_up) vix_ma_dw.push(vix_dw) // Log("vix_ma_up", vix_ma_up) //Log("vix_ma_dw", vix_ma_dw) // 限制所有数组长度 if (vix_arr.length > 2000) { vix_arr.splice(0, 1); } if (vix_ma.length > 2000) { vix_ma.splice(0, 1); } if (vix_ma_up.length > 2000) { vix_ma_up.splice(0, 1); } if (vix_ma_dw.length > 2000) { vix_ma_dw.splice(0, 1); } } LastBarTime = Bar.Time } } // 画线 function PlotMA_Kline(records, isFirst) { //$.PlotRecords(records, "K") if (isFirst) { for (var i = records.length - 1 - N; i <= records.length - 1; i++) { if (vix_ma[i] !== null) { $.PlotLine("vix_arr", vix_arr[i], records[i].Time) $.PlotLine("vix_ma", vix_ma[i], records[i].Time) $.PlotLine("vix_ma_up", vix_ma_up[i], records[i].Time) $.PlotLine("vix_ma_dw", vix_ma_dw[i], records[i].Time) } } PreBarTime = records[records.length - 1].Time } else { if (PreBarTime !== records[records.length - 1].Time) { $.PlotLine("vix_arr", vix_arr[vix_arr.length - 2], records[records.length - 2].Time) $.PlotLine("vix_ma", vix_ma[vix_ma.length - 2], records[records.length - 2].Time) $.PlotLine("vix_ma_up", vix_ma_up[vix_ma_up.length - 2], records[records.length - 2].Time) $.PlotLine("vix_ma_dw", vix_ma_dw[vix_ma_dw.length - 2], records[records.length - 2].Time) PreBarTime = records[records.length - 1].Time } $.PlotLine("vix_arr", vix_arr[vix_arr.length - 1], records[records.length - 1].Time) $.PlotLine("vix_ma", vix_ma[vix_ma.length - 1], records[records.length - 1].Time) $.PlotLine("vix_ma_up", vix_ma_up[vix_ma_up.length - 1], records[records.length - 1].Time) $.PlotLine("vix_ma_dw", vix_ma_dw[vix_ma_dw.length - 1], records[records.length - 1].Time) } } // 交易逻辑 function onTick() { // 无仓位时 if (pos.length == 0) { // Long 当前K线的收盘价 > 上轨 && 之前K线的收盘价 <= 上轨 if (vix_arr[vix_arr.length - 1] > vix_ma_up[vix_ma_up.length - 1] && vix_arr[vix_arr.length - 2] <= vix_ma_up[vix_ma_up.length - 2]) { exchange.SetDirection("buy") exchange.Buy(ticker.Sell, Amount) $.PlotFlag(new Date().getTime(), 'Buy', 'BK') } // Short 当前K线的收盘价 < 下轨 && 之前K线的收盘价 >= 下轨 if (vix_arr[vix_arr.length - 1] < vix_ma_dw[vix_ma_dw.length - 1] && vix_arr[vix_arr.length - 2] >= vix_ma_dw[vix_ma_dw.length - 2]) { exchange.SetDirection("sell") exchange.Sell(ticker.Buy, Amount) $.PlotFlag(new Date().getTime(), 'Sell', 'SK') } } // 多仓时 if (pos.length > 0 && pos[0].Type == 0) { // 平多 当前K线的收盘价 < 中轨 && 之前K线的收盘价 >= 中轨 if (vix_arr[vix_arr.length - 1] < vix_ma[vix_ma.length - 1] && vix_arr[vix_arr.length - 2] >= vix_ma[vix_ma.length - 2]) { exchange.SetDirection("closebuy") exchange.Sell(ticker.Buy, pos[0].Amount) $.PlotFlag(new Date().getTime(), 'Sell', 'SBK') } } // 空仓时 if (pos.length > 0 && pos[0].Type == 1) { // 平空 当前K线的收盘价 > 中轨 && 之前K线的收盘价 <= 中轨 if (vix_arr[vix_arr.length - 1] > vix_ma[vix_ma.length - 1] && vix_arr[vix_arr.length - 2] <= vix_ma[vix_ma.length - 2]) { exchange.SetDirection("closesell") exchange.Buy(ticker.Sell, pos[0].Amount) $.PlotFlag(new Date().getTime(), 'Buy', 'PSK') } } } function main() { initVix() while (1) { UpdateInfo() Vix() onTick() if (records) { PlotMA_Kline(records, isFirst) //Log('画线') isFirst = false } Sleep(5 * 1000) } }template: strategy.tpl:40:21: executing "strategy.tpl" at <.api.GetStrategyListByName>: wrong number of args for GetStrategyListByName: want 7 got 6