Files
profitable-expert-advisor/frontline/MQL5/_united_dynamic/AdaptiveMonthlyRegime.mqh
T
2026-04-15 23:38:45 +02:00

640 lines
21 KiB
Plaintext

//+------------------------------------------------------------------+
//| AdaptiveMonthlyRegime.mqh |
//| Streak unit (input): closed calendar MONTHS or closed DAYS |
//| (server time). Losing streak -> optional CANARY (next full month |
//| or next full day at InpAdaptiveCanaryLotMult). Canary P/L > 0 -> |
//| full size; else HARD PAUSE. CanaryLotMult==0 -> hard pause, no |
//| canary. Per-strat DD lot cap still uses last closed *month* P/L. |
//| Include after all `input` blocks. |
//+------------------------------------------------------------------+
#ifndef ADAPTIVE_MONTHLY_REGIME_MQH
#define ADAPTIVE_MONTHLY_REGIME_MQH
#define UNITED_ADAPTIVE_N 13
#define UNITED_AD_MAX_DAY_BUCKETS 400
#define UNITED_AD_DARVAS 0
#define UNITED_AD_ES 1
#define UNITED_AD_RC 2
#define UNITED_AD_RM 3
#define UNITED_AD_RS_APPL 4
#define UNITED_AD_RS_BTC 5
#define UNITED_AD_RS_NVDA 6
#define UNITED_AD_RS_TSLA 7
#define UNITED_AD_RS_XAU 8
#define UNITED_AD_RRA_EUR 9
#define UNITED_AD_RRA_AUD 10
#define UNITED_AD_RSS 11
#define UNITED_AD_SUPEREMA 12
bool g_adHardPaused[UNITED_ADAPTIVE_N];
bool g_adCanaryWaiting[UNITED_ADAPTIVE_N];
bool g_adCanaryActive[UNITED_ADAPTIVE_N];
datetime g_adCanaryMonthStart[UNITED_ADAPTIVE_N];
datetime g_adCanaryMonthEnd[UNITED_ADAPTIVE_N];
datetime g_adHardPauseUntil[UNITED_ADAPTIVE_N];
datetime g_adPostCanaryCooldownUntil[UNITED_ADAPTIVE_N];
double g_adLastClosedMonthPl[UNITED_ADAPTIVE_N];
datetime g_unitedAdaptiveLastUpdate = 0;
string UnitedAdaptive_StratName(const int s)
{
const string names[] =
{
"DarvasBox", "EMASlope", "RSICrossOver", "RM_MidPoint",
"RS_Scalp_AAPL", "RS_Scalp_BTC", "RS_Scalp_NVDA", "RS_Scalp_TSLA", "RS_Scalp_XAU",
"RRA_EURUSD", "RRA_AUDUSD", "SecretSauce", "SuperEMA"
};
if(s >= 0 && s < UNITED_ADAPTIVE_N)
return names[s];
return "?";
}
void UnitedAdaptive_Init()
{
for(int i = 0; i < UNITED_ADAPTIVE_N; i++)
{
g_adHardPaused[i] = false;
g_adCanaryWaiting[i] = false;
g_adCanaryActive[i] = false;
g_adCanaryMonthStart[i] = 0;
g_adCanaryMonthEnd[i] = 0;
g_adHardPauseUntil[i] = 0;
g_adPostCanaryCooldownUntil[i] = 0;
g_adLastClosedMonthPl[i] = 0.0;
}
g_unitedAdaptiveLastUpdate = 0;
}
datetime UnitedAdaptive_MonthStartInt(const int y, const int m)
{
MqlDateTime d;
d.year = y;
d.mon = m;
d.day = 1;
d.hour = 0;
d.min = 0;
d.sec = 0;
return StructToTime(d);
}
void UnitedAdaptive_NextYm(int &y, int &m)
{
m++;
if(m > 12)
{
m = 1;
y++;
}
}
void UnitedAdaptive_ClosedMonthYm(const int offsetFromLastComplete, int &y, int &m)
{
MqlDateTime now;
TimeToStruct(TimeCurrent(), now);
int ly = now.year;
int lm = now.mon - 1;
if(lm < 1)
{
lm = 12;
ly--;
}
for(int i = 0; i < offsetFromLastComplete; i++)
{
lm--;
if(lm < 1)
{
lm = 12;
ly--;
}
}
y = ly;
m = lm;
}
// Start of calendar day: offset 0 = yesterday 00:00 (last fully closed day), 1 = day before, ...
datetime UnitedAdaptive_ClosedDayStart(const int offsetFromLastCompleteDay)
{
MqlDateTime n;
TimeToStruct(TimeCurrent(), n);
n.hour = 0;
n.min = 0;
n.sec = 0;
const datetime today0 = StructToTime(n);
return today0 - (datetime)((offsetFromLastCompleteDay + 1) * 86400);
}
// Bucket index 0 = yesterday. -1 = today (incomplete) or invalid.
int UnitedAdaptive_ClosedDayOffsetFromDealTime(const datetime dt)
{
MqlDateTime d, n;
TimeToStruct(dt, d);
d.hour = 0;
d.min = 0;
d.sec = 0;
const datetime dealDay0 = StructToTime(d);
TimeToStruct(TimeCurrent(), n);
n.hour = 0;
n.min = 0;
n.sec = 0;
const datetime today0 = StructToTime(n);
const long deltaSec = (long)(today0 - dealDay0);
if(deltaSec < 86400L)
return -1;
const int daysAgo = (int)(deltaSec / 86400L);
return daysAgo - 1;
}
datetime UnitedAdaptive_AddMonthsWallClock(const datetime dt0, const int months)
{
MqlDateTime t;
TimeToStruct(dt0, t);
for(int i = 0; i < months; i++)
{
t.mon++;
if(t.mon > 12)
{
t.mon = 1;
t.year++;
}
}
return StructToTime(t);
}
bool UnitedAdaptive_RMDealMatches(const long mg)
{
if(EnableRSIMidPointHijack)
{
if(RM_InpEnableRSIFollow && mg == (long)RM_InpMagicNumberRSIFollow)
return true;
if(RM_InpEnableRSIReverse && mg == (long)RM_InpMagicNumberRSIReverse)
return true;
if(RM_InpEnableEMACross && mg == (long)RM_InpMagicNumberEMACross)
return true;
}
return false;
}
bool UnitedAdaptive_DealBelongsToStrat(const int s, const long mg)
{
if(s == UNITED_AD_DARVAS)
return EnableDarvasBox && mg == (long)DB_MagicNumber;
if(s == UNITED_AD_ES)
return EnableEMASlopeDistance && mg == (long)ES_MagicNumber;
if(s == UNITED_AD_RC)
return EnableRSICrossOverReversal && mg == (long)RC_MagicNumber;
if(s == UNITED_AD_RM)
return UnitedAdaptive_RMDealMatches(mg);
if(s == UNITED_AD_RS_APPL)
return EnableRSIScalpingAPPL && mg == (long)RS_APPL_MagicNumber;
if(s == UNITED_AD_RS_BTC)
return EnableRSIScalpingBTCUSD && mg == (long)RS_BTCUSD_MagicNumber;
if(s == UNITED_AD_RS_NVDA)
return EnableRSIScalpingNVDA && mg == (long)RS_NVDA_MagicNumber;
if(s == UNITED_AD_RS_TSLA)
return EnableRSIScalpingTSLA && mg == (long)RS_TSLA_MagicNumber;
if(s == UNITED_AD_RS_XAU)
return EnableRSIScalpingXAUUSD && mg == (long)RS_XAUUSD_MagicNumber;
if(s == UNITED_AD_RRA_EUR)
return EnableRSIReversalEURUSD && mg == (long)RRA_EURUSD_MagicNumber;
if(s == UNITED_AD_RRA_AUD)
return EnableRSIReversalAUDUSD && mg == (long)RRA_AUDUSD_MagicNumber;
if(s == UNITED_AD_RSS)
return EnableRSISecretSauceXAUUSD && mg == (long)RSS_XAUUSD_MagicNumber;
if(s == UNITED_AD_SUPEREMA)
return EnableSuperEMA && mg == (long)SE_MagicNumber;
return false;
}
double UnitedAdaptive_SumStratDealsRange(const int s, const datetime from, const datetime to)
{
if(from >= to)
return 0.0;
if(!HistorySelect(from, to))
return 0.0;
double sum = 0.0;
const int n = HistoryDealsTotal();
for(int i = 0; i < n; i++)
{
const ulong t = HistoryDealGetTicket(i);
if(t == 0)
continue;
const long mg = (long)HistoryDealGetInteger(t, DEAL_MAGIC);
if(!UnitedAdaptive_DealBelongsToStrat(s, mg))
continue;
sum += HistoryDealGetDouble(t, DEAL_PROFIT);
sum += HistoryDealGetDouble(t, DEAL_SWAP);
sum += HistoryDealGetDouble(t, DEAL_COMMISSION);
}
return sum;
}
void UnitedAdaptive_StartCanaryWait(const int s)
{
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
{
MqlDateTime t;
TimeToStruct(TimeCurrent(), t);
t.hour = 0;
t.min = 0;
t.sec = 0;
const datetime today0 = StructToTime(t);
g_adCanaryMonthStart[s] = today0 + 86400;
g_adCanaryMonthEnd[s] = g_adCanaryMonthStart[s] + 86400;
g_adCanaryWaiting[s] = true;
g_adCanaryActive[s] = false;
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" -> CANARY WAIT until ", TimeToString(g_adCanaryMonthStart[s], TIME_DATE),
" then 1 day at lot x ", DoubleToString(InpAdaptiveCanaryLotMult, 4));
return;
}
MqlDateTime t;
TimeToStruct(TimeCurrent(), t);
t.mon++;
if(t.mon > 12)
{
t.mon = 1;
t.year++;
}
t.day = 1;
t.hour = 0;
t.min = 0;
t.sec = 0;
g_adCanaryMonthStart[s] = StructToTime(t);
int ey = t.year;
int em = t.mon;
UnitedAdaptive_NextYm(ey, em);
g_adCanaryMonthEnd[s] = UnitedAdaptive_MonthStartInt(ey, em);
g_adCanaryWaiting[s] = true;
g_adCanaryActive[s] = false;
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" -> CANARY WAIT until ", TimeToString(g_adCanaryMonthStart[s], TIME_DATE),
" then 1 month at lot x ", DoubleToString(InpAdaptiveCanaryLotMult, 4));
}
void UnitedAdaptive_TryExpireHardPauses()
{
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
{
if(InpAdaptiveHardRetryDays <= 0)
return;
}
else if(InpAdaptiveHardRetryMonths <= 0)
return;
const datetime now = TimeCurrent();
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
{
if(!g_adHardPaused[s])
continue;
if(g_adHardPauseUntil[s] > 0 && now >= g_adHardPauseUntil[s])
{
g_adHardPaused[s] = false;
g_adHardPauseUntil[s] = 0;
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" hard pause RETRY (after ", InpAdaptiveHardRetryDays, " d)");
else
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" hard pause RETRY (after ", InpAdaptiveHardRetryMonths, " mo)");
}
}
}
void UnitedAdaptive_ProcessCanaryTransitions()
{
if(!InpAdaptiveEnable)
return;
UnitedAdaptive_TryExpireHardPauses();
const datetime now = TimeCurrent();
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
{
if(g_adCanaryWaiting[s] && !g_adCanaryActive[s] && now >= g_adCanaryMonthStart[s])
{
g_adCanaryWaiting[s] = false;
g_adCanaryActive[s] = true;
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s), " CANARY ACTIVE (probation day)");
else
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s), " CANARY ACTIVE (probation month)");
}
if(g_adCanaryActive[s] && now >= g_adCanaryMonthEnd[s])
{
const double pl = UnitedAdaptive_SumStratDealsRange(s, g_adCanaryMonthStart[s], g_adCanaryMonthEnd[s]);
g_adCanaryActive[s] = false;
g_adCanaryWaiting[s] = false;
if(pl > 0.0)
{
if(InpAdaptivePostCanaryCooldownDays > 0)
g_adPostCanaryCooldownUntil[s] = TimeCurrent() + InpAdaptivePostCanaryCooldownDays * 86400;
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" canary OK P/L=", DoubleToString(pl, 2), " -> full size");
}
else
{
g_adHardPaused[s] = true;
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
{
if(InpAdaptiveHardRetryDays > 0)
g_adHardPauseUntil[s] = now + (datetime)InpAdaptiveHardRetryDays * 86400;
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" canary FAIL P/L=", DoubleToString(pl, 2), " -> HARD PAUSE",
(InpAdaptiveHardRetryDays > 0 ? " (auto-retry later)" : ""));
}
else
{
if(InpAdaptiveHardRetryMonths > 0)
g_adHardPauseUntil[s] = UnitedAdaptive_AddMonthsWallClock(now, InpAdaptiveHardRetryMonths);
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" canary FAIL P/L=", DoubleToString(pl, 2), " -> HARD PAUSE",
(InpAdaptiveHardRetryMonths > 0 ? " (auto-retry later)" : ""));
}
}
}
}
}
bool UnitedAdaptive_StratLastMonthIsLosing(const int s)
{
if(s < 0 || s >= UNITED_ADAPTIVE_N)
return false;
const double thr = MathMax(0.0, InpDdLotCapStratLossThreshold);
return g_adLastClosedMonthPl[s] < -thr;
}
void UnitedAdaptive_RecomputeStreaks()
{
const bool needMonthPlCap = InpDdLotCapEnable && InpDdLotCapPerStratEnable;
const bool adaptMonth = InpAdaptiveEnable && InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_MONTH;
const bool adaptDay = InpAdaptiveEnable && InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY;
int nMonthOff = 0;
int streakReqM = 1;
if(adaptMonth)
{
streakReqM = MathMax(1, InpAdaptiveRedStreak);
const int L = MathMax(InpAdaptiveLookbackMonths, streakReqM + 1);
nMonthOff = MathMin(L, 63);
}
else if(needMonthPlCap)
nMonthOff = 2;
int nDayOff = 0;
int streakReqD = 1;
if(adaptDay)
{
streakReqD = MathMax(1, InpAdaptiveRedStreak);
const int L = MathMax(InpAdaptiveLookbackDays, streakReqD + 1);
nDayOff = MathMin(L, UNITED_AD_MAX_DAY_BUCKETS);
}
if(nMonthOff == 0 && nDayOff == 0)
return;
const datetime to = TimeCurrent() + 60;
datetime from = to;
if(nMonthOff > 0)
{
int oy = 0, om = 0;
UnitedAdaptive_ClosedMonthYm(nMonthOff - 1, oy, om);
const datetime mf = UnitedAdaptive_MonthStartInt(oy, om);
if(mf < from)
from = mf;
}
if(nDayOff > 0)
{
const datetime df = UnitedAdaptive_ClosedDayStart(nDayOff - 1);
if(df < from)
from = df;
}
if(from >= to || !HistorySelect(from, to))
return;
double monthBuck[UNITED_ADAPTIVE_N][64];
double dayBuck[UNITED_ADAPTIVE_N][UNITED_AD_MAX_DAY_BUCKETS];
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
{
for(int o = 0; o < 64; o++)
monthBuck[s][o] = 0.0;
for(int o = 0; o < UNITED_AD_MAX_DAY_BUCKETS; o++)
dayBuck[s][o] = 0.0;
}
const int total = HistoryDealsTotal();
for(int i = 0; i < total; i++)
{
const ulong tk = HistoryDealGetTicket(i);
if(tk == 0)
continue;
const long mg = (long)HistoryDealGetInteger(tk, DEAL_MAGIC);
const datetime dt = (datetime)HistoryDealGetInteger(tk, DEAL_TIME);
const double pl = HistoryDealGetDouble(tk, DEAL_PROFIT)
+ HistoryDealGetDouble(tk, DEAL_SWAP)
+ HistoryDealGetDouble(tk, DEAL_COMMISSION);
if(nMonthOff > 0)
{
for(int o = 0; o < nMonthOff; o++)
{
int y = 0, m = 0;
UnitedAdaptive_ClosedMonthYm(o, y, m);
const datetime ms = UnitedAdaptive_MonthStartInt(y, m);
int ny = y, nm = m;
UnitedAdaptive_NextYm(ny, nm);
const datetime me = UnitedAdaptive_MonthStartInt(ny, nm);
if(dt < ms || dt >= me)
continue;
if(EnableDarvasBox && mg == (long)DB_MagicNumber)
monthBuck[UNITED_AD_DARVAS][o] += pl;
if(EnableEMASlopeDistance && mg == (long)ES_MagicNumber)
monthBuck[UNITED_AD_ES][o] += pl;
if(EnableRSICrossOverReversal && mg == (long)RC_MagicNumber)
monthBuck[UNITED_AD_RC][o] += pl;
if(UnitedAdaptive_RMDealMatches(mg))
monthBuck[UNITED_AD_RM][o] += pl;
if(EnableRSIScalpingAPPL && mg == (long)RS_APPL_MagicNumber)
monthBuck[UNITED_AD_RS_APPL][o] += pl;
if(EnableRSIScalpingBTCUSD && mg == (long)RS_BTCUSD_MagicNumber)
monthBuck[UNITED_AD_RS_BTC][o] += pl;
if(EnableRSIScalpingNVDA && mg == (long)RS_NVDA_MagicNumber)
monthBuck[UNITED_AD_RS_NVDA][o] += pl;
if(EnableRSIScalpingTSLA && mg == (long)RS_TSLA_MagicNumber)
monthBuck[UNITED_AD_RS_TSLA][o] += pl;
if(EnableRSIScalpingXAUUSD && mg == (long)RS_XAUUSD_MagicNumber)
monthBuck[UNITED_AD_RS_XAU][o] += pl;
if(EnableRSIReversalEURUSD && mg == (long)RRA_EURUSD_MagicNumber)
monthBuck[UNITED_AD_RRA_EUR][o] += pl;
if(EnableRSIReversalAUDUSD && mg == (long)RRA_AUDUSD_MagicNumber)
monthBuck[UNITED_AD_RRA_AUD][o] += pl;
if(EnableRSISecretSauceXAUUSD && mg == (long)RSS_XAUUSD_MagicNumber)
monthBuck[UNITED_AD_RSS][o] += pl;
if(EnableSuperEMA && mg == (long)SE_MagicNumber)
monthBuck[UNITED_AD_SUPEREMA][o] += pl;
break;
}
}
if(nDayOff > 0)
{
const int dOff = UnitedAdaptive_ClosedDayOffsetFromDealTime(dt);
if(dOff >= 0 && dOff < nDayOff)
{
if(EnableDarvasBox && mg == (long)DB_MagicNumber)
dayBuck[UNITED_AD_DARVAS][dOff] += pl;
if(EnableEMASlopeDistance && mg == (long)ES_MagicNumber)
dayBuck[UNITED_AD_ES][dOff] += pl;
if(EnableRSICrossOverReversal && mg == (long)RC_MagicNumber)
dayBuck[UNITED_AD_RC][dOff] += pl;
if(UnitedAdaptive_RMDealMatches(mg))
dayBuck[UNITED_AD_RM][dOff] += pl;
if(EnableRSIScalpingAPPL && mg == (long)RS_APPL_MagicNumber)
dayBuck[UNITED_AD_RS_APPL][dOff] += pl;
if(EnableRSIScalpingBTCUSD && mg == (long)RS_BTCUSD_MagicNumber)
dayBuck[UNITED_AD_RS_BTC][dOff] += pl;
if(EnableRSIScalpingNVDA && mg == (long)RS_NVDA_MagicNumber)
dayBuck[UNITED_AD_RS_NVDA][dOff] += pl;
if(EnableRSIScalpingTSLA && mg == (long)RS_TSLA_MagicNumber)
dayBuck[UNITED_AD_RS_TSLA][dOff] += pl;
if(EnableRSIScalpingXAUUSD && mg == (long)RS_XAUUSD_MagicNumber)
dayBuck[UNITED_AD_RS_XAU][dOff] += pl;
if(EnableRSIReversalEURUSD && mg == (long)RRA_EURUSD_MagicNumber)
dayBuck[UNITED_AD_RRA_EUR][dOff] += pl;
if(EnableRSIReversalAUDUSD && mg == (long)RRA_AUDUSD_MagicNumber)
dayBuck[UNITED_AD_RRA_AUD][dOff] += pl;
if(EnableRSISecretSauceXAUUSD && mg == (long)RSS_XAUUSD_MagicNumber)
dayBuck[UNITED_AD_RSS][dOff] += pl;
if(EnableSuperEMA && mg == (long)SE_MagicNumber)
dayBuck[UNITED_AD_SUPEREMA][dOff] += pl;
}
}
}
if(nMonthOff > 0)
{
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
g_adLastClosedMonthPl[s] = monthBuck[s][0];
}
if(!InpAdaptiveEnable)
return;
const double thr = MathMax(0.0, InpAdaptiveRedThreshold);
const bool useDay = adaptDay;
const int streakReq = useDay ? streakReqD : streakReqM;
const int nOff = useDay ? nDayOff : nMonthOff;
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
{
if(g_adHardPaused[s])
continue;
if(g_adCanaryActive[s] || g_adCanaryWaiting[s])
{
int consecOk = 0;
for(int o = 0; o < streakReq && o < nOff; o++)
{
const double bpl = useDay ? dayBuck[s][o] : monthBuck[s][o];
if(bpl < -thr)
consecOk++;
else
break;
}
const bool streakBad = (consecOk >= streakReq);
if(!streakBad && g_adCanaryWaiting[s] && !g_adCanaryActive[s])
{
g_adCanaryWaiting[s] = false;
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s), " canary wait CANCELLED (streak cleared)");
}
continue;
}
int consec = 0;
for(int o = 0; o < streakReq && o < nOff; o++)
{
const double bpl = useDay ? dayBuck[s][o] : monthBuck[s][o];
if(bpl < -thr)
consec++;
else
break;
}
const bool streakBad = (consec >= streakReq);
if(!streakBad)
continue;
const bool prevHard = g_adHardPaused[s];
if(InpAdaptiveCanaryLotMult > 0.0)
{
if(!g_adCanaryWaiting[s] && !g_adCanaryActive[s])
{
if(g_adPostCanaryCooldownUntil[s] > TimeCurrent())
continue;
UnitedAdaptive_StartCanaryWait(s);
}
}
else
{
g_adHardPaused[s] = true;
if(!prevHard && useDay && InpAdaptiveHardRetryDays > 0)
g_adHardPauseUntil[s] = TimeCurrent() + (datetime)InpAdaptiveHardRetryDays * 86400;
else if(!prevHard && !useDay && InpAdaptiveHardRetryMonths > 0)
g_adHardPauseUntil[s] = UnitedAdaptive_AddMonthsWallClock(TimeCurrent(), InpAdaptiveHardRetryMonths);
if(!prevHard)
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
" HARD PAUSE (streak, canary disabled)");
}
}
}
void UnitedAdaptive_UpdateIfDue()
{
if(!InpAdaptiveEnable && (!InpDdLotCapEnable || !InpDdLotCapPerStratEnable))
{
UnitedAdaptive_Init();
return;
}
int everySec = 3600;
if(InpAdaptiveEnable)
everySec = MathMin(everySec, MathMax(60, InpAdaptiveUpdateSeconds));
if(InpDdLotCapEnable && InpDdLotCapPerStratEnable)
everySec = MathMin(everySec, MathMax(60, InpDdLotCapUpdateSeconds));
if(g_unitedAdaptiveLastUpdate > 0 && (TimeCurrent() - g_unitedAdaptiveLastUpdate) < everySec)
return;
g_unitedAdaptiveLastUpdate = TimeCurrent();
UnitedAdaptive_RecomputeStreaks();
}
double UnitedAdaptive_GetLotMult(const int stratId)
{
if(stratId < 0 || stratId >= UNITED_ADAPTIVE_N)
return 1.0;
if(!InpAdaptiveEnable)
return 1.0;
if(g_adCanaryActive[stratId])
return MathMax(0.0, InpAdaptiveCanaryLotMult);
return 1.0;
}
bool UnitedAdaptive_StrategyActive(const int stratId)
{
if(stratId < 0 || stratId >= UNITED_ADAPTIVE_N)
return true;
if(!InpAdaptiveEnable)
return true;
if(g_adHardPaused[stratId])
return false;
if(g_adCanaryWaiting[stratId] && !g_adCanaryActive[stratId])
return false;
return true;
}
#endif