MT4 的报警指标

TradigView 的图表很好用,但是免费版只支持一个品种报警,且只支持弹出报警。不得已还是用下 MT4。

MT4 指标只支持三种类型报警:

  • Email
  • Mobile app (push-notifications)
  • On-screen

这里 Moving Average Crossover with Alert for MT4 and MT5 有一个简单的例子,这里改为 vegas 均线交叉信号,短期均线 ema144,长期均线 ema576。

#property link          "https://www.earnforex.com/metatrader-indicators/moving-average-crossover-alert/"
#property version       "1.04"
#property strict
#property copyright     "EarnForex.com - 2020-2022"
#property description   "Moving average crossover alert. Supports simple, exponential, smoothed, and linear weighted."
#property description   " "
#property description   " "
#property description   " "
#property description   "Find More on EarnForex.com"
#property icon          "\\Files\\EF-Icon-64x64px.ico"

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrRed
#property indicator_color2 clrGreen
#property indicator_type1 DRAW_LINE
#property indicator_type2 DRAW_LINE
#property indicator_label1 "Fast MA"
#property indicator_label2 "Slow MA"

#include <MQLTA ErrorHandling.mqh>
#include <MQLTA Utils.mqh>

enum ENUM_TRADE_SIGNAL {
    SIGNAL_BUY = 1,    // Buy
    SIGNAL_SELL = -1,  // Sell
    SIGNAL_NEUTRAL = 0 // Neutral
};

enum ENUM_CANDLE_TO_CHECK {
    CURRENT_CANDLE = 0,  // Current candle
    CLOSED_CANDLE = 1    // Previous candle
};

input string Comment1 = "========================";   // MQLTA Moving Average Crossover Alert
input string IndicatorName = "ROVER报警指标";            // Indicator short name

input string Comment2 = "========================";        // Indicator parameters
input int MAFastPeriod = 144;                               // Fast moving average period
input int MAFastShift = 0;                                 // Fast moving average shift
input ENUM_MA_METHOD MAFastMethod = MODE_EMA;              // Fast moving average method
input ENUM_APPLIED_PRICE MAFastAppliedPrice = PRICE_CLOSE; // Fast moving average applied price
input int MASlowPeriod = 576;                               // Slow moving average period
input int MASlowShift = 0;                                 // Slow moving average shift
input ENUM_MA_METHOD MASlowMethod = MODE_EMA;              // Slow moving average method
input ENUM_APPLIED_PRICE MASlowAppliedPrice = PRICE_CLOSE; // Slow moving average applied price
input ENUM_CANDLE_TO_CHECK CandleToCheck = CURRENT_CANDLE; // Candle to use for analysis
input int BarsToScan = 2000;                                // Number of candles to analyze

input string Comment_3 = "====================";   // Notification options
input bool EnableNotify = true;                   // Enable notifications feature
input bool SendAlert = true;                      // Send alert notification
input bool SendApp = false;                        // Send notification to mobile
input bool SendEmail = false;                      // Send notification via email

input string Comment_4 = "====================";   // Drawing options
input bool EnableDrawArrows = true;                // Draw signal arrows
input int ArrowBuy = 241;                          // Buy arrow code
input int ArrowSell = 242;                         // Sell arrow code
input int ArrowSize = 3;                           // Arrow size (1-5)
input color ArrowBuyColor = clrGreen;              // Buy arrow color
input color ArrowSellColor = clrRed;               // Sell arrow color

double BufferMASlow[];
double BufferMAFast[];

datetime LastNotificationTime;
ENUM_TRADE_SIGNAL LastNotificationDirection;
int Shift = 0;

