利用回归幅度构建多品种反转策略

前言

河水并不需要计划自己的行进路线,却毫无例外的到达海洋。价格也同样如此,它总是沿着最小阻力线去运动,它总是怎么容易怎么来。如果上升的阻力比下跌的阻力小,价格就会上涨,反之亦然。通常一个大幅度的反转形态,意味着随后会有更大幅度的运动。无论是上升趋势,还是下降趋势,在每一次重大的趋势运动之后,都将产生一定程度的回撤。回撤与原有价格幅度往往构成一定程度的百分比,就称之为百分比回撤。

策略原理

价格反转是一种能量转换的结果,是一个艰难的过程,需要充分的时间、空间进行能量的交换。但正如能量守恒定律,时间可以换取空间,反之空间可以抵消时间。反转中既有激烈的单日V型反转,又有耗时颇巨的圆底与圆顶,V型反转,直来直去,干净利落,无半点喘息时间。


相对而言,基于固定点位的反转,可能会受制于品种价格波动率的变化而变化,但是基于固定百分比幅度的反转,则较少受到类似的困扰,除非该品种的波动性水平已经发生变化。本策略正是基于这一点。

同样,在这个策略中,并没有定义如何区分趋势和震荡,而是直奔主题,根据当前价格与前期高低点的关系来开平仓。因为不管是趋势还是震荡,这些都只是人为主观定义的一个概念,在行情走出来之前,谁也不知道是趋势还是震荡,所以这些主观定义是典型的事后分析时用到的概念。


况且,在不同的时间与趋势结构力度框架下,震荡与趋势基本上很难准确的定义,大周期的震荡就是小周期的趋势。那么也就是说,在行情没有走出来的之前,对行情进行震荡与趋势的分析定义,也是没有意义的。

策略构建

第一步,我们先来看下策略框架,在fmz网站的策略广场,有很多不同种类的策略框架,这些框架可以用于不同的策略类型,简单方便还能节省不少时间,比如本篇的利用回归幅度构建多品种反转策略,就比较适合使用CTA策略框架。具体的使用方法,可以参考这个链接

该策略框架后台自动提供数据和基础服务,借助该策略框架可以大幅提高策略编写效率,正常几百行的策略,用CTA策略框架几十行就能实现一个并发稳定可实盘的多品种策略。另外,配合专门的程序化交易数据结构和丰富的金融统计函数库,同样支持复杂的逻辑应用,简单又不失灵活。如下:

function main() {
    $.CTA("RB000,RU000,CF000,TA000,I000,PP000,P000,L000,J000,JM000", function(st) {
        var bars = st.records;  // 获取K线数组
        
        // K线长度过滤
        if (bars.length < 20) {
            return
        }
        
        var unit = 1;  // 下单数量
        var buyToOpen = '多头开仓条件';
        var buyToClose = '多头平仓条件';
        var sellToOpen = '空头开仓条件';
        var sellToClose = '空头平仓条件';
        
        // 多头平仓
        if (buyToClose) {
            return -unit;
        }
        
        // 空头平仓
        if (sellToClose) {
            return unit;
        }
        
        // 多头开仓
        if (buyToOpen) {
            return unit;
        }
        
        // 空头开仓
        if (sellToOpen) {
            return -unit;
        }
        
    });
}

第二步,开始在CTA框架中填充策略逻辑,首先给每个合约创建一个仓位表。大家知道,不同品种在不同行情中,开平仓的时机是不一样的,比如:螺纹钢开了多单,橡胶开了空单;或者螺纹钢平仓了,橡胶还持有空单。所以仓位表可以针对具体合约分别记录和管理持仓,如下:

contractType = 'rb000/rb888,ru000/ru888';                            // 合约类型

var contractType_Dic = {};                                           // 创建一个空对象,用于接收不同的合约类型
var contractType_Array1 = contractType.split(",");                   // 分割合约类型参数
var contractType_Array2 = [];                                        // 创建一个空数组,用于接收不同的交易合约
for (var i = 0; i < contractType_Array1.length; i++) {               // 遍历每个设置的合约
    contractType_Array2.push(contractType_Array1[i].split('/')[1]);  // 分别存储交易合约
}
contractType_Array2.toString();                                      // 把数组转变为字符串
for (var key in contractType_Array2) {                               // 遍历字符串
    contractType_Dic[contractType_Array2[key]] = {
        falsePosition: 0                                             // 把每个交易合约的初始仓位赋值为0
    }
}

Log(contractType_Dic)                                                // 查看处理好的仓位表,打印:{ rb888: { falsePosition: 0 }, ru888: { falsePosition: 0 } }

