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

Pingala Prasthara EA

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

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

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

О программе

Pingala Prasthara EA — это торговый советник для MetaTrader 5, реализующий стратегию на основе свечных паттернов, вдохновлённую индийской системой Пингала. Советник анализирует последовательность свечей на заданном таймфрейме, классифицируя их как «Гуру» (значительное движение) или «Лагху» (незначительное движение), и на основе этого строит числовые оценки силы сигнала. Дополнительно используются фильтры по волатильности (ATR), спреду, сессии и подтверждению со старшего таймфрейма.

Советник поддерживает управление позицией: частичное закрытие на первом целевом уровне, перевод стопа в безубыток, выход при развороте давления или при появлении противоположного сигнала. Реализованы функции риск-менеджмента: расчёт лота от процента риска, ограничение дневного убытка и серии убыточных сделок, ограничение количества одновременных позиций.

Все входные параметры сгруппированы по категориям: общие настройки и таймфреймы, фильтры входа, волатильность и спред, стоп-лосс и цели, управление капиталом, торговые сессии и отладочный вывод. Советник использует стандартную библиотеку Trade для совершения торговых операций.

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

НастройкаОписание
MagicNumber Уникальный идентификатор советника для разделения настроек разных экземпляров.
SignalTF Таймфрейм для поиска сигналов (по умолчанию M5).
ConfirmTF Старший таймфрейм, используемый для подтверждения направления сделки.
OnlyClosedBars Разрешает торговлю только по завершённым свечам (рекомендуется).
PatternLengthN Количество свечей в паттерне Пингала (по умолчанию 8).
GuruThresholdATR Доля ATR, при превышении которой свеча считается «Гуру».
MinDirectionalPressure Минимальное направленное давление B; 0.25 соответствует +/-25%.
MinMeruConcentration Минимальный балл концентрации Meru (от 0 до 100).
MinPingalaScore Минимальный общий балл Pingala (от 0 до 100), включающий компонент силы паттерна.
RequireGuruExpansion Требует наличия недавнего паттерна расширения Лагху-в-Гуру.
ExpansionLookback Количество свечей для проверки наличия паттерна расширения Лагху-в-Гуру.
RequireMatrameruAlign Требует согласованности с уровнем Matrameru/Фибоначчи.
MatrameruMaxDistance Максимальное расстояние от ближайшего уровня Matrameru для признания согласованности.
AllowMovingTowardNext Разрешает считать уровень Matrameru согласованным, если текущее значение S ближе к следующему уровню Фибоначчи, чем предыдущее.
RequireHigherTFConfirm Требует подтверждения давления на старшем таймфрейме в направлении сделки.
ATRPeriod Период расчёта индикатора ATR, используемого для оценки волатильности и расчёта стоп-лосса и целей.
MinATR Минимально допустимое значение ATR в ценовых единицах; 0 отключает проверку.
MaxATR Максимально допустимое значение ATR в ценовых единицах; 0 отключает проверку.
MaxSpreadPoints Максимально допустимый спред в пунктах брокера; 0 отключает проверку.
StopATRMultiplier Базовый множитель ATR для расчёта стоп-лосса (по умолчанию 1.20).
SwingLookback Количество баров для поиска защитного свинг-максимума или свинг-минимума.
UseMinimumSL Включает принудительное применение минимального стопа в зависимости от типа символа.
MinimumSLForexPips Минимальный стоп-лосс в пипсах для 5- и 3-значных валютных пар (5.0 = 5 пипсов).
MinimumSLGoldPrice Минимальный стоп-лосс в ценовых единицах для символов золота; 0 отключает.
MinimumSLOtherPrice Минимальный стоп-лосс в ценовых единицах для прочих символов; 0 отключает.
ScaleTargetsWithMinSL Если минимальный стоп-лосс расширяет стоп, пропорционально расширяет TP1 и TP2.
TP2Multiplier Множитель ATR для второго целевого уровня, применяемый к соотношению Пингала.
TP1ClosePercent Процент позиции, закрываемый при достижении первого целевого уровня.
MoveSLToBEAfterTP1 Переводит стоп-лосс оставшейся позиции в безубыток после достижения первого целевого уровня.
BreakEvenPlusPoints Количество пунктов брокера, добавляемых к цене открытия при переводе стопа в безубыток.
ExitOnPressureFlip Включает выход из позиции, если направленное давление развернулось против неё.
PressureFlipBars Количество последовательных закрытых баров, необходимых для выхода при развороте давления.
ExitOnOppositeSignal Включает закрытие позиции при появлении противоположного сигнала высокой уверенности.
UseRiskPercent При значении true лот рассчитывается от риска на сделку; при false используется фиксированный лот.
RiskPerTradePercent Риск на сделку в процентах от баланса счёта.
FixedLot Фиксированный размер лота, используемый только при отключённом расчёте лота от риска.
MaxDailyLossPercent Максимальный реализованный дневной убыток в процентах от баланса, после которого новые входы блокируются; 0 отключает.
MaxConsecutiveLosses Максимальное количество убыточных сделок подряд, после которого новые входы блокируются; 0 отключает.
MaxOpenPositions Максимальное количество одновременно открытых позиций для данного символа и магического номера.
UseSessionFilter Включает торговлю только между указанными часами начала и окончания сессии.
SessionStartHour Час начала торговой сессии по времени брокера (от 0 до 23).
SessionEndHour Час окончания торговой сессии по времени брокера (от 0 до 23).
PrintDebug Выводит сигналы, фильтры, уровни стоп-лосса и целей, а также детали сделок в журнал.
Получить полный код

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

