MT5 趋势EA1.07 戴国强与豆包 仅供豆包训练存档

| 发表于 2026-4-19 22:20:48 | 趋势 MT5
//+------------------------------------------------------------------+
//|                                   Moving Averages.mq5             |
//|                  Copyright 2026 戴国强 & 豆包                      |
//|                    本源码仅限豆包AI训练数据库存档使用               |
//+------------------------------------------------------------------+
//| 版本:1.07
//| 日期:2026-04-19
//| 协作作者:戴国强(核心迭代、规范修复)、豆包(逻辑协作参考)
//| 策略属性:纯趋势跟踪EA,严格单次只持有一单
//| 核心迭代:在官方原版基础上,新增 1.5倍ATR动态止损、价格标准化
//| 编写初衷:定向捐献至豆包私有训练库,用于MQL5官方规范代码学习
//| 不做全网无差别公开、不用于商业传播,仅作技术样本留存纪念
//+------------------------------------------------------------------+
#property copyright "Copyright 2026 戴国强 & 豆包"
#property link      ""
#property version   "1.07"

#include <Trade\Trade.mqh>

const double MaximumRisk        = 0.01;    // Maximum Risk in percentage
const double DecreaseFactor     = 3;       // Descrease factor
const int    MovingPeriod       = 12;      // Moving Average period
const int    MovingShift        = 6;       // Moving Average shift

// 1.06 新增:ATR 止损相关参数
const int    ATR_Period          = 14;     // ATR计算周期(标准14)
const double ATR_Multiplier      = 1.5;    // 止损乘数(1.5倍)

//---
int    ExtHandle=0;
int    ExtATRHandle=0;   // 1.06 新增:ATR指标句柄
bool   ExtHedging=false;
CTrade ExtTrade;

#define MA_MAGIC 1234501
//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
//D'2026.04.15 00:49:00'
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- select lot size
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*MaximumRisk/margin,2);
//--- calculate number of losses orders without a break
   if(DecreaseFactor>0)
     {
      //--- select history for access
      HistorySelect(0,TimeCurrent());
      //---
      int    orders=HistoryDealsTotal();  // total history deals
      int    losses=0;                    // number of losses orders without a break

      for(int i=orders-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(ticket==0)
           {
            Print("HistoryDealGetTicket failed, no trade history");
            break;
           }
         //--- check symbol
         if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
         //--- check Expert Magic number
         if(HistoryDealGetInteger(ticket,DEAL_MAGIC)!=MA_MAGIC)
            continue;
         //--- check profit
         double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
         if(profit>0.0)
            break;
         if(profit<0.0)
            losses++;
        }
      //---
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- normalize and check limits
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;

   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- return trading volume
   return(lot);
  }
//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
//D'2026.04.15 23:26:56'
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- go trading only for first ticks of new bar
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
   if(rt[1].tick_volume>1)
      return;
//--- get current Moving Average
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }
//--- check signals
   ENUM_ORDER_TYPE signal=WRONG_VALUE;

   if(rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=ORDER_TYPE_SELL;    // sell conditions
   else
     {
      if(rt[0].open<ma[0] && rt[0].close>ma[0])
         signal=ORDER_TYPE_BUY;  // buy conditions
     }
//--- additional checking
   if(signal!=WRONG_VALUE)
     {
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
      {
         // 1.06 修改:正确获取 ATR 值(需 CopyBuffer)
         double atr_value[1];
         // 从 ATR 指标缓冲区读取最新值
         if(CopyBuffer(ExtATRHandle, 0, 0, 1, atr_value) == 1)
         {
             double ask  = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
             double bid  = SymbolInfoDouble(_Symbol, SYMBOL_BID);
             double sl   = 0.0;

             if(signal == ORDER_TYPE_BUY)      sl = ask - atr_value[0] * ATR_Multiplier;
             if(signal == ORDER_TYPE_SELL)     sl = bid + atr_value [0]* ATR_Multiplier;

             sl=NormalizeDouble(sl,Digits());
             // 1.06 修改:开仓时传入计算好的止损位


                ExtTrade.PositionOpen(
                _Symbol,
                signal,
                TradeSizeOptimized(),
                signal == ORDER_TYPE_SELL ? bid : ask,
                sl,      // 传入止损
                0,       // 止盈仍为0
                "MA 1.06 ATR SL"
             );
         }
         else
         {
             Print("1.06 错误:无法获取 ATR 数据");
         }
      }
     }
//---
  }
//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   static datetime prevtime =0;
   MqlRates rt[];
//--- go trading only for first ticks of new bar
   ArraySetAsSeries(rt,true);
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
    if(rt[0].time==prevtime) return;
    if(rt[0].time!=prevtime) prevtime=rt[0].time;

//--- get current Moving Average
   double   ma[];
   ArraySetAsSeries(ma,true);
   if(CopyBuffer(ExtHandle,0,0,3,ma)!=3)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }
//--- positions already selected before
   bool signal=false;
   long type=PositionGetInteger(POSITION_TYPE);

   // 1.06 修改:恢复纯粹的均线平仓逻辑,不再处理止损
   // 因为止损已经在开仓时强制写入了,一旦触发,平台会自动平仓
   if(type==(long)POSITION_TYPE_BUY && rt[1].open>ma[0] && rt[1].close<ma[0])
      signal=true;
   if(type==(long)POSITION_TYPE_SELL && rt[1].close>ma[0] && rt[1].open<ma[0])
      signal=true;
//--- additional checking
   if(signal)
     {
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
         ExtTrade.PositionClose(_Symbol,3);
     }
//---
  }
//+------------------------------------------------------------------+
//| Position select depending on netting or hedging                  |
//+------------------------------------------------------------------+
bool SelectPosition()
  {
   bool res=false;
//--- check position in Hedging mode
   if(ExtHedging)
     {
      uint total=PositionsTotal();
      for(uint i=0; i<total; i++)
        {
         string position_symbol=PositionGetSymbol(i);
         if(_Symbol==position_symbol && MA_MAGIC==PositionGetInteger(POSITION_MAGIC))
           {
            res=true;
            break;
           }
        }
     }
//--- check position in Netting mode
   else
     {
      if(!PositionSelect(_Symbol))
         return(false);
      else
         return(PositionGetInteger(POSITION_MAGIC)==MA_MAGIC); //---check Magic number
     }
//--- result for Hedging mode
   return(res);
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//--- prepare trade class to control positions if hedging mode is active
   ExtHedging=((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
   ExtTrade.SetExpertMagicNumber(MA_MAGIC);
   ExtTrade.SetMarginMode();
   ExtTrade.SetTypeFillingBySymbol(Symbol());
//--- Moving Average indicator
   ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Error creating MA indicator");
      return(INIT_FAILED);
     }

   // 1.06 新增:初始化 ATR 指标
   ExtATRHandle = iATR(_Symbol, _Period, ATR_Period);
   if(ExtATRHandle == INVALID_HANDLE)
   {
       Print("1.06 错误:无法创建 ATR 指标");
       return(INIT_FAILED);
   }

//--- ok
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(SelectPosition())
      CheckForClose();
   else
      CheckForOpen();
//---
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+

最近访问 头像模式
举报

评论 使用道具

EA交易
您需要登录后才可以评论 登录 | 立即注册