在亚洲市场进行夜间交易: 如何保持盈利·进阶篇
🌙

在亚洲市场进行夜间交易: 如何保持盈利·进阶篇

(2/3)· 欧美的睡眠时段里,EURUSD 与 USDJPY 为何走出两种完全不同的夜盘性格

含代码示例偏理论 第 2/3 篇
把亚洲夜盘当成全球安静时段是常见误判,USDJPY 往往在此时最活跃。用欧洲收盘后的惯性去套所有货币对,止损会被频繁扫掉。先分清平盘与活跃品种,再谈策略才有意义。

◍ EA 初始化与按星期过滤交易时段

这段 MT5 专家顾问的骨架先把外部参数和全局句柄定下来,再用 OnInit 把交易对象的行为锁死。magic_number 设成 65758473787389 这种长整型,是为了在多 EA 同跑时避免订单混淆;order_volume 默认 0.01 手,order_deviation 给 100 点偏移容差,都是可直接在 MT5 输入栏改的实值。 OnInit 里四行很关键:SetExpertMagicNumber 绑定幻数,SetDeviationInPoints 把滑点容限钉在 100 点,SetTypeFilling 用 ORDER_FILLING_FOK 强迫全部成交否则作废,SetAsyncMode(false) 让发单走同步模式——回测时少踩坑。 OnTick 开头用 TimeCurrent 取本地结构体时间,再按 day_of_week 的 1~5 映射周一到周五,靠 mon/tue/wen/thu/fri 几个外部开关决定 work_day 真假。time_h_start>time_h_stop 的分支处理跨午夜交易(比如 22 点干到次日 3 点),否则就在同一天内 hour 介于起止之间才把 work 置真。外汇与贵金属杠杆高,这类时段过滤逻辑若没接实盘时区验证,可能在某些经纪商服务器时间下漏单或错单。 别把幻数当摆设 幻数冲突会让平仓函数抓错单,复制代码时先改掉 65758473787389,用自己账号下不重复的随机长整型更稳。

