剥头皮(scalp)交易策略代码与回测
本章我们来介绍一个简单的剥头皮策略,本策略是自己理解了剥头皮策略的核心之后,自己写出的第一个交易策略。目前并未经过严格实测,因为本人目前采用的是趋势跟踪策略。但此策略是博主mt5自动化交易的开端,所以有着极其重要的地位。
下面是此剥头皮策略的核心思想:找到动能强劲的k线,在下一个k线小幅回调后,沿着强劲k线挂突破单,止盈止损采用固定点数,在沿着有利的方向运行一段距离后,启用移动跟踪止损。
什么是动能强劲的k线:1.k线足够大;2.如果是阳线,则其上影线很短;如果是阴线则反之;
什么是小幅回调:如果强劲k线是阳线,下一根k线回调到强劲k线高点以下一定距离(如果10pips);
什么是移动追踪止损:如果做多,价格沿着多的方向走出30pips,则激活移动止损。从此之后,止损一直保持距离价格15pips的距离
下面是剥头皮策略实现代码:
//+------------------------------------------------------------------+ //| 定义输入参数 | //+------------------------------------------------------------------+ input group "====单k线突破scalp策略======" input double tradelots=0.01; //交易手数 input ENUM_TIMEFRAMES tradeFrame = PERIOD_M5; //交易周期 input int InitSl = 150; //初始止损 input int InitTp = 150; //初始止盈 input int TriggerPoints = 30; //移动止损激活pips,0=不启用 input int TriggerSl = 15; //止损点数 input int pullbackPoints = 10; //回调多少点以上再入场 input int Magic = 223456; input group "====过滤器=====" input double minBarPoints = 90; //待突破k线最小pips,0=不启用 input int maxPinbar = 5; //做多上影线不能超过k线的几分之一,0=不启用 input int startMiniutes = 600; //开始交易分钟数 input int durationMiniutes = 240; //交易持续时间,0=不启用时间过滤
上述代码参数均有说明,我们增加了一个时间过滤器,在不活跃的时段,禁止交易。
//+------------------------------------------------------------------+ //| 全局变量 | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> CTrade trade; CPositionInfo pos; COrderInfo ord; MqlRates g_bar; //保存信号k线信息
定义一些交易中的全局变量,以便程序中使用,g_bar存储强势k线的信息。其它几个变量是操作订单的变量。
在OnInit函数中,我们设置好交易的魔幻数字
trade.SetExpertMagicNumber(Magic); trade.SetDeviationInPoints(5);
在OnTick函数中,实现整个逻辑
static int signal = 0; //信号:1-做多;-1:做空 static datetime prevTime = 0; datetime currentTime = iTime(_Symbol, tradeFrame, 0); if(TriggerPoints>0) { trainStop(); } int total = 0; for(int i=PositionsTotal()-1; i>=0; i--) { if(!pos.SelectByIndex(i) || pos.Symbol()!=_Symbol || pos.Magic()!=Magic) continue; total++; } if(total>0) { return; } if(signal != 0) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(ask-bid>TriggerSl) return; if(g_bar.close>g_bar.open) { if(g_bar.high-ask>pullbackPoints*_Point) { double entry = g_bar.high+_Point; double sl = entry-InitSl*_Point; double tp = entry+InitTp*_Point; trade.BuyStop(tradelots, entry, _Symbol, sl, tp, ORDER_TIME_SPECIFIED, currentTime+PeriodSeconds(tradeFrame)-1, __FILE__); signal = 0; } } if(g_bar.close<g_bar.open) { if(bid-g_bar.low>pullbackPoints*_Point) { double entry = g_bar.low+_Point; double sl = entry+InitSl*_Point; double tp = entry-InitTp*_Point; trade.SellStop(tradelots, entry, _Symbol, sl, tp, ORDER_TIME_SPECIFIED, currentTime+PeriodSeconds(tradeFrame)-1, __FILE__); signal = 0; } } } if(prevTime==currentTime) return; prevTime = currentTime; signal = 0; if(durationMiniutes>0) { //检查是否在交易时间内 MqlDateTime dt; TimeToStruct(currentTime, dt); if(dt.min+dt.hour*60<startMiniutes || dt.min+dt.hour*60>startMiniutes+durationMiniutes) return; } //获取前一根k线信息 MqlRates rates[1]; if(CopyRates(_Symbol, tradeFrame, 1, 1, rates)!=1) return; //检查是否满足信号k线要求 if(minBarPoints>0 && rates[0].high-rates[0].low<minBarPoints*_Point) return; if(rates[0].open<rates[0].close) {//阳线 if(maxPinbar>0 && (rates[0].high-rates[0].close)*maxPinbar>rates[0].high-rates[0].low) return; g_bar = rates[0]; signal = 1; } else if(rates[0].open>rates[0].close) { if(maxPinbar>0 && (rates[0].close-rates[0].low)*maxPinbar>rates[0].high-rates[0].low) return; g_bar = rates[0]; signal = -1; }
有几个特别说明的地方:
只在当前k结束后,下一根k线开始才去检查是否是强劲k线;
同时只有一个持仓订单
进行了交易时间过滤
移动止损在每个tick上检查,以便可以及时追踪止损
下面是ontick中调用的移动止损追踪函数:
void trainStop() { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double tp,sl; for(int i=PositionsTotal()-1;i>=0; i--) { if(pos.SelectByIndex(i)) { if(pos.Magic()!=Magic || pos.Symbol()!=_Symbol) return; ulong ticket = pos.Ticket(); if(pos.PositionType()==POSITION_TYPE_BUY) { if(bid-pos.PriceOpen()>TriggerPoints*_Point) { tp = NormalizeDouble(pos.TakeProfit(), _Digits); sl = NormalizeDouble(bid-(TriggerSl*_Point), _Digits); if(sl>pos.StopLoss() && sl>0) { trade.PositionModify(ticket, sl, tp); } } } if(pos.PositionType()==POSITION_TYPE_SELL) { if(ask<pos.PriceOpen()-(TriggerPoints*_Point)) { tp = NormalizeDouble(pos.TakeProfit(), _Digits); sl = NormalizeDouble(ask+(TriggerSl*_Point),_Digits); if(sl<pos.StopLoss() && sl>0) { trade.PositionModify(ticket, sl, tp); } } } } } }
下面是回测的参数与结果:

从上述回测结果可以看出,剥头皮策略的特点:
胜率很高,回测中达到了89%;
盈亏比差,平均盈利0.79平均亏损4.10
交易频次高,每天进行数次交易
图中靠着大量交易,8个月利润达到了惊人的150%。但这个只是回测数据,真实情况如何,还需要在实盘中测试。
另外,上述经纪商的点差很小,且没有佣金。如果你换一个点差较大且有佣金的经纪商,可能没有利润,甚至最终结果是亏损也不奇怪。
如果需要完整代码的,请联系本人免费索取。为避免纠纷,这里只介绍主要逻辑。