// 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.
}