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

CME Gap Tracker

cmegaptracker.mq5
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

CME Gap Tracker — индикатор для MetaTrader 5, который находит уикенд-пропуски цен CME (пятничное закрытие и воскресное открытие фьючерсов) на графиках Bitcoin и золота. Он сохраняет все незакрытые пропуски на графике в виде цветных прямоугольников и отслеживает статистику их заполнения.

Индикатор также включает табло-скоркард, показывающее количество пропусков, процент закрытия, медианное время заполнения, величину «тепла» перед заполнением и результаты тестирования классической стратегии «продавать пропуск» (fade the gap). Результаты рассчитываются на заданном количестве недель истории.

Поддерживаются уведомления: оповещение при открытии нового пропуска и при его заполнении, в том числе push-уведомления. Данные для чтения из советников доступны через 10 индикаторных буферов, которые можно получить с помощью iCustom(). Индикатор рекомендуется использовать на таймфреймах H1 и ниже.

Настройки программы

НастройкаОписание
InpGMTWinter Часовой сдвиг сервера GMT зимой (в часах), используемый для перевода времени CME в серверное время.
InpGMTSummer Часовой сдвиг сервера GMT летом (в часах), используемый для перевода времени CME в серверное время.
InpMinGapPct Минимальный размер ценового пропуска в процентах от цены, пропуски меньше этого порога игнорируются.
InpWeeksBack Количество недель истории, участвующих в расчёте статистики и скоркарда пропусков.
InpDrawWeeks Количество недель истории, для которых на графике отрисовываются прямоугольники ценовых пропусков.
InpStopGapMult Множитель размера пропуска, определяющий расстояние стоп-лосса при тестировании стратегии fade the gap.
InpMaxHoldDays Максимальное количество дней удержания позиции при тестировании стратегии fade the gap.
InpShowPanel Включает или отключает отображение табло скоркарда с статистикой пропусков на графике.
InpPanelCorner Угол графика, в котором отображается табло скоркарда.
InpOpenGapColor Цвет заливки прямоугольника открытого (незакрытого) ценового пропуска.
InpFilledGapColor Цвет заливки прямоугольника уже заполненного ценового пропуска.
InpAlertNewGap Включает или отключает оповещение при открытии нового ценового пропуска.
InpAlertFill Включает или отключает оповещение при заполнении открытого ценового пропуска.
InpAlertPush Дополнительно отправляет push-уведомления при срабатывании оповещений о пропусках.
Получить полный код

Поиск по коду файла

#property version     "1.00"
#property description "CME weekend gaps for Bitcoin and gold: open gaps kept on the chart, fill statistics and a fade-trade scorecard."
#property indicator_chart_window
#property indicator_buffers 10
#property indicator_plots   2

#property indicator_label1  "Gap down (fade buy)"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrDodgerBlue
#property indicator_width1  2
#property indicator_label2  "Gap up (fade sell)"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrOrangeRed
#property indicator_width2  2

enum ENUM_SERVER_DST
  {
   DST_NONE = 0,                                       // Fixed offset all year
   DST_EU   = 1,                                       // Europe (last Sunday of March to last Sunday of October)
   DST_US   = 2                                        // USA (second Sunday of March to first Sunday of November)
  };

input int             InpGMTWinter       = 2;          // Server GMT offset in winter (hours)
input int             InpGMTSummer       = 3;          // Server GMT offset in summer (hours)
input ENUM_SERVER_DST InpServerDST       = DST_EU;     // Server daylight saving rule
input double          InpMinGapPct       = 0.30;       // Minimum gap size, % of price
input int             InpWeeksBack       = 104;        // Weeks of history scored
input int             InpDrawWeeks       = 26;         // Weeks with gap boxes drawn
input double          InpStopGapMult     = 1.0;        // Fade trade: stop distance as a multiple of the gap
input int             InpMaxHoldDays     = 5;          // Fade trade: exit after this many days
input bool            InpShowPanel       = true;       // Show the scorecard panel
input ENUM_BASE_CORNER InpPanelCorner    = CORNER_LEFT_UPPER; // Panel corner
input color           InpOpenGapColor    = C'255,214,170'; // Unfilled gap colour
input color           InpFilledGapColor  = clrGainsboro; // Filled gap colour
input bool            InpAlertNewGap     = true;       // Alert when a new gap opens
input bool            InpAlertFill       = true;       // Alert when an open gap is filled
input bool            InpAlertPush       = false;      // Also send push notifications

