返回《給 CFD 交易者的 MetaTrader 5 與 MQL5》
第四部分

計時器、事件與警示

OnTimer、OnTrade、OnChartEvent,以及把一個通知推到你的手機上。

進階閱讀時間約 10 分鐘初學 → 進階第 16 / 17 堂
在 MetaEditor 實際跑一次
計時器、交易事件、圖表按鍵與推播警示

存成 MQL5/Experts/Lesson16Events.mq5。它用計時器在圖表上放一個即時儀表板、記錄交易事件,並在你按下 B 時送出一個推播通知。

//+------------------------------------------------------------------+
//| Lesson 16 - Timers, trade events, chart events, notifications    |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"
#property strict

input int TimerSeconds = 60;

int OnInit()
{
   EventSetTimer(TimerSeconds);
   Print("Timer set to ", TimerSeconds, "s. Press 'B' on the chart to send a test alert.");
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   EventKillTimer();          // always - a stray timer is a nasty bug
   Comment("");               // clear the on-chart dashboard
}

//+------------------------------------------------------------------+
//| Time-based work: runs whether or not the market is moving        |
//+------------------------------------------------------------------+
void OnTimer()
{
   double bid    = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double free   = AccountInfoDouble(ACCOUNT_MARGIN_FREE);

   Comment("Lesson 16 dashboard",
           "\nSymbol:  ", _Symbol,
           "\nBid:     ", DoubleToString(bid, _Digits),
           "\nEquity:  ", DoubleToString(equity, 2),
           "\nFree:    ", DoubleToString(free, 2),
           "\nPositions: ", PositionsTotal(),
           "\nUpdated: ", TimeToString(TimeCurrent(), TIME_SECONDS));
}

//+------------------------------------------------------------------+
//| Fires when anything trade-related happens on the account         |
//+------------------------------------------------------------------+
void OnTrade()
{
   Print("Trade event. Positions total: ", PositionsTotal(),
         "   orders: ", OrdersTotal());

   // React, but do not place new orders from in here - set a flag instead.
   if(PositionSelect(_Symbol))
   {
      double sl = PositionGetDouble(POSITION_SL);
      double tp = PositionGetDouble(POSITION_TP);
      Print("Position on ", _Symbol,
            "  type=", (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? "BUY" : "SELL"),
            "  volume=", DoubleToString(PositionGetDouble(POSITION_VOLUME), 2),
            "  sl=", DoubleToString(sl, _Digits),
            "  tp=", DoubleToString(tp, _Digits));
   }
}

//+------------------------------------------------------------------+
//| Keyboard and object interaction                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if(id == CHARTEVENT_KEYDOWN)
   {
      if(lparam == 66)   // 'B'
      {
         double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         string msg = _Symbol + " manual check at " + DoubleToString(bid, _Digits);

         Alert(msg);
         Print("Alert raised: ", msg);

         // Requires push notifications enabled in terminal settings.
         if(!SendNotification(msg))
            Print("SendNotification failed - enable push notifications in terminal options.");
      }
   }
}
如何執行
  1. 1. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——ExpertsIndicators Scripts
  2. 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
  3. 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester

超越 OnTick

tick 只在市場有動靜時才來。而一個 EA 需要的東西,有很多是時間導向或事件導向的,不是價格導向的。MQL5 為每一種都提供了處理函式。

OnTimer

OnInit 裡呼叫 EventSetTimer(seconds)OnTimer() 不管市場有沒有活動,都會按那個間隔觸發。用它做時段檢查、每日風險重置、週期性健康報告,以及任何即使在死寂市場上也必須做的雜務。永遠在 OnDeinitEventKillTimer()——一個活得比它的 EA 還久的計時器,是一個日後非常難找的 bug。

OnTrade 與 OnTradeTransaction

這些在帳戶上發生事情時觸發:一張單被送出、一筆成交被執行、一個部位被關閉。用 OnTrade 來反應——更新你的狀態、寫紀錄、或送出通知。不要直接在裡面下新單;設一個旗標,在下一個 tick 時才行動,否則你會有重入迴圈的風險。

OnChartEvent

在滑鼠、鍵盤與物件事件時觸發。它是你做互動式 EA 的方式:按一個鍵關掉全部、點一個按鈕切換交易開關。id 參數告訴你發生了什麼;lparam 則帶著 CHARTEVENT_KEYDOWN 的鍵碼。

把警示送到你手上

  • Alert()——終端機裡的彈出視窗。大聲、本地,而且很容易錯過。
  • SendNotification()——推播到 MT5 手機 App。需要在終端機設定裡開啟通知,並設定你的 MetaQuotes ID。這是真正會送到你手上的那一個。
  • SendMail()——電子郵件,如果有設定 SMTP 的話。
  • PlaySound()——當你坐在桌前的時候用。

用 Comment 做一個即時儀表板

Comment() 把文字寫到圖表上。它是最便宜的狀態顯示——淨值、未平倉部位、目前的訊號——而且在測試器裡不花任何代價。在結束時用 Comment("") 清掉,不要留下過期的文字。

你剛完成了什麼

給 CFD 交易者的 MetaTrader 5 與 MQL5》的第 16 / 17 堂課。跑完範例或讀完這段之後, 把它勾起來,然後進下一堂課。