Linda Bradford Raschke — 3/10 Oscillator Anti and Holy Grail
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «raschkeea.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
RaschkeEA — торговый советник для MetaTrader 5, реализующий две классические стратегии Линды Брэдфорд Рэшке: 3/10 Oscillator Anti и Holy Grail. Советник работает на ценовых данных текущего таймфрейма и рекомендуется для H4. Обе стратегии построены на конечных автоматах состояний и отслеживают вход в позицию, управление стоп-лоссом и выход по заданным условиям.
Стратегия Anti использует осциллятор 3/10 (разность быстрой и медленной скользящих средних) с сигнальной линией. Вход осуществляется после пересечения сигнальной линии нулевого уровня с последующим откатом и разворотом быстрой линии через сигнал. Выход — при обратном пересечении осциллятором сигнальной линии.
Стратегия Holy Grail основана на сочетании индекса направленного движения ADX и экспоненциальной скользящей средней EMA. Вход требует сильного и растущего ADX при наличии направления EMA, после чего цена касается EMA. Выход происходит при пересечении цены EMA в обратном направлении или падении ADX ниже 20.
Советник рассчитывает объём позиции на основе процента риска от баланса и расстояния до стоп-лосса, использует ATR для буфера стопа, поддерживает восстановление состояния при перезапуске и позволяет выбирать приоритет обработки стратегий.
Настройки программы
| Настройка | Описание |
|---|---|
| InpFastSMA | Период быстрой простой скользящей средней (SMA), используемой для расчёта быстрой линии осциллятора 3/10. |
| InpSlowSMA | Период медленной простой скользящей средней (SMA), используемой для расчёта быстрой линии осциллятора 3/10. |
| InpSignalSMA | Период простой скользящей средней (SMA), используемой для расчёта сигнальной линии осциллятора 3/10. |
| InpAntiEnabled | Включает или отключает стратегию 3/10 Oscillator Anti. При отключении стратегия Anti не обрабатывается. |
| InpEMAPeriod | Период экспоненциальной скользящей средней EMA, используемой для определения направления тренда и точек входа в стратегии Holy Grail. |
| InpADXPeriod | Период индикатора ADX (индекс направленного движения), используемого для оценки силы тренда в стратегии Holy Grail. |
| InpADXThreshold | Минимальный уровень ADX, при котором считается, что тренд достаточно силён для входа. ADX должен быть не ниже этого значения и растущим два бара подряд. |
| InpHGEnabled | Включает или отключает стратегию Holy Grail. При отключении стратегия Holy Grail не обрабатывается. |
| InpRiskPercent | Процент от баланса, рискуемый на каждую сделку. Используется для расчёта объёма позиции. |
| InpATRPeriod | Период индикатора ATR (средний истинный диапазон), используемого для расчёта буфера стоп-лосса. |
| InpATRStopMult | Множитель ATR, добавляемый к свинг-стопу при формировании стоп-лосса. Значение 0 означает точный свинг-стоп без буфера. |
| InpMagicNumber | Магический номер, идентифицирующий позиции, открытые данным советником, для корректного восстановления состояния при перезапуске. |
| InpSlippage | Допустимое проскальзывание в пунктах при исполнении торговых ордеров. |
| InpAntiFirst | Определяет порядок обработки стратегий при одновременном появлении сигналов. true — стратегия Anti обрабатывается первой, false — Holy Grail первой. |
| InpShowLabels | Включает или отключает отображение текстовых меток на графике для текущих позиций и сигналов. |
Поиск по коду файла
#property version "1.00"
#property description "Automating Classic Market Methods in MQL5 Part 9"
#property description "Linda Bradford Raschke — 3/10 Oscillator Anti and Holy Grail"
#property description "H4 timeframe recommended"
#include <Trade\Trade.mqh>
enum ENUM_ANTI_STATE
{
ANTI_IDLE, // Watching for signal line zero cross
ANTI_WAITING_PULLBACK, // Zero cross confirmed — fast line not yet at signal
ANTI_WAITING_REVERSAL, // Fast line touched signal — waiting for cross back
ANTI_IN_TRADE // Position open — watching for exit cross
};
enum ENUM_HG_STATE
{
HG_IDLE, // Watching for ADX >= 30 rising 2 bars, EMA sloping
HG_WAITING_PULLBACK, // ADX confirmed — watching for price to touch 20 EMA
HG_IN_TRADE // Position open — watching for EMA cross or ADX drop
};
input group "=== 3/10 Oscillator (Anti Setup) ==="
input int InpFastSMA = 3; // Fast SMA period
input int InpSlowSMA = 10; // Slow SMA period
input int InpSignalSMA = 16; // Signal line SMA period
input bool InpAntiEnabled = true; // Enable the Anti setup
input group "=== Holy Grail Setup ==="
input int InpEMAPeriod = 20; // EMA period for pullback
input int InpADXPeriod = 14; // ADX period
input double InpADXThreshold = 30.0; // Minimum ADX level (must be rising for 2 bars)
input bool InpHGEnabled = true; // Enable the Holy Grail setup
input group "=== Risk ==="
input double InpRiskPercent = 1.0; // Risk per trade (% of balance)
input int InpATRPeriod = 14; // ATR period
input double InpATRStopMult = 0.0; // ATR buffer added to swing stop (0 = exact swing stop)
input group "=== General ==="
input int InpMagicNumber = 100901;
input int InpSlippage = 10;
input bool InpAntiFirst = true; // true = Anti evaluated first; false = Holy Grail first
input bool InpShowLabels = true;
int g_ema_handle = INVALID_HANDLE;
int g_adx_handle = INVALID_HANDLE;
int g_atr_handle = INVALID_HANDLE;
ENUM_ANTI_STATE g_anti_state = ANTI_IDLE;
ENUM_HG_STATE g_hg_state = HG_IDLE;
bool g_anti_is_long = true;
bool g_hg_is_long = true;
ulong g_ticket = 0;
double g_stop_price = 0;
datetime g_last_bar = 0;
CTrade g_trade;
double g_anti_swing_stop = 0;
double g_hg_pb_extreme = 0;
bool g_hg_needs_adx_reset = false; // After a trade, require ADX to drop below threshold
double PipSize()
{
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
return (digits == 3 || digits == 5) ? _Point * 10.0 : _Point;
}
double CalcLots(double sl_pips)
{
if(sl_pips <= 0)
return 0;
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double risk_amt = balance * InpRiskPercent / 100.0;
double tick_val = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tick_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double pip_size = PipSize();
if(tick_size <= 0 || tick_val <= 0)
return 0;
double pip_value = (pip_size / tick_size) * tick_val;
double lots = risk_amt / (sl_pips * pip_value);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
lots = MathFloor(lots / step) * step;
return MathMax(min_lot, MathMin(max_lot, lots));
}
void RecoverState()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol)
continue;
if(PositionGetInteger(POSITION_MAGIC) != (long)InpMagicNumber)
continue;
g_ticket = ticket;
g_stop_price = PositionGetDouble(POSITION_SL);
bool is_long = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
string comment = PositionGetString(POSITION_COMMENT);
if(StringFind(comment, "Anti") >= 0)
{
g_anti_is_long = is_long;
g_anti_state = ANTI_IN_TRADE;
g_hg_state = HG_IDLE;
Print(StringFormat("RaschkeEA: Recovered Anti position | %s | Ticket:%I64u",
(is_long ? "LONG" : "SHORT"), ticket));
}
else
if(StringFind(comment, "HolyGrail") >= 0)
{
g_hg_is_long = is_long;
g_hg_state = HG_IN_TRADE;
g_hg_needs_adx_reset = true;
g_anti_state = ANTI_IDLE;
Print(StringFormat("RaschkeEA: Recovered HolyGrail position | %s | Ticket:%I64u",
(is_long ? "LONG" : "SHORT"), ticket));
}
break; // Only one position tracked
}
}
void DrawLabel(string name, datetime time, double price, string text, color clr)
{
if(!InpShowLabels)
return;
string obj = "LBR_" + name;
ObjectDelete(0, obj);
ObjectCreate(0, obj, OBJ_TEXT, 0, time, price);
ObjectSetString(0, obj, OBJPROP_TEXT, text);
ObjectSetInteger(0, obj, OBJPROP_COLOR, clr);
ObjectSetInteger(0, obj, OBJPROP_FONTSIZE, 9);
ChartRedraw(0);
}
void ClearLabels()
{
int total = ObjectsTotal(0);
for(int i = total - 1; i >= 0; i--)
{
string name = ObjectName(0, i);
if(StringFind(name, "LBR_") == 0)
ObjectDelete(0, name);
}
ChartRedraw(0);
}
bool Compute310(double &fast_curr, double &fast_prev,
double &sig_curr, double &sig_prev)
{
int needed = InpSlowSMA + InpSignalSMA + 5;
double close[];
ArraySetAsSeries(close, true);
if(CopyClose(_Symbol, PERIOD_CURRENT, 1, needed, close) < needed)
return false;
double fast_vals[];
ArrayResize(fast_vals, InpSignalSMA + 2);
for(int i = 0; i < InpSignalSMA + 2; i++)
{
double sma3 = 0, sma10 = 0;
for(int j = 0; j < InpFastSMA; j++)
sma3 += close[i + j];
for(int j = 0; j < InpSlowSMA; j++)
sma10 += close[i + j];
fast_vals[i] = (sma3 / InpFastSMA) - (sma10 / InpSlowSMA);
}
fast_curr = fast_vals[0];
fast_prev = fast_vals[1];
double sc = 0, sp = 0;
for(int i = 0; i < InpSignalSMA; i++)
{
sc += fast_vals[i];
sp += fast_vals[i + 1];
}
sig_curr = sc / InpSignalSMA;
sig_prev = sp / InpSignalSMA;
return true;
}
bool OpenTrade(bool is_long, double swing_stop, double atr, string label)
{
double sl_buffer = atr * InpATRStopMult;
double sl = is_long
? NormalizeDouble(swing_stop - sl_buffer, _Digits)
: NormalizeDouble(swing_stop + sl_buffer, _Digits);
long stop_lv = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double min_dist = stop_lv * _Point;
bool ok = false;
if(is_long)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(ask - sl < min_dist)
sl = NormalizeDouble(ask - min_dist - _Point, _Digits);
double sl_pips = (ask - sl) / PipSize();
double lots = CalcLots(sl_pips);
if(lots <= 0)
{
Print("RaschkeEA: CalcLots returned 0 — skipping entry.");
return false;
}
ok = g_trade.Buy(lots, _Symbol, ask, sl, 0, label);
}
else
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(sl - bid < min_dist)
sl = NormalizeDouble(bid + min_dist + _Point, _Digits);
double sl_pips = (sl - bid) / PipSize();
double lots = CalcLots(sl_pips);
if(lots <= 0)
{
Print("RaschkeEA: CalcLots returned 0 — skipping entry.");
return false;
}
ok = g_trade.Sell(lots, _Symbol, bid, sl, 0, label);
}
if(!ok)
{
Print(StringFormat("RaschkeEA: Order failed | Retcode:%d | Error:%d",
g_trade.ResultRetcode(), GetLastError()));
return false;
}
ulong deal = g_trade.ResultDeal();
if(deal > 0 && HistoryDealSelect(deal))
g_ticket = (ulong)HistoryDealGetInteger(deal, DEAL_POSITION_ID);
else
{
g_ticket = g_trade.ResultOrder(); // Fallback — order ticket may differ from position ticket
Print("RaschkeEA: ResultDeal() unavailable — using ResultOrder() as ticket fallback.");
}
g_stop_price = sl;
datetime t = iTime(_Symbol, PERIOD_CURRENT, 1);
DrawLabel(label, t,
is_long ? iLow(_Symbol, PERIOD_CURRENT, 1) - PipSize() * 5
: iHigh(_Symbol, PERIOD_CURRENT, 1) + PipSize() * 5,
label, is_long ? clrDodgerBlue : clrOrangeRed);
Print(StringFormat("RaschkeEA: %s [%s] | SL:%.5f | SwingStop:%.5f | ATRBuf:%.5f | Ticket:%I64u",
(is_long ? "LONG" : "SHORT"), label, sl, swing_stop, sl_buffer, g_ticket));
return true;
}
void CloseTrade(string reason)
{
if(!PositionSelectByTicket(g_ticket))
{
g_ticket = 0;
return;
}
double profit = PositionGetDouble(POSITION_PROFIT);
if(g_trade.PositionClose(g_ticket))
{
Print(StringFormat("RaschkeEA: Closed | Reason:%s | P&L:%.2f", reason, profit));
g_ticket = 0;
g_stop_price = 0;
ClearLabels();
}
}
void ProcessAnti(double fast_curr, double fast_prev,
double sig_curr, double sig_prev,
double atr)
{
switch(g_anti_state)
{
case ANTI_IDLE:
{
bool bull_zero = (sig_prev <= 0.0 && sig_curr > 0.0);
bool bear_zero = (sig_prev >= 0.0 && sig_curr < 0.0);
if(bull_zero || bear_zero)
{
g_anti_state = ANTI_WAITING_PULLBACK;
g_anti_is_long = bull_zero;
g_anti_swing_stop = 0.0;
Print(StringFormat(
"RaschkeEA [ANTI]: IDLE ? WAITING_PULLBACK | %s | Fast:%.6f Sig:%.6f",
(g_anti_is_long ? "BULL" : "BEAR"), fast_curr, sig_curr));
}
}
break;
case ANTI_WAITING_PULLBACK:
{
if(g_anti_is_long && sig_curr < 0.0)
{
Print("RaschkeEA [ANTI]: WAITING_PULLBACK ? IDLE (signal reversed below zero)");
g_anti_state = ANTI_IDLE;
break;
}
if(!g_anti_is_long && sig_cuПоказано первые 50% кода (символов: 14255)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.