A puzzle to solve.

Code
// SevenBandVWAP TickReactive HFT
// H1FT_EA.mq5 
// Research code: validate with TICKS and broker-specific spread/volume data.

#include <default.c>

// -----------------------------------------------------------------------------
// Enumerations
// -----------------------------------------------------------------------------
#define PR_CLOSE       0
#define PR_OPEN        1
#define PR_HIGH        2
#define PR_LOW         3
#define PR_MEDIAN      4
#define PR_TYPICAL     5
#define PR_WEIGHTED    6
#define PR_AVERAGE     7
#define PR_MEDIAN_BODY 8
#define PR_TBIASED     9
#define PR_TBIASED2    10

#define ST_FLAT           0
#define ST_LONG_ARMED     1
#define ST_LONG_ACTIVE    2
#define ST_LONG_HEDGED    3
#define ST_LONG_RECOVERY  4
#define ST_SHORT_ARMED    5
#define ST_SHORT_ACTIVE   6
#define ST_SHORT_HEDGED   7
#define ST_SHORT_RECOVERY 8
#define ST_EXIT_PENDING   9
#define ST_COOLDOWN       10
#define ST_EMERGENCY      11

#define B_D3 0
#define B_D2 1
#define B_D1 2
#define B_M  3
#define B_U1 4
#define B_U2 5
#define B_U3 6

#define ROLE_PRIMARY_LONG  101
#define ROLE_PRIMARY_SHORT 102
#define ROLE_H1            201
#define ROLE_H2            202
#define ROLE_H3            203
#define ROLE_HFT_LONG      301
#define ROLE_HFT_SHORT     302

#define TV_ROLE       0
#define TV_BAND       1
#define TV_OPEN_MS    2
#define TV_SCORE      3
#define TV_CYCLE      4
#define TV_SLICE      5

// -----------------------------------------------------------------------------
// User parameters. Convert selected values to optimize(...) when desired.
// -----------------------------------------------------------------------------
int AvgPeriod = 20;
int PriceMode = PR_CLOSE;
int UseRealVolume = 0;        // Zorro normally exposes tick volume through marketVol().
int DeviationSample = 0;
var DeviationMultiplier1 = 1.0;
var DeviationMultiplier2 = 2.0;
var DeviationMultiplier3 = 2.5;

var MinimumWickRatio = 0.35;
var MinimumWickDominance = 1.25;
var MinimumBodyRatio = 0.20;
var AcceptanceBodyRatio = 0.40;
var AcceptanceCloseLevel = 0.70;
int ConfirmationBars = 2;

int EnableLong = 1;
int EnableShort = 1;
int EnableHedging = 1;
int MaximumHoldingBars = 100;
int CooldownBars = 3;
var EmergencySigmaBuffer = 0.15;

var HedgeRatio1 = 0.33;
var HedgeRatio2 = 0.66;
var HedgeRatio3 = 1.00;

var PartialAtD2U2 = 0.10;
var PartialAtD1U1 = 0.10;
var PartialAtMiddle = 0.20;
var PartialAtU1D1 = 0.15;
var PartialAtU2D2 = 0.20;

int UseFixedLots = 1;
var FixedLots = 0.10;
var RiskPercent = 0.50;
var MaximumSpreadPoints = 50;
int UseBrokerEmergencyStop = 1;

int EnableTickReactiveHFT = 1;
int EnableBarStateMachine = 0;
int HFTUseFixedLots = 1;
var HFTFixedLots = 0.01;
var HFTRiskPercent = 0.05;
var HFTMaximumSpreadPoints = 200;
int HFTMaximumOpenPositions = 50;
int HFTMaximumPositionsPerSide = 25;
int HFTMaximumEntriesPerTick = 2;
int HFTMaximumClosuresPerTick = 10;
int HFTMaximumEntriesPerSecond = 10;
int HFTMaximumEntriesPerMinute = 200;
int HFTMaximumDailyEntries = 3000;
int HFTMinimumMillisecondsBetweenEntries = 50;
int HFTSignalCooldownMilliseconds = 100;
int HFTMaximumHoldingMilliseconds = 30000;
var HFTTakeProfitPoints = 20;
var HFTStopLossPoints = 30;
int HFTUseAdjacentBandTargets = 1;
int HFTCloseOnOppositeSignal = 1;
int HFTAllowOppositePositions = 1;
int HFTEnableBandCrossEntries = 1;
int HFTEnableZoneTransitionEntries = 1;
int HFTEnableWickReclaimEntries = 1;
int HFTEnableMomentumEntries = 1;
int HFTMinimumSignalScore = 2;
var HFTMinimumWickRatio = 0.10;
var HFTMinimumWickDominance = 0.75;
var HFTMinimumBodyRatio = 0.00;
var HFTMinimumTickMomentumPoints = 1;
int HFTMinimumTicksPerSecond = 1;
int HFTRequireCostEdge = 0;
var HFTMinimumEdgeCostMultiple = 1.20;
int HFTWriteDiagnostics = 1;
int WriteDiagnostics = 1;

// -----------------------------------------------------------------------------
// Data structures
// -----------------------------------------------------------------------------
typedef struct SNAPSHOT {
    DATE Time;
    var O,H,L,C,Selected,VWAP,Dev;
    var Band[7];
    var TickVolume;
    var SpreadPoints;
    var Range,Body,UW,LW,UWR,LWR,BR,CLV,WI;
    int LowerDom,UpperDom,BullReject,BearReject;
} SNAPSHOT;

typedef struct CONTEXT {
    int Mode;
    int Progress;
    int HedgeDepth;
    int ArmAge;
    int Holding;
    int Cooldown;
    var RejectionHigh;
    var RejectionLow;
    var InitialLots;
    long CycleID;
} CONTEXT;

CONTEXT Ctx;

// HFT state.
var HFTPrevPrice = 0;
var HFTPrevBand[7];
int HFTPrevZone = -1;
int HFTStateReady = 0;
long HFTLastEntryMS = 0;
long HFTLastLongSignalMS[7];
long HFTLastShortSignalMS[7];
long HFTSecondWindowMS = 0;
long HFTMinuteWindowMS = 0;
long HFTTickWindowMS = 0;
int HFTEntriesSecond = 0;
int HFTEntriesMinute = 0;
int HFTTicksCurrentSecond = 0;
int HFTTicksLastSecond = 0;
int HFTDailyEntries = 0;
int HFTDayKey = 0;
long HFTTickCounter = 0;
long HFTEntryCounter = 0;
long HFTCloseCounter = 0;

