量化策略开发,高质量社群,交易思路分享等相关内容
在市场中,价格的扩张通常紧随价格的犹豫之后。"周因子"指标有助于捕捉这一模式。了解如何使用它来筛选交易,从而提高成功率。
作者:Andrea Unger
作为系统交易员,我们有许多工具可以在进入交易时使用。一个简单且有效的工具是模式过滤器。通过几行代码,我们可以快速确定基于价格走势的当前市场状况,并判断何时这些条件对我们的交易入场更有利。
在本文中,我将讨论最有用的模式过滤器之一:周因子。
什么是周因子?
周因子观察一个交易周内的交易区间(即最近五个交易日的最高点和最低点),并将其与五天前的开盘价和一天前的收盘价(一个“周体”)进行比较,这个时间段与最高点和最低点的范围是一致的。(参见图1)
图1:周体和区间。使用“周因子”模式时,交易周的区间(即最近五个交易日的最高点和最低点之间的距离)与同一交易周的“周体”进行比较(即五天前的开盘价与一天前的收盘价之间的差值)。这一指标有助于识别市场“犹豫期”(即市场收缩)。
在 MultiCharts Power Language 中,可以这样编写代码:
AbsValue(OpenS(5) – CloseS(1)) < RangeFilter * maxlist(highS(1), highS(2), highS(3), highS(4), highS(5)) - minlist(lowS(1), lowS(2), lowS(3), lowS(4), lowS(5));
在这个示例代码中,"RangeFilter" 是一个输入值,可以通过测试和优化来找出定义“犹豫”的五日区间的百分比。而这正是我们在寻找的犹豫信号。
事实上,过去五天内的一个小的“周体”相比延展的区间可以识别出一个犹豫模式,这可能会伴随扩张而来。此外,一个不那么延展的“周体”对趋势跟随策略是有利的,因为这意味着趋势尚未启动。
众所周知,在大多数流动性市场中,价格的“犹豫”或“压缩”之后会出现价格的“扩张”,而这种扩张最终又会被压缩所替代,形成一个价格探索的循环,这定义了我们交易的市场。如果我们能够识别出价格的压缩,我们可以添加参数,在压缩转为扩张时进入市场。这就是所谓的“突破交易”。
因此,使用像周因子这样的模式过滤器来识别较长时间的犹豫(例如五天的犹豫)是对我们的交易有利的。让我们来看看一些例子。
一个简单的测试策略
以下简单的策略在2010年至2022年的12年回测中进行了测试,测试市场为三个金属市场,带有和不带有周因子过滤器。策略尝试在价格突破时进入市场,并在当天结束时退出。没有硬性止损,相反,交易将通过定时退出或反转交易(止损反手)关闭。该策略的目的是展示周因子的效果。
在 MultiCharts Power Language 中,该策略可以这样编写:
// 使用15分钟K线
Inputs:
RangeFilter ( 1 );
Var:
BarCount ( 0 ),
MP ( 0 ),
SLB ( false ) ,
DayCounter ( 0 ),
WeeklyFactor (false);
if SLB[1] then barcount = 1
else BarCount = barcount+1;
MP = marketposition;
SLB = SessionLastBar;
WeeklyFactor = AbsValue(OpenS(5) - CloseS(1)) < RangeFilter * (maxlist(highS(1), highS(2), highS(3), highS(4), highS(5))
- minlist(lowS(1), lowS(2), lowS(3), lowS(4), lowS(5)));
If WeeklyFactor then begin
if barcount > 1 and barcount < 91 then begin
buy ("Brkout_LE") next bar at HighS(1) stop;
sellshort ("Brkout_SE") next bar at LowS(1) stop;
end;
end;
If MP <> MP[1] and MP <> 0 then DayCounter = 0;
if SLB[1] then DayCounter = DayCounter + 1;
if DayCounter > 1 and contractprofit > 0 then setexitonclose;
我们可以使用15分钟K线图对以下三个金属期货市场进行测试:黄金(GC)、铜(HG)和铂金(PL)。初步结果(未使用周因子模式)见图2(权益曲线)和图3(交易指标)。在此期间的权益曲线是正向的。每笔交易的平均利润为20美元,显然不适合实际交易,因为佣金和滑点会抹去任何潜在的利润。
图2:未使用模式过滤器的示例策略权益曲线。一个简单的交易策略,在没有启用周因子模式过滤器的情况下,针对三个金属期货市场进行了测试。总体上,权益曲线呈正向增长,这是一个良好的起点,但在多个方面仍有改进的空间。系统能否通过使用周因子过滤交易入场来得到改进呢?
图3:未使用模式过滤器的示例策略交易指标。这里展示的是在没有使用周因子模式作为交易过滤器时的初始统计数据和结果。结果是正向的,但每笔交易的平均收益(20美元)太小,无法用于实际交易。
但这仍是一个良好的起点,表明所考虑的三个市场主要是趋势跟随市场。
添加周因子到策略中
通过将周因子添加到计算中,我们可以测试在交易入场前的五个交易日内价格犹豫的影响。输入的“RangeFilter”从0.1到1进行优化(即总范围的1%至100%)。
随着过滤器的减少,过去五天的犹豫变得更为重要。图4中的表格展示了RangeFilter如何影响投资组合。值为1显示了之前的情况,而所有其他输入过滤了最后五天的“周体”相对于周范围的大小。
图4:优化表。优化表显示了将RangeFilter(区间过滤器)添加到策略后对投资组合的影响。值1显示了之前的情况,而其他输入则过滤了过去五天的“周体”相对于周区间的大小。最佳解决方案似乎在0.6到0.9之间。
在优化表格中,我们可以看到最好的结果在0.6到0.9之间。我们可以使用0.7,这个值显示了附近的稳定性范围,并且比其他良好值具有更好的回撤值。
这个0.7的值意味着“周体”应小于整个周范围的70%,并且大约过滤掉了2000笔交易(20%)。这不是一个大的交易量,但仍然是有效的。
图5显示了使用周因子过滤器后的权益曲线,图6显示了交易指标。正如你所看到的,使用周因子作为交易过滤器显著改善了交易结果。权益曲线变得更加平滑,并且回测的最后几年也得到了极大改善。每笔交易的平均收益也增加了50%,达到了30美元。
图5:使用模式过滤器的示例策略权益曲线。当将周因子模式作为交易入场过滤器时,简单策略的回测结果显示,权益曲线变得更加平滑。
图6:使用模式过滤器的示例策略交易指标。使用周因子作为交易入场过滤器时,结果有所改善。回测的最后几年表现大幅提升,每笔交易的平均收益增加了50%。
最终的结论
与之前的结果相比,这是一项重要的改进,但仍不足以用于实际交易。该策略仍然没有止损或止盈,因此还可以进一步过滤和改进,以便在实际市场中交易。
还需要注意的是,这个投资组合由不同的期货组成,具有不同的点值和名义合同价值(例如,铂金的价值小于黄金和铜),因此评估平均交易更加困难。
尽管如此,过滤器在这次回测中证明了其有效性,将平均交易增加了50%,从20美元增加到30美元。其他过滤器值也表现良好,获得了更好的平均交易,进一步确认了周因子的效率。
最后的话
在选择过滤器或入场触发条件时,净利润不应该是唯一的考虑因素。一个多样化市场、交易方式和风险配置的全面方法对于实现持续盈利是必不可少的。
在这个简短的演示中,我展示了通过几行代码,我们能够显著提高一个简单突破策略在三个不同市场中的交易质量和整体成功率。通过将过去五天的区间与开盘和收盘价进行对比,我们证明了价格扩张确实紧随价格犹豫之后。现在,轮到你发挥创意,跟随你的好奇心了!
策略代码
Params
Numeric RangeFilter(1); // 1 = 100%
Numeric NX(20); // 犹豫周期
Vars
Series<Numeric> weekrange(0);
Series<Numeric> weekbody(0);
Series<Numeric> WeeklyFactor(0);
Numeric Lots(0);
Numeric i;
Numeric i_N(0);
Series<Numeric> highline(0);
Series<Numeric> lowline(0);
Global Integer CloseClear(0);
Array<Numeric> higharray;
Array<Numeric> lowarray;
Numeric Fund(20000); //投入保证金;
Events
// Bar更新事件函数
OnBar(ArrayRef<Integer> indexs)
{
// 计算WeeklyFactor
for i=0 to NX
{
i_N=i+1;
higharray[i]=High[i_N];
lowarray[i]=Low[i_N];
}
weekrange=Abs(Open[NX] - Close);
weekbody=HighestArray(higharray)- LowestArray(lowarray);
WeeklyFactor = iif( weekrange< RangeFilter * weekbody,1,0);
Commentary(text(WeeklyFactor[1]));
// 更新BarCount
Lots = max(1,Round(Fund*0.01 / (AvgTrueRange(20) * BigPointValue*ContractUnit/rollover),0));
// 当WeeklyFactor满足条件时,在突破高点和低点时下单
if (WeeklyFactor[1]>0 )
{
highline=HighestArray(higharray);
lowline=LowestArray(lowarray);
PlotNumeric("highline",highline);
PlotNumeric("lowline",lowline);
Commentary("highh:"+Text(HighestArray(higharray)));
Commentary("lowl:"+Text(LowestArray(lowarray)));
If ( close[1]>=highline[1] And MarketPosition==0 )
{
Buy(lots,Open);
} // 突破高点开多单
If ( Close[1]<=lowline[1] and MarketPosition==0 )
{
SellShort(Lots,Open);} // 突破低点开空单
}
if(time >= 0.1400-BarInterval*0.0001 and time<0.1500)
{
if(MarketPosition>0)
{
Sell(Lots,open);
PlotString("平多","平多",close,Blue);
ArrayClear(higharray);
ArrayClear(lowarray);
WeeklyFactor=0;
}
if(MarketPosition<0)
{
BuyToCover(Lots,open);
PlotString("平空","平空",close,Yellow);
ArrayClear(higharray);
ArrayClear(lowarray);
WeeklyFactor=0;
}
if(time>=0.2100 and time<0.2100+BarInterval*5*0.0001) //日内情况下,前5根bar线,因子值为0
{
WeeklyFactor=0;
}
}
}