Name
吕神-简易波动率策略
Author
扁豆子
Strategy Description
完全的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大佬的群里。
最后再次感谢吕神的精彩讲解!
还没有加入量化讨论群的朋友们速来加群领取学习资料哦!!!
千千本尊镇楼!
微信扫一扫 关注该公众号
Strategy Arguments
Argument | Default | Description |
---|---|---|
N | 90 | 指数计算周期 |
Amount | 100 | 下单量 |
Source (javascript)
/*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)
}
}
Detail
https://www.fmz.com/strategy/200131
Last Modified
2020-04-23 12:25:16