// Forming candle state used by tick().
DATE FormingBarTime = 0;
var FormingOpen = 0;
var FormingHigh = 0;
var FormingLow = 0;
var FormingClose = 0;
var FormingTickVolume = 0;

// Completed bar series, initialized in run().
vars SOpen, SHigh, SLow, SClose, SVolume;
int SeriesReady = 0;

// Diagnostics handles.
int BarLog = 0;
int HFTLogFile = 0;

// -----------------------------------------------------------------------------
// Utility
// -----------------------------------------------------------------------------
long NowMS()
{
    // wdate() is expressed in days. This preserves sub-second precision when
    // supplied by the feed, but some Zorro feeds only timestamp to seconds.
    return (long)(wdate()*86400000.0);
}

int CurrentDayKey()
{
    return year()*10000 + month()*100 + day();
}

string ModeName(int Mode)
{
    if(Mode == ST_FLAT) return "FLAT";
    if(Mode == ST_LONG_ARMED) return "LONG_ARMED";
    if(Mode == ST_LONG_ACTIVE) return "LONG_ACTIVE";
    if(Mode == ST_LONG_HEDGED) return "LONG_HEDGED";
    if(Mode == ST_LONG_RECOVERY) return "LONG_RECOVERY";
    if(Mode == ST_SHORT_ARMED) return "SHORT_ARMED";
    if(Mode == ST_SHORT_ACTIVE) return "SHORT_ACTIVE";
    if(Mode == ST_SHORT_HEDGED) return "SHORT_HEDGED";
    if(Mode == ST_SHORT_RECOVERY) return "SHORT_RECOVERY";
    if(Mode == ST_EXIT_PENDING) return "EXIT_PENDING";
    if(Mode == ST_COOLDOWN) return "COOLDOWN";
    if(Mode == ST_EMERGENCY) return "EMERGENCY";
    return "UNKNOWN";
}

string BandName(int Band)
{
    if(Band == B_D3) return "D3";
    if(Band == B_D2) return "D2";
    if(Band == B_D1) return "D1";
    if(Band == B_M) return "M";
    if(Band == B_U1) return "U1";
    if(Band == B_U2) return "U2";
    if(Band == B_U3) return "U3";
    return "NONE";
}

void ResetContext()
{
    Ctx.Mode = ST_FLAT;
    Ctx.Progress = -1;
    Ctx.HedgeDepth = 0;
    Ctx.ArmAge = 0;
    Ctx.Holding = 0;
    Ctx.Cooldown = 0;
    Ctx.RejectionHigh = 0;
    Ctx.RejectionLow = 0;
    Ctx.InitialLots = 0;
}

var SelectedPriceAt(int Shift)
{
    var O = SOpen[Shift];
    var H = SHigh[Shift];
    var L = SLow[Shift];
    var C = SClose[Shift];

    if(PriceMode == PR_OPEN) return O;
    if(PriceMode == PR_HIGH) return H;
    if(PriceMode == PR_LOW) return L;
    if(PriceMode == PR_MEDIAN) return 0.5*(H+L);
    if(PriceMode == PR_TYPICAL) return (H+L+C)/3.;
    if(PriceMode == PR_WEIGHTED) return (H+L+2*C)/4.;
    if(PriceMode == PR_AVERAGE) return (O+H+L+C)/4.;
    if(PriceMode == PR_MEDIAN_BODY) return 0.5*(O+C);
    if(PriceMode == PR_TBIASED) {
        if(C > O) return 0.5*(H+C);
        return 0.5*(L+C);
    }
    if(PriceMode == PR_TBIASED2) {
        if(C>O) return H;
        if(C<O) return L;
        return C;
    }
    return C;
}

var SelectedFormingPrice()
{
    if(PriceMode == PR_OPEN) return FormingOpen;
    if(PriceMode == PR_HIGH) return FormingHigh;
    if(PriceMode == PR_LOW) return FormingLow;
    if(PriceMode == PR_MEDIAN) return 0.5*(FormingHigh+FormingLow);
    if(PriceMode == PR_TYPICAL) return (FormingHigh+FormingLow+FormingClose)/3.;
    if(PriceMode == PR_WEIGHTED) return (FormingHigh+FormingLow+2*FormingClose)/4.;
    if(PriceMode == PR_AVERAGE) return (FormingOpen+FormingHigh+FormingLow+FormingClose)/4.;
    if(PriceMode == PR_MEDIAN_BODY) return 0.5*(FormingOpen+FormingClose);
    if(PriceMode == PR_TBIASED) {
        if(FormingClose > FormingOpen) return 0.5*(FormingHigh+FormingClose);
        return 0.5*(FormingLow+FormingClose);
    }
    if(PriceMode == PR_TBIASED2) {
        if(FormingClose>FormingOpen) return FormingHigh;
        if(FormingClose<FormingOpen) return FormingLow;
        return FormingClose;
    }
    return FormingClose;
}

void CompleteSnapshot(SNAPSHOT* S)
{
    S->Band[B_D3] = S->VWAP-DeviationMultiplier3*S->Dev;
    S->Band[B_D2] = S->VWAP-DeviationMultiplier2*S->Dev;
    S->Band[B_D1] = S->VWAP-DeviationMultiplier1*S->Dev;
    S->Band[B_M]  = S->VWAP;
    S->Band[B_U1] = S->VWAP+DeviationMultiplier1*S->Dev;
    S->Band[B_U2] = S->VWAP+DeviationMultiplier2*S->Dev;
    S->Band[B_U3] = S->VWAP+DeviationMultiplier3*S->Dev;

    S->Range = S->H-S->L;
    S->Body = abs(S->C-S->O);
    S->UW = S->H-max(S->O,S->C);
    S->LW = min(S->O,S->C)-S->L;
    var R = max(S->Range,0.1*PIP);
    S->UWR = S->UW/R;
    S->LWR = S->LW/R;
    S->BR = S->Body/R;
    S->CLV = (S->C-S->L)/R;
    S->WI = (S->LW-S->UW)/R;
    S->LowerDom = S->LWR>=MinimumWickRatio && S->LW>=MinimumWickDominance*max(S->UW,0.1*PIP) && S->BR>=MinimumBodyRatio;
    S->UpperDom = S->UWR>=MinimumWickRatio && S->UW>=MinimumWickDominance*max(S->LW,0.1*PIP) && S->BR>=MinimumBodyRatio;
    S->BullReject = S->C>S->O && S->LowerDom && S->CLV>=0.65;
    S->BearReject = S->C<S->O && S->UpperDom && S->CLV<=0.35;
}

