mt4软件自带两个ea交易策略,macd和moving average(ma),这里解析的是ma。
一、策略思路
K线上穿均线时,如果无仓,则开多仓,如果有空仓,则平仓;
K线下穿均线时,如果无仓,则开空仓,如果有多仓,则平仓。
二、代码解析
//双斜线后为注释内容,对程序执行没影响。注:绿色字体为我的注释,黑色注释为原程序自带。
#define MAGICMA 20210201//全局标识,用于区分该策略与别的策略,在对单子进行筛选时会用到,确保该策略不会操作其它策略的单子
//--- Inputs(输入变量,这些变量允许用户输入,也可以加载、保存,如下图所示)
input double Lots =0.1;//下单手数
input double MaximumRisk =0.02;//可用的最大资金比例2%
input double DecreaseFactor=3;//作者自己定义的数据,通过下文可以看到,影响下单量
input int MovingPeriod =12;//移动平均线周期
input int MovingShift =6;//均线向左的偏移量
//| Calculate Open positions |
//计算当前开单的数量,包括买单和卖单,不考虑锁单的情况,只有买单、卖单、空仓三种情况
int CalculateCurrentOrders(string Symbol)
{
int buys=0,sells=0;(初始化买单数和卖单数为0)
for(int i=0;i<OrdersTotal();i )
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
(单子的货币对是当前的货币对,并且策略标识符是该策略的)
{
if(OrderType()==OP_BUY) buys ;
if(OrderType()==OP_SELL) sells ;
//订单类型为整数型,0-BUY,1-SELL,2-BUYLIMT,3-BUYSTOP,4-SELLLIMT,5-SELLSTOP,下文中还会用到“>OP_SELL”代表挂单
}
}
if(buys>0) return(buys);
else return(-sells);
(如果买单数大于0,返回买单数,否则返回卖单数的负数,如果空仓就会返回0。)
}
//| Calculate optimal lot size |//计算下单的数量
double LotsOptimized()
{
double lot=Lots;
int orders=HistoryTotal(); // history orders total
int losses=0; // number of losses orders without a break亏损的单量
//--- select lot size
lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//--- calcuulate number of losses orders without a break
if(DecreaseFactor>0)
{
for(int i=orders-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
{
Print("Error in history!");
break;
}
if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL)
continue;
//---当不是买单和卖单时(比如挂单),继续
if(OrderProfit()>0) break;
if(OrderProfit()<0) losses ;//利润小于0的,亏单数 1
}
if(losses>1)
lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
//修正下单量, 如果 亏损单数>1时,则重新计算下单量,并保留小数点后1位,其计算公式为:下单量=(lot-lot*losses/DecreaseFactor(=3))。
}
//--- return lot size
if(lot<0.1) lot=0.1;
return(lot);
}
//| Check for open order conditions |(建仓函数)
void CheckForOpen()
{
double ma;
int res;
//--- go trading only for first tiks of new bar
if(Volume[0]>1) return;
//只有在新K线的首次报价时执行,如果当前K线的成交价次数大于1时,返回。
(不是K线的开盘时间点,即当前k线还没收盘确定,则直接返回;否则,如果是K线第一个成交价,则向下继续运行)
//--- get Moving Average计算ma值
ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_Close,0);
//--- sell conditions
if(Open[1]>ma && Close[1]<ma)
// 如果前1根K线下穿均线(即K线的开盘价大于均线值、收盘价小于均线值)
{
res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
// 发送仓单(当前货币对,卖出方向,开仓量计算(),买价,滑点=3,无止损,无止赢,订单编号,标上红色箭头)
return;
}
//--- buy conditions
if(Open[1]<ma && Close[1]>ma)
// 如果前1根K线上穿均线(即K线的开盘价小于均线值、收盘价大于均线值)
{
res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
// 发送仓单(当前货币对,买入方向,开仓量计算(),卖价,滑点=3,无止损,无止赢,订单编号,标上蓝色箭头)
return;
}
}
//| Check for close order conditions |(平仓函数)
void CheckForClose()
{
double ma;
//--- go trading only for first tiks of new bar
if(Volume[0]>1) return;
//--- get Moving Average
ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//---
for(int i=0;i<OrdersTotal();i )
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
// 如果 没有本系统所交易的仓单时,跳出循环
if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
// 如果 仓单编号不是本系统编号,或者 仓单货币对不是当前货币对时,继续选择
//--- check order type
if(OrderType()==OP_BUY)
{
if(Open[1]>ma && Close[1]<ma)
{
if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
// 如果第1根K线开盘价下穿均线(即开盘价高于均价而收盘价低于均价),则进行多头平仓(仓单编号,持仓数量,买价,滑点=3,用白色箭头显示)
Print("OrderClose error ",GetLastError());
}
break;
}
if(OrderType()==OP_SELL)
{
if(Open[1]<ma && Close[1]>ma)
{
if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
// 如果第1根K线开盘价上穿均线(即开盘价低于均价而收盘价高于均价),则进行空头平仓(仓单编号,持仓数量,卖价,滑点=3,用白色箭头显示)
Print("OrderClose error ",GetLastError());
}
break;
}
}
}
//| OnTick function |(循环函数,每更新一次数据执行一次函数)
void OnTick()
{
//--- check for history and trading
if(Bars<100 || IsTradeAllowed()==false)
//K线数小于100或不允许智能交易时,返回
return;
//--- calculate open orders by current symbol
if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();
else CheckForClose();
//如果当前无单,进入建仓函数,否则进入平仓函数
}
三、策略回测
回测时,需要先下载历史数据,工具---历史数据中心---选择标的对象,下载。
这里选择了欧美货币对,打开策略测试窗口,按钮在新订单左边,或是按快捷键ctrl r,进行如下设置:
选择交易策略、交易品种、ma时间周期、测试时间区间。
点击开始,进行测试,结果如下: