Advertisement IC Markets

Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Optimize MetaTrader 4, MetaTrader 5, cTrader, and TradingView for speed. Discuss Level II Market Depth (DOM), custom hotkeys, and volume indicators.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

Hi traders,

i would like to share with you one of my favorite setup.
I love Fibonacci and Fibonacci retracement, especially in longer term charts like H4 and D1.

Here is the complete, single-file MQL4 source code combining the Volume-Weighted OTE setup, the in-memory dynamic Fibonacci calculation, and the real-time ATR trailing stop.
You can copy and paste this directly into MT4's MetaEditor (F4), compile it, and attach it to your chart.

Code: Select all

//+------------------------------------------------------------------+
//|                                     VolumeWeightedOTE_EA.mq4     |
//|                                     Dynamic Fib OTE + MFI Scalper|
//+------------------------------------------------------------------+
#property copyright "Forex Scalping EA"
#property link      ""
#property version   "1.00"
#property strict

//--- General Inputs
input double LotSize          = 0.1;
input int    Slippage         = 3;
input int    MagicNumber      = 888888;

//--- Indicator Inputs
input int    SwingLookback    = 40;     // Bars scanned for dynamic impulse swing
input int    EmaPeriod        = 200;    // Macro trend filter
input int    MfiPeriod        = 3;      // Fast tick volume tracking
input double StopLossBuffer   = 2.0;    // Initial SL buffer in pips beyond swing high/low

//--- Trailing Stop Inputs
input bool   UseAtrTrailing   = true;   // Enable ATR Trailing Stop
input int    AtrPeriod        = 14;     // ATR calculation period
input double AtrMultiplier     = 2.0;    // Multiplier for trailing distance

//--- Global Variables
datetime lastBarTime = 0;
double   Pips;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // Standardize pip values for 4-digit and 5-digit brokers
    Pips = Point;
    if(Digits == 3 || Digits == 5) Pips = Point * 10;

    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 1. Manage existing trades on EVERY tick (Dynamic ATR Trailing)
    ManageTrailingStop();

    // 2. Bar Close Lock: Pause entry execution until the current candle closes
    if(Time[0] == lastBarTime) return; 

    // 3. Fetch Indicator Data from the last completed bar (shift = 1)
    double ema200_1 = iMA(NULL, 0, EmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    double mfi1     = iMFI(NULL, 0, MfiPeriod, 1);
    double mfi2     = iMFI(NULL, 0, MfiPeriod, 2);

    // 4. Locate Dynamic Swing High and Low over the Lookback Window
    int highestIndex = iHighest(NULL, 0, MODE_HIGH, SwingLookback, 1);
    int lowestIndex  = iLowest(NULL, 0, MODE_LOW, SwingLookback, 1);
    
    double swingHigh = High[highestIndex];
    double swingLow  = Low[lowestIndex];
    double swingRange= swingHigh - swingLow;

    if(swingRange == 0) return; // Prevent division by zero if market is dead flat

    // Setup Flags
    bool isBuySetup  = false;
    bool isSellSetup = false;
    
    double initialSL = 0;
    double initialTP = 0;

    // --- BUY SETUP EVALUATION ---
    // Rule A: Macro Uptrend (Price > 200 EMA)
    // Rule B: Valid upward impulse leg (Lowest low formed BEFORE Highest high in history)
    if(Close[1] > ema200_1 && lowestIndex > highestIndex)
    {
        double fib618 = swingHigh - (swingRange * 0.618);
        double fib786 = swingHigh - (swingRange * 0.786);
        
        // Rule C: Price retraced into the Optimal Trade Entry (OTE) Kill Zone
        bool inKillZone = (Close[1] <= fib618) && (Close[1] >= fib786);
        
        // Rule D: Volume Exhaustion (MFI dipped below 20 and turned back up)
        bool mfiTrigger = (mfi2 <= 20) && (mfi1 > 20);

        if(inKillZone && mfiTrigger)
        {
            isBuySetup = true;
            initialSL  = swingLow - (StopLossBuffer * Pips); 
            initialTP  = swingHigh; // Primary target at impulse high
        }
    }

    // --- SELL SETUP EVALUATION ---
    // Rule A: Macro Downtrend (Price < 200 EMA)
    // Rule B: Valid downward impulse leg (Highest high formed BEFORE Lowest low in history)
    if(Close[1] < ema200_1 && highestIndex > lowestIndex)
    {
        double fib618 = swingLow + (swingRange * 0.618);
        double fib786 = swingLow + (swingRange * 0.786);
        
        // Rule C: Price retraced into the Optimal Trade Entry (OTE) Kill Zone
        bool inKillZone = (Close[1] >= fib618) && (Close[1] <= fib786);
        
        // Rule D: Volume Exhaustion (MFI spiked above 80 and turned back down)
        bool mfiTrigger = (mfi2 >= 80) && (mfi1 < 80);

        if(inKillZone && mfiTrigger)
        {
            isSellSetup = true;
            initialSL   = swingHigh + (StopLossBuffer * Pips);
            initialTP   = swingLow; // Primary target at impulse low
        }
    }

    // 5. Order Execution Engine
    if(CountOpenPositions() == 0) 
    {
        if(isBuySetup)
        {
            int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, Slippage, initialSL, initialTP, "OTE-MFI-Buy", MagicNumber, 0, clrDodgerBlue);
            if(ticket > 0) lastBarTime = Time[0];
        }
        else if(isSellSetup)
        {
            int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, Slippage, initialSL, initialTP, "OTE-MFI-Sell", MagicNumber, 0, clrCrimson);
            if(ticket > 0) lastBarTime = Time[0];
        }
    }
}

