640 lines
21 KiB
Plaintext
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
|