Code
// BogieNN_v3_TrendML.c
// -----------------------------------------------------------------------------
// Direction 1: Bogie-NN Trend / Continuation ML
// Zorro S 3.11+ lite-C
//
// Goal:
//   Predict continuation over a medium H1 horizon, but only trade when the
//   market already exhibits directional structure.
//
// ML:
//   PERCEPTRON + FUZZY + BALANCED
//
// 8 engineered features, all approximately normalized to -1..+1:
//   1 Bogie EMA oscillator level
//   2 1-bar Bogie slope
//   3 3-bar Bogie slope
//   4 6-bar ATR-normalized price momentum
//   5 +DI/-DI directional spread
//   6 ADX trend strength
//   7 Aroon oscillator
//   8 MMI "trendiness" (higher when MMI is lower)
//
// Entry regime:
//   ADX >= TrendADXMin
//   MMI <= TrendMMIMax
//   DI direction agrees with ML prediction
//
// Trade management:
//   ATR-based stop and ATR-based trailing distance.
// -----------------------------------------------------------------------------

string BogieAsset = "EUR/USD";

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

int WFOCycles = 8;
int WFOTrainPercent = 85;
int PredictionHorizonBars = 12;

var ConfidenceThreshold = 20.0;

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

int ADXPeriod = 14;
int AroonPeriod = 25;
int MMIPeriod = 100;

var TrendADXMin = 20.0;
var TrendMMIMax = 65.0;

var StopATRMult = 2.5;
var TrailATRMult = 3.0;
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);
}


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 = StopATRMult*ATRNow;
	TakeProfit = 0;
	Trail = 0;
}


// Custom fixed-distance trailing based on ATR measured at entry.
// Parameter is a PRICE DISTANCE, not pips.
int TrendTrailTMF(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 LogEntry(string Side,var Score,var ADXNow,var MMINow,var ATRNow)
{
	if(!UseDiagnostics)
		return;

	printf(
		"\n%s Bar %i %s | TrendScore %.2f | ADX %.2f | MMI %.2f | ATR %.5f | Amount %.3f",
		Asset,Bar,Side,Score,ADXNow,MMINow,ATRNow,Amount);
}


function run()
{
	var RawBogie;
	var SmoothNow;
	var ATRNow;
	var PlusNow;
	var MinusNow;
	var ADXNow;
	var AroonNow;
	var MMINow;
	var MLTarget;
	var MLScore;
	var TrailDistance;
	var GuardDistance;

	var Signals[8];

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

	int Allowed;
	int TrendRegime;
	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;
	DataHorizon = PredictionHorizonBars;

	asset(BogieAsset);
	algo("BogieTrendML");

	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);

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

	MLTarget = 0.0;

	if(Train)
	{
		if(priceC(-PredictionHorizonBars) > priceC(0))
			MLTarget = 1.0;
		else
			MLTarget = -1.0;
	}

	MLScore = adviseLong(
		PERCEPTRON+FUZZY+BALANCED,
		MLTarget,
		Signals,
		FeatureCount);

	if(Train)
		return;

	if(is(LOOKBACK))
		return;

	plot("Trend ML",MLScore,NEW,BLUE);
	plot("Long Gate",ConfidenceThreshold,0,BLACK);
	plot("Short Gate",-ConfidenceThreshold,0,BLACK);

	TrendRegime = 0;
	if(ADXNow >= TrendADXMin && MMINow <= TrendMMIMax)
		TrendRegime = 1;

	LongSignal = 0;
	ShortSignal = 0;

	if(TrendRegime)
	{
		if(MLScore > ConfidenceThreshold && PlusNow > MinusNow)
			LongSignal = 1;
		else if(MLScore < -ConfidenceThreshold && MinusNow > PlusNow)
			ShortSignal = 1;
	}

	Allowed = TradeAllowedToday();

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

			if(NumOpenShort > 0)
				exitShort();
		}

		return;
	}

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

		if(NumOpenLong == 0 && NumOpenShort == 0)
		{
			ConfigureTrendTrade(ATRNow);
			TrailDistance = TrailATRMult*ATRNow;
			GuardDistance = TrailGuardPips*PIP;

			LogEntry("LONG",MLScore,ADXNow,MMINow,ATRNow);
			enterLong(TrendTrailTMF,TrailDistance,GuardDistance);
		}

		return;
	}

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

		if(NumOpenShort == 0 && NumOpenLong == 0)
		{
			ConfigureTrendTrade(ATRNow);
			TrailDistance = TrailATRMult*ATRNow;
			GuardDistance = TrailGuardPips*PIP;

			LogEntry("SHORT",MLScore,ADXNow,MMINow,ATRNow);
			enterShort(TrendTrailTMF,TrailDistance,GuardDistance);
		}

		return;
	}

	// When trend structure disappears, do not immediately force an exit.
	// The position remains protected by its ATR stop and trailing rule.
}