//+------------------------------------------------------------------+
//| Helper: Dynamic ATR Trailing Stop Engine                         |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
    if(!UseAtrTrailing) return;
    
    // Calculate ATR distance from closed bar
    double atr = iATR(NULL, 0, AtrPeriod, 1); 
    double trailDistance = atr * AtrMultiplier;
    
    // Respect broker minimum stop level distance
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;

    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                if(OrderType() == OP_BUY)
                {
                    double newSL = NormalizeDouble(Bid - trailDistance, Digits);
                    
                    // Trail up only when new SL is higher than current SL
                    if(newSL > OrderStopLoss() || OrderStopLoss() == 0)
                    {
                        if((Bid - newSL) >= stopLevel)
                        {
                            bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
                        }
                    }
                }
                else if(OrderType() == OP_SELL)
                {
                    double newSL = NormalizeDouble(Ask + trailDistance, Digits);
                    
                    // Trail down only when new SL is lower than current SL
                    if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
                    {
                        if((newSL - Ask) >= stopLevel)
                        {
                            bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrRed);
                        }
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Helper: Count open positions belonging to this Magic Number      |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                count++;
            }
        }
    }
    return count;
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

Do you like it? Or do you use slightly different setup? You can share with us :-)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

I rechecked that code, it is nice and clean.
But i decided to extend it to higher level.

Here is what I upgraded to make this professional-grade:

1.) Broker Server Protection (Trailing Stop Spam):

Your original trailing stop modified the order on every single tick if the ATR changed slightly. This will get you blocked by a broker (Error 1: ERR_NO_RESULT). I added a minimum step threshold so it only modifies when the stop moves a meaningful distance.

2.) Dynamic Money Management:

Hardcoded lots are fine for testing, but pros scale risk. I added an auto-lot sizing module based on your account balance and the dynamic stop-loss distance.

3.) Execution Safety & Error Logging:

Added GetLastError() checks. If a trade fails, you will now know exactly why in the journal.

4.) Slippage & StopLevel Standardization:

Handled 4-digit and 5-digit broker point conversions properly, and added logic to push the SL/TP out if they fall inside the broker's minimum STOPLEVEL.

5.) Modular Architecture:

Broke the logic into cleaner IsNewBar(), ManageEntry(), and CalculateLotSize() functions for easier maintenance.

Here is your upgraded, professional-level EA:

Code: Select all

//+------------------------------------------------------------------+
//|                                     VolumeWeightedOTE_EA_Pro.mq4 |
//|                                     Dynamic Fib OTE + MFI Scalper|
//+------------------------------------------------------------------+
#property copyright "Forex Scalping EA - Pro Version"
#property link      ""
#property version   "2.00"
#property strict

//--- Group: Money Management
input bool   UseDynamicRisk   = true;     // Use % Risk instead of Fixed Lots
input double RiskPercent      = 1.0;      // Risk % per trade
input double FixedLotSize     = 0.1;      // Fixed Lot Size (if Dynamic is false)

//--- Group: Trade Settings
input int    MaxSlippagePips  = 3;        // Maximum Slippage in Pips
input int    MagicNumber      = 888888;
input string TradeComment     = "OTE_MFI";

//--- Group: Indicator Inputs
input int    SwingLookback    = 40;     // Bars scanned for dynamic impulse swing
input int    EmaPeriod        = 200;    // Macro trend filter
input int    MfiPeriod        = 3;      // Fast tick volume tracking
input double StopLossBuffer   = 2.0;    // SL buffer in pips beyond swing high/low

//--- Group: Trailing Stop
input bool   UseAtrTrailing   = true;   // Enable ATR Trailing Stop
input int    AtrPeriod        = 14;     // ATR calculation period
input double AtrMultiplier    = 2.0;    // Multiplier for trailing distance
input double TrailStepPips    = 1.0;    // Min movement in pips before modifying SL

//--- Global Variables
double Pips;
int    SlippagePoints;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // Standardize pip values for 4-digit and 5-digit brokers
    Pips = Point;
    SlippagePoints = MaxSlippagePips;
    
    if(Digits == 3 || Digits == 5) 
    {
        Pips = Point * 10;
        SlippagePoints = MaxSlippagePips * 10;
    }

    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 1. Manage existing trades on EVERY tick (Dynamic ATR Trailing)
    ManageTrailingStop();

    // 2. Bar Close Lock: Pause entry execution until the current candle closes
    if(!IsNewBar()) return; 

    // 3. Scan for Entries if we have no open positions
    if(CountOpenPositions() == 0)
    {
        ScanForEntries();
    }
}

