Code
// BogieNN_v3_RegimeHybridML.c
// -----------------------------------------------------------------------------
// Direction 3: Bogie-NN Regime-Adaptive Hybrid ML
// Zorro S 3.11+ lite-C
//
// This branch trains TWO separate native models:
//
//   adviseLong  -> TREND continuation model
//   adviseShort -> MEAN-REVERSION model
//
// The Zorro manual permits adviseLong/adviseShort to generate two different
// models for the same asset/algo when an explicit Objective is supplied.
//
// Regime selector:
//   TREND regime:
//      ADX >= TrendADXMin and MMI <= TrendMMIMax
//
//   MEAN regime:
//      ADX <= MeanADXMax and MMI >= MeanMMIMin
//
//   otherwise:
//      NEUTRAL, no new trade.
//
// This is deliberately a model-of-models architecture:
//   market regime -> choose specialist ML score -> trade.
// -----------------------------------------------------------------------------

string BogieAsset = "EUR/USD";

int BacktestStart = 2010;
int BacktestEnd = 2026;
int StrategyBarPeriod = 60;

int WFOCycles = 8;
int WFOTrainPercent = 85;

int TrendPredictionHorizonBars = 12;
int MeanPredictionHorizonBars = 4;

var TrendConfidenceThreshold = 20.0;
var MeanConfidenceThreshold = 20.0;

int NocPeriod = 12;
int EmaPeriod = 5;
int FeatureCount = 8;

int ADXPeriod = 14;
int AroonPeriod = 25;
int MMIPeriod = 100;
int RSIPeriod = 14;
int BBPeriod = 20;
int MeanPeriod = 20;

var TrendADXMin = 25.0;
var TrendMMIMax = 64.0;

var MeanADXMax = 20.0;
var MeanMMIMin = 60.0;

var MeanLongExtreme = -0.45;
var MeanShortExtreme = 0.45;
var MeanLongRSIMax = 40.0;
var MeanShortRSIMin = 60.0;

var TrendStopATRMult = 2.5;
var TrendTrailATRMult = 3.0;
var MeanStopATRMult = 1.6;

var TrailGuardPips = 0.5;

int UseMM = 1;
int MiniAcct = 0;
var RiskPercent = 5.0;
var FixedAmount = 0.10;

int NoTradeDay_1 = 0;
int NoTradeDay_2 = 0;
int CloseOnNoTradeDay = 0;

int UseDiagnostics = 1;


var BogieRangePosition()
{
	var Highest;
	var Lowest;
	var Range;
	var Position;

	Highest = HH(NocPeriod,0);
	Lowest = LL(NocPeriod,0);
	Range = Highest-Lowest;

	if(Range <= 0.0)
		return 0.0;

	Position = 2.0*(priceC(0)-Lowest)/Range-1.0;
	return clamp(Position,-1.0,1.0);
}


void BuildTrendSignals(
	var* SmoothSeries,
	var ATRNow,
	var PlusNow,
	var MinusNow,
	var ADXNow,
	var AroonNow,
	var MMINow,
	var* Signals)
{
	var ATRSafe;
	var Momentum6;
	var DISpread;
	var TrendStrength;
	var Trendiness;

	ATRSafe = max(ATRNow,PIP);

	Momentum6 = (priceC(0)-priceC(6))/(3.0*ATRSafe);
	DISpread = (PlusNow-MinusNow)/100.0;
	TrendStrength = (ADXNow-25.0)/25.0;
	Trendiness = (75.0-MMINow)/25.0;

	Signals[0] = clamp(SmoothSeries[0],-1.0,1.0);
	Signals[1] = clamp(2.0*(SmoothSeries[0]-SmoothSeries[1]),-1.0,1.0);
	Signals[2] = clamp(SmoothSeries[0]-SmoothSeries[3],-1.0,1.0);
	Signals[3] = clamp(Momentum6,-1.0,1.0);
	Signals[4] = clamp(DISpread,-1.0,1.0);
	Signals[5] = clamp(TrendStrength,-1.0,1.0);
	Signals[6] = clamp(AroonNow/100.0,-1.0,1.0);
	Signals[7] = clamp(Trendiness,-1.0,1.0);
}