第三步,把策略开平仓逻辑写到里面就可以了。其中用到了K线周期内最高价和最低价与当前价格的相互位置关系。策略没有附带止盈止损,只有开仓和平仓,核心思想就是:截断亏损,让利润奔跑!大家注意看下面策略代码中的注释。

  • 多头开仓:如果当前没有持仓,并且价格大于前 N 根 K 线内的最低价 + 百分比幅度。
  • 空头开仓:如果当前没有持仓,并且价格小于前 N 根 K 线内的最高价 - 百分比幅度。
  • 多头平仓:如果当前持有多单,并且价格小于前 N 根 K 线内的最低价与前 N 根 K 线内的最高价的和的一半。
  • 空头平仓:如果当前持有空单,并且价格大于前 N 根 K 线内的最低价与前 N 根 K 线内的最高价的和的一半。
function main() {
    // 参数
    cycleLength = 50;                                                    // 周期长度
    backRatio = 1;                                                       // 回撤比率
    contractType = 'rb000/rb888,ru000/ru888';                            // 合约类型
    unit = 1;                                                            // 下单数量
    
    // 仓位表
    var contractType_Dic = {};                                           // 创建一个空对象,用于接收不同的合约类型
    var contractType_Array1 = contractType.split(",");                   // 分割合约类型参数
    var contractType_Array2 = [];                                        // 创建一个空数组,用于接收不同的交易合约
    for (var i = 0; i < contractType_Array1.length; i++) {               // 遍历每个设置的合约
        contractType_Array2.push(contractType_Array1[i].split('/')[1]);  // 分别存储交易合约
    }
    contractType_Array2.toString();                                      // 把数组转变为字符串
    for (var key in contractType_Array2) {                               // 遍历字符串
        contractType_Dic[contractType_Array2[key]] = {
            falsePosition: 0                                             // 把每个交易合约的初始仓位赋值为0
        }
    }
    
    // CTA框架
    $.CTA(contractType, function(st) {
        var bars = st.records;                                           // 获取K线数组
        var j = bars[bars.length - 2].Close;                             // 获取上根K线收盘价
        var high = TA.Highest(bars, cycleLength, 'High');                // 计算N日内的最高价
        var low = TA.Lowest(bars, cycleLength, 'Low');                   // 计算N日内的最低价
        var highBack = high * (1 - backRatio / 100);                     // 计算N日内的最高价的回撤1%的值
        var lowBack = low * (1 + backRatio / 100);                       // 计算N日内的最低价的回撤1%的值
        
        // 过滤K线数量
        if (!bars || bars.length < cycleLength + 1) {
            return;
        }
        
        //多头平仓
        if (contractType_Dic[st.symbol].falsePosition > 0 && j < (lowBack + highBack) / 2) {
            contractType_Dic[st.symbol].falsePosition = 0;
            return -unit;
        }
        
        //空头平仓
        if (contractType_Dic[st.symbol].falsePosition < 0 && j > (lowBack + highBack) / 2) {
            contractType_Dic[st.symbol].falsePosition = 0;
            return unit;
        }
        
        //多头开仓
        if (contractType_Dic[st.symbol].falsePosition == 0 && j > lowBack && j > highBack) {
            contractType_Dic[st.symbol].falsePosition = 1;
            return unit;
        }
        
        //空头开仓
        if (contractType_Dic[st.symbol].falsePosition == 0 && j < lowBack && j < highBack) {
            contractType_Dic[st.symbol].falsePosition = -1;
            return -unit;
        }
        
    });
}

完整策略源码已经公开到发明者量化 https://www.fmz.com/strategy/69937 ,无需配置直接回测。

策略改进

总的来说,这是一个通用性极强的策略。当然这只是个简单的策略思路,该策略或许可以在其他地方改进:

1、增加波动率因子。我们都知道,每个品种的都有其性格,基本面与技术面互相影响。增加波动率因子,可以更客观的反映出当前品种的价格走势。

2、将固定周期改为自适应周期。这个策略核心参数,其实只有一个,而且参数是固定。如果我们通过价格变化速度与加速度的关系,动态的将固定参数加减,可以更能即时反映当时的行情。

3、将百分比回撤改为固定的数值。举个例子,如果当前价格是1000,那么其1%就是10;如果当前价格是5000,那么其1%就是50。10与50之间在相差了好几个数量级。同样的合约品种,因为不同时期的当前价格,结果导致开平仓条件相差很大。

结尾

总之,任何一种价格形态,想要孕育出范围广泛的新趋势,就需要一定的时间才能形成。市场有它自己的时间观念,切忌不分春夏秋冬,晴天还是下雨,天天进场。因为,重挫一次需要很长时间才能复原,而且既费时又破坏了心态。

你可能感兴趣的:(利用回归幅度构建多品种反转策略)