int OnInit(void) {

    IndicatorSetString(INDICATOR_SHORTNAME, IndicatorName);

    OnInitInitialization();
    if (!OnInitPreChecksPass()) {
        return INIT_FAILED;
    }

    InitialiseBuffers();

    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[]) {
    if ((rates_total <= MASlowPeriod) || (MASlowPeriod <= 0)) return 0;
    if ((rates_total <= MAFastPeriod) || (MAFastPeriod <= 0)) return 0;
    if (MAFastPeriod > MASlowPeriod) return 0;

    bool IsNewCandle = CheckIfNewCandle();

    if (Bars(Symbol(), PERIOD_CURRENT) < (MASlowPeriod + MASlowShift)) {
        Print("Not Enough Historical Candles");
        return 0;
    }

    int pos = 0, upTo;
    if ((prev_calculated == 0) || (IsNewCandle)) {
        upTo = BarsToScan - 1;
    } else {
        upTo = 0;
    }

    for (int i = pos; (i <= upTo) && (!IsStopped()); i++) {
        BufferMASlow[i] = iMA(Symbol(), PERIOD_CURRENT, MASlowPeriod, MASlowShift, MASlowMethod, MASlowAppliedPrice, i);
        BufferMAFast[i] = iMA(Symbol(), PERIOD_CURRENT, MAFastPeriod, MAFastShift, MAFastMethod, MAFastAppliedPrice, i);
    }

    if ((IsNewCandle) || (prev_calculated == 0)) {
        if (EnableDrawArrows) DrawArrows();
    }

    if (EnableDrawArrows) DrawArrow(0);

    if (EnableNotify) NotifyHit();

    return rates_total;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    CleanChart();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnInitInitialization() {
    LastNotificationTime = TimeCurrent();
    LastNotificationDirection = SIGNAL_NEUTRAL;
    Shift = CandleToCheck;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool OnInitPreChecksPass() {
    if ((MASlowPeriod <= 0) || (MAFastPeriod <= 0) || (MAFastPeriod > MASlowPeriod)) {
        Print("Wrong input parameter");
        return false;
    }
    return true;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CleanChart() {
    ObjectsDeleteAll(ChartID(), IndicatorName);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void InitialiseBuffers() {
    SetIndexBuffer(0, BufferMAFast);
    SetIndexShift(0, MAFastShift);
    SetIndexDrawBegin(0, MAFastPeriod + MAFastShift);
    SetIndexBuffer(1, BufferMASlow);
    SetIndexShift(1, MASlowShift);
    SetIndexDrawBegin(1, MASlowPeriod + MASlowShift);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime NewCandleTime = TimeCurrent();
bool CheckIfNewCandle() {
    if (NewCandleTime == iTime(Symbol(), 0, 0)) return false;
    else {
        NewCandleTime = iTime(Symbol(), 0, 0);
        return true;
    }
}

//Check if it is a trade Signla 0 - Neutral, 1 - Buy, -1 - Sell
ENUM_TRADE_SIGNAL IsSignal(int i) {
    int j = i + Shift;
    if(BufferMAFast[j + 1] < BufferMASlow[j + 1] && BufferMAFast[j] > BufferMASlow[j]) return SIGNAL_BUY;
    if(BufferMAFast[j + 1] > BufferMASlow[j + 1] && BufferMAFast[j] < BufferMASlow[j]) return SIGNAL_SELL;

    return SIGNAL_NEUTRAL;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void NotifyHit() {
    if (!EnableNotify) return;
    if ((!SendAlert) && (!SendApp) && (!SendEmail)) return;
    if ((CandleToCheck == CLOSED_CANDLE) && (Time[0] <= LastNotificationTime)) return;
    ENUM_TRADE_SIGNAL Signal = IsSignal(0);
    if (Signal == SIGNAL_NEUTRAL) {
        LastNotificationDirection = Signal;
        return;
    }
    if (Signal == LastNotificationDirection) return;
    string EmailSubject = IndicatorName + " " + Symbol() + " Notification ";
    string EmailBody = AccountCompany() + " - " + AccountName() + " - " + IntegerToString(AccountNumber()) + "\r\n\r\n" + IndicatorName + " Notification for " + Symbol() + " @ " + EnumToString((ENUM_TIMEFRAMES)Period()) + "\r\n\r\n";
    string AlertText = IndicatorName + " - " + Symbol() + " @ " + EnumToString((ENUM_TIMEFRAMES)Period()) + " ";
    string AppText = AccountCompany() + " - " + AccountName() + " - " + IntegerToString(AccountNumber()) + " - " + IndicatorName + " - " + Symbol() + " @ " + EnumToString((ENUM_TIMEFRAMES)Period()) + " - ";
    string Text = "";

    Text += "Slow and Fast Moving Average Crossed - " + ((Signal == SIGNAL_SELL) ? "Sell" : "Buy");

    EmailBody += Text;
    AlertText += Text;
    AppText += Text;
    if (SendAlert) Alert(AlertText);
    if (SendEmail) {
        if (!SendMail(EmailSubject, EmailBody)) Print("Error sending email " + IntegerToString(GetLastError()));
    }
    if (SendApp) {
        if (!SendNotification(AppText)) Print("Error sending notification " + IntegerToString(GetLastError()));
    }
    LastNotificationTime = Time[0];
    LastNotificationDirection = Signal;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawArrows() {
    RemoveArrows();
    if(!EnableDrawArrows || BarsToScan == 0) return;
    if ((!EnableDrawArrows) || (BarsToScan == 0)) return;
    int MaxBars = Bars(Symbol(), PERIOD_CURRENT);
    if (MaxBars > BarsToScan) MaxBars = BarsToScan;
    for (int i = MaxBars - 2; i >= 1; i--) {
        DrawArrow(i);
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void RemoveArrows() {
    ObjectsDeleteAll(ChartID(), IndicatorName + "-ARWS-");
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawArrow(int i) {
    RemoveArrowCurr();
    if (!EnableDrawArrows) {
        RemoveArrows();
        return;
    }
    ENUM_TRADE_SIGNAL Signal = IsSignal(i);
    if (Signal == SIGNAL_NEUTRAL) return;
    datetime ArrowDate = iTime(Symbol(), 0, i);
    string ArrowName = IndicatorName + "-ARWS-" + IntegerToString(ArrowDate);
    double ArrowPrice = 0;
    int ArrowType = 0;
    color ArrowColor = 0;
    int ArrowAnchor = 0;
    string ArrowDesc = "";
    if (Signal == SIGNAL_BUY) {
        ArrowPrice = Low[i];
        ArrowType = ArrowBuy;
        ArrowColor = ArrowBuyColor;
        ArrowAnchor = ANCHOR_TOP;
        ArrowDesc = "BUY";
    }
    if(Signal == SIGNAL_SELL) {
        ArrowPrice = High[i];
        ArrowType = ArrowSell;
        ArrowColor = ArrowSellColor;
        ArrowAnchor = ANCHOR_BOTTOM;
        ArrowDesc = "SELL";
    }
    ObjectCreate(0, ArrowName, OBJ_ARROW, 0, ArrowDate, ArrowPrice);
    ObjectSetInteger(0, ArrowName, OBJPROP_COLOR, ArrowColor);
    ObjectSetInteger(0, ArrowName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, ArrowName, OBJPROP_HIDDEN, true);
    ObjectSetInteger(0, ArrowName, OBJPROP_ANCHOR, ArrowAnchor);
    ObjectSetInteger(0, ArrowName, OBJPROP_ARROWCODE, ArrowType);
    ObjectSetInteger(0, ArrowName, OBJPROP_WIDTH, ArrowSize);
    ObjectSetInteger(0, ArrowName, OBJPROP_STYLE, STYLE_SOLID);
    ObjectSetInteger(0, ArrowName, OBJPROP_BGCOLOR, ArrowColor);
    ObjectSetString(0, ArrowName, OBJPROP_TEXT, ArrowDesc);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void RemoveArrowCurr() {
    datetime ArrowDate = iTime(Symbol(), 0, Shift);
    string ArrowName = IndicatorName + "-ARWS-" + IntegerToString(ArrowDate);
    ObjectDelete(0, ArrowName);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

打印/导出