//+------------------------------------------------------------------+
//| Core Entry Logic                                                 |
//+------------------------------------------------------------------+
void ScanForEntries()
{
    double ema200_1 = iMA(Symbol(), 0, EmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    double mfi1     = iMFI(Symbol(), 0, MfiPeriod, 1);
    double mfi2     = iMFI(Symbol(), 0, MfiPeriod, 2);

    int highestIndex = iHighest(Symbol(), 0, MODE_HIGH, SwingLookback, 1);
    int lowestIndex  = iLowest(Symbol(), 0, MODE_LOW, SwingLookback, 1);
    
    double swingHigh = High[highestIndex];
    double swingLow  = Low[lowestIndex];
    double swingRange = swingHigh - swingLow;

    if(swingRange == 0) return; // Prevent division by zero

    double initialSL = 0, initialTP = 0;
    int orderType = -1;

    // --- BUY SETUP ---
    if(Close[1] > ema200_1 && lowestIndex > highestIndex)
    {
        double fib618 = swingHigh - (swingRange * 0.618);
        double fib786 = swingHigh - (swingRange * 0.786);
        
        bool inKillZone = (Close[1] <= fib618) && (Close[1] >= fib786);
        bool mfiTrigger = (mfi2 <= 20) && (mfi1 > 20);

        if(inKillZone && mfiTrigger)
        {
            orderType = OP_BUY;
            initialSL = swingLow - (StopLossBuffer * Pips); 
            initialTP = swingHigh; 
        }
    }
    // --- SELL SETUP ---
    else if(Close[1] < ema200_1 && highestIndex > lowestIndex)
    {
        double fib618 = swingLow + (swingRange * 0.618);
        double fib786 = swingLow + (swingRange * 0.786);
        
        bool inKillZone = (Close[1] >= fib618) && (Close[1] <= fib786);
        bool mfiTrigger = (mfi2 >= 80) && (mfi1 < 80);

        if(inKillZone && mfiTrigger)
        {
            orderType = OP_SELL;
            initialSL = swingHigh + (StopLossBuffer * Pips);
            initialTP = swingLow; 
        }
    }

    // --- EXECUTION ENGINE ---
    if(orderType != -1)
    {
        double price = (orderType == OP_BUY) ? Ask : Bid;
        
        // Ensure SL is legal by broker standards
        initialSL = AdjustToStopLevel(orderType, price, initialSL);
        
        // Calculate dynamic lot size based on SL distance
        double slDistance = MathAbs(price - initialSL) / Pips;
        double lotSize = CalculateLotSize(slDistance);
        
        color arrowColor = (orderType == OP_BUY) ? clrDodgerBlue : clrCrimson;
        
        int ticket = OrderSend(Symbol(), orderType, lotSize, price, SlippagePoints, initialSL, initialTP, TradeComment, MagicNumber, 0, arrowColor);
        
        if(ticket < 0)
            Print("OrderSend Failed. Error: ", GetLastError());
        else
            Print("Successfully entered trade. Ticket: ", ticket);
    }
}

//+------------------------------------------------------------------+
//| Dynamic ATR Trailing Stop Engine (Server-Safe)                   |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
    if(!UseAtrTrailing) return;
    
    double atr = iATR(Symbol(), 0, AtrPeriod, 1); 
    double trailDistance = atr * AtrMultiplier;
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    double minStep = TrailStepPips * Pips; // Prevents server spam

    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                double currentSL = OrderStopLoss();
                
                if(OrderType() == OP_BUY)
                {
                    double newSL = NormalizeDouble(Bid - trailDistance, Digits);
                    
                    // Trail up only if new SL is higher AND passes the min step filter
                    if(newSL > currentSL + minStep || currentSL == 0)
                    {
                        if((Bid - newSL) >= stopLevel)
                        {
                            if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue))
                                Print("Trail Stop Modify Failed. Error: ", GetLastError());
                        }
                    }
                }
                else if(OrderType() == OP_SELL)
                {
                    double newSL = NormalizeDouble(Ask + trailDistance, Digits);
                    
                    // Trail down only if new SL is lower AND passes the min step filter
                    if(newSL < currentSL - minStep || currentSL == 0)
                    {
                        if((newSL - Ask) >= stopLevel)
                        {
                            if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrRed))
                                Print("Trail Stop Modify Failed. Error: ", GetLastError());
                        }
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Helper: Calculate Dynamic Lot Size based on Risk %               |
//+------------------------------------------------------------------+
double CalculateLotSize(double slPips)
{
    if(!UseDynamicRisk || slPips <= 0) return FixedLotSize;

    double riskAmount = AccountBalance() * (RiskPercent / 100.0);
    double tickValue  = MarketInfo(Symbol(), MODE_TICKVALUE);
    double lotStep    = MarketInfo(Symbol(), MODE_LOTSTEP);
    double minLot     = MarketInfo(Symbol(), MODE_MINLOT);
    double maxLot     = MarketInfo(Symbol(), MODE_MAXLOT);

    if(tickValue == 0) return FixedLotSize; // Failsafe

    // Calculate Raw Lots (assumes ticksize == point, which is standard)
    double rawLot = riskAmount / (slPips * tickValue * (Pips / Point));
    
    // Normalize to broker lot step
    double finalLot = MathFloor(rawLot / lotStep) * lotStep;

    // Clamp to broker limits
    if(finalLot < minLot) finalLot = minLot;
    if(finalLot > maxLot) finalLot = maxLot;

    return NormalizeDouble(finalLot, 2);
}

//+------------------------------------------------------------------+
//| Helper: Adjust StopLoss to comply with Broker StopLevel          |
//+------------------------------------------------------------------+
double AdjustToStopLevel(int type, double openPrice, double slPrice)
{
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    
    if(type == OP_BUY)
    {
        if(openPrice - slPrice < stopLevel) 
            return NormalizeDouble(openPrice - stopLevel, Digits);
    }
    else if(type == OP_SELL)
    {
        if(slPrice - openPrice < stopLevel) 
            return NormalizeDouble(openPrice + stopLevel, Digits);
    }
    
    return NormalizeDouble(slPrice, Digits);
}

//+------------------------------------------------------------------+
//| Helper: Check for a new bar                                      |
//+------------------------------------------------------------------+
bool IsNewBar()
{
    static datetime lastBarTime = 0;
    datetime currentBarTime = iTime(Symbol(), 0, 0);
    
    if(lastBarTime != currentBarTime)
    {
        lastBarTime = currentBarTime;
        return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| Helper: Count open positions                                     |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
                count++;
        }
    }
    return count;
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

And if you make it even better, i prepared V3.

To take this from a "Pro-Level" EA to an Institutional-Grade algorithmic system, we need to address the environment and the psychology of the trade. Professional systems don't just manage risk on entry; they actively scale out of risk as the trade progresses, and they protect themselves from poor market conditions.

Here are the four advanced mechanisms I have added to this version (v3.00):

Partial Profit Taking (Scale-Out):

Automatically closes a percentage of your position (e.g., 50%) when it reaches a predefined profit target in pips. This secures capital while letting the "runner" catch the macro trend.

Auto Break-Even (Risk Free):

Once the trade reaches a profit threshold, the EA instantly moves the Stop Loss to your Entry Price + a small locked-in profit to cover commissions.

Spread Protection Filter:

Prevents the EA from executing trades during extreme market volatility or rollover periods when brokers artificially widen the spread.

Session Time Filters:

Confines trading to high-liquidity windows (e.g., London and New York sessions) to avoid false breakouts in dead Asian session hours.

Here is your ultimate v3.00 source code:

Code: Select all

//+------------------------------------------------------------------+
//|                                     VolumeWeightedOTE_EA_v3.mq4  |
//|                                     Institutional OTE Scalper    |
//+------------------------------------------------------------------+
#property copyright "Forex Scalping EA - Institutional Version"
#property link      ""
#property version   "3.00"
#property strict

