前言
河水并不需要计划自己的行进路线,却毫无例外的到达海洋。价格也同样如此,它总是沿着最小阻力线去运动,它总是怎么容易怎么来。如果上升的阻力比下跌的阻力小,价格就会上涨,反之亦然。通常一个大幅度的反转形态,意味着随后会有更大幅度的运动。无论是上升趋势,还是下降趋势,在每一次重大的趋势运动之后,都将产生一定程度的回撤。回撤与原有价格幅度往往构成一定程度的百分比,就称之为百分比回撤。
策略原理
价格反转是一种能量转换的结果,是一个艰难的过程,需要充分的时间、空间进行能量的交换。但正如能量守恒定律,时间可以换取空间,反之空间可以抵消时间。反转中既有激烈的单日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线周期内最高价和最低价与当前价格的相互位置关系。策略没有附带止盈止损,只有开仓和平仓,核心思想就是:截断亏损,让利润奔跑!大家注意看下面策略代码中的注释。
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.cn/strategy/69937 ,无需配置直接回测。
策略改进
总的来说,这是一个通用性极强的策略。当然这只是个简单的策略思路,该策略或许可以在其他地方改进:
1、增加波动率因子。我们都知道,每个品种的都有其性格,基本面与技术面互相影响。增加波动率因子,可以更客观的反映出当前品种的价格走势。
2、将固定周期改为自适应周期。这个策略核心参数,其实只有一个,而且参数是固定。如果我们通过价格变化速度与加速度的关系,动态的将固定参数加减,可以更能即时反映当时的行情。
3、将百分比回撤改为固定的数值。举个例子,如果当前价格是1000,那么其1%就是10;如果当前价格是5000,那么其1%就是50。10与50之间在相差了好几个数量级。同样的合约品种,因为不同时期的当前价格,结果导致开平仓条件相差很大。
结尾
总之,任何一种价格形态,想要孕育出范围广泛的新趋势,就需要一定的时间才能形成。市场有它自己的时间观念,切忌不分春夏秋冬,晴天还是下雨,天天进场。因为,重挫一次需要很长时间才能复原,而且既费时又破坏了心态。