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? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.