int MakeBarSnapshot(int Shift, SNAPSHOT* S)
{
    if(!SeriesReady) return 0;
    S->Time = 0;
    S->O = SOpen[Shift];
    S->H = SHigh[Shift];
    S->L = SLow[Shift];
    S->C = SClose[Shift];
    S->Selected = SelectedPriceAt(Shift);
    S->TickVolume = SVolume[Shift];
    S->SpreadPoints = Spread/PIP;

    var WSum = 0, VSum = 0, Mean = 0, M2 = 0;
    int Count = 0;
    int K;
    for(K=0; K<AvgPeriod; K++) {
        int I = Shift+K;
        var X = SelectedPriceAt(I);
        var V = max(SVolume[I],1);
        WSum += V*X;
        VSum += V;
        Count++;
        var D = X-Mean;
        Mean += D/Count;
        M2 += D*(X-Mean);
    }
    if(VSum != 0)
        S->VWAP = WSum/VSum;
    else
        S->VWAP = S->Selected;
    S->Dev = sqrt(max(M2,0)/max(Count-ifelse(DeviationSample,1,0),1));
    CompleteSnapshot(S);
    return 1;
}

int MakeTickSnapshot(SNAPSHOT* S)
{
    if(!SeriesReady || FormingOpen <= 0) return 0;
    S->Time = wdate();
    S->O = FormingOpen;
    S->H = FormingHigh;
    S->L = FormingLow;
    S->C = FormingClose;
    S->Selected = SelectedFormingPrice();
    S->TickVolume = FormingTickVolume;
    S->SpreadPoints = Spread/PIP;

    var WSum = max(FormingTickVolume,1)*S->Selected;
    var VSum = max(FormingTickVolume,1);
    var Mean = S->Selected;
    var M2 = 0;
    int Count = 1;
    int K;
    for(K=0; K<AvgPeriod-1; K++) {
        var X = SelectedPriceAt(K);
        var V = max(SVolume[K],1);
        WSum += V*X;
        VSum += V;
        Count++;
        var D = X-Mean;
        Mean += D/Count;
        M2 += D*(X-Mean);
    }
    S->VWAP = WSum/VSum;
    S->Dev = sqrt(max(M2,0)/max(Count-ifelse(DeviationSample,1,0),1));
    CompleteSnapshot(S);
    return 1;
}

int Touch(SNAPSHOT* S,int B) { return S->L<=S->Band[B] && S->H>=S->Band[B]; }
int CrossUp(SNAPSHOT* C,SNAPSHOT* P,int B) { return P->C<=P->Band[B] && C->C>C->Band[B]; }
int CrossDown(SNAPSHOT* C,SNAPSHOT* P,int B) { return P->C>=P->Band[B] && C->C<C->Band[B]; }
int LowerReclaim(SNAPSHOT* S,int B) { return S->L<S->Band[B] && S->C>S->Band[B] && S->BullReject; }
int UpperReclaim(SNAPSHOT* S,int B) { return S->H>S->Band[B] && S->C<S->Band[B] && S->BearReject; }

int AcceptUp(SNAPSHOT* C,SNAPSHOT* P,int B)
{
    if(CrossUp(C,P,B) && C->BR>=AcceptanceBodyRatio && C->CLV>=AcceptanceCloseLevel) return 1;
    return C->C>C->Band[B] && P->C>P->Band[B] && C->BR>=AcceptanceBodyRatio && C->CLV>=AcceptanceCloseLevel;
}

int AcceptDown(SNAPSHOT* C,SNAPSHOT* P,int B)
{
    if(CrossDown(C,P,B) && C->BR>=AcceptanceBodyRatio && C->CLV<=1.-AcceptanceCloseLevel) return 1;
    return C->C<C->Band[B] && P->C<P->Band[B] && C->BR>=AcceptanceBodyRatio && C->CLV<=1.-AcceptanceCloseLevel;
}

int ZoneAt(var Price,SNAPSHOT* S)
{
    if(Price<S->Band[B_D3]) return 0;
    if(Price<S->Band[B_D2]) return 1;
    if(Price<S->Band[B_D1]) return 2;
    if(Price<S->Band[B_M]) return 3;
    if(Price<S->Band[B_U1]) return 4;
    if(Price<S->Band[B_U2]) return 5;
    if(Price<S->Band[B_U3]) return 6;
    return 7;
}

// -----------------------------------------------------------------------------
// Trade helpers. TradeVar tags replace MT5 magic numbers and comments.
// -----------------------------------------------------------------------------
int IsMacroRole(int Role) { return Role>=ROLE_PRIMARY_LONG && Role<=ROLE_H3; }
int IsHFTRole(int Role) { return Role==ROLE_HFT_LONG || Role==ROLE_HFT_SHORT; }

int CountTradesByRole(int Role)
{
    int N = 0;
    for(open_trades) if((int)TradeVar[TV_ROLE] == Role) N++;
    return N;
}

int CountHFTTrades(int Side)
{
    int N = 0;
    for(open_trades) {
        int Role = (int)TradeVar[TV_ROLE];
        if(!IsHFTRole(Role)) continue;
        if(Side>0 && !TradeIsLong) continue;
        if(Side<0 && TradeIsLong) continue;
        N++;
    }
    return N;
}

var LotsByRole(int Role)
{
    var Total = 0;
    for(open_trades) if((int)TradeVar[TV_ROLE] == Role) Total += TradeLots;
    return Total;
}

