//+------------------------------------------------------------------+ //| My_First_EA.mq5 | //| Copyright 2010, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "http://www.mql5.com" #property version "1.00" //--- 输入参数 input int StopLoss=30; // 止损 input int TakeProfit=100; // 获利 input int ADX_Period=8; // ADX 周期 input int MA_Period=8; // 移动平均周期 input int EA_Magic=12345; // EA 幻数 input double Adx_Min=22.0; // 最小 ADX 值 input double Lot=0.1; // 交易手数 //--- 其他参数 int adxHandle; // 我们 ADX 指标的句柄 int maHandle; // 我们移动平均指标的句柄 double plsDI[],minDI[],adxVal[]; // 用于保存每个柱 +DI, -DI 和 ADX 数值的动态数组 double maVal[]; // 用来保存每个柱移动平均值的动态数组 double p_close; // 保存一个柱的收盘价的变量 int STP, TKP; // 用于计算止损和获利数值 //+------------------------------------------------------------------+ //| EA 初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- 得到ADX指标句柄 adxHandle=iADX(NULL,0,ADX_Period); //--- 得到移动平均指标的句柄 maHandle=iMA(_Symbol,_Period,MA_Period,0,MODE_EMA,PRICE_CLOSE); //--- 如果句柄返回了无效句柄 if(adxHandle<0 || maHandle<0) { Alert("创建指标句柄出错 - 错误: ",GetLastError(),"!!"); return(-1); } //--- 让我们处理5位或3位小数的价格而不是4位小数价格的情况 STP = StopLoss; TKP = TakeProfit; if(_Digits==5 || _Digits==3) { STP = STP*10; TKP = TKP*10; } return(0); } //+------------------------------------------------------------------+ //| EA 去初始化函数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- 释放我们的指标句柄 IndicatorRelease(adxHandle); IndicatorRelease(maHandle); } //+------------------------------------------------------------------+ //| EA 订单函数 | //+------------------------------------------------------------------+ void OnTick() { //--- 我们是否有足够用于处理的柱 if(Bars(_Symbol,_Period)<60) // 如果总柱数少于60个柱 { Alert("我们只有不到60个柱, EA 将要退出!!"); return; } // 我们将会使用 Old_Time 静态变量来保存柱时间. // 在每一次执行 OnTick 函数的时候我们都将检查当前柱的时间和保存的时间. // 如果柱时间不等于保存的时间,说明我们有了一个新柱. static datetime Old_Time; datetime New_Time[1]; bool IsNewBar=false; // 把最新的柱时间复制到 New_Time[0] int copied=CopyTime(_Symbol,_Period,0,1,New_Time); if(copied>0) // 数据被成功复制 { if(Old_Time!=New_Time[0]) // 如果旧的时间与新柱时间不相等 { IsNewBar=true; // 如果不是第一次调用,新柱出现 if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("我们有了新柱 ",New_Time[0]," 原时间为 ",Old_Time); Old_Time=New_Time[0]; // 保存柱时间 } } else { Alert("复制历史时间数据出错, 错误 =",GetLastError()); ResetLastError(); return; } //--- EA 应该只在有新柱的时候检查新的交易条件 if(IsNewBar==false) { return; } //--- 我们是否有足够用于处理的柱 int Mybars=Bars(_Symbol,_Period); if(Mybars<60) // 如果总柱数少于60个柱 { Alert("我们只有不到60个柱, EA 将要退出!!"); return; } //--- 定义一些我们将用于交易的MQL5结构 MqlTick latest_price; // 用于取得最近/最新报价 MqlTradeRequest mrequest; // 用于发送我们的交易请求 MqlTradeResult mresult; // 用于获得我们的交易结果 MqlRates mrate[]; // 用于保存每个柱的价格,交易量和差价 ZeroMemory(mrequest); // 初始化mrequest结构 /* 让我们确认用于保存报价, ADX 值 和 MA 值的数组都以 时间序列数组相同的形式存放 */ // 报价数组 ArraySetAsSeries(mrate,true); // ADX DI+值数组 ArraySetAsSeries(plsDI,true); // ADX DI-值数组 ArraySetAsSeries(minDI,true); // ADX 值数组 ArraySetAsSeries(adxVal,true); // MA-8 值数组 ArraySetAsSeries(maVal,true); //--- 使用MQL5的MqlTick结构取得最后报价 if(!SymbolInfoTick(_Symbol,latest_price)) { Alert("获取最新报价出错 - 错误:",GetLastError(),"!!"); return; } //--- 取得最新三个柱的详细信息 if(CopyRates(_Symbol,_Period,0,3,mrate)<0) { Alert("复制报价/历史数据出错 - 错误:",GetLastError(),"!!"); ResetLastError(); return; } //--- 使用句柄把我们指标的新值复制到缓冲区(数组)中 if(CopyBuffer(adxHandle,0,0,3,adxVal)<0 || CopyBuffer(adxHandle,1,0,3,plsDI)<0 || CopyBuffer(adxHandle,2,0,3,minDI)<0) { Alert("复制 ADX 指标缓冲区出错 - 错误:",GetLastError(),"!!"); ResetLastError(); return; } if(CopyBuffer(maHandle,0,0,3,maVal)<0) { Alert("复制移动平均指标缓冲区出错 - 错误:",GetLastError()); ResetLastError(); return; } //--- 我们没有遇到错误,所以继续 //--- 我们是否已经有持仓? bool Buy_opened=false; // 用于保存买入持仓结果的变量 bool Sell_opened=false; // 用于保存卖出持仓结果的变量 if(PositionSelect(_Symbol)==true) // 我们有持仓 { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) { Buy_opened=true; //是买入 } else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL) { Sell_opened=true; // 是卖出 } } // 复制当前柱的前一个柱的收盘价, 也就是柱 1 p_close=mrate[1].close; // 柱1收盘价 /* 1. 检查买入设置 : MA-8 向上增加, 前一收盘价比它高, ADX > 22, +DI > -DI */ //--- 声明bool类型变量用于保存我们的买入条件 bool Buy_Condition_1=(maVal[0]>maVal[1]) && (maVal[1]>maVal[2]); // MA-8 向上增加 bool Buy_Condition_2 = (p_close > maVal[1]); // 前一收盘价高于 MA-8 bool Buy_Condition_3 = (adxVal[0]>Adx_Min); // 当前 ADX 值比最小值大 (22) bool Buy_Condition_4 = (plsDI[0]>minDI[0]); // +DI 比 -DI 大 //--- 放到一起 if(Buy_Condition_1 && Buy_Condition_2) { if(Buy_Condition_3 && Buy_Condition_4) { // 有买入持仓吗? if(Buy_opened) { Alert("我们已经有了买入仓位!!!"); return; // 不开启新的买入仓位 } ZeroMemory(mrequest); mrequest.action = TRADE_ACTION_DEAL; // 立即执行订单 mrequest.price = NormalizeDouble(latest_price.ask,_Digits); // 最新卖家报价 mrequest.sl = NormalizeDouble(latest_price.ask - STP*_Point,_Digits); // 止损 mrequest.tp = NormalizeDouble(latest_price.ask + TKP*_Point,_Digits); // 获利 mrequest.symbol = _Symbol; // 货币对 mrequest.volume = Lot; // 交易手数 mrequest.magic = EA_Magic; // 订单幻数 mrequest.type = ORDER_TYPE_BUY; // 买入订单 mrequest.type_filling = ORDER_FILLING_FOK; // 订单执行类型 mrequest.deviation=100; // 当前价格偏移 //--- 发送订单 OrderSend(mrequest,mresult); // 取得结果代码 if(mresult.retcode==10009 || mresult.retcode==10008) //请求完成或者已经下单 { Alert("已经成功下买单,订单#:",mresult.order,"!!"); } else { Alert("买入订单请求无法完成 -错误:",GetLastError()); ResetLastError(); return; } } } /* 2. 检查卖出设定 : MA-8 向下降低, 前一收盘价低于它, ADX > 22, -DI > +DI */ //--- 声明bool类型变量用于保存我们的卖出条件 bool Sell_Condition_1 = (maVal[0]Adx_Min); // 当前 ADX 值比最小值大 (22) bool Sell_Condition_4 = (plsDI[0]