← К каталогу
Исходный код · ID 4559

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 и перейдите к оплате.

Стоимость полного кода
1 425,50₽ ≈ $17.69