var PrimaryLongLots() { return LotsByRole(ROLE_PRIMARY_LONG); }
var PrimaryShortLots() { return LotsByRole(ROLE_PRIMARY_SHORT); }
var PrimaryLots() { return PrimaryLongLots()+PrimaryShortLots(); }
var HedgeLots() { return LotsByRole(ROLE_H1)+LotsByRole(ROLE_H2)+LotsByRole(ROLE_H3); }

int ActualHedgeDepth()
{
    if(CountTradesByRole(ROLE_H3)>0) return 3;
    if(CountTradesByRole(ROLE_H2)>0) return 2;
    if(CountTradesByRole(ROLE_H1)>0) return 1;
    return 0;
}

var MacroEntryLots(int IsLong,SNAPSHOT* S)
{
    if(UseFixedLots) return FixedLots;
    var EntryPrice = priceClose();
    var StopPrice;
    if(IsLong)
        StopPrice = S->Band[B_D3]-EmergencySigmaBuffer*S->Dev;
    else
        StopPrice = S->Band[B_U3]+EmergencySigmaBuffer*S->Dev;
    var RiskDistance = abs(EntryPrice-StopPrice);
    if(RiskDistance<=0 || PIPCost<=0) return FixedLots;
    var RiskMoney = Balance*RiskPercent/100.;
    return max(1, RiskMoney/(RiskDistance/PIP*PIPCost));
}

TRADE* OpenTaggedTrade(int IsLong,var TradeLotsValue,int Role,int Band,int Score,long OpenMS)
{
    TradeLotsValue = max(TradeLotsValue,1);
    TRADE* T;
    if(IsLong)
        T = enterLong(TradeLotsValue);
    else
        T = enterShort(TradeLotsValue);
    if(T) {
        T->Skill[TV_ROLE] = Role;
        T->Skill[TV_BAND] = Band;
        T->Skill[TV_OPEN_MS] = OpenMS;
        T->Skill[TV_SCORE] = Score;
        T->Skill[TV_CYCLE] = Ctx.CycleID;
    }
    return T;
}

int CloseRole(int Role)
{
    int Closed = 0;
    for(open_trades) {
        if((int)TradeVar[TV_ROLE] != Role) continue;
        exitTrade(ThisTrade);
        Closed++;
    }
    return Closed;
}

void CloseAllMacro()
{
    for(open_trades) if(IsMacroRole((int)TradeVar[TV_ROLE])) exitTrade(ThisTrade);
}

// Zorro partial-close behavior differs across broker plugins. This function
// uses exitTrade(ThisTrade,Lots) where supported. When unsupported, replace
// it with primary slices at entry or a broker-specific order command.
int PartialPrimary(int IsLong,var Fraction)
{
    int Role;
    if(IsLong)
        Role = ROLE_PRIMARY_LONG;
    else
        Role = ROLE_PRIMARY_SHORT;
    var TargetLots = Ctx.InitialLots*Fraction;
    for(open_trades) {
        if((int)TradeVar[TV_ROLE] != Role) continue;
        var CloseLots = min(TradeLots,TargetLots);
        if(CloseLots > 0) {
            exitTrade(ThisTrade,CloseLots);
            return 1;
        }
    }
    return 0;
}

int OpenPrimary(int IsLong,SNAPSHOT* S)
{
    var L = MacroEntryLots(IsLong,S);
    Ctx.CycleID++;
    int Role;
    if(IsLong)
        Role = ROLE_PRIMARY_LONG;
    else
        Role = ROLE_PRIMARY_SHORT;
    TRADE* T = OpenTaggedTrade(IsLong,L,Role,-1,0,NowMS());
    if(!T) return 0;
    Ctx.InitialLots = L;
    return 1;
}

int OpenHedge(int IsLong,int Stage,var Ratio)
{
    if(!EnableHedging) return 0;
    var Primary = PrimaryLots();
    var Target = Ratio*Primary;
    var AddLots = Target-HedgeLots();
    if(AddLots <= 0) return 0;
    int Role = ROLE_H3;
    if(Stage == 1)
        Role = ROLE_H1;
    else if(Stage == 2)
        Role = ROLE_H2;
    return OpenTaggedTrade(IsLong,AddLots,Role,-1,0,NowMS()) != 0;
}

void EnterCooldown()
{
    Ctx.Mode = ST_COOLDOWN;
    Ctx.Progress = -1;
    Ctx.HedgeDepth = 0;
    Ctx.Holding = 0;
    Ctx.Cooldown = CooldownBars;
    Ctx.InitialLots = 0;
}

void CloseAllToCooldown()
{
    CloseAllMacro();
    EnterCooldown();
}

// -----------------------------------------------------------------------------
// Bar state machine
// -----------------------------------------------------------------------------
var LongPart(int B)
{
    if(B==B_D2) return PartialAtD2U2;
    if(B==B_D1) return PartialAtD1U1;
    if(B==B_M) return PartialAtMiddle;
    if(B==B_U1) return PartialAtU1D1;
    if(B==B_U2) return PartialAtU2D2;
    return 0;
}

var ShortPart(int B)
{
    if(B==B_U2) return PartialAtD2U2;
    if(B==B_U1) return PartialAtD1U1;
    if(B==B_M) return PartialAtMiddle;
    if(B==B_D1) return PartialAtU1D1;
    if(B==B_D2) return PartialAtU2D2;
    return 0;
}

int LongFinal(SNAPSHOT* C,SNAPSHOT* P)
{
    return AcceptUp(C,P,B_U3) || UpperReclaim(C,B_U3) || (Touch(C,B_U3)&&C->UpperDom&&C->C<C->Band[B_U3]);
}

int ShortFinal(SNAPSHOT* C,SNAPSHOT* P)
{
    return AcceptDown(C,P,B_D3) || LowerReclaim(C,B_D3) || (Touch(C,B_D3)&&C->LowerDom&&C->C>C->Band[B_D3]);
}

int LongEmergency(SNAPSHOT* C)
{
    if(C->C<C->Band[B_D3]-EmergencySigmaBuffer*C->Dev) return 1;
    if(Ctx.Progress>=B_U1 && Ctx.HedgeDepth>=3 && C->C<C->Band[B_M]) return 1;
    return Ctx.Holding>=MaximumHoldingBars;
}