#property strict
#property version   "1.20"
#property description "Pingala Prasthara strategy v1.20: proper Nasta even/odd reconstruction, symbol-aware minimum SL, clear inputs and diagnostics."

#include <Trade/Trade.mqh>
CTrade trade;

input group "1. GENERAL / TIMEFRAMES"
input ulong            MagicNumber              = 26090401;   // Unique EA ID - use different number for separate EA setups
input ENUM_TIMEFRAMES  SignalTF                 = PERIOD_M5;   // Signal timeframe - strategy default M5
input ENUM_TIMEFRAMES  ConfirmTF                = PERIOD_M15;  // Higher timeframe confirmation - strategy default M15
input bool             OnlyClosedBars           = true;       // true = trade only completed candles (recommended)
input int              PatternLengthN           = 8;          // Number of candles in Pingala pattern - default 8
input double           GuruThresholdATR         = 0.50;       // Candle becomes Guru when move >= this fraction of ATR

input group "2. ENTRY FILTERS / SIGNAL QUALITY"
input double           MinDirectionalPressure   = 0.25;       // Minimum directional pressure B; 0.25 = +/-25%
input double           MinMeruConcentration     = 65.0;       // Minimum Meru concentration score (0-100)
input double           MinPingalaScore          = 75.0;       // Minimum total Pingala score (0-100); includes interpreted Pattern Strength component
input bool             RequireGuruExpansion     = true;       // Require recent Laghu-to-Guru expansion pattern
input int              ExpansionLookback        = 4;          // Candles checked for expansion; default 4
input bool             RequireMatrameruAlign    = true;       // Require Matrameru/Fibonacci state alignment
input double           MatrameruMaxDistance     = 1.0;        // Maximum distance from nearest Matrameru level
input bool             AllowMovingTowardNext    = true;       // INTERPRETED RULE: accept if current S is closer to next level than previous window
input bool             RequireHigherTFConfirm   = true;       // Require ConfirmTF pressure in same trade direction

input group "3. ATR / VOLATILITY / SPREAD"
input int              ATRPeriod                = 14;         // ATR calculation period
input double           MinATR                   = 0.0;        // Minimum ATR in PRICE UNITS; 0 = disabled
input double           MaxATR                   = 0.0;        // Maximum ATR in PRICE UNITS; 0 = disabled
input int              MaxSpreadPoints          = 30;         // Maximum spread in broker POINTS; 0 = disabled

input group "4. STOP LOSS / TARGETS"
input double           StopATRMultiplier        = 1.20;       // Base ATR stop multiplier; strategy default 1.20
input int              SwingLookback            = 5;          // Bars used to find protective swing high/low
input bool             UseMinimumSL              = true;       // Enforce a minimum stop distance by symbol type
input double           MinimumSLForexPips        = 5.0;        // 5/3-digit forex: minimum SL in PIPS (5.0 = 5 pips)
input double           MinimumSLGoldPrice        = 0.0;        // XAU symbols: minimum SL in PRICE ($); 0 = disabled
input double           MinimumSLOtherPrice       = 0.0;        // Other symbols: minimum SL in PRICE units; 0 = disabled
input bool             ScaleTargetsWithMinSL     = true;       // If minimum SL widens stop, widen TP1/TP2 by same factor
input double           TP2Multiplier            = 1.60;       // TP2 ATR multiplier applied to Pingala ratio
input double           TP1ClosePercent          = 50.0;       // Percent of position closed when TP1 is reached
input bool             MoveSLToBEAfterTP1       = true;       // Move remaining position stop to breakeven after TP1
input int              BreakEvenPlusPoints      = 0;          // Extra broker POINTS beyond entry when moving to BE
input bool             ExitOnPressureFlip       = true;       // Exit if directional pressure flips against position
input int              PressureFlipBars         = 2;          // Consecutive closed bars required for pressure-flip exit
input bool             ExitOnOppositeSignal     = true;       // Exit on a full opposite high-confidence Pingala signal

