存成 MQL5/Experts/Lesson14Handles.mq5。它在 OnInit 建立 handle、在 OnTick 讀取、在 OnDeinit 釋放——正確的生命週期。
//+------------------------------------------------------------------+
//| Lesson 14 - Indicator handles: iMA + iATR |
//| Read-only: this EA prints values, it does not trade. |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version "1.00"
#property strict
input int MAPeriod = 20;
input int ATRPeriod = 14;
int maHandle = INVALID_HANDLE;
int atrHandle = INVALID_HANDLE;
datetime lastBarTime = 0;
int OnInit()
{
maHandle = iMA(_Symbol, _Period, MAPeriod, 0, MODE_EMA, PRICE_CLOSE);
atrHandle = iATR(_Symbol, _Period, ATRPeriod);
if(maHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE)
{
Print("Failed to create indicator handles. Error: ", GetLastError());
return(INIT_FAILED);
}
Print("Handles created. MA=", maHandle, " ATR=", atrHandle);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
// Always release - a leaked handle per backtest pass will stall the tester.
if(maHandle != INVALID_HANDLE) IndicatorRelease(maHandle);
if(atrHandle != INVALID_HANDLE) IndicatorRelease(atrHandle);
}
//+------------------------------------------------------------------+
//| Pull one value out of an indicator handle |
//+------------------------------------------------------------------+
bool ReadValue(const int handle, const int buffer, const int shift, double &out)
{
double buf[];
ArraySetAsSeries(buf, true); // 0 = newest
int need = shift + 3;
int got = CopyBuffer(handle, buffer, 0, need, buf);
if(got < need)
return false;
double v = buf[shift];
if(v == EMPTY_VALUE || v == 0.0)
return false;
out = v;
return true;
}
void OnTick()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == lastBarTime) return;
lastBarTime = t;
// shift 1 = last CLOSED bar. shift 0 is still forming and will repaint.
double ma = 0.0;
double atr = 0.0;
if(!ReadValue(maHandle, 0, 1, ma))
{
Print("Could not read MA yet - not enough bars.");
return;
}
if(!ReadValue(atrHandle, 0, 1, atr))
{
Print("Could not read ATR yet - not enough bars.");
return;
}
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
Print("bid=", DoubleToString(bid, _Digits),
" EMA(", MAPeriod, ")=", DoubleToString(ma, _Digits),
" ATR(", ATRPeriod, ")=", DoubleToString(atr, _Digits),
" ATR in points=", DoubleToString(atr / _Point, 1),
" price is ", (bid > ma ? "ABOVE" : "below"), " the MA");
}