Page 2 of 4

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:24 am
by PTScalper
By tying your stop loss directly to the physical structure of the sweep candle, you remove the arbitrary nature of ATR and place your exit where the setup mathematically invalidates itself.

Here is the updated script. The ATR variables have been stripped out and replaced with a structural calculation. It measures the exact distance from the entry price (the close of the engulfing candle) to the extreme wick of that same candle, adds a 1-tick protective buffer, and projects exactly double that distance for the take profit.

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:24 am
by PTScalper
Pine script ver. 3.0

Code: Select all

//@version=5
strategy("Fairman's Blueprint: Structural Exits", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=1)

// ==========================================
// RULE 2: SESSIONS AND HOURS TRADED
// ==========================================
session_time = input.session("0800-1100", title="Active Trading Window")
in_session = not na(time(timeframe.period, session_time))
bgcolor(in_session ? color.new(color.blue, 95) : na, title="Session Background")

// ==========================================
// RULE 5 & 6: POSITION SIZING & LOSS LIMITS
// ==========================================
risk_per_trade = input.float(1.0, title="Risk % per Trade")
max_drawdown_limit = input.float(5.0, title="Max Drawdown Limit (%)")
strategy.risk.max_drawdown(max_drawdown_limit, strategy.percent_of_equity) 

// ==========================================
// RULE 3: ENTRY CRITERIA (Daily Sweep & 15m Engulfing)
// ==========================================
pdh = request.security(syminfo.tickerid, "D", high[1])
pdl = request.security(syminfo.tickerid, "D", low[1])

plot(pdh, color=color.red, style=plot.style_linebr, title="Previous Day High")
plot(pdl, color=color.green, style=plot.style_linebr, title="Previous Day Low")

prev_bullish = close[1] > open[1]
curr_bearish = close < open
bearish_engulfing = prev_bullish and curr_bearish and (open >= close[1]) and (close <= open[1])

prev_bearish = close[1] < open[1]
curr_bullish = close > open
bullish_engulfing = prev_bearish and curr_bullish and (open <= close[1]) and (close >= open[1])

sweep_high = high > pdh
sweep_low = low < pdl

short_setup = sweep_high and bearish_engulfing and in_session
long_setup = sweep_low and bullish_engulfing and in_session

plotshape(short_setup, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, title="Short Trigger")
plotshape(long_setup, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, title="Long Trigger")

// ==========================================
// RULE 4: EXIT CRITERIA (Structural SL & Fixed R:R)
// ==========================================
rr_ratio = input.float(2.0, title="Risk to Reward Ratio")
sl_buffer_ticks = input.int(1, title="SL Buffer (Ticks)", tooltip="Adds a tiny buffer above/below the wick to prevent getting stopped out by exact price touches.")
sl_buffer = sl_buffer_ticks * syminfo.mintick

var float long_sl = na
var float long_tp = na
var float short_sl = na
var float short_tp = na

// ==========================================
// EXECUTION LOGIC
// ==========================================
if long_setup and strategy.position_size == 0
    strategy.entry("Long", strategy.long)
    // SL is the low of the signal candle minus the buffer
    long_sl := low - sl_buffer
    // Risk is entry price (close of signal bar) minus SL
    long_risk = close - long_sl
    // TP is entry price plus 2x the risk
    long_tp := close + (long_risk * rr_ratio)

if short_setup and strategy.position_size == 0
    strategy.entry("Short", strategy.short)
    // SL is the high of the signal candle plus the buffer
    short_sl := high + sl_buffer
    // Risk is SL minus entry price (close of signal bar)
    short_risk = short_sl - close
    // TP is entry price minus 2x the risk
    short_tp := close - (short_risk * rr_ratio)

if strategy.position_size > 0
    strategy.exit("Exit Long", from_entry="Long", stop=long_sl, limit=long_tp)

if strategy.position_size < 0
    strategy.exit("Exit Short", from_entry="Short", stop=short_sl, limit=short_tp)

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:24 am
by PTScalper
What changed in the mechanics:

Dynamic Risk Calculation: When short_setup fires, the script measures the exact distance from the close (where your entry order is triggered) up to the high of that exact 15-minute candle.

The Protective Tick Buffer (sl_buffer): Institutional algos often push price exactly to the high of a liquidity sweep to take out stops resting exactly on the line before reversing. Adding syminfo.mintick places your stop just a fraction above the actual wick to survive those exact-match tests. You can adjust this in the settings.

Fixed 1:2 R:R Projection: The script takes your calculated risk size, multiplies it by the rr_ratio input (defaulting to 2.0), and projects the Take Profit limit order down the chart automatically.

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:25 am
by PTScalper
Adding dynamic JSON payloads directly into the execution block allows your script to act as the primary engine for an external execution platform.

By constructing the JSON string using str.tostring(), the exact structural Stop Loss and Take Profit levels calculated on the chart are bundled into the alert the millisecond the 15-minute engulfing candle closes.

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:25 am
by PTScalper
Pine script ver. 4.0