input group "5. MONEY / RISK MANAGEMENT"
input bool             UseRiskPercent           = true;       // true = auto lot from SL risk; false = use FixedLot
input double           RiskPerTradePercent      = 0.50;       // Account balance risk per trade in percent
input double           FixedLot                 = 0.10;       // Lot size used only when UseRiskPercent=false
input double           MaxDailyLossPercent      = 2.00;       // Stop new entries after this realized daily loss; 0=off
input int              MaxConsecutiveLosses     = 3;          // Stop new entries after this many losses; 0=off
input int              MaxOpenPositions         = 1;          // Maximum simultaneous positions for this symbol/magic

input group "6. TRADING SESSION (BROKER SERVER TIME)"
input bool             UseSessionFilter         = false;      // true = only trade between start/end hours below
input int              SessionStartHour         = 8;          // Session start hour, broker/server time (0-23)
input int              SessionEndHour           = 18;         // Session end hour, broker/server time (0-23)

input group "7. DEBUG / JOURNAL LOGGING"
input bool             PrintDebug               = true;       // Print signal, filter, SL/TP and trade details to Journal

struct PingalaData
{
   bool   valid;
   int    N;
   int    guruCount;
   int    decimalValue;
   int    rank;
   int    matraS;
   int    nearestF;
   int    nextF1;
   int    nextF2;
   double ratio1;
   double ratio2;
   double pressureB;
   double meruScore;
   double directionalStrength;
   double matrameruAlignment;
   double patternStrength;
   double higherTFScore;
   double pingalaScore;
   bool   nastaValid;
   bool   matrameruAligned;
   bool   guruExpansionBuy;
   bool   guruExpansionSell;
};

datetime g_lastSignalBar = 0;
ulong    g_managedTicket  = 0;
double   g_initialVolume  = 0.0;
bool     g_tp1Done        = false;

void Dbg(string s)
{
   if(PrintDebug) Print("PINGALA: ", s);
}

int FibLevels[] = {1,2,3,5,8,13,21,34,55,89,144};

int FindNearestFib(const int S)
{
   int best=FibLevels[0];
   int bestDist=MathAbs(S-best);
   for(int i=1;i<ArraySize(FibLevels);i++)
   {
      int d=MathAbs(S-FibLevels[i]);
      if(d<bestDist)
      {
         best=FibLevels[i];
         bestDist=d;
      }
   }
   return best;
}

void GetFibTriplet(const int S,int &F,int &F1,int &F2)
{
   F=FindNearestFib(S);
   int idx=0;
   for(int i=0;i<ArraySize(FibLevels);i++)
      if(FibLevels[i]==F){ idx=i; break; }

   F1 = FibLevels[MathMin(idx+1,ArraySize(FibLevels)-1)];
   F2 = FibLevels[MathMin(idx+2,ArraySize(FibLevels)-1)];
}

double Combination(const int n,const int k)
{
   if(k<0 || k>n) return 0.0;
   int kk=MathMin(k,n-k);
   double r=1.0;
   for(int i=1;i<=kk;i++)
      r = r * (n-kk+i) / i;
   return r;
}

double GetATR(ENUM_TIMEFRAMES tf,int shift)
{
   int h=iATR(_Symbol,tf,ATRPeriod);
   if(h==INVALID_HANDLE) return 0.0;
   double b[];
   ArraySetAsSeries(b,true);
   double v=0.0;
   if(CopyBuffer(h,0,shift,1,b)==1) v=b[0];
   IndicatorRelease(h);
   return v;
}

bool IsGoldSymbol()
{
   string s=_Symbol;
   StringToUpper(s);
   return (StringFind(s,"XAU")>=0);
}

double ForexPipSize()
{
   int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
   if(digits==5 || digits==3) return 10.0*_Point;
   return _Point;
}

double MinimumSLDistancePrice()
{
   if(!UseMinimumSL) return 0.0;

   if(IsGoldSymbol())
      return MathMax(0.0,MinimumSLGoldPrice);

   int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
   if(digits==5 || digits==3)
      return MathMax(0.0,MinimumSLForexPips)*ForexPipSize();

   return MathMax(0.0,MinimumSLOtherPrice);
}