int ShortEmergency(SNAPSHOT* C)
{
    if(C->C>C->Band[B_U3]+EmergencySigmaBuffer*C->Dev) return 1;
    if(Ctx.Progress<=B_D1 && Ctx.HedgeDepth>=3 && C->C>C->Band[B_M]) return 1;
    return Ctx.Holding>=MaximumHoldingBars;
}

int LAdv(int D) { return max(Ctx.Progress-D,B_D3); }
int SAdv(int D) { return min(Ctx.Progress+D,B_U3); }

int LongH1(SNAPSHOT* C,SNAPSHOT* P)
{
    if(!EnableHedging || Ctx.Progress<B_M || Ctx.HedgeDepth!=0) return 0;
    int B=LAdv(1); return C->C<C->Band[B] && (AcceptDown(C,P,B)||UpperReclaim(C,Ctx.Progress));
}
int LongH2(SNAPSHOT* C,SNAPSHOT* P)
{
    if(Ctx.HedgeDepth!=1) return 0; int B=LAdv(2); return C->C<C->Band[B] && (AcceptDown(C,P,B)||C->BearReject);
}
int LongH3(SNAPSHOT* C,SNAPSHOT* P)
{
    if(Ctx.HedgeDepth!=2) return 0; int B=LAdv(3); return C->C<C->Band[B] && AcceptDown(C,P,B);
}
int ShortH1(SNAPSHOT* C,SNAPSHOT* P)
{
    if(!EnableHedging || Ctx.Progress>B_M || Ctx.HedgeDepth!=0) return 0;
    int B=SAdv(1); return C->C>C->Band[B] && (AcceptUp(C,P,B)||LowerReclaim(C,Ctx.Progress));
}
int ShortH2(SNAPSHOT* C,SNAPSHOT* P)
{
    if(Ctx.HedgeDepth!=1) return 0; int B=SAdv(2); return C->C>C->Band[B] && (AcceptUp(C,P,B)||C->BullReject);
}
int ShortH3(SNAPSHOT* C,SNAPSHOT* P)
{
    if(Ctx.HedgeDepth!=2) return 0; int B=SAdv(3); return C->C>C->Band[B] && AcceptUp(C,P,B);
}

int AdvanceLong(SNAPSHOT* C,SNAPSHOT* P)
{
    int Next=Ctx.Progress+1;
    if(Next>B_U3 || !AcceptUp(C,P,Next)) return 0;
    if(Next==B_U3) { CloseAllToCooldown(); return 1; }
    var F=LongPart(Next); if(F>0) PartialPrimary(1,F);
    Ctx.Progress=Next; return 1;
}

int AdvanceShort(SNAPSHOT* C,SNAPSHOT* P)
{
    int Next=Ctx.Progress-1;
    if(Next<B_D3 || !AcceptDown(C,P,Next)) return 0;
    if(Next==B_D3) { CloseAllToCooldown(); return 1; }
    var F=ShortPart(Next); if(F>0) PartialPrimary(0,F);
    Ctx.Progress=Next; return 1;
}

