一步步学习如何利用公允价值缺口(FVG)或市场不平衡性来交易的策略:一种聪明资金的交易方法·综合运用
⚖️

一步步学习如何利用公允价值缺口(FVG)或市场不平衡性来交易的策略:一种聪明资金的交易方法·综合运用

(3/3)·当你已懂FVG定义与识别,却卡在策略落地与回测验证,这篇把闭环补齐

含代码示例偏理论 第 3/3 篇
很多交易者能肉眼认出三根K线缺口,却在下单逻辑上把引线和实体混为一谈,导致回测与实盘背离。FVG不是画个框就完事,缺口区域与进场触发要分开定义。先把边界理清,EA才不会乱追影线。

◍ FVG 对象的登记与存续判定

这段逻辑解决两件事:新出现的公平价值缺口(FVG)如何落进全局数组,以及已有图形对象是否还活在该品种的 K 线结构里。外汇与贵金属市场跳空频繁,FVG 失效速度可能快于预期,属于高风险识别动作,务必在 MT5 实盘前用策略测试器跑一遍。 先说新建分支:当 ObjectFind 在当前图表找不到同名矩形,说明这是一个未被记录的 FVG。代码先调用 CreateRec 画出缺口区域,随后三次 ArrayResize 把 totalFVGs、barTIMEs、signalFVGs 各扩容 1,并把新名字、触发时间、信号标记 false 写进末尾。Print 输出的 Old/New ArraySize 差值恒为 1,可直接在终端日志核对扩容是否生效。 存续检查放在独立 for 循环,从数组末尾倒序扫到 0。对每个对象取出名称、上下边界与颜色,再向内回溯 FVG_Rec_Ext_Bars 根 K 线,只要某根 bar 的高或低碰到 fvgLow 就置 fvgExist=true 并 break。这里只判边界接触,不判实体填充,回测时若发现缺口被毛刺刺穿却仍保留,大概率是这个等号逻辑在起作用。 最后两行取规范化后的 Ask、Bid,为后续信号触发准备实时报价。注意 NormalizeDouble 用了 _Digits,黄金 XAUUSD 的 _Digits 通常是 2 或 3,EURUSD 多为 5,复制代码前先确认品种报价精度,否则边界比对会偏一格。

MQL5 / C++
class="type">color fvgClr = FVG_UP ? CLR_UP : CLR_DOWN;