void BuildMeanSignals(
	var RawBogie,
	var SmoothNow,
	var RSINow,
	var BBOscNow,
	var MeanNow,
	var ATRNow,
	var MMINow,
	var ADXNow,
	var* Signals)
{
	var ATRSafe;
	var MeanDeviation;
	var Momentum3;
	var MeanTendency;
	var LowTrendStrength;

	ATRSafe = max(ATRNow,PIP);

	MeanDeviation = (priceC(0)-MeanNow)/(2.0*ATRSafe);
	Momentum3 = (priceC(0)-priceC(3))/(2.0*ATRSafe);
	MeanTendency = (MMINow-50.0)/25.0;
	LowTrendStrength = (25.0-ADXNow)/25.0;

	Signals[0] = clamp(SmoothNow,-1.0,1.0);
	Signals[1] = clamp(RawBogie,-1.0,1.0);
	Signals[2] = clamp((RSINow-50.0)/50.0,-1.0,1.0);
	Signals[3] = clamp((BBOscNow-50.0)/50.0,-1.0,1.0);
	Signals[4] = clamp(MeanDeviation,-1.0,1.0);
	Signals[5] = clamp(Momentum3,-1.0,1.0);
	Signals[6] = clamp(MeanTendency,-1.0,1.0);
	Signals[7] = clamp(LowTrendStrength,-1.0,1.0);
}


int MQLDayToZorro(int MqlDay)
{
	if(MqlDay == 0)
		return 7;

	return MqlDay;
}


int TradeAllowedToday()
{
	int DayNow;

	DayNow = dow(0);

	if(DayNow == MQLDayToZorro(NoTradeDay_1))
		return 0;

	if(DayNow == MQLDayToZorro(NoTradeDay_2))
		return 0;

	return 1;
}


var LegacyBogieAmount()
{
	var AmountValue;
	var FreeMargin;
	var Step;

	if(!UseMM)
		return FixedAmount;

	FreeMargin = Equity-MarginVal;
	if(FreeMargin < 0.0)
		FreeMargin = 0.0;

	AmountValue = FreeMargin*RiskPercent/100.0/1000.0;

	if(MiniAcct)
	{
		Step = 0.01;
		AmountValue = roundto(AmountValue,Step);

		if(AmountValue < 0.01)
			AmountValue = 0.01;
	}
	else
	{
		Step = 0.10;
		AmountValue = roundto(AmountValue,Step);

		if(AmountValue < 0.10)
			AmountValue = 0.10;
	}

	if(AmountValue > 50.0)
		AmountValue = 50.0;

	return AmountValue;
}


void ConfigureTrendTrade(var ATRNow)
{
	Amount = LegacyBogieAmount();
	Risk = 0;

	Stop = TrendStopATRMult*ATRNow;
	TakeProfit = 0;
	Trail = 0;
}


void ConfigureMeanTrade(var ATRNow)
{
	Amount = LegacyBogieAmount();
	Risk = 0;

	Stop = MeanStopATRMult*ATRNow;
	TakeProfit = 0;
	Trail = 0;
}


int HybridTrendTrailTMF(var TrailDistance,var GuardDistance)
{
	var Candidate;

	if(!TradeIsOpen)
		return 0;

	if(TrailDistance <= 0.0)
		return 0;

	if(TradeIsShort)
	{
		Candidate = priceC(0)+TrailDistance;

		if(TradeStopLimit > Candidate+GuardDistance)
			TradeStopLimit = Candidate;
	}
	else
	{
		Candidate = priceC(0)-TrailDistance;

		if(TradeStopLimit < Candidate-GuardDistance)
			TradeStopLimit = Candidate;
	}

	return 0;
}