void ProcessMacroBar()
{
    SNAPSHOT C,P;
    if(!MakeBarSnapshot(1,&C) || !MakeBarSnapshot(2,&P)) return;

    if(Ctx.Mode==ST_FLAT) {
        if(EnableLong && LowerReclaim(&C,B_D3)) {
            Ctx.Mode=ST_LONG_ARMED; Ctx.ArmAge=0; Ctx.RejectionHigh=C.H; Ctx.RejectionLow=C.L;
        } else if(EnableShort && UpperReclaim(&C,B_U3)) {
            Ctx.Mode=ST_SHORT_ARMED; Ctx.ArmAge=0; Ctx.RejectionHigh=C.H; Ctx.RejectionLow=C.L;
        }
    }
    else if(Ctx.Mode==ST_LONG_ARMED) {
        Ctx.ArmAge++;
        if(C.C<C.Band[B_D3]) ResetContext();
        else if((AcceptUp(&C,&P,B_D2)||(C.C>Ctx.RejectionHigh&&C.C>C.O&&C.CLV>=AcceptanceCloseLevel)) && OpenPrimary(1,&C)) {
            Ctx.Mode=ST_LONG_ACTIVE; Ctx.Progress=B_D3; Ctx.HedgeDepth=0; Ctx.Holding=0;
        } else if(Ctx.ArmAge>ConfirmationBars) ResetContext();
    }
    else if(Ctx.Mode==ST_SHORT_ARMED) {
        Ctx.ArmAge++;
        if(C.C>C.Band[B_U3]) ResetContext();
        else if((AcceptDown(&C,&P,B_U2)||(C.C<Ctx.RejectionLow&&C.C<C.O&&C.CLV<=1.-AcceptanceCloseLevel)) && OpenPrimary(0,&C)) {
            Ctx.Mode=ST_SHORT_ACTIVE; Ctx.Progress=B_U3; Ctx.HedgeDepth=0; Ctx.Holding=0;
        } else if(Ctx.ArmAge>ConfirmationBars) ResetContext();
    }
    else if(Ctx.Mode==ST_LONG_ACTIVE) {
        Ctx.Holding++;
        if(PrimaryLongLots()<=0 || LongEmergency(&C) || LongFinal(&C,&P)) CloseAllToCooldown();
        else if(!AdvanceLong(&C,&P) && LongH1(&C,&P) && OpenHedge(0,1,HedgeRatio1)) { Ctx.HedgeDepth=1; Ctx.Mode=ST_LONG_HEDGED; }
    }
    else if(Ctx.Mode==ST_SHORT_ACTIVE) {
        Ctx.Holding++;
        if(PrimaryShortLots()<=0 || ShortEmergency(&C) || ShortFinal(&C,&P)) CloseAllToCooldown();
        else if(!AdvanceShort(&C,&P) && ShortH1(&C,&P) && OpenHedge(1,1,HedgeRatio1)) { Ctx.HedgeDepth=1; Ctx.Mode=ST_SHORT_HEDGED; }
    }
    else if(Ctx.Mode==ST_LONG_HEDGED) {
        Ctx.Holding++;
        if(PrimaryLongLots()<=0 || LongEmergency(&C) || LongFinal(&C,&P)) CloseAllToCooldown();
        else if(Ctx.HedgeDepth==3 && LowerReclaim(&C,LAdv(3)) && CloseRole(ROLE_H3)) Ctx.HedgeDepth=2;
        else if(Ctx.HedgeDepth==2 && LowerReclaim(&C,LAdv(2)) && CloseRole(ROLE_H2)) Ctx.HedgeDepth=1;
        else if(Ctx.HedgeDepth==1 && LowerReclaim(&C,LAdv(1)) && CloseRole(ROLE_H1)) { Ctx.HedgeDepth=0; Ctx.Mode=ST_LONG_RECOVERY; }
        else if(LongH3(&C,&P) && OpenHedge(0,3,HedgeRatio3)) Ctx.HedgeDepth=3;
        else if(LongH2(&C,&P) && OpenHedge(0,2,HedgeRatio2)) Ctx.HedgeDepth=2;
    }
    else if(Ctx.Mode==ST_SHORT_HEDGED) {
        Ctx.Holding++;
        if(PrimaryShortLots()<=0 || ShortEmergency(&C) || ShortFinal(&C,&P)) CloseAllToCooldown();
        else if(Ctx.HedgeDepth==3 && UpperReclaim(&C,SAdv(3)) && CloseRole(ROLE_H3)) Ctx.HedgeDepth=2;
        else if(Ctx.HedgeDepth==2 && UpperReclaim(&C,SAdv(2)) && CloseRole(ROLE_H2)) Ctx.HedgeDepth=1;
        else if(Ctx.HedgeDepth==1 && UpperReclaim(&C,SAdv(1)) && CloseRole(ROLE_H1)) { Ctx.HedgeDepth=0; Ctx.Mode=ST_SHORT_RECOVERY; }
        else if(ShortH3(&C,&P) && OpenHedge(1,3,HedgeRatio3)) Ctx.HedgeDepth=3;
        else if(ShortH2(&C,&P) && OpenHedge(1,2,HedgeRatio2)) Ctx.HedgeDepth=2;
    }
    else if(Ctx.Mode==ST_LONG_RECOVERY) {
        Ctx.Holding++;
        if(PrimaryLongLots()<=0 || LongEmergency(&C) || LongFinal(&C,&P)) CloseAllToCooldown();
        else if(AcceptUp(&C,&P,Ctx.Progress)||(C.C>C.Band[Ctx.Progress]&&C.BullReject)) Ctx.Mode=ST_LONG_ACTIVE;
        else if(LongH1(&C,&P)&&OpenHedge(0,1,HedgeRatio1)) { Ctx.HedgeDepth=1; Ctx.Mode=ST_LONG_HEDGED; }
    }
    else if(Ctx.Mode==ST_SHORT_RECOVERY) {
        Ctx.Holding++;
        if(PrimaryShortLots()<=0 || ShortEmergency(&C) || ShortFinal(&C,&P)) CloseAllToCooldown();
        else if(AcceptDown(&C,&P,Ctx.Progress)||(C.C<C.Band[Ctx.Progress]&&C.BearReject)) Ctx.Mode=ST_SHORT_ACTIVE;
        else if(ShortH1(&C,&P)&&OpenHedge(1,1,HedgeRatio1)) { Ctx.HedgeDepth=1; Ctx.Mode=ST_SHORT_HEDGED; }
    }
    else if(Ctx.Mode==ST_COOLDOWN) {
        if(Ctx.Cooldown>0) Ctx.Cooldown--;
        if(Ctx.Cooldown<=0) ResetContext();
    }
    else if(Ctx.Mode==ST_EMERGENCY || Ctx.Mode==ST_EXIT_PENDING) CloseAllToCooldown();
}

// -----------------------------------------------------------------------------
// Tick-reactive engine
// -----------------------------------------------------------------------------
void UpdateFormingCandle(var Price)
{
    DATE CurrentBar = floor(wdate()*24*60/BarPeriod)/(24*60./BarPeriod);
    if(FormingBarTime==0 || CurrentBar!=FormingBarTime) {
        FormingBarTime=CurrentBar;
        FormingOpen=FormingHigh=FormingLow=FormingClose=Price;
        FormingTickVolume=1;
    } else {
        FormingClose=Price;
        FormingHigh=max(FormingHigh,Price);
        FormingLow=min(FormingLow,Price);
        FormingTickVolume++;
    }
}

void UpdateHFTRateWindows(long NowMSValue)
{
    if(!HFTSecondWindowMS) HFTSecondWindowMS=NowMSValue;
    if(!HFTMinuteWindowMS) HFTMinuteWindowMS=NowMSValue;
    if(!HFTTickWindowMS) HFTTickWindowMS=NowMSValue;
    if(NowMSValue-HFTSecondWindowMS>=1000) { HFTEntriesSecond=0; HFTSecondWindowMS=NowMSValue; }
    if(NowMSValue-HFTMinuteWindowMS>=60000) { HFTEntriesMinute=0; HFTMinuteWindowMS=NowMSValue; }
    if(NowMSValue-HFTTickWindowMS>=1000) {
        HFTTicksLastSecond=HFTTicksCurrentSecond;
        HFTTicksCurrentSecond=0;
        HFTTickWindowMS=NowMSValue;
    }
    HFTTicksCurrentSecond++;
    int Key=CurrentDayKey();
    if(Key!=HFTDayKey) { HFTDayKey=Key; HFTDailyEntries=0; }
}

int HFTCooldownReady(int IsLong,int Band,long NowMSValue)
{
    long Last;
    if(IsLong)
        Last = HFTLastLongSignalMS[Band];
    else
        Last = HFTLastShortSignalMS[Band];
    return !Last || NowMSValue-Last>=HFTSignalCooldownMilliseconds;
}

void HFTMarkSignal(int IsLong,int Band,long NowMSValue)
{
    if(IsLong) HFTLastLongSignalMS[Band]=NowMSValue;
    else HFTLastShortSignalMS[Band]=NowMSValue;
}

