我自研的第三套EA终于编译通过了。交易逻辑设定:大非农CPI事件驱动锁仓交易,用量价发展等价格行为自动触发运行,数据公布前5分 ...

| 发表于 2026-6-5 09:28:53 | 显示全部楼层 |复制链接
我自研的第三套EA终于编译通过了。交易逻辑设定:大非农CPI事件驱动锁仓交易,用量价发展等价格行为自动触发运行,数据公布前5分钟自动锁仓,数据公布后2分钟自动判断方向保留有利方向单,达到预期盈亏比自动清仓,未达成条件也自动平仓。今天晚上就可以用模拟盘试水了。欢迎感兴趣的朋友一起交流!如果证明有效,届时我会将MQL5源码在这里公开,算来到这里送给大家的一个玩具吧。
image.png
image.png
举报

评论 使用道具

精彩评论3

chinalingbao
DD
 楼主 | 发表于 2026-6-5 10:57:27 | 显示全部楼层
没想到管理后台还是审核通过了之前发的同一条帖子,本人声明下:其中个别字眼不代表任何平台推荐,网络世界杀猪盘很多很常见,科学上网不能忘!本人也是几年前从血雨腥风里好不容易爬出来还活着的一个,所以对这些都格外小心谨慎,也请大家严防死守,绝不要轻信他人误导。这年头活着就好!
举报

点赞 评论 使用道具

chinalingbao
DD
 楼主 | 发表于 2026-6-5 20:47:07 | 显示全部楼层
很遗憾,没有触发交易。排查,继续试吧。很受打击!
举报

点赞 评论 使用道具

chinalingbao
DD
 楼主 | 发表于 2026-6-5 23:13:35 | 显示全部楼层
总算解决了触发问题,是个还很简单粗暴的玩意。之前曾见识过一位高人用这种交易手法做的很不错,所以一直妄想模仿他的逻辑开发EA出来,也许这段历程还需要很久,也许这辈子都做不出来。MQL5源码奉上,请朋友们模拟盘把玩就好,或在此基础上继续开发,切勿实盘赌行情。
//+------------------------------------------------------------------+
//|                          PriceAction_EA.mq5                      |
//|                       非农CPI事件驱动锁仓交易法                  |
//|                        纯价格行为模式 - 全自动                   |
//|                    开发者:ChinaLingbao@outlook.com              |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026"
#property version   "1.10"
#property strict
//+------------------------------------------------------------------+
//| 输入参数                                                          |
//+------------------------------------------------------------------+
input string   EventTimeStr = "2026.06.05 15:30";   // 测试时间(服务器) - 改成当前时间+3分钟
input double   FixedLotSize = 0.01;                 // 固定手数
input double   TakeProfitRatio = 3.0;               // 止盈盈亏比
input int      PreEventMinutes = 5;                 // 提前开仓分钟数
input int      PriceActionWaitSeconds = 120;        // 价格行为等待秒数(2分钟)
input int      PriceActionMinPoints = 500;          // 最小波动点数(5美元)
input double   VolumeSurgeRatio = 1.0;              // 成交量激增倍数
input int      RiskPoints = 1000;                   // 风险点数(1点=0.01美元, 1000点=10美元)
input int      Slippage = 100;                      // 允许滑点
input int      MagicNumber = 20260605;              // EA魔术号

//+------------------------------------------------------------------+
//| 全局变量                                                          |
//+------------------------------------------------------------------+
datetime eventTime;
datetime preTradeTime;
datetime priceActionDeadline;
datetime decisionTimeOut;
bool tradesOpened = false;
bool decisionMade = false;
int keptDirection = 0;
ulong buyTicket = 0;
ulong sellTicket = 0;