Code: Select all

//@version=5
strategy("Fairman's Blueprint: Webhook Edition", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=1)

// ==========================================
// RULE 2: SESSIONS AND HOURS TRADED
// ==========================================
session_time = input.session("0800-1100", title="Active Trading Window")
in_session = not na(time(timeframe.period, session_time))
bgcolor(in_session ? color.new(color.blue, 95) : na, title="Session Background")

// ==========================================
// RULE 5 & 6: POSITION SIZING & LOSS LIMITS
// ==========================================
risk_per_trade = input.float(1.0, title="Risk % per Trade")
max_drawdown_limit = input.float(5.0, title="Max Drawdown Limit (%)")
strategy.risk.max_drawdown(max_drawdown_limit, strategy.percent_of_equity) 

// ==========================================
// RULE 3: ENTRY CRITERIA (Daily Sweep & 15m Engulfing)
// ==========================================
pdh = request.security(syminfo.tickerid, "D", high[1])
pdl = request.security(syminfo.tickerid, "D", low[1])

plot(pdh, color=color.red, style=plot.style_linebr, title="Previous Day High")
plot(pdl, color=color.green, style=plot.style_linebr, title="Previous Day Low")

prev_bullish = close[1] > open[1]
curr_bearish = close < open
bearish_engulfing = prev_bullish and curr_bearish and (open >= close[1]) and (close <= open[1])

prev_bearish = close[1] < open[1]
curr_bullish = close > open
bullish_engulfing = prev_bearish and curr_bullish and (open <= close[1]) and (close >= open[1])

sweep_high = high > pdh
sweep_low = low < pdl

short_setup = sweep_high and bearish_engulfing and in_session
long_setup = sweep_low and bullish_engulfing and in_session

plotshape(short_setup, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, title="Short Trigger")
plotshape(long_setup, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, title="Long Trigger")

// ==========================================
// RULE 4: EXIT CRITERIA VARIABLES
// ==========================================
rr_ratio = input.float(2.0, title="Risk to Reward Ratio")
sl_buffer_ticks = input.int(1, title="SL Buffer (Ticks)")
sl_buffer = sl_buffer_ticks * syminfo.mintick

var float long_sl = na
var float long_tp = na
var float short_sl = na
var float short_tp = na

// ==========================================
// EXECUTION LOGIC & JSON ALERTS
// ==========================================
if long_setup and strategy.position_size == 0
    long_sl := low - sl_buffer
    long_risk = close - long_sl
    long_tp := close + (long_risk * rr_ratio)
    
    // Construct dynamic JSON for Long Entry
    string long_json = '{"action": "long", "symbol": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + ', "sl": ' + str.tostring(long_sl) + ', "tp": ' + str.tostring(long_tp) + '}'
    strategy.entry("Long", strategy.long, alert_message=long_json)

if short_setup and strategy.position_size == 0
    short_sl := high + sl_buffer
    short_risk = short_sl - close
    short_tp := close - (short_risk * rr_ratio)
    
    // Construct dynamic JSON for Short Entry
    string short_json = '{"action": "short", "symbol": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + ', "sl": ' + str.tostring(short_sl) + ', "tp": ' + str.tostring(short_tp) + '}'
    strategy.entry("Short", strategy.short, alert_message=short_json)

if strategy.position_size > 0
    // Triggers when SL or TP is physically hit on the chart
    string exit_long_json = '{"action": "exit_long", "symbol": "' + syminfo.ticker + '"}'
    strategy.exit("Exit Long", from_entry="Long", stop=long_sl, limit=long_tp, alert_message=exit_long_json)

if strategy.position_size < 0
    // Triggers when SL or TP is physically hit on the chart
    string exit_short_json = '{"action": "exit_short", "symbol": "' + syminfo.ticker + '"}'
    strategy.exit("Exit Short", from_entry="Short", stop=short_sl, limit=short_tp, alert_message=exit_short_json)

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:26 am
by PTScalper
TradingView Alert Configuration

When you set up the actual alert in the TradingView UI for this script:

1.) Select the script as the Condition.

2.) In the "Message" box, delete the default text and paste exactly this: {{strategy.order.alert_message}}

3.) Enable "Webhook URL" and paste your third-party endpoint.

4.) When a condition is met, TradingView swaps that placeholder out for the dynamically generated JSON string and fires it off to your server.

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:27 am
by PTScalper
Because MetaTrader 5 cannot directly expose a public URL to the internet to "listen" for webhooks, you need a two-part architecture to bridge TradingView and your MT5 terminal.

The Middleman (Webhook Receiver): A lightweight server (like a Python Flask app or a PHP script on a VPS) that receives the POST request from TradingView and stores the JSON payload.