if (ObjectFind(class="num">0,fvgNAME) < class="num">0){
   CreateRec(fvgNAME,time1,price1,time2,price2,fvgClr);
   Print("Old ArraySize = ",ArraySize(totalFVGs));
   ArrayResize(totalFVGs,ArraySize(totalFVGs)+class="num">1);
   ArrayResize(barTIMEs,ArraySize(barTIMEs)+class="num">1);
   ArrayResize(signalFVGs,ArraySize(signalFVGs)+class="num">1);
   Print("New ArraySize = ",ArraySize(totalFVGs));
   totalFVGs[ArraySize(totalFVGs)-class="num">1] = fvgNAME;
   barTIMEs[ArraySize(barTIMEs)-class="num">1] = time1;
   signalFVGs[ArraySize(signalFVGs)-class="num">1] = false;
   ArrayPrint(totalFVGs);
   ArrayPrint(barTIMEs);
   ArrayPrint(signalFVGs);
   }
   }
   }

 for (class="type">int j=ArraySize(totalFVGs)-class="num">1; j>=class="num">0; j--){
   class="type">bool fvgExist = false;
   class="type">class="kw">string objName = totalFVGs[j];
   class="type">class="kw">string fvgNAME = ObjectGetString(class="num">0,objName,OBJPROP_NAME);
   class="type">class="kw">double fvgLow = ObjectGetDouble(class="num">0,fvgNAME,OBJPROP_PRICE,class="num">0);
   class="type">class="kw">double fvgHigh = ObjectGetDouble(class="num">0,fvgNAME,OBJPROP_PRICE,class="num">1);
   class="type">color fvgColor = (class="type">color)ObjectGetInteger(class="num">0,fvgNAME,OBJPROP_COLOR);

   for (class="type">int k=class="num">1; k<=FVG_Rec_Ext_Bars; k++){
     class="type">class="kw">double barLow = iLow(_Symbol,_Period,k);
     class="type">class="kw">double barHigh = iHigh(_Symbol,_Period,k);

     if (barHigh == fvgLow || barLow == fvgLow){
       class=class="str">"cmt">//Print("Found: ",fvgNAME," @ bar ",k);
       fvgExist = true;
       break;
     }
   }

   class=class="str">"cmt">//Print("Existence of ",fvgNAME," = ",fvgExist);

   class="type">class="kw">double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   class="type">class="kw">double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

FVG 被吃后的双向挂单与数组清理

这段逻辑处理公允值缺口(FVG)失效后的交易触发与内存回收。向下缺口(CLR_DOWN)时,若 Bid 已站上 fvgHigh 且未发过信号,则打印 SELL 信号,并以 Ask 加 10 倍缺口跨度作止损、fvgLow 作止盈尝试卖出;向上缺口反之用 Ask 跌破 fvgLow 触发 BUY。 止损距离用 NormalizeDouble 按 _Digits 对齐:((fvgHigh-fvgLow)/_Point)*10*_Point,即缺口高度的 10 倍点数。外汇与贵金属杠杆高,这类固定倍数止损在跳空时可能直接穿损,实盘前应在 MT5 策略测试器用 0.01 手跑一轮观察最大回撤。 下单前依次过 Check2_Margin(保证金)、Check3_VolumeLimit(限量)、Check4_TradeLevels(层级合规),三者全过才 obj_Trade.Sell/Buy,并把 signalFVGs[j] 置 true 防重复触发。 当 fvgExist 为 false,说明缺口已被完全回补,代码用 ArrayRemove 把 totalFVGs、barTIMEs、signalFVGs 的 0 号元素同步删掉,打印剩余数组大小确认回收成功。注意三个数组必须同下标操作,否则后续 j 循环会错位。

MQL5 / C++
   if (fvgColor == CLR_DOWN && Bid > fvgHigh && !signalFVGs[j]){
         Print("SELL SIGNAL For(",fvgNAME,") Now @ ",Bid);
         class="type">class="kw">double SL_sell = Ask + NormalizeDouble((((fvgHigh-fvgLow)/_Point)*class="num">10)*_Point,_Digits);
         class="type">class="kw">double trade_lots = Check1_ValidateVolume_Lots(class="num">0.01);
         
         if (Check2_Margin(ORDER_TYPE_SELL,trade_lots) &&
             Check3_VolumeLimit(trade_lots) &&
             Check4_TradeLevels(POSITION_TYPE_SELL,SL_sell,fvgLow)){
            obj_Trade.Sell(trade_lots,_Symbol,Bid,SL_sell,fvgLow);
            signalFVGs[j] = true;
         }
         ArrayPrint(totalFVGs,_Digits," [< >] ");
         ArrayPrint(signalFVGs,_Digits," [< >] ");
      }
      else if (fvgColor == CLR_UP && Ask < fvgLow && !signalFVGs[j]){
         Print("BUY SIGNAL For(",fvgNAME,") Now @ ",Ask);
         class="type">class="kw">double SL_buy = Bid - NormalizeDouble((((fvgHigh-fvgLow)/_Point)*class="num">10)*_Point,_Digits);
         class="type">class="kw">double trade_lots = Check1_ValidateVolume_Lots(class="num">0.01);
         if (Check2_Margin(ORDER_TYPE_BUY,trade_lots) &&
             Check3_VolumeLimit(trade_lots) &&
             Check4_TradeLevels(POSITION_TYPE_BUY,SL_buy,fvgHigh)){
            obj_Trade.Buy(trade_lots,_Symbol,Ask,SL_buy,fvgHigh);
            signalFVGs[j] = true;
         }
         ArrayPrint(totalFVGs,_Digits," [< >] ");
         ArrayPrint(signalFVGs,_Digits," [< >] ");
      }
      
      if (fvgExist == false){
         class="type">bool removeName = ArrayRemove(totalFVGs,class="num">0,class="num">1);
         class="type">bool removeTime = ArrayRemove(barTIMEs,class="num">0,class="num">1);
         class="type">bool removeSignal = ArrayRemove(signalFVGs,class="num">0,class="num">1);
         if (removeName && removeTime && removeSignal){
            Print("Success removing the FVG DATA from the arrays. New Data as Below:");
            Print("FVGs: ",ArraySize(totalFVGs)," TIMEs: ",ArraySize(barTIMEs),
                  " SIGNALs: ",ArraySize(signalFVGs));
            ArrayPrint(totalFVGs);
            ArrayPrint(barTIMEs);

「回测里看 FVG 信号数组的实际产出」

把 signalFVGs 数组用 ArrayPrint 打进日志后,在 MT5 策略测试器跑一轮,能直接看到每一根 K 线识别出的 FVG 结构编号与方向。 回测输出的余额/资产净值曲线只是表象,真正有含金量的是诊断数组本身:若某段行情 signalFVGs 持续为空,说明该周期 FVG 条件未被触发,策略在那段大概率是空仓。 建议你在自己的品种上(如 XAUUSD、EURUSD,均属高风险杠杆市场)复跑这段代码,把日志导出来数一下有效 FVG 信号占比,再决定是否调小实体阈值来提升触发频率。

MQL5 / C++
ArrayPrint(signalFVGs);

◍ 把 SMC 缺口策略真正跑起来之前

公允价值缺口策略的核心,是识别价格与内在价值之间的偏离并用统计方法量化,而不是凭肉眼猜影线。前面几节给出的 FVG_SMC_EA.mq5 附件约 21.23 KB,已经把数据分析、K线结构与 MQL5 自动化串成了一条可验证链路。 在 MT5 里加载该 EA 后,优先看时间序列与 K 线分析模块是否按预期标记不平衡区;若标记逻辑与你手动画的 FVG 区吻合度低,先调检测窗口参数而非直接上实盘。外汇与贵金属杠杆高,这类统计套利模型在历史样本上有效,不等于未来概率不变。 真要落地,就把它当基础框架:自己补优化与数据提取,别信任何「保证结果」的说法。开 MT5 跑一遍附件里的代码,比读十遍结论更有用。

把缺口扫描交给小布盯盘
这些诊断小布盯盘的AIGC已内置,打开对应品种页即可看到FVG区域标记与不平衡强度,你只需把规则写进EA,重复画线劳动留给小布。

常见问题

需约束第一根与第三根引线不重叠且中间K线实体占比偏高,同时前后波动幅度超过ATR阈值,避免低波动假缺口进入信号池。
目前小布在品种页可视化缺口区域与强度,坐标可人工抄入策略参数;深度API对接倾向后续版本,外汇贵金属属高风险品类请自审逻辑。
样本外回测若曲线平稳、回撤可控,概率上值得小仓位验证;但MT5模拟与真实点差滑点可能改写结论,需分阶段放大。
黄金对利率与避险流更敏感,缺口回补速度常快于欧美;参数应分品种标定,不可一套模板跨市场硬套。