MQL5 / C++
class="kw">input class="type">long magic_number=class="num">65758473787389; class=class="str">"cmt">// 幻数
class="kw">input class="type">class="kw">double order_volume=class="num">0.01;         class=class="str">"cmt">// 手数大小
class="kw">input class="type">int order_deviation=class="num">100;          class=class="str">"cmt">// 仓位开启的偏移
class=class="str">"cmt">//--- 变量
class="type">MqlDateTime time_now_str;
class="type">class="kw">datetime time_now_var;
CTrade trade;
class="type">int bb_handle;
class="type">class="kw">double bb_base_line[class="num">3];
class="type">class="kw">double bb_upper_line[class="num">3];
class="type">class="kw">double bb_lower_line[class="num">3];
class="type">bool work_day=true;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA交易初始化函数                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//---
   trade.SetExpertMagicNumber(magic_number);
   trade.SetDeviationInPoints(order_deviation);
   trade.SetTypeFilling(ORDER_FILLING_FOK);
   trade.SetAsyncMode(class="kw">false);
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA交易订单分时函数                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//---
   time_now_var=TimeCurrent(time_now_str);class=class="str">"cmt">// 当前时间
   class="type">bool work=class="kw">false;

      class="kw">switch(time_now_str.day_of_week)
      {
      case class="num">1: if(mon==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">2: if(tue==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">3: if(wen==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">4: if(thu==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">5: if(fri==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      }
class=class="str">"cmt">//--- 检查工作时间
   if(time_h_start>time_h_stop)             class=class="str">"cmt">// 工作直到第二天
     {
      if(time_now_str.hour>=time_h_start || time_now_str.hour<=time_h_stop)
        {
         work=true;
        }                                   class=class="str">"cmt">// 传入标志以启用工作
     }
   else                                     class=class="str">"cmt">// 在一天之内工作
     {
      if(time_now_str.hour>=time_h_start && time_now_str.hour<=time_h_stop)
        {
         work=true;
        }

「布林带触带的反转下单逻辑」

这段执行块只在 work 与 work_day 同时为 true 时介入。先用 iBands 拿到当前品种周期的布林带句柄,随后用 CopyBuffer 分别把中轨、上轨、下轨最近 3 根 K 线的数值拷进数组,任意一个返回 -1 就弹 Alert 报错,避免脏数据继续跑。 无持仓时(pos<1),若卖价减去 div_signal 点后落在上轨第 3 根(索引 2)加减 div_work 点的窄区间内,倾向视为向上触带反转,发出 Sell;买价加上 div_signal 点后落在下轨同位置区间内,则发 Buy。两者都带基于 _Point 计算的止损止盈。 已有多头且 work_alt 开启时,同样的上轨贴合条件会先平多再反手做空。外汇与贵金属杠杆高,触带反转胜率随周期波动,实盘前请在 MT5 策略测试器用 2020—2023 年 XAUUSD H1 跑一遍验证参数敏感性。

MQL5 / C++
 }                                     class=class="str">"cmt">// 传入标志以启用工作
  class="type">int pos=PositionsTotal();
  if(work==true && work_day==true)        class=class="str">"cmt">// 工作已启用
   {
     bb_handle=iBands(_Symbol,_Period,bands_period,bands_shift,bands_diviation,PRICE_CLOSE);         class=class="str">"cmt">// 得到布林带指标句柄
     class="type">int i_bl=CopyBuffer(bb_handle,class="num">0,class="num">0,class="num">3,bb_base_line);
     class="type">int i_ul=CopyBuffer(bb_handle,class="num">1,class="num">0,class="num">3,bb_upper_line);
     class="type">int i_ll=CopyBuffer(bb_handle,class="num">2,class="num">0,class="num">3,bb_lower_line);
     if(i_bl==-class="num">1 || i_ul==-class="num">1 || i_ll==-class="num">1)
       {Alert("从 iBands 复制数据错误: base line=",i_bl,", upper band=",i_ul,", lower band=",i_ll);}   class=class="str">"cmt">// 检查复制的数据
     class="type">class="kw">double price_ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
     class="type">class="kw">double price_bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
     if(pos<class="num">1)
       {
        if((price_ask-(div_signal*_Point))>=bb_upper_line[class="num">2]-(div_work*_Point) && (price_ask-(div_signal*_Point))<=bb_upper_line[class="num">2]+(div_work*_Point))class=class="str">"cmt">// 卖出信号 
         {
          trade.Sell(order_volume,_Symbol,price_bid,(price_bid+(stop_loss*_Point)),(price_bid-(take_profit*_Point)),"pos<1_sell");
         }
        if((price_bid+(div_signal*_Point))<=bb_lower_line[class="num">2]+(div_work*_Point) && (price_bid+(div_signal*_Point))>=bb_lower_line[class="num">2]-(div_work*_Point))class=class="str">"cmt">// 买入信号
         {
          trade.Buy(order_volume,_Symbol,price_ask,(price_ask-(stop_loss*_Point)),(price_ask+(take_profit*_Point)),"pos<1_buy");
         }
       }
     if(pos>class="num">0 && work_alt==true)
       {
        if(trade.RequestType()==ORDER_TYPE_BUY)                     class=class="str">"cmt">// 如果在那之前有买入订单
         if((price_ask-(div_signal*_Point))>=bb_upper_line[class="num">2]-(div_work*_Point) && (price_ask-(div_signal*_Point))<=bb_upper_line[class="num">2]+(div_work*_Point))class=class="str">"cmt">// 卖出信号 
          {
           trade.PositionClose(_Symbol,order_deviation);
           trade.Sell(order_volume,_Symbol,price_bid,(price_bid+(stop_loss*_Point)),(price_bid-(take_profit*_Point)),"pos>0_sell");
          }

卖出持仓下的反手买入触发逻辑

当账户里已经挂有卖出单(ORDER_TYPE_SELL)时,EA 不会干等,而是用布林下轨做反向过滤。具体看 price_bid 加上 div_signal 个点的偏移后,是否落在 bb_lower_line[2] 加减 div_work 个点的窄区间内;若满足,视为价格触到下轨支撑带、可能反弹,随即平掉卖单并反向开买。 这段判定把「下轨附近 + 信号偏移」做成双容差通道,比单点穿越更抗毛刺。实盘里 div_signal 与 div_work 若设得过小,在黄金 5 位数报价下容易频繁误触发,外汇与贵金属杠杆高,误触发会迅速放大滑点损耗。 代码里的平仓用 PositionClose(_Symbol, order_deviation),开买则带止损 stop_loss 点、止盈 take_profit 点,备注打 "pos>0_buy" 方便复盘筛选。若 pos 不大于 0 且走 else 分支,则仅平掉已有多单、不再新开,相当于只做卖单清理。

MQL5 / C++
if(trade.RequestType()==ORDER_TYPE_SELL)                   class=class="str">"cmt">// 如果在那之前有卖出订单
  if((price_bid+(div_signal*_Point))<=bb_lower_line[class="num">2]+(div_work*_Point) && (price_bid+(div_signal*_Point))>=bb_lower_line[class="num">2]-(div_work*_Point))class=class="str">"cmt">// 买入信号
    {
     trade.PositionClose(_Symbol,order_deviation);
     trade.Buy(order_volume,_Symbol,price_ask,(price_ask-(stop_loss*_Point)),(price_ask+(take_profit*_Point)),"pos>0_buy");
    }
   }
  }
 else
  {
   if(pos>class="num">0)
     {
      trade.PositionClose(_Symbol,order_deviation);
     }
  }

◍ 用挂单把时点卡进指定小时

这段逻辑把交易触发收敛到某个固定小时:当系统时间小时数等于 order_time 且当日开关 work_day 为真时,才去取盘口报价并计算挂单位置。 time_now_str.hour==order_time 这一判断是整段 EA 的闸门,配合前面按 day_of_week 设定的 work_day,能实现「只在周一至周五某小时跑一次」的约束。外汇与贵金属杠杆高,这种定时挂单仍可能因跳空触发在不利价位,实际滑点概率需自己在 MT5 里跑模拟观察。 价格计算上,price_buy=price_ask+div 把买入止损挂单放在卖价上方 div 点,卖出则在买价下方对称位置;sl、tp 均用 _Point 倍数换算。time_end 设为当前时间加 time_to_del(注释里写 3600 秒即一小时),挂单有效期由此封死,过期自动作废。 下面这段代码是 OnTick 里的核心声明与挂单触发段,逐行拆开看更直观。

MQL5 / C++
class="kw">input class="type">long magic_number=class="num">65758473787389;             class=class="str">"cmt">// 幻数
class="kw">input class="type">class="kw">double order_volume=class="num">0.01;                     class=class="str">"cmt">// 手数大小
class="kw">input class="type">int order_deviation=class="num">100;                      class=class="str">"cmt">// 开启仓位的偏移
class=class="str">"cmt">//--- 变量
CTrade trade;
class="type">MqlDateTime time_now_str;
class="type">class="kw">datetime time_now_var;
class="type">bool work=true;
class="type">bool work_del=true;
class="type">bool work_day=true;
class=class="str">"cmt">//---
class="type">MqlTradeResult result_buy={class="num">0};
class="type">MqlTradeResult result_sell={class="num">0};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA交易订单分时函数                                                        |  
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//---
   time_now_var=TimeCurrent(time_now_str);class=class="str">"cmt">// 当前时间
   class="kw">switch(time_now_str.day_of_week)
     {
      case class="num">1: if(mon==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">2: if(tue==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">3: if(wen==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">4: if(thu==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
      case class="num">5: if(fri==class="kw">false){work_day=class="kw">false;}
      else {work_day=true;}
      class="kw">break;
     }
   if(time_now_str.hour==order_time && work==true && work_day==true)
     {
      class="type">class="kw">double price_ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      class="type">class="kw">double price_bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
      class="type">class="kw">double div=order_div*_Point;
      class="type">class="kw">double sl=order_sl*_Point;
      class="type">class="kw">double tp=order_tp*_Point;
      class="type">class="kw">double price_buy=price_ask+div;
      class="type">class="kw">double price_sell=price_bid-div;
      class="type">class="kw">double buy_sl=price_buy-sl;
      class="type">class="kw">double buy_tp=price_buy+tp;
      class="type">class="kw">double sell_sl=price_sell+sl;
      class="type">class="kw">double sell_tp=price_sell-tp;
      class="type">class="kw">datetime time_end=time_now_var+time_to_del;     class=class="str">"cmt">//class="num">3600 秒, 一个小时
      trade.BuyStop(order_volume,price_buy,_Symbol,buy_sl,buy_tp,ORDER_TIME_SPECIFIED,time_end,"BuyLimit");
      trade.Result(result_buy);
让小布替你分好夜盘品种
小布盯盘的 AIGC 已内置各货币对分时段波动画像,打开对应品种页即可看到亚洲时段的历史活跃度分布,省去你手动翻 H1 图表的对冲功夫。

常见问题

亚洲时段大致在 UTC 22:00 至次日 08:00,此时美洲已收盘、欧洲在睡眠,时区错位造成本地认知的‘夜间’并不统一。
可以,品种页的波动分层模块会按近期布林带带宽收缩自动提示平盘概率,并列出同时段活跃度对照,方便切换标的。
均线在窄幅来回里会反复交叉制造噪音,布林带上下轨天然框住通道边界,对‘不确定性’区间的可视化更直观,参数仍需按品种调整。
倾向失效而非绝对,趋势突破多发生在宏观新闻或欧美尾盘延续,亚洲平盘内更宜用通道内振荡逻辑,突破交易胜率可能偏低。