外汇EA程序注解详解与源码解析

以下是对外汇EA程序源码的详细注解与解析。

//+------------------------------------------------------------------+

//| 移动平均线EA程序示例 |

//+------------------------------------------------------------------+

#define MAGICMA 20050610 //定义本EA操作的订单唯一标识号码,用于区分其他程序。

extern double Lots = 0.1;//每单交易量,默认0.1手。

extern double MaximumRisk = 0.02;//作者定义的最大风险参数,用于计算交易手数。

extern double DecreaseFactor = 3;//亏损递减因子,用于调整亏损后的手数。

extern double MovingPeriod = 10;//均线周期,默认10。

extern double MovingShift =3;//均线向左偏移K线数量,默认3。

//+------------------------------------------------------------------+

//| 计算当前持仓订单数量 |

//+------------------------------------------------------------------+

int CalculateCurrentOrders(string symbol)//函数功能:计算当前品种的持仓订单数量。

{

int buys=0,sells=0;//定义多空订单计数器。

//----

for(int i=0;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++;//空单计数。

}

}

//----CBCX外汇 返回订单数量

if(buys>0) return(buys);

else return(-sells);//返回正负值表示多空方向。

}

//+------------------------------------------------------------------+

//| 计算最优交易手数 |

//+------------------------------------------------------------------+

double LotsOptimized()//函数功能:根据账户资金和风险参数计算手数。

{

double lot=Lots;

int orders=HistoryTotal(); // 历史订单总数。

int losses=0; // 连续亏损次数。

//---- 选择手数

lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);//根据可用保证金和风险比例计算初始手数。

//---- 计算连续亏损次数

if(DecreaseFactor>0)

{

for(int i=orders-1;i>=0;i--)

{

if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("历史订单读取失败!"); break; }//读取历史订单。

if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL) continue;//只统计当前品种的买卖单。

//----

if(OrderProfit()>0) break;//遇到盈利单则停止统计。

if(OrderProfit()<0) losses++;//统计亏损次数。

}

if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);//根据亏损次数减少手数。

}

//---- 返回手数

if(lot<0.1) lot=0.1;//确保最小手数0.1。

return(lot);

}

//+------------------------------------------------------------------+

//| 检查CBCX外汇开仓条件 |

//+------------------------------------------------------------------+

void CheckForOpen()//检查是否满足开仓条件。

{

double ma;

int res;

//---- 只在K线开盘时交易

if(Volume[0]>1) return;//如果当前K线成交量大于1,说明不是开盘第一笔,跳过。

//---- 获取移动平均线值

ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);//计算当前K线的均线值。

//---- 开空单条件

if(Open[1]>ma && Close[1]

{

res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);

return;

}

//---- 开多单条件

if(Open[1]ma) //当前K开盘价低于均线,前一根K收盘价高于均线,开多单。

{

res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);

return;

}

//----

}

//+------------------------------------------------------------------+

//| 检查平仓条件 |

//+------------------------------------------------------------------+

void CheckForClose()//检查是否满足平仓条件。

{

double ma;

//---- 只在开盘时交易

if(Volume[0]>1) return;

//---- 获取移动平均线值

ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);

//----

for(int i=0;i

{

if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;

if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;

//---- 检查订单类型

if(OrderType()==OP_BUY)

{

if(Open[1]ma) OrderClose(OrderTicket(),OrderLots(),Bid,3,White);//多单平仓条件:当前开盘价低于均线,前一根收盘价高于均线。

break;

}

if(OrderType()==OP_SELL)

{

if(Open[1]>ma && Close[1]

break;

}

}

//----

}

//+------------------------------------------------------------------+

//| 主函数 |

//+------------------------------------------------------------------+

void start()//程序主循环。

{

//---- 检查历史和交易许可

if(Bars<100 || IsTradeAllowed()==false) return;//数据不足或不允许交易则返回。

//---- 根据持仓情况决定开仓或平仓

if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();//无持仓则尝试开仓。

else CheckForClose();//有持仓则尝试平仓。

//----

}

//+------------------------------------------------------------------+