这次,我们在之前课程的基础上,给EA设定一个下单条件,也就是抛物线指标转向的时候,下单,去掉之前的挂上就买入一单。
具体是,抛物线从k线下面转到k线上面去之后,第二根k线开盘价卖出,如图中标记5处。
反之,抛物线从k线上面转到k线下面去之后,第二根k线开盘价买入,如图中标记1处。
一、引入抛物线指标函数 iSAR函数
double iSAR( string symbol, // 交易品种 int timeframe, // 时间周期 double step, // 步长 double maximum, // 最大值 int shift // 位移 );
这个函数有5个参数,前面4个看字面意思就知道其意思了,其中最后一个比较难以理解,涉及到MT4平台的K线位移。
什么是K线位移呢?
MT4平台,对于k线图上每一个k线,都设置了个位置编号,这个编号就是位移。从右往左,从0开始。
0号k线的开盘价就是Open[0];
1号K线的最高价就是High[1]。
如果要获取3号k线对应的抛物线的值就是 iSAR(NULL,0,0.02,0.2,3)。
二、根据上面的知识,我们现在来写一个函数Signal(),用来定义本EA的信号,返回值为1表示买入信号,返回值为-1表示卖出信号。
int signal() { int res=0; double A=iSAR(NULL,0,0.02,0.2,1); double B=iSAR(NULL,0,0.02,0.2,2); if(A>Close[1] && B<Close[2]) { res=1; } if(A<Close[1] && B>Close[2]) { res=-1; } return(res); }
三、现在,我们来开始编程写EA了。
1.在程序OnTick()函数的开始,我们定义两个变量,用来记录EA的持仓状态。
顺便也定义一个变量,从信号函数中返回信号值。
int buys=0; //多单持仓有几笔 int sells=0; //空单持仓有几笔 int signal=signal();
2.然后通过for循环遍历持仓单,分别找到多单持仓几笔和空单持仓几笔,并分别赋值给变量buys和sells。
for(int i=0; i<OrdersTotal(); i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { if(OrderSymbol()==Symbol() && OrderMagicNumber()==16384 && OrderType()==OP_BUY) { buys++; } if(OrderSymbol()==Symbol() && OrderMagicNumber()==16384 && OrderType()==OP_SELL) { sells++; } } }
3.然后加入开仓代码,当多单持仓数为0并且买入信号出现的时候,下多单;反之,当空单持仓数为0并且卖出信号出现的时候,下空单。
if(signal>0 && buys==0) { int ticket=OrderSend(Symbol(),OP_BUY,lots,Ask,3,0,0,"My buy order",16384,0,clrGreen); if(ticket<0) { Print("OrderSend failed with error #",GetLastError()); } else { Print("OrderSend placed successfully"); } } if(signal<0 && sells==0) { int ticket=OrderSend(Symbol(),OP_SELL,lots,Bid,3,0,0,"My sell order",16384,0,clrRed); if(ticket<0) { Print("OrderSend failed with error #",GetLastError()); } else { Print("OrderSend placed successfully"); } }
4.下单解决了,再就是加入平仓代码。
平仓代码加入到之前的for循环里面去,这样,整个程序在每次tick里就只有一次遍历订单,让程序运行更加高效。
为了节省篇幅,顺便把修改订单止损止盈也加入进去。
for(int i=0; i<OrdersTotal(); i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { if(OrderSymbol()==Symbol() && OrderMagicNumber()==16384 && OrderType()==OP_BUY) { buys++; if(signal<0) { bool res=OrderClose(OrderTicket(),OrderLots(),Bid,0); if(res) { Print("订单平仓成功"); } return; } if(OrderStopLoss()==0) { bool res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-SL*Point,OrderOpenPrice()+TP*Point,0); if(res) Print("订单修改成功"); } } if(OrderSymbol()==Symbol() && OrderMagicNumber()==16384 && OrderType()==OP_SELL) { sells++; if(OrderStopLoss()==0) { bool res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+SL*Point,OrderOpenPrice()-TP*Point,0); if(res) Print("订单修改成功"); } if(signal>0) { bool res=OrderClose(OrderTicket(),OrderLots(),Ask,0); if(res) { Print("订单平仓成功"); } return; } } } }
这里面需要注意一点的就是,多单的止损价是开盘价-点数*Point,多单止盈价是开盘价+点数*Point;
反之,空单的止损价是开盘价+点数*Point,空单的止盈价是开盘价-点数*Point。
四、到此,整个程序就完全修改好了,用历史数据测试下,正常交易。
完整代码如下:
//+------------------------------------------------------------------+ //| Test_EA_05.mq4 | //| 云开 | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "http://www.forexmt4.cn" #property link "http://www.forexmt4.cn" #property description "【漆天编程】 测试EA" #property description " " #property description "这是一款测试EA,作者QQ:80364276" #property description " " #property description "发布时间:2020.06.07" #property strict #property icon "//Images//sea.ico" input double lots=0.1; //交易手数 input int SL=600; //止损点数 input int TP=200; //止盈点数 //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int buys=0; //多单持仓有几笔 int sells=0; //空单持仓有几笔 int signal=signal(); for(int i=0; i<OrdersTotal(); i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { if(OrderSymbol()==Symbol() && OrderMagicNumber()==16384 && OrderType()==OP_BUY) { buys++; if(signal<0) { bool res=OrderClose(OrderTicket(),OrderLots(),Bid,0); if(res) { Print("订单平仓成功"); } return; } if(OrderStopLoss()==0) { bool res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-SL*Point,OrderOpenPrice()+TP*Point,0); if(res) Print("订单修改成功"); } } if(OrderSymbol()==Symbol() && OrderMagicNumber()==16384 && OrderType()==OP_SELL) { sells++; if(OrderStopLoss()==0) { bool res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+SL*Point,OrderOpenPrice()-TP*Point,0); if(res) Print("订单修改成功"); } if(signal>0) { bool res=OrderClose(OrderTicket(),OrderLots(),Ask,0); if(res) { Print("订单平仓成功"); } return; } } } } //--- if(signal>0 && buys==0) { int ticket=OrderSend(Symbol(),OP_BUY,lots,Ask,3,0,0,"My buy order",16384,0,clrGreen); if(ticket<0) { Print("OrderSend failed with error #",GetLastError()); } else { Print("OrderSend placed successfully"); } } if(signal<0 && sells==0) { int ticket=OrderSend(Symbol(),OP_SELL,lots,Bid,3,0,0,"My sell order",16384,0,clrRed); if(ticket<0) { Print("OrderSend failed with error #",GetLastError()); } else { Print("OrderSend placed successfully"); } } } //+------------------------------------------------------------------+ int signal() { int res=0; double A=iSAR(NULL,0,0.02,0.2,1); double B=iSAR(NULL,0,0.02,0.2,2); if(A>Close[1] && B<Close[2]) { res=1; } if(A<Close[1] && B>Close[2]) { res=-1; } return(res); } //+------------------------------------------------------------------+