The MQL5 Expert Advisor (EA): An MT5 script that polls the middleman server every second using WebRequest, parses the JSON, and executes the physical trade via the standard CTrade class.

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:28 am
by PTScalper
The MQL5 Execution Logic

Since MQL5 does not have a native JSON parser built into the standard library, this implementation relies on JAson.mqh, the industry-standard open-source JSON library available for free in the MQL5 CodeBase.

This EA polls your local server, deserializes the JSON string we built in Pine Script, and routes the exact structural Stop Loss and Take Profit parameters directly to your broker.

Code: Select all

//+------------------------------------------------------------------+
//|                                           TV_Webhook_Receiver.mq5|
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <JAson.mqh> // Download from MQL5 CodeBase

CTrade trade;
string server_url = "http://localhost:5000/get_latest_alert"; 
string last_processed_signal = "";

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // Enable polling every 1 second
    EventSetTimer(1); 
    
    // Set a unique magic number so the EA only manages its own trades
    trade.SetExpertMagicNumber(777777); 
    
    // Ensure WebRequest is permitted in MT5 settings
    Print("EA Initialized. Listening for TradingView signals...");
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()
{
    string cookie = NULL, headers;
    char post[], result[];
    
    // Poll the middleman server for the latest JSON payload
    int res = WebRequest("GET", server_url, cookie, NULL, 500, post, 0, result, headers);
    
    if(res == 200)
    {
        string json_string = CharArrayToString(result);
        
        // Prevent duplicate execution of the same signal
        if(json_string != last_processed_signal && json_string != "") 
        {
            ParseAndExecute(json_string);
            last_processed_signal = json_string;
        }
    }
}

//+------------------------------------------------------------------+
//| Parse JSON and Execute Trade                                     |
//+------------------------------------------------------------------+
void ParseAndExecute(string json_payload)
{
    CJAVal json;
    
    // Deserialize the JSON string sent by TradingView
    if(json.Deserialize(json_payload))
    {
        string action = json["action"].ToStr();
        string symbol = json["symbol"].ToStr();
        
        // Ensure the symbol is active in the MT5 Market Watch
        SymbolSelect(symbol, true);
        
        // Normalize symbol data
        double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
        double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
        
        // Calculate lot size based on your risk management rules
        // This should be dynamically calculated based on AccountFreeMargin()
        double lot_size = 0.1; 
        
        if(action == "long")
        {
            double sl = json["sl"].ToDbl();
            double tp = json["tp"].ToDbl();
            
            trade.Buy(lot_size, symbol, ask, sl, tp, "TV Long Sweep");
            Print("Executed Long on ", symbol, " | SL: ", sl, " | TP: ", tp);
        }
        else if(action == "short")
        {
            double sl = json["sl"].ToDbl();
            double tp = json["tp"].ToDbl();
            
            trade.Sell(lot_size, symbol, bid, sl, tp, "TV Short Sweep");
            Print("Executed Short on ", symbol, " | SL: ", sl, " | TP: ", tp);
        }
        else if(action == "exit_long" || action == "exit_short")
        {
            // Iterate backwards through open positions to close the matching symbol
            for(int i = PositionsTotal() - 1; i >= 0; i--)
            {
                ulong ticket = PositionGetTicket(i);
                if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == 777777)
                {
                    trade.PositionClose(ticket);
                    Print("Closed position on ", symbol, " due to TV exit signal.");
                }
            }
        }
    }
}

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:28 am
by PTScalper
Critical MT5 Configuration Steps

Allow WebRequest: By default, MT5 blocks external HTTP calls. You must go to Tools > Options > Expert Advisors, check "Allow WebRequest for listed URL," and add your local server address (e.g., http://localhost:5000) or your VPS IP.

Symbol Mapping: The JSON payload sends the TradingView ticker (e.g., "EURUSD"). If your MT5 broker uses suffixes (like "EURUSD.r" or "EURUSD.pro"), you must append that suffix to the symbol string in the MQL5 parser before executing SymbolSelect() or trade.Buy().

Lot Sizing (Rule 5): The MQL5 script currently uses a static 0.1 lot size placeholder. To strictly enforce Fairman's Rule 5, you will need to replace this with a dynamic formula using AccountInfoDouble(ACCOUNT_BALANCE), the stop-loss distance (MathAbs(ask - sl)), and the symbol's tick value (SYMBOL_TRADE_TICK_VALUE).

Re: Your Trading Plan Needs These 7 Non-Negotiable Sections

Posted: Wed Sep 23, 2026 8:30 am
by PTScalper
Routine search completed.

Let's build the Flask server.

Requirements:

1.) Python Flask app to listen for TradingView webhooks.

2.) An endpoint /webhook (POST) to receive the JSON payload.

3.) An endpoint /get_latest_alert (GET) for the MT5 EA to poll.

4.) Explanations on how to expose it to the internet using Ngrok (since MT5 is polling localhost, this means MT5 and Flask run on the same VPS/machine, but TradingView needs a public URL to hit the Flask app).