int HFTLowerDominant(SNAPSHOT* S)
{
    return S->LWR>=HFTMinimumWickRatio && S->LW>=HFTMinimumWickDominance*max(S->UW,0.1*PIP) && S->BR>=HFTMinimumBodyRatio;
}
int HFTUpperDominant(SNAPSHOT* S)
{
    return S->UWR>=HFTMinimumWickRatio && S->UW>=HFTMinimumWickDominance*max(S->LW,0.1*PIP) && S->BR>=HFTMinimumBodyRatio;
}

int HFTCanEnter(int IsLong,long NowMSValue)
{
    if(Spread/PIP>HFTMaximumSpreadPoints) return 0;
    if(HFTMinimumTicksPerSecond>0 && HFTTicksLastSecond>0 && HFTTicksLastSecond<HFTMinimumTicksPerSecond) return 0;
    if(HFTMaximumDailyEntries>0 && HFTDailyEntries>=HFTMaximumDailyEntries) return 0;
    if(HFTMaximumEntriesPerSecond>0 && HFTEntriesSecond>=HFTMaximumEntriesPerSecond) return 0;
    if(HFTMaximumEntriesPerMinute>0 && HFTEntriesMinute>=HFTMaximumEntriesPerMinute) return 0;
    if(HFTLastEntryMS && NowMSValue-HFTLastEntryMS<HFTMinimumMillisecondsBetweenEntries) return 0;
    if(CountHFTTrades(0)>=HFTMaximumOpenPositions) return 0;
    if(IsLong && CountHFTTrades(1)>=HFTMaximumPositionsPerSide) return 0;
    if(!IsLong && CountHFTTrades(-1)>=HFTMaximumPositionsPerSide) return 0;
    if(!HFTAllowOppositePositions && CountHFTTrades(ifelse(IsLong,-1,1))>0) return 0;
    return 1;
}

var HFTEntryLots(int IsLong)
{
    if(HFTUseFixedLots) return HFTFixedLots;
    if(HFTStopLossPoints<=0 || PIPCost<=0) return HFTFixedLots;
    var RiskMoney=Balance*HFTRiskPercent/100.;
    return max(1,RiskMoney/(HFTStopLossPoints*PIPCost));
}

int HFTCostPass(int IsLong,int Band,SNAPSHOT* S,var Price)
{
    if(!HFTRequireCostEdge) return 1;
    int Target;
    if(IsLong)
        Target = min(Band+1,B_U3);
    else
        Target = max(Band-1,B_D3);
    var Edge=abs(S->Band[Target]-Price)/PIP;
    var Cost=max(Spread/PIP,1);
    return Edge>=HFTMinimumEdgeCostMultiple*Cost;
}

int HFTOpen(int IsLong,int Band,int Score,SNAPSHOT* S,long NowMSValue)
{
    if(!HFTCanEnter(IsLong,NowMSValue) || !HFTCooldownReady(IsLong,Band,NowMSValue) || !HFTCostPass(IsLong,Band,S,priceClose())) return 0;
    int Role;
    if(IsLong)
        Role = ROLE_HFT_LONG;
    else
        Role = ROLE_HFT_SHORT;
    TRADE* T=OpenTaggedTrade(IsLong,HFTEntryLots(IsLong),Role,Band,Score,NowMSValue);
    if(!T) return 0;
    HFTLastEntryMS=NowMSValue;
    HFTEntriesSecond++;
    HFTEntriesMinute++;
    HFTDailyEntries++;
    HFTEntryCounter++;
    HFTMarkSignal(IsLong,Band,NowMSValue);
    return 1;
}

int HFTLongScore(int Band,SNAPSHOT* S,var Price,var Delta,int ZoneNow)
{
    int Cross=HFTPrevPrice<=HFTPrevBand[Band] && Price>S->Band[Band];
    int Reclaim=S->L<S->Band[Band] && Price>S->Band[Band] && HFTLowerDominant(S);
    int ZoneEvent=HFTPrevZone>=0 && ZoneNow>HFTPrevZone && Cross;
    int Momentum=Delta>=HFTMinimumTickMomentumPoints;
    int Score=0;
    if(HFTEnableBandCrossEntries&&Cross) Score+=2;
    if(HFTEnableZoneTransitionEntries&&ZoneEvent) Score++;
    if(HFTEnableWickReclaimEntries&&Reclaim) Score+=2;
    if(HFTEnableMomentumEntries&&Momentum) Score++;
    if(HFTLowerDominant(S)) Score++;
    return Score;
}

int HFTShortScore(int Band,SNAPSHOT* S,var Price,var Delta,int ZoneNow)
{
    int Cross=HFTPrevPrice>=HFTPrevBand[Band] && Price<S->Band[Band];
    int Reclaim=S->H>S->Band[Band] && Price<S->Band[Band] && HFTUpperDominant(S);
    int ZoneEvent=HFTPrevZone>=0 && ZoneNow<HFTPrevZone && Cross;
    int Momentum=Delta<=-HFTMinimumTickMomentumPoints;
    int Score=0;
    if(HFTEnableBandCrossEntries&&Cross) Score+=2;
    if(HFTEnableZoneTransitionEntries&&ZoneEvent) Score++;
    if(HFTEnableWickReclaimEntries&&Reclaim) Score+=2;
    if(HFTEnableMomentumEntries&&Momentum) Score++;
    if(HFTUpperDominant(S)) Score++;
    return Score;
}

void ManageHFTPositions(SNAPSHOT* S,var Bid,var Ask,int OppositeLong,int OppositeShort,long NowMSValue)
{
    int Closed=0;
    for(open_trades) {
        int Role=(int)TradeVar[TV_ROLE];
        if(!IsHFTRole(Role) || Closed>=HFTMaximumClosuresPerTick) continue;
        int IsLong=TradeIsLong;
        int Band=(int)TradeVar[TV_BAND];
        long Age=NowMSValue-(long)TradeVar[TV_OPEN_MS];
        var Points;
        if(IsLong)
            Points = (Bid-TradePriceOpen)/PIP;
        else
            Points = (TradePriceOpen-Ask)/PIP;
        int Close=0;
        if(HFTTakeProfitPoints>0 && Points>=HFTTakeProfitPoints) Close=1;
        else if(HFTStopLossPoints>0 && Points<=-HFTStopLossPoints) Close=1;
        else if(HFTMaximumHoldingMilliseconds>0 && Age>=HFTMaximumHoldingMilliseconds) Close=1;
        else if(HFTUseAdjacentBandTargets && Band>=B_D3 && Band<=B_U3) {
            int Target;
            if(IsLong)
                Target = min(Band+1,B_U3);
            else
                Target = max(Band-1,B_D3);
            if((IsLong&&Bid>=S->Band[Target])||(!IsLong&&Ask<=S->Band[Target])) Close=1;
        }
        if(!Close && HFTCloseOnOppositeSignal && ((IsLong&&OppositeLong)||(!IsLong&&OppositeShort))) Close=1;
        if(Close) { exitTrade(ThisTrade); Closed++; HFTCloseCounter++; }
    }
}