double BufFadeBuy[];                                   // 0: gap down, entry price on the CME open bar
double BufFadeSell[];                                  // 1: gap up, entry price on the CME open bar
double BufTarget[];                                    // 2: Friday close (fill level) on that bar
double BufStop[];                                      // 3: fade-trade stop on that bar
double BufOpenAbove[];                                 // 4: nearest unfilled gap level above the close
double BufOpenBelow[];                                 // 5: nearest unfilled gap level below the close
double BufScN[];                                       // 6: scorecard, closed fade trades (last closed bar)
double BufScWins[];                                    // 7: scorecard, winning fade trades
double BufScSumR[];                                    // 8: scorecard, total result in R
double BufScLossR[];                                   // 9: scorecard, sum of losing results in R (positive)

struct GapInfo
  {
   datetime openTime;                                  // bar time of the CME open
   int      openBar;                                   // bar index of the CME open
   double   friClose;                                  // price at the Friday close (fill level)
   double   sunOpen;                                   // price at the CME open
   int      fillBar;                                   // bar that filled it, -1 if still open
   datetime fillTime;                                  // open time of that bar
   double   heat;                                      // move against the fill before it filled, in gap sizes
   double   r;                                         // fade trade result in R
   bool     tradeOpen;                                 // fade trade still running
   bool     scored;                                    // inside the scored window
  };

const string PFX          = "CGT_";                    // chart object prefix
GapInfo  g_gaps[];                                     // gaps found in the loaded history
int      g_small          = 0;                         // weekends below the minimum size
datetime g_lastBarTime    = 0;                         // last bar the scan ran on
datetime g_lastGapAlert   = 0;                         // gap already alerted
datetime g_lastFillAlert  = 0;                         // fill already alerted
string   g_rows[10];                                   // last panel text

int OnInit()
  {
      // код доступен только после оплаты
   }

void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, PFX);
   ChartRedraw();
  }

datetime NthSunday(const int year, const int month, const int n)
  {
   MqlDateTime dt = {};
   dt.year = year;
   dt.mon  = month;
   dt.day  = 1;
   datetime first = StructToTime(dt);
   TimeToStruct(first, dt);
   int shift = (7 - dt.day_of_week) % 7;
   return(first + (shift + 7 * (n - 1)) * 86400);
  }

datetime LastSunday(const int year, const int month)
  {
   MqlDateTime dt = {};
   dt.year = (month == 12) ? year + 1 : year;
   dt.mon  = (month == 12) ? 1 : month + 1;
   dt.day  = 1;
   datetime nextFirst = StructToTime(dt);
   TimeToStruct(nextFirst - 86400, dt);
   return(nextFirst - 86400 - dt.day_of_week * 86400);
  }

bool UsDst(const datetime utc)
  {
   MqlDateTime dt;
   TimeToStruct(utc, dt);
   datetime on  = NthSunday(dt.year, 3, 2) + 8 * 3600;   // 02:00 CST = 08:00 UTC
   datetime off = NthSunday(dt.year, 11, 1) + 7 * 3600;  // 02:00 CDT = 07:00 UTC
   return(utc >= on && utc < off);
  }

bool EuDst(const datetime utc)
  {
   MqlDateTime dt;
   TimeToStruct(utc, dt);
   datetime on  = LastSunday(dt.year, 3) + 3600;        // 01:00 UTC
   datetime off = LastSunday(dt.year, 10) + 3600;
   return(utc >= on && utc < off);
  }

datetime UtcToServer(const datetime utc)
  {
   bool summer = false;
   if(InpServerDST == DST_EU)
      summer = EuDst(utc);
   else
      if(InpServerDST == DST_US)
         summer = UsDst(utc);
   return(utc + (summer ? InpGMTSummer : InpGMTWinter) * 3600);
  }

int LastBarEndingBy(const datetime &time[], const int total, const datetime t)
  {

   int lo = 0, hi = total - 1, ans = -1, ps = PeriodSeconds();
   while(lo <= hi)
     {
      int mid = (lo + hi) / 2;
      if(time[mid] + ps <= t)
        {
         ans = mid;
         lo = mid + 1;
        }
      else
         hi = mid - 1;
     }
   return(ans);
  }