void LogHybrid(
	string Side,
	string RegimeName,
	var ActiveScore,
	var ADXNow,
	var MMINow)
{
	if(!UseDiagnostics)
		return;

	printf(
		"\n%s Bar %i %s | Regime %s | Score %.2f | ADX %.2f | MMI %.2f | Amount %.3f",
		Asset,Bar,Side,RegimeName,ActiveScore,ADXNow,MMINow,Amount);
}


function run()
{
	var RawBogie;
	var SmoothNow;
	var ATRNow;
	var PlusNow;
	var MinusNow;
	var ADXNow;
	var AroonNow;
	var MMINow;
	var RSINow;
	var BBOscNow;
	var MeanNow;

	var TrendTarget;
	var MeanTarget;
	var TrendScore;
	var MeanScore;

	var TrendSignals[8];
	var MeanSignals[8];

	var* PriceSeries;
	var* RawSeries;
	var* SmoothSeries;

	var TrailDistance;
	var GuardDistance;

	int Allowed;
	int Regime;
	int LongSignal;
	int ShortSignal;

	if(is(FIRSTINITRUN))
		require(-3.11);

	set(RULES);
	set(TICKS);
	set(RECALCULATE);
	set(LOGFILE);

	if(Train)
		set(PEEK);

	BarPeriod = StrategyBarPeriod;
	LookBack = 300;
	Capital = 10000;

	StartDate = BacktestStart;
	EndDate = BacktestEnd;

	NumWFOCycles = WFOCycles;
	DataSplit = WFOTrainPercent;

	// The longest future target determines the leakage guard.
	DataHorizon = TrendPredictionHorizonBars;

	asset(BogieAsset);
	algo("BogieHybridML");

	Hedge = 0;
	MaxLong = 1;
	MaxShort = 1;

	PriceSeries = series(priceC(0),256);

	RawBogie = BogieRangePosition();
	RawSeries = series(RawBogie,64);

	SmoothNow = EMA(RawSeries,EmaPeriod);
	SmoothSeries = series(SmoothNow,64);

	ATRNow = ATR(14);

	PlusNow = PlusDI(ADXPeriod);
	MinusNow = MinusDI(ADXPeriod);
	ADXNow = ADX(ADXPeriod);
	AroonNow = AroonOsc(AroonPeriod);
	MMINow = MMI(PriceSeries,MMIPeriod);

	RSINow = RSI(PriceSeries,RSIPeriod);
	BBOscNow = BBOsc(PriceSeries,BBPeriod,2.0,MAType_SMA);
	MeanNow = EMA(PriceSeries,MeanPeriod);

	BuildTrendSignals(
		SmoothSeries,
		ATRNow,
		PlusNow,
		MinusNow,
		ADXNow,
		AroonNow,
		MMINow,
		TrendSignals);

	BuildMeanSignals(
		RawBogie,
		SmoothNow,
		RSINow,
		BBOscNow,
		MeanNow,
		ATRNow,
		MMINow,
		ADXNow,
		MeanSignals);

	TrendTarget = 0.0;
	MeanTarget = 0.0;

	if(Train)
	{
		if(priceC(-TrendPredictionHorizonBars) > priceC(0))
			TrendTarget = 1.0;
		else
			TrendTarget = -1.0;

		if(priceC(-MeanPredictionHorizonBars) > priceC(0))
			MeanTarget = 1.0;
		else
			MeanTarget = -1.0;
	}

	// Explicit objectives are supplied. Therefore adviseLong and adviseShort
	// act as two separately trained models rather than long/short trade-return
	// targets.
	TrendScore = adviseLong(
		PERCEPTRON+FUZZY+BALANCED,
		TrendTarget,
		TrendSignals,
		FeatureCount);

	MeanScore = adviseShort(
		PERCEPTRON+FUZZY+BALANCED,
		MeanTarget,
		MeanSignals,
		FeatureCount);

	if(Train)
		return;

	if(is(LOOKBACK))
		return;

	plot("Trend Model",TrendScore,NEW,BLUE);
	plot("Mean Model",MeanScore,0,RED);

	Regime = 0;

	if(ADXNow >= TrendADXMin && MMINow <= TrendMMIMax)
		Regime = 1;
	else if(ADXNow <= MeanADXMax && MMINow >= MeanMMIMin)
		Regime = -1;

	// Mean-reversion regime positions exit at the center. Since no new mean
	// trade can be opened outside Regime -1, this also prevents stale mean
	// positions from remaining after the snap-back has completed.
	if(Regime == -1)
	{
		if(NumOpenLong > 0 && priceC(0) >= MeanNow)
		{
			exitLong();
			return;
		}

		if(NumOpenShort > 0 && priceC(0) <= MeanNow)
		{
			exitShort();
			return;
		}
	}

	LongSignal = 0;
	ShortSignal = 0;

	// Specialist 1: continuation.
	if(Regime == 1)
	{
		if(TrendScore > TrendConfidenceThreshold && PlusNow > MinusNow)
			LongSignal = 1;
		else if(TrendScore < -TrendConfidenceThreshold && MinusNow > PlusNow)
			ShortSignal = 1;
	}

	// Specialist 2: snap-back.
	if(Regime == -1)
	{
		if(
			MeanScore > MeanConfidenceThreshold
			&& SmoothNow <= MeanLongExtreme
			&& RSINow <= MeanLongRSIMax)
			LongSignal = 1;
		else if(
			MeanScore < -MeanConfidenceThreshold
			&& SmoothNow >= MeanShortExtreme
			&& RSINow >= MeanShortRSIMin)
			ShortSignal = 1;
	}

	Allowed = TradeAllowedToday();

	if(!Allowed)
	{
		if(CloseOnNoTradeDay)
		{
			if(NumOpenLong > 0)
				exitLong();

			if(NumOpenShort > 0)
				exitShort();
		}

		return;
	}

	if(LongSignal)
	{
		if(NumOpenShort > 0)
		{
			exitShort();
			return;
		}

		if(NumOpenLong == 0)
		{
			if(Regime == 1)
			{
				ConfigureTrendTrade(ATRNow);
				TrailDistance = TrendTrailATRMult*ATRNow;
				GuardDistance = TrailGuardPips*PIP;

				LogHybrid("LONG","TREND",TrendScore,ADXNow,MMINow);
				enterLong(HybridTrendTrailTMF,TrailDistance,GuardDistance);
			}
			else if(Regime == -1)
			{
				ConfigureMeanTrade(ATRNow);

				LogHybrid("LONG","MEAN",MeanScore,ADXNow,MMINow);
				enterLong();
			}
		}

		return;
	}

	if(ShortSignal)
	{
		if(NumOpenLong > 0)
		{
			exitLong();
			return;
		}

		if(NumOpenShort == 0)
		{
			if(Regime == 1)
			{
				ConfigureTrendTrade(ATRNow);
				TrailDistance = TrendTrailATRMult*ATRNow;
				GuardDistance = TrailGuardPips*PIP;

				LogHybrid("SHORT","TREND",TrendScore,ADXNow,MMINow);
				enterShort(HybridTrendTrailTMF,TrailDistance,GuardDistance);
			}
			else if(Regime == -1)
			{
				ConfigureMeanTrade(ATRNow);

				LogHybrid("SHORT","MEAN",MeanScore,ADXNow,MMINow);
				enterShort();
			}
		}

		return;
	}

	// Neutral regime: no new entries.
	// Existing trend trades keep their stop/trailing protection.
	// Existing mean trades keep their ATR stop and wait for the next bar's
	// regime/mean-exit evaluation.
}