//--- Group: Money Management
input bool   UseDynamicRisk    = true;     // Use % Risk instead of Fixed Lots
input double RiskPercent       = 1.0;      // Risk % per trade
input double FixedLotSize      = 0.1;      // Fixed Lot Size (if Dynamic is false)

//--- Group: Advanced Risk Exits (New)
input bool   UsePartialClose   = true;     // Enable scaling out (Partial Close)
input double PartialTargetPips = 15.0;     // Pips in profit to trigger partial close
input double PartialClosePct   = 50.0;     // % of lots to close (e.g., 50 for half)
input bool   UseBreakEven      = true;     // Move SL to entry at target
input double BreakEvenPips     = 10.0;     // Pips in profit to trigger BE
input double LockInPips        = 1.0;      // Pips to lock in when moving to BE

//--- Group: Environment Filters (New)
input double MaxSpreadPips     = 2.0;      // Max allowable spread to enter trade
input int    StartTradingHour  = 8;        // Start trading (Broker Server Time)
input int    EndTradingHour    = 20;       // Stop trading (Broker Server Time)

//--- Group: Trade Settings
input int    MaxSlippagePips   = 3;        
input int    MagicNumber       = 888888;
input string TradeComment      = "OTE_MFI";

//--- Group: Indicator Inputs
input int    SwingLookback     = 40;     
input int    EmaPeriod         = 200;    
input int    MfiPeriod         = 3;      
input double StopLossBuffer    = 2.0;    

//--- Group: Trailing Stop
input bool   UseAtrTrailing    = true;   
input int    AtrPeriod         = 14;     
input double AtrMultiplier     = 2.0;    
input double TrailStepPips     = 1.0;    

//--- Global Variables
double Pips;
int    SlippagePoints;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    Pips = Point;
    SlippagePoints = MaxSlippagePips;
    
    if(Digits == 3 || Digits == 5) 
    {
        Pips = Point * 10;
        SlippagePoints = MaxSlippagePips * 10;
    }
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 1. Manage Active Trades (Trailing, Break-Even, Partial Closes)
    ManageAdvancedExits();
    ManageTrailingStop();

    // 2. Filter: Only run entry logic on a new bar
    if(!IsNewBar()) return; 

    // 3. Filter: Check Trading Hours and Max Spread before scanning
    if(!IsTradingHour()) return;
    if((MarketInfo(Symbol(), MODE_SPREAD) * Point) > (MaxSpreadPips * Pips)) return;

    // 4. Scan for Entries if we have no open positions
    if(CountOpenPositions() == 0)
    {
        ScanForEntries();
    }
}