double NormalizePrice(double p)
{
   return NormalizeDouble(p,(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS));
}

double NormalizeVolume(double lots)
{
   double minv=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   double maxv=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   double step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   if(step<=0.0) step=minv;
   lots=MathMax(minv,MathMin(maxv,lots));
   lots=MathFloor(lots/step + 1e-9)*step;
   int vd=2;
   if(step>=1.0) vd=0;
   else if(step>=0.1) vd=1;
   else if(step>=0.01) vd=2;
   else vd=3;
   return NormalizeDouble(lots,vd);
}

bool InSession()
{
   if(!UseSessionFilter) return true;
   MqlDateTime dt; TimeToStruct(TimeCurrent(),dt);
   if(SessionStartHour==SessionEndHour) return true;
   if(SessionStartHour<SessionEndHour)
      return (dt.hour>=SessionStartHour && dt.hour<SessionEndHour);
   return (dt.hour>=SessionStartHour || dt.hour<SessionEndHour);
}

int CurrentSpreadPoints()
{
   MqlTick t;
   if(!SymbolInfoTick(_Symbol,t)) return 999999;
   return (int)MathRound((t.ask-t.bid)/_Point);
}

int CountOurOpenPositions()
{
   int count=0;
   for(int i=PositionsTotal()-1;i>=0;i--)
   {
      ulong ticket=PositionGetTicket(i);
      if(ticket==0) continue;
      if(!PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL)==_Symbol &&
         (ulong)PositionGetInteger(POSITION_MAGIC)==MagicNumber)
         count++;
   }
   return count;
}

bool SelectOurPosition(ulong &ticket)
{
   for(int i=PositionsTotal()-1;i>=0;i--)
   {
      ulong t=PositionGetTicket(i);
      if(t==0 || !PositionSelectByTicket(t)) continue;
      if(PositionGetString(POSITION_SYMBOL)==_Symbol &&
         (ulong)PositionGetInteger(POSITION_MAGIC)==MagicNumber)
      {
         ticket=t;
         return true;
      }
   }
   return false;
}

double TodayProfit(int &consecutiveLosses)
{
   consecutiveLosses=0;
   MqlDateTime dt; TimeToStruct(TimeCurrent(),dt);
   dt.hour=0; dt.min=0; dt.sec=0;
   datetime dayStart=StructToTime(dt);
   if(!HistorySelect(dayStart,TimeCurrent())) return 0.0;

   double pnl=0.0;
   int deals=HistoryDealsTotal();

   for(int i=0;i<deals;i++)
   {
      ulong d=HistoryDealGetTicket(i);
      if(d==0) continue;
      if(HistoryDealGetString(d,DEAL_SYMBOL)!=_Symbol) continue;
      if((ulong)HistoryDealGetInteger(d,DEAL_MAGIC)!=MagicNumber) continue;
      if((ENUM_DEAL_ENTRY)HistoryDealGetInteger(d,DEAL_ENTRY)!=DEAL_ENTRY_OUT) continue;
      pnl += HistoryDealGetDouble(d,DEAL_PROFIT)
           + HistoryDealGetDouble(d,DEAL_SWAP)
           + HistoryDealGetDouble(d,DEAL_COMMISSION);
   }

   for(int i=deals-1;i>=0;i--)
   {
      ulong d=HistoryDealGetTicket(i);
      if(d==0) continue;
      if(HistoryDealGetString(d,DEAL_SYMBOL)!=_Symbol) continue;
      if((ulong)HistoryDealGetInteger(d,DEAL_MAGIC)!=MagicNumber) continue;
      if((ENUM_DEAL_ENTRY)HistoryDealGetInteger(d,DEAL_ENTRY)!=DEAL_ENTRY_OUT) continue;
      double p=HistoryDealGetDouble(d,DEAL_PROFIT)
              +HistoryDealGetDouble(d,DEAL_SWAP)
              +HistoryDealGetDouble(d,DEAL_COMMISSION);
      if(p<0.0) consecutiveLosses++;
      else if(p>0.0) break;
   }
   return pnl;
}

bool RiskLimitsOK()
{
   int consec=0;
   double pnl=TodayProfit(consec);
   double bal=AccountInfoDouble(ACCOUNT_BALANCE);
   if(MaxDailyLossPercent>0.0 && pnl <= -(bal*MaxDailyLossPercent/100.0))
   {
      Dbg(StringFormat("BLOCK daily loss: %.2f",pnl));
      return false;
   }
   if(MaxConsecutiveLosses>0 && consec>=MaxConsecutiveLosses)
   {
      Dbg(StringFormat("BLOCK consecutive losses: %d",consec));
      return false;
   }
   return true;
}

bool BuildPingalaData(ENUM_TIMEFRAMES tf,int startShift,PingalaData &pd)
{
   pd.valid=false;
   int N=MathMax(2,MathMin(PatternLengthN,16));
   pd.N=N;

   MqlRates rates[];
   ArraySetAsSeries(rates,true);

   if(CopyRates(_Symbol,tf,startShift,N+1,rates)<N+1)
      return false;

   int atrHandle=iATR(_Symbol,tf,ATRPeriod);
   if(atrHandle==INVALID_HANDLE) return false;
   double atr[];
   ArraySetAsSeries(atr,true);
   if(CopyBuffer(atrHandle,0,startShift,N+1,atr)<N+1)
   {
      IndicatorRelease(atrHandle);
      return false;
   }
   IndicatorRelease(atrHandle);

   int state[]; ArrayResize(state,N);       // 0=L,1=G
   int dir[];   ArrayResize(dir,N);         // -1,0,+1
   int weight[];ArrayResize(weight,N);      // 1 or 2

   int guru=0, S=0, bull=0, bear=0;
   int dec=0;

   for(int j=0;j<N;j++)
   {
      int i=N-1-j; // rates index: oldest selected candle toward newest
      double change=rates[i].close-rates[i+1].close;
      double a=atr[i];
      if(a<=0.0) return false;
      double M=MathAbs(change)/a;
      state[j]=(M>=GuruThresholdATR ? 1:0);
      weight[j]=(state[j]==1 ? 2:1);
      dir[j]=(change>0.0 ? 1 : (change<0.0 ? -1:0));
      if(state[j]==1) guru++;
      S+=weight[j];
      if(dir[j]>0) bull+=weight[j];
      if(dir[j]<0) bear+=weight[j];
      dec=(dec<<1)|state[j];
   }

   pd.guruCount=guru;
   pd.matraS=S;
   pd.decimalValue=dec;
   pd.rank=(1<<N)-dec; // one-based ordering per infographic

   int reconstructedState[];
   ArrayResize(reconstructedState,N);
   int nastaN=pd.rank;
   bool nastaOK=(nastaN>0);
   for(int pos=N-1; pos>=0 && nastaOK; pos--)
   {
      if((nastaN%2)==0)
      {
         reconstructedState[pos]=0; // Laghu
         nastaN=nastaN/2;
      }
      else
      {
         reconstructedState[pos]=1; // Guru
         nastaN=(nastaN+1)/2;
      }
   }
   if(nastaOK)
   {
      for(int j=0;j<N;j++)
      {
         if(reconstructedState[j]!=state[j])
         {
            nastaOK=false;
            break;
         }
      }
   }
   pd.nastaValid=nastaOK;

   double ck=Combination(N,guru);
   double cmax=0.0;
   for(int k=0;k<=N;k++) cmax=MathMax(cmax,Combination(N,k));
   pd.meruScore=(cmax>0.0 ? (1.0-ck/cmax)*100.0 : 0.0);
   pd.meruScore=MathMax(0.0,MathMin(100.0,pd.meruScore));

   int denom=bull+bear;
   pd.pressureB=(denom>0 ? (double)(bull-bear)/(double)denom : 0.0);
   pd.directionalStrength=MathAbs(pd.pressureB)*100.0;

   GetFibTriplet(S,pd.nearestF,pd.nextF1,pd.nextF2);
   pd.ratio1=(pd.nearestF>0 ? (double)pd.nextF1/(double)pd.nearestF : 1.0);
   pd.ratio2=(pd.nearestF>0 ? (double)pd.nextF2/(double)pd.nearestF : 1.0);
   double dist=MathAbs((double)S-(double)pd.nearestF);
   bool near=(dist<=MatrameruMaxDistance);

   bool moving=false;
   if(AllowMovingTowardNext)
   {
      MqlRates prevRates[];
      ArraySetAsSeries(prevRates,true);
      if(CopyRates(_Symbol,tf,startShift+1,N+1,prevRates)>=N+1)
      {
         int prevS=0;
         int prevAtrHandle=iATR(_Symbol,tf,ATRPeriod);
         double prevAtr[]; ArraySetAsSeries(prevAtr,true);
         if(prevAtrHandle!=INVALID_HANDLE && CopyBuffer(prevAtrHandle,0,star

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

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

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

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

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

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

Стоимость полного кода
2 288,20₽ ≈ $27.97