void StoreHFTState(var Price,int ZoneNow,SNAPSHOT* S)
{
    HFTPrevPrice=Price;
    HFTPrevZone=ZoneNow;
    int B; for(B=0;B<7;B++) HFTPrevBand[B]=S->Band[B];
    HFTStateReady=1;
}

void ProcessHFTTick()
{
    if(!EnableTickReactiveHFT || !SeriesReady) return;
    long NowMSValue=NowMS();
    UpdateHFTRateWindows(NowMSValue);
    HFTTickCounter++;

    var Bid=priceClose();
    var Ask=Bid+Spread;
    UpdateFormingCandle(Bid);

    SNAPSHOT S;
    if(!MakeTickSnapshot(&S)) return;
    int ZoneNow=ZoneAt(Bid,&S);
    if(!HFTStateReady) { StoreHFTState(Bid,ZoneNow,&S); return; }

    var Delta=(Bid-HFTPrevPrice)/PIP;
    int OppositeLong=0,OppositeShort=0;
    int B;
    for(B=0;B<7;B++) {
        if(HFTPrevPrice>=HFTPrevBand[B] && Bid<S.Band[B]) OppositeLong=1;
        if(HFTPrevPrice<=HFTPrevBand[B] && Bid>S.Band[B]) OppositeShort=1;
    }

    ManageHFTPositions(&S,Bid,Ask,OppositeLong,OppositeShort,NowMSValue);

    int Opened=0;
    for(B=B_D3;B<=B_U3 && Opened<HFTMaximumEntriesPerTick;B++) {
        int Score=HFTLongScore(B,&S,Bid,Delta,ZoneNow);
        int Edge=(HFTPrevPrice<=HFTPrevBand[B]&&Bid>S.Band[B]) || (S.L<S.Band[B]&&Bid>S.Band[B]&&HFTLowerDominant(&S)) || (Delta>=HFTMinimumTickMomentumPoints&&ZoneNow>HFTPrevZone);
        if(EnableLong&&Edge&&Score>=HFTMinimumSignalScore&&HFTOpen(1,B,Score,&S,NowMSValue)) Opened++;
    }
    for(B=B_U3;B>=B_D3 && Opened<HFTMaximumEntriesPerTick;B--) {
        int Score=HFTShortScore(B,&S,Bid,Delta,ZoneNow);
        int Edge=(HFTPrevPrice>=HFTPrevBand[B]&&Bid<S.Band[B]) || (S.H>S.Band[B]&&Bid<S.Band[B]&&HFTUpperDominant(&S)) || (Delta<=-HFTMinimumTickMomentumPoints&&ZoneNow<HFTPrevZone);
        if(EnableShort&&Edge&&Score>=HFTMinimumSignalScore&&HFTOpen(0,B,Score,&S,NowMSValue)) Opened++;
    }
    StoreHFTState(Bid,ZoneNow,&S);
}

// Called by Zorro for every incoming tick when set(TICKS) is active.
void tick()
{
    ProcessHFTTick();
}

// Zorro's tock() cadence is approximately one second, not an MT5 millisecond
// timer. It is used only to force time-based HFT exits during sparse ticks.
void tock()
{
    if(!EnableTickReactiveHFT || !SeriesReady || FormingOpen<=0) return;
    SNAPSHOT S;
    if(!MakeTickSnapshot(&S)) return;
    var Bid=priceClose(), Ask=Bid+Spread;
    ManageHFTPositions(&S,Bid,Ask,0,0,NowMS());
}

void run()
{
    BarPeriod = 1;
    LookBack = max(AvgPeriod+10,100);
    set(PARAMETERS,LOGFILE,TICKS);
    Hedge = 2;                 // Permit simultaneous long and short trades.
    Fill = 0;                  // Broker/simulator-dependent immediate fill model.
    MaxLong = HFTMaximumOpenPositions + 10;
    MaxShort = HFTMaximumOpenPositions + 10;

    asset("US30");            // Change to the exact broker asset name.

    SOpen = series(priceOpen());
    SHigh = series(priceHigh());
    SLow = series(priceLow());
    SClose = series(priceClose());
    SVolume = series(marketVol());
    SeriesReady = 1;

    // Initialize the forming candle from the latest bar. tick() will then
    // update it with each incoming quote.
    if(FormingBarTime==0) {
        FormingBarTime=wdate();
        FormingOpen=priceOpen();
        FormingHigh=priceHigh();
        FormingLow=priceLow();
        FormingClose=priceClose();
        FormingTickVolume=max(marketVol(),1);
        ResetContext();
        HFTDayKey=CurrentDayKey();
    }

    if(EnableBarStateMachine) ProcessMacroBar();

    // Plot all seven bands from the current completed-bar snapshot.
    SNAPSHOT S;
    if(MakeBarSnapshot(0,&S)) {
        plot("U3",S.Band[B_U3],NEW,0x00AA00);
        plot("U2",S.Band[B_U2],0,0x00CC00);
        plot("U1",S.Band[B_U1],0,0x00EE00);
        plot("M", S.Band[B_M], 0,0xAAAAAA);
        plot("D1",S.Band[B_D1],0,0xCCAA66);
        plot("D2",S.Band[B_D2],0,0xCC8844);
        plot("D3",S.Band[B_D3],0,0xCC6622);
    }
}

Last edited by TipmyPip; Yesterday at 23:01.