//+------------------------------------------------------------------+
//| Advanced Exits: Partial Profit & Break Even                      |
//+------------------------------------------------------------------+
void ManageAdvancedExits()
{
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;

    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                double profitPips = 0;
                double openPrice  = OrderOpenPrice();
                double currentSL  = OrderStopLoss();
                int    type       = OrderType();
                
                if(type == OP_BUY)  profitPips = (Bid - openPrice) / Pips;
                if(type == OP_SELL) profitPips = (openPrice - Ask) / Pips;

                // --- BREAK EVEN LOGIC ---
                if(UseBreakEven && profitPips >= BreakEvenPips)
                {
                    double newBE = 0;
                    if(type == OP_BUY)
                    {
                        newBE = openPrice + (LockInPips * Pips);
                        if(currentSL < newBE && (Bid - newBE) >= stopLevel)
                            OrderModify(OrderTicket(), openPrice, NormalizeDouble(newBE, Digits), OrderTakeProfit(), 0, clrGreen);
                    }
                    else if(type == OP_SELL)
                    {
                        newBE = openPrice - (LockInPips * Pips);
                        if((currentSL > newBE || currentSL == 0) && (newBE - Ask) >= stopLevel)
                            OrderModify(OrderTicket(), openPrice, NormalizeDouble(newBE, Digits), OrderTakeProfit(), 0, clrGreen);
                    }
                }

                // --- PARTIAL CLOSE LOGIC ---
                if(UsePartialClose && profitPips >= PartialTargetPips)
                {
                    // MT4 adds "to #ticket" / "from #ticket" to comments on partial close. 
                    // We check this to ensure we only partially close the order ONCE.
                    if(StringFind(OrderComment(), "from #") == -1 && StringFind(OrderComment(), "to #") == -1)
                    {
                        double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
                        double lotsToClose = OrderLots() * (PartialClosePct / 100.0);
                        lotsToClose = MathFloor(lotsToClose / lotStep) * lotStep; // Normalize to broker steps
                        
                        double minLot = MarketInfo(Symbol(), MODE_MINLOT);
                        if(lotsToClose >= minLot && lotsToClose < OrderLots())
                        {
                            double closePrice = (type == OP_BUY) ? Bid : Ask;
                            color  closeColor = (type == OP_BUY) ? clrBlue : clrRed;
                            
                            if(OrderClose(OrderTicket(), lotsToClose, closePrice, SlippagePoints, closeColor))
                                Print("Partial profit taken successfully. Ticket: ", OrderTicket());
                        }
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Core Entry Logic                                                 |
//+------------------------------------------------------------------+
void ScanForEntries()
{
    double ema200_1 = iMA(Symbol(), 0, EmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    double mfi1     = iMFI(Symbol(), 0, MfiPeriod, 1);
    double mfi2     = iMFI(Symbol(), 0, MfiPeriod, 2);

    int highestIndex = iHighest(Symbol(), 0, MODE_HIGH, SwingLookback, 1);
    int lowestIndex  = iLowest(Symbol(), 0, MODE_LOW, SwingLookback, 1);
    
    double swingHigh = High[highestIndex];
    double swingLow  = Low[lowestIndex];
    double swingRange = swingHigh - swingLow;

    if(swingRange == 0) return; 

    double initialSL = 0, initialTP = 0;
    int orderType = -1;

    // BUY SETUP
    if(Close[1] > ema200_1 && lowestIndex > highestIndex)
    {
        double fib618 = swingHigh - (swingRange * 0.618);
        double fib786 = swingHigh - (swingRange * 0.786);
        
        if((Close[1] <= fib618) && (Close[1] >= fib786) && (mfi2 <= 20) && (mfi1 > 20))
        {
            orderType = OP_BUY;
            initialSL = swingLow - (StopLossBuffer * Pips); 
            initialTP = swingHigh; 
        }
    }
    // SELL SETUP
    else if(Close[1] < ema200_1 && highestIndex > lowestIndex)
    {
        double fib618 = swingLow + (swingRange * 0.618);
        double fib786 = swingLow + (swingRange * 0.786);
        
        if((Close[1] >= fib618) && (Close[1] <= fib786) && (mfi2 >= 80) && (mfi1 < 80))
        {
            orderType = OP_SELL;
            initialSL = swingHigh + (StopLossBuffer * Pips);
            initialTP = swingLow; 
        }
    }

    // EXECUTION
    if(orderType != -1)
    {
        double price = (orderType == OP_BUY) ? Ask : Bid;
        initialSL = AdjustToStopLevel(orderType, price, initialSL);
        
        double slDistance = MathAbs(price - initialSL) / Pips;
        double lotSize = CalculateLotSize(slDistance);
        
        color arrowColor = (orderType == OP_BUY) ? clrDodgerBlue : clrCrimson;
        
        int ticket = OrderSend(Symbol(), orderType, lotSize, price, SlippagePoints, initialSL, initialTP, TradeComment, MagicNumber, 0, arrowColor);
        if(ticket < 0) Print("OrderSend Failed. Error: ", GetLastError());
    }
}

//+------------------------------------------------------------------+
//| Dynamic ATR Trailing Stop Engine                                 |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
    if(!UseAtrTrailing) return;
    
    double atr = iATR(Symbol(), 0, AtrPeriod, 1); 
    double trailDistance = atr * AtrMultiplier;
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    double minStep = TrailStepPips * Pips; 

    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                double currentSL = OrderStopLoss();
                
                if(OrderType() == OP_BUY)
                {
                    double newSL = NormalizeDouble(Bid - trailDistance, Digits);
                    if(newSL > currentSL + minStep || currentSL == 0)
                    {
                        if((Bid - newSL) >= stopLevel)
                            OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
                    }
                }
                else if(OrderType() == OP_SELL)
                {
                    double newSL = NormalizeDouble(Ask + trailDistance, Digits);
                    if(newSL < currentSL - minStep || currentSL == 0)
                    {
                        if((newSL - Ask) >= stopLevel)
                            OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrRed);
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Helper: Check Trading Session                                    |
//+------------------------------------------------------------------+
bool IsTradingHour()
{
    int h = Hour();
    if(StartTradingHour < EndTradingHour) 
        return (h >= StartTradingHour && h < EndTradingHour);
    else if (StartTradingHour > EndTradingHour) // Handles overnight (e.g., 22 to 04)
        return (h >= StartTradingHour || h < EndTradingHour);
    
    return true; // If equal, trade 24 hours
}

//+------------------------------------------------------------------+
//| Helper: Calculate Dynamic Lot Size based on Risk %               |
//+------------------------------------------------------------------+
double CalculateLotSize(double slPips)
{
    if(!UseDynamicRisk || slPips <= 0) return FixedLotSize;

    double riskAmount = AccountBalance() * (RiskPercent / 100.0);
    double tickValue  = MarketInfo(Symbol(), MODE_TICKVALUE);
    double lotStep    = MarketInfo(Symbol(), MODE_LOTSTEP);
    
    if(tickValue == 0) return FixedLotSize; 

    double rawLot = riskAmount / (slPips * tickValue * (Pips / Point));
    double finalLot = MathFloor(rawLot / lotStep) * lotStep;

    if(finalLot < MarketInfo(Symbol(), MODE_MINLOT)) finalLot = MarketInfo(Symbol(), MODE_MINLOT);
    if(finalLot > MarketInfo(Symbol(), MODE_MAXLOT)) finalLot = MarketInfo(Symbol(), MODE_MAXLOT);

    return NormalizeDouble(finalLot, 2);
}

//+------------------------------------------------------------------+
//| Helper: Adjust StopLoss to comply with Broker StopLevel          |
//+------------------------------------------------------------------+
double AdjustToStopLevel(int type, double openPrice, double slPrice)
{
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    if(type == OP_BUY && openPrice - slPrice < stopLevel) return NormalizeDouble(openPrice - stopLevel, Digits);
    if(type == OP_SELL && slPrice - openPrice < stopLevel) return NormalizeDouble(openPrice + stopLevel, Digits);
    return NormalizeDouble(slPrice, Digits);
}

//+------------------------------------------------------------------+
//| Helper: Check for a new bar                                      |
//+------------------------------------------------------------------+
bool IsNewBar()
{
    static datetime lastBarTime = 0;
    datetime currentBarTime = iTime(Symbol(), 0, 0);
    if(lastBarTime != currentBarTime)
    {
        lastBarTime = currentBarTime;
        return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| Helper: Count open positions                                     |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) count++;
        }
    }
    return count;
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
LondonScalper
Posts: 770
Joined: Sat Sep 05, 2026 7:54 am

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by LondonScalper »

PTScalper wrote:complete, single-file MQL4 source code combining the Volume-Weighted OTE setup... dynamic Fibonacci... ATR trailing stop
Sharing full code is generous. A London caution before anyone pastes it into live: treat indicators and EAs as decision support, not autopilot — especially anything combining Fib OTE, volume weighting, and ATR trail on M1.

Fib clusters are sensitive to which swing anchors you feed them; volume-weighted twists can look precise while still being arbitrary on FX (no central volume). ATR trails help lock gains but also exit you on routine London noise if the multiple is tight.

Before size: forward-test on demo with your real spread, log whether the trail or the Fib logic is actually responsible for results, and keep discretionary veto for news. Code quality ≠ edge.

Useful if you later post a simple rules card: when you ignore the signal.

What timeframe are the Fib anchors taken from versus the execution chart?
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

LondonScalper wrote: Sun Sep 13, 2026 5:28 pm
PTScalper wrote:complete, single-file MQL4 source code combining the Volume-Weighted OTE setup... dynamic Fibonacci... ATR trailing stop
Sharing full code is generous. A London caution before anyone pastes it into live: treat indicators and EAs as decision support, not autopilot — especially anything combining Fib OTE, volume weighting, and ATR trail on M1.

Fib clusters are sensitive to which swing anchors you feed them; volume-weighted twists can look precise while still being arbitrary on FX (no central volume). ATR trails help lock gains but also exit you on routine London noise if the multiple is tight.

Before size: forward-test on demo with your real spread, log whether the trail or the Fib logic is actually responsible for results, and keep discretionary veto for news. Code quality ≠ edge.

Useful if you later post a simple rules card: when you ignore the signal.

What timeframe are the Fib anchors taken from versus the execution chart?
Hi LondonScalper,

thank you for your feedback.
You are welcome, you can test it as you want.

Plus i prepared another versions in PineScript, MQL5 and for Ctrader as well.

Have a great trades.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

This script calculates the dynamic swing highs/lows, draws the 61.8% to 78.6% Fibonacci OTE (Optimal Trade Entry) zones, anchors a VWAP to the start of the retracement for volume confluence, and manages the trade using a real-time ATR trailing stop.

The Pine Script Setup
Open TradingView, go to the Pine Editor at the bottom, clear any existing code, and paste this in:

Code: Select all

//@version=5
strategy("Volume-Weighted OTE & ATR Trailing Stop", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)

// =========================================================================
// 1. INPUTS
// =========================================================================
grp_fib = "Fibonacci OTE Settings"
pivot_left = input.int(15, "Pivot Left Lookback", group=grp_fib)
pivot_right = input.int(15, "Pivot Right Lookback", group=grp_fib)
fib_upper = input.float(0.618, "OTE Upper Bound", group=grp_fib)
fib_lower = input.float(0.786, "OTE Lower Bound", group=grp_fib)

grp_stop = "ATR Trailing Stop Settings"
atr_length = input.int(14, "ATR Length", group=grp_stop)
atr_mult = input.float(2.0, "ATR Multiplier", step=0.1, group=grp_stop)

// =========================================================================
// 2. DYNAMIC PIVOTS & SWING TRACKING
// =========================================================================
ph = ta.pivothigh(high, pivot_left, pivot_right)
pl = ta.pivotlow(low, pivot_left, pivot_right)

var float swing_h = na
var float swing_l = na
var int swing_h_bar = na
var int swing_l_bar = na
var int swing_dir = 0 // 1 = Uptrend (Buy Dip), -1 = Downtrend (Sell Rally)

if not na(ph)
    swing_h := ph
    swing_h_bar := bar_index - pivot_right
    if not na(swing_l) and swing_h_bar > swing_l_bar
        swing_dir := 1 

if not na(pl)
    swing_l := pl
    swing_l_bar := bar_index - pivot_right
    if not na(swing_h) and swing_l_bar > swing_h_bar
        swing_dir := -1 

// Fibonacci Zone Math
float swing_range = swing_h - swing_l
float ote_long_upper = swing_h - (swing_range * fib_upper)
float ote_long_lower = swing_h - (swing_range * fib_lower)

float ote_short_lower = swing_l + (swing_range * fib_upper)
float ote_short_upper = swing_l + (swing_range * fib_lower)

// =========================================================================
// 3. VOLUME-WEIGHTED CONFLUENCE (RETROSPECTIVE ANCHORED VWAP)
// =========================================================================
var float cum_vol = 0.0
var float cum_src_vol = 0.0
cum_vol += volume
cum_src_vol += hlc3 * volume

var float anchor_vol = 0.0
var float anchor_src_vol = 0.0

if not na(ph) and swing_dir == 1
    // Uptrend swing finished. Anchor VWAP to the Swing High (start of the dip)
    anchor_vol := cum_vol[pivot_right + 1]
    anchor_src_vol := cum_src_vol[pivot_right + 1]

if not na(pl) and swing_dir == -1
    // Downtrend swing finished. Anchor VWAP to the Swing Low (start of the rally)
    anchor_vol := cum_vol[pivot_right + 1]
    anchor_src_vol := cum_src_vol[pivot_right + 1]

float avwap = (cum_vol - anchor_vol) > 0 ? (cum_src_vol - anchor_src_vol) / (cum_vol - anchor_vol) : na
plot(avwap, "Anchored VWAP", color=color.new(color.blue, 0), linewidth=2)

// =========================================================================
// 4. VISUALIZING THE OTE ZONE
// =========================================================================
var box ote_box = na
var line swing_line = na

if not na(ph) or not na(pl)
    box.delete(ote_box)
    line.delete(swing_line)

    if swing_dir == 1
        ote_box := box.new(left=swing_h_bar, top=ote_long_upper, right=bar_index, bottom=ote_long_lower, border_color=color.new(color.teal, 30), bgcolor=color.new(color.teal, 85), extend=extend.right)
        swing_line := line.new(x1=swing_l_bar, y1=swing_l, x2=swing_h_bar, y2=swing_h, color=color.gray, style=line.style_dashed)
    else if swing_dir == -1
        ote_box := box.new(left=swing_l_bar, top=ote_short_upper, right=bar_index, bottom=ote_short_lower, border_color=color.new(color.orange, 30), bgcolor=color.new(color.orange, 85), extend=extend.right)
        swing_line := line.new(x1=swing_h_bar, y1=swing_h, x2=swing_l_bar, y2=swing_l, color=color.gray, style=line.style_dashed)

// =========================================================================
// 5. ENTRY LOGIC
// =========================================================================
var bool visited_ote_long = false
var bool visited_ote_short = false

// Reset visits on new pivots
if not na(ph) or not na(pl)
    visited_ote_long := false
    visited_ote_short := false

if swing_dir == 1 and low <= ote_long_upper and high >= ote_long_lower
    visited_ote_long := true

if swing_dir == -1 and high >= ote_short_lower and low <= ote_short_upper
    visited_ote_short := true

// Trigger: Touched OTE zone, then closed across the Volume VWAP
bool long_trigger = swing_dir == 1 and visited_ote_long and ta.crossover(close, avwap)
bool short_trigger = swing_dir == -1 and visited_ote_short and ta.crossunder(close, avwap)

// =========================================================================
// 6. ATR TRAILING STOP & TRADE EXECUTION
// =========================================================================
float atr = ta.atr(atr_length)
var float trail_stop = na

// Enter Trades
if long_trigger and strategy.position_size == 0
    strategy.entry("Long OTE", strategy.long)
    trail_stop := close - (atr * atr_mult)

if short_trigger and strategy.position_size == 0
    strategy.entry("Short OTE", strategy.short)
    trail_stop := close + (atr * atr_mult)

// Manage Trailing Stop
if strategy.position_size > 0
    float new_stop = close - (atr * atr_mult)
    trail_stop := math.max(nz(trail_stop, new_stop), new_stop)
    strategy.exit("Exit Long", "Long OTE", stop=trail_stop)

else if strategy.position_size < 0
    float new_stop = close + (atr * atr_mult)
    trail_stop := math.min(nz(trail_stop, new_stop), new_stop)
    strategy.exit("Exit Short", "Short OTE", stop=trail_stop)
else
    trail_stop := na

// Plot Trailing Stop
plot(strategy.position_size != 0 ? trail_stop : na, "ATR Trailing Stop", color=strategy.position_size > 0 ? color.new(color.green, 0) : color.new(color.red, 0), style=plot.style_linebr, linewidth=2)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

How the Logic Works:

Dynamic Swings: It finds pivot highs/lows using a 15-bar lookback (customizable in settings) and plots the exact 61.8% - 78.6% Retracement box for you.

Volume-Weighted Confluence: Instead of just trusting the Fib blindly, it takes an Anchored VWAP from the top of the retracement down. If price hits the Fib box but volume isn't stepping in to support a reversal, it won't fire. The trigger requires a candle closure across that dynamic volume line.

Chandelier ATR Stop: Once triggered, it paints a stepping line directly beneath/above your trade, locking in profits incrementally until stopped out.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

To elevate this to a professional-grade TradingView tool, I have completely rewritten the architecture to include:

Dynamic Risk-Based Sizing: Calculates exact position sizing based on Account Equity % and the distance to the structural Stop Loss (Swing High/Low), rather than fixed lot sizes.

Structural Stop Loss + Breakeven Engine: Initial stops are placed safely beyond the swing pivot (plus a small ATR buffer to avoid liquidity sweeps), and trailing kicks in only after the trade is in profit.

Session "Kill Zone" Filters: Prevents the algorithm from trading during dead volume hours (e.g., Asian session chop).

Telemetry Dashboard: A real-time HUD (Heads Up Display) table rendering current algorithm states, risk parameters, and dynamic pivot values without cluttering the chart.

Clean UI Toggles & Tooltips: Organized input groups with tooltips, matching C# configuration paradigms.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Post by PTScalper »

The Pro-Grade Pine Script v5 Architecture

Clear your Pine Editor and paste this in:

Code: Select all

//@version=5
strategy("Pro Volume OTE Architecture", overlay=true, initial_capital=10000, default_qty_type=strategy.cash, commission_type=strategy.commission.percent, commission_value=0.03, max_labels_count=50, max_boxes_count=50)

// =========================================================================
// 1. CONFIGURATION & INPUTS
// =========================================================================
grp_risk = "Risk & Execution Engine"
risk_pct = input.float(1.0, "Risk Per Trade (%)", step=0.25, group=grp_risk, tooltip="Calculates position size based on SL distance to risk exactly this % of total equity.")
atr_len  = input.int(14, "ATR Buffer Length", group=grp_risk)
atr_mult = input.float(0.5, "ATR Stop Buffer", step=0.1, group=grp_risk, tooltip="Buffer added to the structural swing high/low for the initial stop loss to avoid liquidity sweeps.")
trail_on = input.bool(true, "Enable ATR Trailing?", group=grp_risk)

grp_fib = "Market Structure & OTE"
piv_len = input.int(15, "Structural Pivot Lookback", minval=5, group=grp_fib)
fib_up  = input.float(0.618, "OTE Upper Boundary", group=grp_fib)
fib_dn  = input.float(0.786, "OTE Lower Boundary", group=grp_fib)

grp_sess = "Time & Session Filters"
use_sess = input.bool(true, "Use Session Filter", group=grp_sess)
session  = input.session("0800-1700", "Trading Window (Exchange Time)", group=grp_sess)

grp_ui = "Telemetry & UI"
show_hud = input.bool(true, "Show Telemetry HUD", group=grp_ui)
show_ote = input.bool(true, "Draw OTE Zones", group=grp_ui)

// =========================================================================
// 2. SESSION STATE & INDICATORS
// =========================================================================
in_session = use_sess ? not na(time(timeframe.period, session)) : true
atr = ta.atr(atr_len)

// =========================================================================
// 3. STRUCTURAL PIVOT TRACKING (STATE MANAGEMENT)
// =========================================================================
var float sw_h = na
var float sw_l = na
var int sw_h_bar = na
var int sw_l_bar = na
var int trend_dir = 0 

ph = ta.pivothigh(high, piv_len, piv_len)
pl = ta.pivotlow(low, piv_len, piv_len)

if not na(ph)
    sw_h := ph
    sw_h_bar := bar_index - piv_len
    if not na(sw_l) and sw_h_bar > sw_l_bar
        trend_dir := 1 

if not na(pl)
    sw_l := pl
    sw_l_bar := bar_index - piv_len
    if not na(sw_h) and sw_l_bar > sw_h_bar
        trend_dir := -1 

// OTE Calculations
range_val = sw_h - sw_l
ote_l_up = sw_h - (range_val * fib_up)
ote_l_dn = sw_h - (range_val * fib_dn)
ote_s_dn = sw_l + (range_val * fib_up)
ote_s_up = sw_l + (range_val * fib_dn)

// =========================================================================
// 4. VOLUME MICROSTRUCTURE (ANCHORED VWAP)
// =========================================================================
var float cum_v = 0.0
var float cum_sv = 0.0
cum_v += volume
cum_sv += hlc3 * volume

var float anch_v = 0.0
var float anch_sv = 0.0

// Anchor to the origin of the retracement
if not na(ph) and trend_dir == 1
    anch_v := cum_v[piv_len + 1]
    anch_sv := cum_sv[piv_len + 1]

if not na(pl) and trend_dir == -1
    anch_v := cum_v[piv_len + 1]
    anch_sv := cum_sv[piv_len + 1]

avwap = (cum_v - anch_v) > 0 ? (cum_sv - anch_sv) / (cum_v - anch_v) : na
plot(avwap, "AVWAP", color=color.new(color.fuchsia, 0), linewidth=2)

// =========================================================================
// 5. ZONE RENDERING
// =========================================================================
var box ote_box = na
if not na(ph) or not na(pl)
    if show_ote
        box.delete(ote_box)
        if trend_dir == 1
            ote_box := box.new(left=sw_h_bar, top=ote_l_up, right=bar_index, bottom=ote_l_dn, border_color=color.new(color.teal, 30), bgcolor=color.new(color.teal, 85), extend=extend.right)
        else if trend_dir == -1
            ote_box := box.new(left=sw_l_bar, top=ote_s_up, right=bar_index, bottom=ote_s_dn, border_color=color.new(color.orange, 30), bgcolor=color.new(color.orange, 85), extend=extend.right)

// =========================================================================
// 6. EXECUTION LOGIC & POSITION SIZING
// =========================================================================
var bool inside_ote_l = false
var bool inside_ote_s = false

if not na(ph) or not na(pl)
    inside_ote_l := false
    inside_ote_s := false

if trend_dir == 1 and low <= ote_l_up and high >= ote_l_dn
    inside_ote_l := true

if trend_dir == -1 and high >= ote_s_dn and low <= ote_s_up
    inside_ote_s := true

trigger_long = in_session and trend_dir == 1 and inside_ote_l and ta.crossover(close, avwap)
trigger_short = in_session and trend_dir == -1 and inside_ote_s and ta.crossunder(close, avwap)

// Risk & Stop Loss Math
float risk_amt = strategy.equity * (risk_pct / 100)
var float sl_level = na
var float trail_level = na

if trigger_long and strategy.position_size == 0
    sl_level := sw_l - (atr * atr_mult) // Stop placed below structural swing low + buffer
    qty = risk_amt / math.abs(close - sl_level)
    strategy.entry("Long", strategy.long, qty=qty)
    trail_level := sl_level

if trigger_short and strategy.position_size == 0
    sl_level := sw_h + (atr * atr_mult) // Stop placed above structural swing high + buffer
    qty = risk_amt / math.abs(sl_level - close)
    strategy.entry("Short", strategy.short, qty=qty)
    trail_level := sl_level

// =========================================================================
// 7. TRADE MANAGEMENT (TRAILING & EXITS)
// =========================================================================
if strategy.position_size > 0
    if trail_on
        // Trail using ATR, but never lower than the initial structural stop
        new_trail = close - (atr * 2.0)
        trail_level := math.max(nz(trail_level, sl_level), new_trail)
    strategy.exit("Exit L", "Long", stop=trail_level)

else if strategy.position_size < 0
    if trail_on
        new_trail = close + (atr * 2.0)
        trail_level := math.min(nz(trail_level, sl_level), new_trail)
    strategy.exit("Exit S", "Short", stop=trail_level)
else
    trail_level := na
    sl_level := na

plot(strategy.position_size != 0 ? trail_level : na, "Stop Level", color=strategy.position_size > 0 ? color.lime : color.red, style=plot.style_circles, linewidth=1)

// =========================================================================
// 8. TELEMETRY HUD (DASHBOARD)
// =========================================================================
var table hud = table.new(position.bottom_right, 2, 5, border_width=1, border_color=color.new(color.gray, 80), frame_color=color.new(color.gray, 80), frame_width=1)

if barstate.islast and show_hud
    table.cell(hud, 0, 0, "SYSTEM TELEMETRY", text_color=color.white, bgcolor=color.new(color.blue, 60), text_halign=text.align_left, text_size=size.small)
    table.cell(hud, 1, 0, "", bgcolor=color.new(color.blue, 60))
    
    table.cell(hud, 0, 1, "Market State", text_color=color.gray, bgcolor=color.new(color.black, 40), text_halign=text.align_left, text_size=size.small)
    table.cell(hud, 1, 1, trend_dir == 1 ? "BULLISH" : "BEARISH", text_color=trend_dir == 1 ? color.teal : color.orange, bgcolor=color.new(color.black, 40), text_size=size.small)
    
    table.cell(hud, 0, 2, "Session Active", text_color=color.gray, bgcolor=color.new(color.black, 40), text_halign=text.align_left, text_size=size.small)
    table.cell(hud, 1, 2, in_session ? "YES" : "NO", text_color=in_session ? color.lime : color.red, bgcolor=color.new(color.black, 40), text_size=size.small)
    
    table.cell(hud, 0, 3, "Current Position", text_color=color.gray, bgcolor=color.new(color.black, 40), text_halign=text.align_left, text_size=size.small)
    table.cell(hud, 1, 3, strategy.position_size > 0 ? "LONG" : strategy.position_size < 0 ? "SHORT" : "FLAT", text_color=strategy.position_size != 0 ? color.white : color.gray, bgcolor=color.new(color.black, 40), text_size=size.small)
    
    table.cell(hud, 0, 4, "Risk Per Trade", text_color=color.gray, bgcolor=color.new(color.black, 40), text_halign=text.align_left, text_size=size.small)
    table.cell(hud, 1, 4, str.tostring(risk_pct) + "%", text_color=color.white, bgcolor=color.new(color.black, 40), text_size=size.small)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply