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);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+