外汇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();//有持仓则尝试平仓。
//----
}
//+------------------------------------------------------------------+