// 新增全局变量 - 记录事件公布时的价格
datetime eventPublishedTime;
double eventStartPrice = 0;
bool priceRecorded = false;
//+------------------------------------------------------------------+
//| 初始化                                                           |
//+------------------------------------------------------------------+
int OnInit()
{
   if(!ParseTime(EventTimeStr, eventTime))
   {
      Print("ERROR: Time format error. Use YYYY.MM.DD HH:MM");
      return INIT_FAILED;
   }
   preTradeTime = eventTime - PreEventMinutes * 60;
   priceActionDeadline = eventTime + PriceActionWaitSeconds;
   decisionTimeOut = eventTime + 600;
   Print("============================================");
   Print("PriceAction_EA Loaded");
   Print("Event Time: ", TimeToString(eventTime));
   Print("Open Time: ", TimeToString(preTradeTime));
   Print("Decision Deadline: ", TimeToString(priceActionDeadline));
   Print("============================================");
   Print("Risk Points: ", RiskPoints, " (", RiskPoints/100.0, " USD)");
   Print("Take Profit: ", RiskPoints * TakeProfitRatio, " (", RiskPoints * TakeProfitRatio/100.0, " USD)");
   Print("Price Threshold: ", PriceActionMinPoints, " (", PriceActionMinPoints/100.0, " USD)");
   Print("Volume Ratio: ", VolumeSurgeRatio);
   Print("============================================");
   
   // 重置标志
   priceRecorded = false;
   eventStartPrice = 0;
   
   return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 反初始化                                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print("EA Unloaded");
}
//+------------------------------------------------------------------+
//| 主函数                                                            |
//+------------------------------------------------------------------+
void OnTick()
{
   datetime now = TimeCurrent();
   // 阶段1: 开锁仓
   if(!tradesOpened && now >= preTradeTime && now < eventTime)
   {
      OpenLockPositions();
      tradesOpened = true;
      Print("[OPEN] Lock positions completed");
   }
   // 阶段2: 决策
   if(tradesOpened && !decisionMade && now >= eventTime)
   {
      // 第一次进入决策阶段时,记录事件公布时的价格
      if(!priceRecorded)
      {
         eventPublishedTime = now;
         MqlTick tick;
         if(SymbolInfoTick(_Symbol, tick))
         {
            eventStartPrice = (tick.ask + tick.bid) / 2;
            priceRecorded = true;
            Print("[RECORD] Event published at: ", TimeToString(eventPublishedTime), " Start Price: ", eventStartPrice);
         }
         else
         {
            Print("[ERROR] Failed to get start price");
         }
      }
      
      if(now > decisionTimeOut)
      {
         CloseAllPositions();
         decisionMade = true;
         Print("[TIMEOUT] Decision timeout, all closed");
         return;
      }
      
      if(now >= priceActionDeadline)
      {
         int decision = 0;
         string reason = "";
         decision = GetPriceActionDecision(reason);
         ExecuteDecision(decision, reason);
         decisionMade = true;
      }
   }
   // 阶段3: 持仓管理
   if(decisionMade && keptDirection != 0)
   {
      CheckTakeProfit();
      ManageTrailingStop();
   }
}
//+------------------------------------------------------------------+
//| 开锁仓订单                                                       |
//+------------------------------------------------------------------+
void OpenLockPositions()
{
   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick))
   {
      Print("[ERROR] Failed to get tick");
      return;
   }
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   if(point == 0) point = 0.01;
   double riskPoints = RiskPoints;
   double tpPoints = riskPoints * TakeProfitRatio;
   double tpBuy = tick.ask + tpPoints * point;
   double tpSell = tick.bid - tpPoints * point;
   buyTicket = OpenOrder(ORDER_TYPE_BUY, FixedLotSize, tick.ask, 0, tpBuy, "Lock Buy");
   sellTicket = OpenOrder(ORDER_TYPE_SELL, FixedLotSize, tick.bid, 0, tpSell, "Lock Sell");
   if(buyTicket > 0)
      Print("[ORDER] Buy: ", buyTicket, " @ ", tick.ask);
   if(sellTicket > 0)
      Print("[ORDER] Sell: ", sellTicket, " @ ", tick.bid);
}
//+------------------------------------------------------------------+
//| 价格行为决策 - 修复版:使用记录的事件公布价格                        |
//+------------------------------------------------------------------+
int GetPriceActionDecision(string &reason)
{
   // 获取当前价格
   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick))
   {
      reason = "Failed to get current tick";
      return 0;
   }
   double currentPrice = (tick.ask + tick.bid) / 2;
   
   // 检查是否已记录公布价格
   if(eventStartPrice == 0)
   {
      reason = "Event start price not recorded";
      return 0;
   }
   
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   if(point == 0) point = 0.01;
   
   // 计算从公布到现在的价格变化(点数)
   double priceChange = (currentPrice - eventStartPrice) / point;
   
   // 获取成交量数据
   MqlRates rates[];
   int copied = CopyRates(_Symbol, PERIOD_M1, 0, 2, rates);
   if(copied < 2)
   {
      reason = "Failed to get volume data";
      return 0;
   }
   
   long currentVolume = rates[0].tick_volume;
   long previousVolume = rates[1].tick_volume;
   double volumeRatio = (previousVolume > 0) ? (double)currentVolume / previousVolume : 1.0;
   
   Print("[PA] Start Price: ", eventStartPrice);
   Print("[PA] Current Price: ", currentPrice);
   Print("[PA] Price Change: ", DoubleToString(priceChange, 0), " points (", DoubleToString(MathAbs(priceChange)/100.0, 2), " USD)");
   Print("[PA] Volume Ratio: ", DoubleToString(volumeRatio, 1));
   Print("[PA] Threshold: ", PriceActionMinPoints, " points (", PriceActionMinPoints/100.0, " USD)");
   
   // 判断方向
   if(MathAbs(priceChange) >= PriceActionMinPoints && volumeRatio >= VolumeSurgeRatio)
   {
      if(priceChange > 0)
      {
         reason = StringFormat("Price UP %.0f points + Volume %.1f -> BULLISH", priceChange, volumeRatio);
         Print("[DECISION] ✅ BULLISH - Keep LONG");
         return 1;
      }
      else
      {
         reason = StringFormat("Price DOWN %.0f points + Volume %.1f -> BEARISH", MathAbs(priceChange), volumeRatio);
         Print("[DECISION] ✅ BEARISH - Keep SHORT");
         return -1;
      }
   }
   
   reason = StringFormat("Conditions not met: Price Change %.0f (need %d), Volume Ratio %.1f (need %.1f)",
                         MathAbs(priceChange), PriceActionMinPoints, volumeRatio, VolumeSurgeRatio);
   Print("[DECISION] ❌ ", reason);
   return 0;
}
//+------------------------------------------------------------------+
//| 执行决策                                                         |
//+------------------------------------------------------------------+
void ExecuteDecision(int decision, string reason)
{
   Print("[DECISION] ", reason);
   if(decision == 1)
   {
      CloseOrder(sellTicket);
      keptDirection = 1;
      Print("[EXECUTE] Keep LONG, closed SHORT");
   }
   else if(decision == -1)
   {
      CloseOrder(buyTicket);
      keptDirection = -1;
      Print("[EXECUTE] Keep SHORT, closed LONG");
   }
   else
   {
      CloseOrder(buyTicket);
      CloseOrder(sellTicket);
      keptDirection = 0;
      Print("[EXECUTE] No clear signal, all closed");
   }
}
//+------------------------------------------------------------------+
//| 检查止盈                                                         |
//+------------------------------------------------------------------+
void CheckTakeProfit()
{
   if(keptDirection == 0) return;
   ulong ticket = (keptDirection == 1) ? buyTicket : sellTicket;
   if(!PositionSelectByTicket(ticket)) return;
   double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double currentPrice = (keptDirection == 1) ?
                         SymbolInfoDouble(_Symbol, SYMBOL_BID) :
                         SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   if(point == 0) point = 0.01;
   double profitPoints = (keptDirection == 1) ?
                         (currentPrice - openPrice) / point :
                         (openPrice - currentPrice) / point;
   double targetPoints = RiskPoints * TakeProfitRatio;
   if(profitPoints >= targetPoints)
   {
      CloseOrder(ticket);
      Print("[TAKE PROFIT] ", profitPoints, " points");
      keptDirection = 0;
   }
}
//+------------------------------------------------------------------+
//| 移动止损 - 已添加 IOC 填充模式                                     |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
   if(keptDirection == 0) return;
   ulong ticket = (keptDirection == 1) ? buyTicket : sellTicket;
   if(!PositionSelectByTicket(ticket)) return;
   double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double currentSL = PositionGetDouble(POSITION_SL);
   double currentPrice = (keptDirection == 1) ?
                         SymbolInfoDouble(_Symbol, SYMBOL_BID) :
                         SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   if(point == 0) point = 0.01;
   double profitPoints = (keptDirection == 1) ?
                         (currentPrice - openPrice) / point :
                         (openPrice - currentPrice) / point;
   int trailStart = 300;
   int trailStep = 50;
   if(profitPoints >= trailStart)
   {
      double newSL;
      if(keptDirection == 1)
         newSL = currentPrice - trailStep * point;
      else
         newSL = currentPrice + trailStep * point;
      if(newSL > currentSL)
      {
         MqlTradeRequest req = {};
         MqlTradeResult res = {};
         req.action = TRADE_ACTION_SLTP;
         req.position = ticket;
         req.sl = newSL;
         req.tp = PositionGetDouble(POSITION_TP);
         req.symbol = _Symbol;
         req.magic = MagicNumber;
         req.type_filling = ORDER_FILLING_IOC;
         if(OrderSend(req, res))
         {
            if(res.retcode == TRADE_RETCODE_DONE)
               Print("[TRAIL STOP] Updated to: ", DoubleToString(newSL, _Digits));
            else
               Print("[TRAIL STOP] Failed, retcode: ", res.retcode);
         }
         else
         {
            Print("[TRAIL STOP] OrderSend error: ", GetLastError());
         }
      }
   }
}
//+------------------------------------------------------------------+
//| 全部平仓                                                         |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
   CloseOrder(buyTicket);
   CloseOrder(sellTicket);
   keptDirection = 0;
}
//+------------------------------------------------------------------+
//| 开单函数 - 使用 IOC 填充模式                                       |
//+------------------------------------------------------------------+
ulong OpenOrder(ENUM_ORDER_TYPE type, double volume, double price, double sl, double tp, string comment)
{
   MqlTradeRequest req = {};
   MqlTradeResult res = {};
   req.action = TRADE_ACTION_DEAL;
   req.symbol = _Symbol;
   req.volume = volume;
   req.type = type;
   req.price = price;
   req.sl = sl;
   req.tp = tp;
   req.deviation = Slippage;
   req.magic = MagicNumber;
   req.comment = comment;
   req.type_filling = ORDER_FILLING_IOC;
   if(OrderSend(req, res))
   {
      if(res.retcode == TRADE_RETCODE_DONE)
         return res.order;
      else
         Print("Open order failed, retcode: ", res.retcode);
   }
   else
   {
      Print("Open order failed, error: ", GetLastError());
   }
   return 0;
}
//+------------------------------------------------------------------+
//| 平仓函数 - 添加 IOC 填充模式                                       |
//+------------------------------------------------------------------+
void CloseOrder(ulong ticket)
{
   if(ticket == 0) return;
   if(!PositionSelectByTicket(ticket)) return;
   MqlTradeRequest req = {};
   MqlTradeResult res = {};
   req.action = TRADE_ACTION_DEAL;
   req.symbol = PositionGetString(POSITION_SYMBOL);
   req.volume = PositionGetDouble(POSITION_VOLUME);
   req.deviation = Slippage;
   req.position = ticket;
   req.type_filling = ORDER_FILLING_IOC;
   ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
   if(posType == POSITION_TYPE_BUY)
   {
      req.type = ORDER_TYPE_SELL;
      req.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   }
   else
   {
      req.type = ORDER_TYPE_BUY;
      req.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   }
   if(OrderSend(req, res))
   {
      if(res.retcode == TRADE_RETCODE_DONE)
         Print("[CLOSE] Order ", ticket, " closed");
      else
         Print("[CLOSE] Failed, retcode: ", res.retcode);
   }
   else
   {
      Print("[CLOSE] OrderSend error: ", GetLastError());
   }
}
//+------------------------------------------------------------------+
//| 解析时间                                                         |
//+------------------------------------------------------------------+
bool ParseTime(string str, datetime &out)
{
   if(StringLen(str) < 16) return false;
   int year = (int)StringToInteger(StringSubstr(str, 0, 4));
   int mon  = (int)StringToInteger(StringSubstr(str, 5, 2));
   int day  = (int)StringToInteger(StringSubstr(str, 8, 2));
   int hour = (int)StringToInteger(StringSubstr(str, 11, 2));
   int min  = (int)StringToInteger(StringSubstr(str, 14, 2));
   if(year < 2000 || mon < 1 || mon > 12 || day < 1 || day > 31) return false;
   if(hour < 0 || hour > 23 || min < 0 || min > 59) return false;
   MqlDateTime dt = {0};
   dt.year = year;
   dt.mon = mon;
   dt.day = day;
   dt.hour = hour;
   dt.min = min;
   dt.sec = 0;
   out = StructToTime(dt);
   return true;
}
//+------------------------------------------------------------------+
举报

点赞 评论 使用道具

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