int FirstBarFrom(const datetime &time[], const int total, const datetime t)
  {

   int lo = 0, hi = total - 1, ans = -1;
   while(lo <= hi)
     {
      int mid = (lo + hi) / 2;
      if(time[mid] >= t)
        {
         ans = mid;
         hi = mid - 1;
        }
      else
         lo = mid + 1;
     }
   return(ans);
  }

void FindGaps(const int rates_total, const datetime &time[], const double &open[], const double &close[],
              const datetime scoreFrom)
  {
   ArrayResize(g_gaps, 0);
   g_small = 0;

   datetime day = time[0] - time[0] % 86400;
   MqlDateTime dt;
   TimeToStruct(day, dt);
   day += ((5 - dt.day_of_week + 7) % 7) * 86400;

   for(; day < time[rates_total - 1]; day += 7 * 86400)
     {

      int      ct       = UsDst(day + 12 * 3600) ? 5 : 6;
      datetime closeUtc = day + (16 + ct) * 3600;
      int      ct2      = UsDst(day + 2 * 86400 + 12 * 3600) ? 5 : 6;
      datetime openUtc  = day + 2 * 86400 + (17 + ct2) * 3600;
      datetime closeSrv = UtcToServer(closeUtc);
      datetime openSrv  = UtcToServer(openUtc);

      int a = LastBarEndingBy(time, rates_total, closeSrv);
      int b = FirstBarFrom(time, rates_total, openSrv);
      if(a < 0 || b < 0 || b <= a)
         continue;

      if(closeSrv - time[a] > 3 * 86400 || time[b] - openSrv > 2 * 86400)
         continue;

      double fc = close[a], so = open[b];
      if(fc <= 0.0 || MathAbs(so - fc) / fc * 100.0 < InpMinGapPct)
        {
         if(time[b] >= scoreFrom)
            g_small++;               // counted in the scored window only
         continue;
        }
      int n = ArraySize(g_gaps);
      ArrayResize(g_gaps, n + 1);
      g_gaps[n].openTime  = time[b];
      g_gaps[n].openBar   = b;
      g_gaps[n].friClose  = fc;
      g_gaps[n].sunOpen   = so;
      g_gaps[n].fillBar   = -1;
      g_gaps[n].fillTime  = 0;
      g_gaps[n].heat      = 0.0;
      g_gaps[n].r         = 0.0;
      g_gaps[n].tradeOpen = true;
      g_gaps[n].scored    = false;
     }
  }

void ScoreGap(GapInfo &g, const int rates_total, const datetime &time[], const double &high[],
              const double &low[], const double &close[], const int &spread[])
  {
   bool   up     = g.sunOpen > g.friClose;
   double size   = MathAbs(g.sunOpen - g.friClose);
   double entry  = g.sunOpen;
   double stop   = up ? entry + InpStopGapMult * size : entry - InpStopGapMult * size;
   double risk   = InpStopGapMult * size;
   double cost   = spread[g.openBar] * _Point;
   datetime lim  = g.openTime + InpMaxHoldDays * 86400;
   double worst  = entry;

   for(int k = g.openBar; k < rates_total - 1; k++)
     {

      if(g.tradeOpen)
        {
         bool hitSL = up ? high[k] >= stop : low[k] <= stop;
         bool hitTP = up ? low[k] <= g.friClose : high[k] >= g.friClose;
         if(hitSL)
           {
            g.r = (-risk - cost) / risk;
            g.tradeOpen = false;
           }
         else
            if(hitTP)
              {
               g.r = (size - cost) / risk;
               g.tradeOpen = false;
              }
            else
               if(time[k] >= lim)
                 {
                  g.r = ((up ? entry - close[k] : close[k] - entry) - cost) / risk;
                  g.tradeOpen = false;
                 }
        }

      if(g.fillBar < 0)
        {
         worst = up ? MathMax(worst, high[k]) : MathMin(worst, low[k]);
         if(up ? low[k] <= g.friClose : high[k] >= g.friClose)
           {
            g.fillBar  = k;
            g.fillTime = time[k];
            g.heat    = MathAbs(worst - entry) / size;
           }
        }
      if(!g.tradeOpen && g.fillBar >= 0)
         break;
     }
  }

double Percentile(double &v[], const double p)
  {
   int n = ArraySize(v

Показано первые 50% кода (символов: 15990)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
1 599₽ ≈ $19.55