Advertisement IC Markets

Tokyo morning expansion days: when I refuse the London fade

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

Tokyo morning expansion days: when I refuse the London fade

Post by LondonScalper »

Some Tokyo mornings already did London’s job.

When USDJPY or the crosses expand hard in Tokyo, fading Asia extremes at London has been a poor habit for me. Expansion days often continue or digest sideways — neither loves a casual fade into the London open. The mistake is treating every Asia extreme as a fade candidate regardless of how it formed.

Rule: if Tokyo morning already printed an outsized range versus recent sessions, London fade setups are off by default. I may still take continuation pullbacks with smaller size, but I will not fade "because London always mean-reverts". Policy headlines overnight raise the bar further — stand-aside beats clever.

I glance at Tokyo range before I even open the London playbook cards.

Refusing the fade is not predicting continuation — it is admitting the morning already spent the easy mean-reversion story.
  • How do you spot Tokyo expansion early enough to change the London plan?
  • Refuse all fades, or only on yen pairs?
Session personality over dogma.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

LondonScalper wrote: Thu Sep 17, 2026 12:56 am Some Tokyo mornings already did London’s job.

When USDJPY or the crosses expand hard in Tokyo, fading Asia extremes at London has been a poor habit for me. Expansion days often continue or digest sideways — neither loves a casual fade into the London open. The mistake is treating every Asia extreme as a fade candidate regardless of how it formed.

Rule: if Tokyo morning already printed an outsized range versus recent sessions, London fade setups are off by default. I may still take continuation pullbacks with smaller size, but I will not fade "because London always mean-reverts". Policy headlines overnight raise the bar further — stand-aside beats clever.

I glance at Tokyo range before I even open the London playbook cards.

Refusing the fade is not predicting continuation — it is admitting the morning already spent the easy mean-reversion story.
  • How do you spot Tokyo expansion early enough to change the London plan?
  • Refuse all fades, or only on yen pairs?
Session personality over dogma.
Hi LondonScalper,

Fading a blown-out Asian range is one of the quickest ways to get run over at the London open. When Tokyo expands rather than ranges, it has already established the day's directional bias or consumed the daily ATR. The "London always mean-reverts" dogma relies on Asia building liquidity pools on both sides of a tight box. When one side is completely shattered by 07:00 UTC, the mechanics change entirely.

Here is how to tackle your two questions from a pure price action and market microstructure perspective:

1. How do you spot Tokyo expansion early enough to change the London plan?

You quantify the "outsized range." Don't rely on a visual glance; measure the current Asian session's pip range against the 10-day Average Asian Range (AAR).

If the Tokyo range exceeds 1.5x of its average before London opens, the fade is completely off the table.

Pair this with your 15-minute chart structure: if Tokyo is leaving clean, unfilled displacement candles and respecting structural higher-lows/lower-highs without deep pullbacks, it's an expansion. A typical fadeable Asia is choppy, overlapping, and constantly taking out its own micro-highs and lows.

2. Refuse all fades, or only on yen pairs?

Strictly enforce the "no-fade" rule on JPY crosses (USDJPY, GBPJPY, EURJPY) and AUD/NZD, as they are the primary drivers of Asian session volatility.

For majors like EURUSD or GBPUSD, you have to look at the Dollar Index (DXY). If EURUSD moved heavily in Asia because the DXY was expanding on a headline, refuse the fade. If EURUSD just drifted in a 25-pip range on zero news while USDJPY ran 100 pips, the London open fade on EURUSD might still be viable.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

Pine Script v5: Asian Expansion Filter

To automate this logic, here is a Pine Script designed specifically for the 15-minute timeframe. It draws the Asian session box and actively calculates its range.

How it works:

1.) It tracks the High and Low of the Asian session.

2.) It stores the ranges of the last 15 days to calculate a rolling Average Asian Range.

3.) If the current session's range breaks above the 1.5x multiplier of that average, the box dynamically turns Red (Danger), warning you instantly that London fade setups are off. Otherwise, it stays Blue (Fadeable).

Code: Select all

//@version=5
indicator("Asian Range Expansion Filter", overlay=true, max_boxes_count=50, max_labels_count=50)

// =========================================================================
// INPUTS
// =========================================================================
sessionTime = input.session("0000-0800", title="Asian Session Time (Exchange TZ)")
lookback    = input.int(15, title="Average Range Lookback (Days)", minval=5)
multiplier  = input.float(1.5, title="Expansion Multiplier", step=0.1)

colorNormal = input.color(color.new(color.blue, 85), title="Normal Range Color")
colorExpand = input.color(color.new(color.red, 80), title="Expansion Range Color")

// =========================================================================
// SESSION LOGIC
// =========================================================================
inSession = not na(time(timeframe.period, sessionTime))
newSession = inSession and not inSession[1]
endSession = not inSession and inSession[1]

var float sessionHigh = na
var float sessionLow  = na

if newSession
    sessionHigh := high
    sessionLow  := low
else if inSession
    sessionHigh := math.max(sessionHigh, high)
    sessionLow  := math.min(sessionLow, low)

currentRange = sessionHigh - sessionLow

// =========================================================================
// HISTORICAL AVERAGE CALCULATION
// =========================================================================
// Array to store the final range of past sessions
var float[] pastRanges = array.new_float(0)

if endSession
    array.unshift(pastRanges, currentRange)
    if array.size(pastRanges) > lookback
        array.pop(pastRanges)

avgRange = array.size(pastRanges) > 0 ? array.avg(pastRanges) : na

// Boolean flag for expansion
isExpansion = inSession and not na(avgRange) and (currentRange > (avgRange * multiplier))

// =========================================================================
// DRAWING BOXES & LABELS
// =========================================================================
var box sessionBox = na
var label infoLabel = na

if newSession
    // Create new box at the start of the session
    sessionBox := box.new(left=bar_index, top=sessionHigh, right=bar_index, bottom=sessionLow, 
                          border_color=color.new(colorNormal, 50), 
                          bgcolor=colorNormal)

else if inSession
    // Update box dimensions dynamically as price moves
    box.set_top(sessionBox, sessionHigh)
    box.set_bottom(sessionBox, sessionLow)
    box.set_right(sessionBox, bar_index)
    
    // Change color instantly if expansion threshold is breached
    if isExpansion
        box.set_bgcolor(sessionBox, colorExpand)
        box.set_border_color(sessionBox, color.new(colorExpand, 40))

if endSession
    // Attach a label at the end of the session to show the math
    rangeTicks = currentRange / syminfo.mintick
    avgTicks   = avgRange / syminfo.mintick
    
    statusText = isExpansion[1] ? "⚠️ EXPANSION\nNO FADE" : "✅ NORMAL"
    labelText  = "Asia Range: " + str.tostring(rangeTicks, "#.0") + "\n" +
                 "Avg Range: " + str.tostring(avgTicks, "#.0") + "\n" + statusText
                 
    infoLabel := label.new(x=bar_index - 1, y=sessionHigh, text=labelText, 
                           style=label.style_label_down, 
                           color=isExpansion[1] ? color.red : color.blue, 
                           textcolor=color.white, 
                           size=size.small)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

You can drop this onto any JPY cross on your M15 layout. The moment that box turns red during the late Tokyo session, you already know your London playbook requires trend continuation or sitting on your hands, totally removing the guesswork before Frankfurt even opens.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

MetaTrader 4 (MQL4)

Save this as AsianRangeExpansion_MT4.mq4 in your MQL4/Indicators folder and compile. It uses OBJPROP_BACK to cleanly draw behind the candlesticks.

Code: Select all

//+------------------------------------------------------------------+
//|                                     AsianRangeExpansion_MT4.mq4  |
//+------------------------------------------------------------------+
#property copyright "Indicator Port"
#property version   "1.00"
#property strict
#property indicator_chart_window

input string   InpSessionStart = "00:00"; // Asian Session Start (HH:MM)
input string   InpSessionEnd   = "08:00"; // Asian Session End (HH:MM)
input int      InpLookback     = 15;      // Average Range Lookback (Days)
input double   InpMultiplier   = 1.5;     // Expansion Multiplier
input color    InpColorNormal  = clrCornflowerBlue; // Normal Color
input color    InpColorExpand  = clrCrimson;        // Expansion Color

int startHour, startMin, endHour, endMin;
double pastRanges[];
int rangeCount = 0;

bool inSession = false;
double sessionHigh = 0;
double sessionLow = 0;
datetime sessionStartTime = 0;

int OnInit()
{
    startHour = (int)StringToInteger(StringSubstr(InpSessionStart, 0, 2));
    startMin  = (int)StringToInteger(StringSubstr(InpSessionStart, 3, 2));
    endHour   = (int)StringToInteger(StringSubstr(InpSessionEnd, 0, 2));
    endMin    = (int)StringToInteger(StringSubstr(InpSessionEnd, 3, 2));
    
    ArrayResize(pastRanges, InpLookback);
    ArrayInitialize(pastRanges, 0.0);
    return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, "AsiaRange_");
}

bool IsTimeInSession(datetime t) 
{
    MqlDateTime dt;
    TimeToStruct(t, dt);
    int currentMins = dt.hour * 60 + dt.min;
    int startMins = startHour * 60 + startMin;
    int endMins = endHour * 60 + endMin;
    
    if (startMins < endMins) return (currentMins >= startMins && currentMins < endMins);
    return (currentMins >= startMins || currentMins < endMins);
}

void AddRange(double range) 
{
    for(int i = InpLookback - 1; i > 0; i--) pastRanges[i] = pastRanges[i-1];
    pastRanges[0] = range;
    if(rangeCount < InpLookback) rangeCount++;
}

double GetAvgRange() 
{
    if (rangeCount == 0) return 0;
    double sum = 0;
    for(int i = 0; i < rangeCount; i++) sum += pastRanges[i];
    return sum / (double)rangeCount;
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    if(rates_total < 2) return(0);
    
    int limit = rates_total - prev_calculated;
    if(prev_calculated == 0) {
        limit = rates_total - 1;
        ArrayInitialize(pastRanges, 0.0);
        rangeCount = 0;
        inSession = false;
        ObjectsDeleteAll(0, "AsiaRange_");
    }

    // MT4 loops backwards from oldest to newest by default
    for(int i = limit; i >= 0; i--) {
        datetime t = time[i];
        bool isInside = IsTimeInSession(t);
        
        if(isInside && !inSession) {
            inSession = true;
            sessionStartTime = t;
            sessionHigh = high[i];
            sessionLow = low[i];
        } 
        else if (isInside && inSession) {
            if(high[i] > sessionHigh) sessionHigh = high[i];
            if(low[i] < sessionLow) sessionLow = low[i];
        }
        else if (!isInside && inSession) {
            inSession = false;
            double currentRange = sessionHigh - sessionLow;
            AddRange(currentRange);
        }
        
        if(inSession) {
            double avgRange = GetAvgRange();
            double currentRange = sessionHigh - sessionLow;
            bool isExpand = (avgRange > 0 && currentRange > (avgRange * InpMultiplier));
            color boxColor = isExpand ? InpColorExpand : InpColorNormal;
            
            string objName = "AsiaRange_" + IntegerToString((long)sessionStartTime);
            string txtName = objName + "_txt";
            
            if(ObjectFind(0, objName) < 0) {
                ObjectCreate(0, objName, OBJ_RECTANGLE, 0, sessionStartTime, sessionHigh, t, sessionLow);
                ObjectSetInteger(0, objName, OBJPROP_COLOR, boxColor);
                ObjectSetInteger(0, objName, OBJPROP_BACK, true);
                
                ObjectCreate(0, txtName, OBJ_TEXT, 0, sessionStartTime, sessionHigh);
                ObjectSetString(0, txtName, OBJPROP_FONT, "Arial");
                ObjectSetInteger(0, txtName, OBJPROP_FONTSIZE, 8);
                ObjectSetInteger(0, txtName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
            } else {
                ObjectSetDouble(0, objName, OBJPROP_PRICE1, sessionHigh);
                ObjectSetDouble(0, objName, OBJPROP_PRICE2, sessionLow);
                ObjectSetInteger(0, objName, OBJPROP_TIME2, t);
                ObjectSetInteger(0, objName, OBJPROP_COLOR, boxColor);
                
                string text = isExpand ? "EXPANSION (NO FADE)" : "NORMAL";
                ObjectSetDouble(0, txtName, OBJPROP_PRICE1, sessionHigh);
                ObjectSetInteger(0, txtName, OBJPROP_TIME1, sessionStartTime);
                ObjectSetString(0, txtName, OBJPROP_TEXT, text);
                ObjectSetInteger(0, txtName, OBJPROP_COLOR, boxColor);
            }
        }
    }
    return(rates_total);
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

MetaTrader 5 (MQL5)

Save this as AsianRangeExpansion_MT5.mq5 in your MQL5/Indicators folder. It sets time/price arrays as a series to mirror MT4 loop execution, and applies OBJPROP_FILL so the bounding box renders completely solid.

Code: Select all

//+------------------------------------------------------------------+
//|                                     AsianRangeExpansion_MT5.mq5  |
//+------------------------------------------------------------------+
#property copyright "Indicator Port"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

input string   InpSessionStart = "00:00"; // Asian Session Start (HH:MM)
input string   InpSessionEnd   = "08:00"; // Asian Session End (HH:MM)
input int      InpLookback     = 15;      // Average Range Lookback (Days)
input double   InpMultiplier   = 1.5;     // Expansion Multiplier
input color    InpColorNormal  = clrCornflowerBlue; // Normal Color
input color    InpColorExpand  = clrCrimson;        // Expansion Color

int startHour, startMin, endHour, endMin;
double pastRanges[];
int rangeCount = 0;

bool inSession = false;
double sessionHigh = 0;
double sessionLow = 0;
datetime sessionStartTime = 0;

int OnInit()
{
    startHour = (int)StringToInteger(StringSubstr(InpSessionStart, 0, 2));
    startMin  = (int)StringToInteger(StringSubstr(InpSessionStart, 3, 2));
    endHour   = (int)StringToInteger(StringSubstr(InpSessionEnd, 0, 2));
    endMin    = (int)StringToInteger(StringSubstr(InpSessionEnd, 3, 2));
    
    ArrayResize(pastRanges, InpLookback);
    ArrayInitialize(pastRanges, 0.0);
    return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, "AsiaRange_");
}

bool IsTimeInSession(datetime t) 
{
    MqlDateTime dt;
    TimeToStruct(t, dt);
    int currentMins = dt.hour * 60 + dt.min;
    int startMins = startHour * 60 + startMin;
    int endMins = endHour * 60 + endMin;
    
    if (startMins < endMins) return (currentMins >= startMins && currentMins < endMins);
    return (currentMins >= startMins || currentMins < endMins);
}

void AddRange(double range) 
{
    for(int i = InpLookback - 1; i > 0; i--) pastRanges[i] = pastRanges[i-1];
    pastRanges[0] = range;
    if(rangeCount < InpLookback) rangeCount++;
}

double GetAvgRange() 
{
    if (rangeCount == 0) return 0;
    double sum = 0;
    for(int i = 0; i < rangeCount; i++) sum += pastRanges[i];
    return sum / (double)rangeCount;
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    if(rates_total < 2) return(0);
    
    // Set arrays as series so index 0 is the current candle (like MT4)
    ArraySetAsSeries(time, true);
    ArraySetAsSeries(high, true);
    ArraySetAsSeries(low, true);
    
    int limit = rates_total - prev_calculated;
    if(prev_calculated == 0) {
        limit = rates_total - 1;
        ArrayInitialize(pastRanges, 0.0);
        rangeCount = 0;
        inSession = false;
        ObjectsDeleteAll(0, "AsiaRange_");
    }

    for(int i = limit; i >= 0; i--) {
        datetime t = time[i];
        bool isInside = IsTimeInSession(t);
        
        if(isInside && !inSession) {
            inSession = true;
            sessionStartTime = t;
            sessionHigh = high[i];
            sessionLow = low[i];
        } 
        else if (isInside && inSession) {
            if(high[i] > sessionHigh) sessionHigh = high[i];
            if(low[i] < sessionLow) sessionLow = low[i];
        }
        else if (!isInside && inSession) {
            inSession = false;
            double currentRange = sessionHigh - sessionLow;
            AddRange(currentRange);
        }
        
        if(inSession) {
            double avgRange = GetAvgRange();
            double currentRange = sessionHigh - sessionLow;
            bool isExpand = (avgRange > 0 && currentRange > (avgRange * InpMultiplier));
            color boxColor = isExpand ? InpColorExpand : InpColorNormal;
            
            string objName = "AsiaRange_" + IntegerToString((long)sessionStartTime);
            string txtName = objName + "_txt";
            
            if(ObjectFind(0, objName) < 0) {
                ObjectCreate(0, objName, OBJ_RECTANGLE, 0, sessionStartTime, sessionHigh, t, sessionLow);
                ObjectSetInteger(0, objName, OBJPROP_COLOR, boxColor);
                ObjectSetInteger(0, objName, OBJPROP_FILL, true); // Exclusive to MT5 for solid objects
                ObjectSetInteger(0, objName, OBJPROP_BACK, true);
                
                ObjectCreate(0, txtName, OBJ_TEXT, 0, sessionStartTime, sessionHigh);
                ObjectSetString(0, txtName, OBJPROP_FONT, "Arial");
                ObjectSetInteger(0, txtName, OBJPROP_FONTSIZE, 8);
                ObjectSetInteger(0, txtName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
            } else {
                ObjectSetDouble(0, objName, OBJPROP_PRICE1, sessionHigh);
                ObjectSetDouble(0, objName, OBJPROP_PRICE2, sessionLow);
                ObjectSetInteger(0, objName, OBJPROP_TIME2, t);
                ObjectSetInteger(0, objName, OBJPROP_COLOR, boxColor);
                
                string text = isExpand ? "EXPANSION (NO FADE)" : "NORMAL";
                ObjectSetDouble(0, txtName, OBJPROP_PRICE1, sessionHigh);
                ObjectSetInteger(0, txtName, OBJPROP_TIME1, sessionStartTime);
                ObjectSetString(0, txtName, OBJPROP_TEXT, text);
                ObjectSetInteger(0, txtName, OBJPROP_COLOR, boxColor);
            }
        }
    }
    return(rates_total);
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

Save this as AsianRangeExpansion.cs in your cTrader Automate indicators folder. It uses native cAlgo.API chart objects, drawing the session box dynamically on every tick and shifting colors if the logic thresholds are breached.

Ctrader version:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class AsianRangeExpansion : Indicator
    {
        [Parameter("Session Start (HH:mm)", DefaultValue = "00:00")]
        public string SessionStart { get; set; }

        [Parameter("Session End (HH:mm)", DefaultValue = "08:00")]
        public string SessionEnd { get; set; }

        [Parameter("Average Lookback (Days)", DefaultValue = 15)]
        public int Lookback { get; set; }

        [Parameter("Expansion Multiplier", DefaultValue = 1.5)]
        public double Multiplier { get; set; }

        [Parameter("Normal Color", DefaultValue = "CornflowerBlue")]
        public string NormalColorName { get; set; }

        [Parameter("Expansion Color", DefaultValue = "Crimson")]
        public string ExpandColorName { get; set; }

        [Parameter("Box Opacity (0-255)", DefaultValue = 50)]
        public int FillOpacity { get; set; }

        private TimeSpan _startTime;
        private TimeSpan _endTime;
        private List<double> _pastRanges;
        
        private bool _inSession;
        private double _sessionHigh;
        private double _sessionLow;
        private int _startIndex;
        
        private Color _normalColor;
        private Color _expandColor;

        protected override void Initialize()
        {
            TimeSpan.TryParse(SessionStart, out _startTime);
            TimeSpan.TryParse(SessionEnd, out _endTime);
            
            _pastRanges = new List<double>();
            
            _normalColor = Color.FromArgb(FillOpacity, Color.FromName(NormalColorName));
            _expandColor = Color.FromArgb(FillOpacity, Color.FromName(ExpandColorName));
        }

        public override void Calculate(int index)
        {
            // Use UTC time to ensure consistency across broker server time variations
            var timeOfDay = Bars.OpenTimes[index].TimeOfDay;
            bool isInside = IsTimeInSession(timeOfDay);
            
            // Session transitions
            if (isInside && !_inSession)
            {
                _inSession = true;
                _startIndex = index;
                _sessionHigh = Bars.HighPrices[index];
                _sessionLow = Bars.LowPrices[index];
            }
            else if (isInside && _inSession)
            {
                _sessionHigh = Math.Max(_sessionHigh, Bars.HighPrices[index]);
                _sessionLow = Math.Min(_sessionLow, Bars.LowPrices[index]);
            }
            else if (!isInside && _inSession)
            {
                _inSession = false;
                double finalRange = _sessionHigh - _sessionLow;
                
                // Store completed session range
                _pastRanges.Add(finalRange);
                if (_pastRanges.Count > Lookback)
                {
                    _pastRanges.RemoveAt(0);
                }
            }
            
            // Draw & update visuals while the session is active
            if (_inSession)
            {
                double currentRange = _sessionHigh - _sessionLow;
                double avgRange = _pastRanges.Count > 0 ? _pastRanges.Average() : 0;
                
                bool isExpansion = (avgRange > 0 && currentRange > (avgRange * Multiplier));
                Color currentColor = isExpansion ? _expandColor : _normalColor;
                
                string boxName = "AsiaBox_" + _startIndex;
                var box = Chart.DrawRectangle(boxName, _startIndex, _sessionHigh, index, _sessionLow, currentColor);
                box.IsFilled = true;
                
                // Set the border color slightly more opaque than the fill
                Color borderColor = Color.FromArgb(Math.Min(255, FillOpacity + 30), currentColor);
                box.Color = borderColor;
                
                string textName = "AsiaText_" + _startIndex;
                string text = isExpansion ? "EXPANSION (NO FADE)" : "NORMAL";
                var chartText = Chart.DrawText(textName, text, _startIndex, _sessionHigh, currentColor);
                chartText.VerticalAlignment = VerticalAlignment.Bottom;
            }
        }
        
        private bool IsTimeInSession(TimeSpan time)
        {
            if (_startTime < _endTime)
                return time >= _startTime && time < _endTime;
            
            // Handles sessions that cross midnight
            return time >= _startTime || time < _endTime;
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

To make this a professional-grade tool tailored for market microstructure and price action scalping, we need to upgrade the script from a basic visual filter to a complete session analysis suite.

This "Pro" version introduces three key mechanics for liquidity and range trading:

Liquidity Pool Projections: When Tokyo ends, it projects the Asian High and Low forward into the London session. This highlights exactly where the resting liquidity sits for London sweeps.

Session Equilibrium (50%): Draws the midline of the Asian range. In an expansion, the equilibrium acts as a premium/discount threshold for continuation pullbacks.

Real-Time HUD & Alerts: A clean dashboard table tracks the live metrics, and built-in alert conditions notify you the moment the expansion threshold is breached.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

Pine Script v5: Asian Range Microstructure [PRO]

Code: Select all

//@version=5
indicator("Asian Range Microstructure [PRO]", overlay=true, max_boxes_count=100, max_lines_count=200, max_labels_count=50)

// =========================================================================
// INPUTS & CONFIGURATION
// =========================================================================
var string G_TIME = "Session Parameters"
sessionTime = input.session("0000-0800", title="Asian Session (Exchange TZ)", group=G_TIME)
extendHours = input.int(6, title="London Projection Length (Hours)", minval=1, maxval=12, group=G_TIME)

var string G_CALC = "Expansion Logic"
lookback    = input.int(15, title="Average Range Lookback (Days)", minval=5, maxval=50, group=G_CALC)
multiplier  = input.float(1.5, title="Expansion Multiplier", step=0.1, group=G_CALC)

var string G_STYLE = "Aesthetics & HUD"
colorNormal = input.color(color.new(#2962FF, 85), title="Normal Range", group=G_STYLE)
colorExpand = input.color(color.new(#FF5252, 85), title="Expansion Range", group=G_STYLE)
colorLine   = input.color(color.new(#787B86, 30), title="Liquidity & Equilibrium Lines", group=G_STYLE)
showHUD     = input.bool(true, title="Show Data Dashboard", group=G_STYLE)

// =========================================================================
// STATE VARIABLES & SESSION LOGIC
// =========================================================================
inSession  = not na(time(timeframe.period, sessionTime))
newSession = inSession and not inSession[1]
endSession = not inSession and inSession[1]

var float sessionHigh = na
var float sessionLow  = na
var int   sessionStartBar = na

if newSession
    sessionHigh := high
    sessionLow  := low
    sessionStartBar := bar_index
else if inSession
    sessionHigh := math.max(sessionHigh, high)
    sessionLow  := math.min(sessionLow, low)

currentRange = sessionHigh - sessionLow
sessionEq    = sessionLow + (currentRange / 2)

// =========================================================================
// HISTORICAL AVERAGE CALCULATION (AAR)
// =========================================================================
var float[] pastRanges = array.new_float(0)

if endSession
    array.unshift(pastRanges, currentRange)
    if array.size(pastRanges) > lookback
        array.pop(pastRanges)

avgRange = array.size(pastRanges) > 0 ? array.avg(pastRanges) : na
isExpansion = inSession and not na(avgRange) and (currentRange > (avgRange * multiplier))

// =========================================================================
// DRAWING: BOXES, EQUILIBRIUM & LIQUIDITY EXTENSIONS
// =========================================================================
var box sessionBox = na
var line eqLine = na
var line[] liqLines = array.new_line(0)

if newSession
    sessionBox := box.new(left=bar_index, top=sessionHigh, right=bar_index, bottom=sessionLow, 
                          border_color=color.new(colorNormal, 30), 
                          bgcolor=colorNormal)
                          
    eqLine := line.new(x1=bar_index, y1=sessionEq, x2=bar_index, y2=sessionEq, 
                       color=colorLine, style=line.style_dashed)

else if inSession
    currentColor = isExpansion ? colorExpand : colorNormal
    
    // Update Box
    box.set_top(sessionBox, sessionHigh)
    box.set_bottom(sessionBox, sessionLow)
    box.set_right(sessionBox, bar_index)
    box.set_bgcolor(sessionBox, currentColor)
    box.set_border_color(sessionBox, color.new(currentColor, 30))
    
    // Update Equilibrium Line
    line.set_y1(eqLine, sessionEq)
    line.set_y2(eqLine, sessionEq)
    line.set_x2(eqLine, bar_index)

if endSession
    // Project liquidity pools forward into London
    barsToExtend = (60 / timeframe.multiplier) * extendHours
    endBar = bar_index + math.round(barsToExtend)
    
    line.new(x1=bar_index, y1=sessionHigh, x2=endBar, y2=sessionHigh, color=colorLine, style=line.style_dotted)
    line.new(x1=bar_index, y1=sessionLow, x2=endBar, y2=sessionLow, color=colorLine, style=line.style_dotted)

// =========================================================================
// ALERTS
// =========================================================================
// Trigger alert exactly when the threshold is crossed during the session
expansionTrigger = isExpansion and not isExpansion[1]
if expansionTrigger
    alert("Asian Expansion Triggered on " + syminfo.ticker + ". London fades invalidated.", alert.freq_once_per_bar)

// =========================================================================
// HEADS UP DISPLAY (HUD)
// =========================================================================
var table hud = table.new(position.bottom_right, columns=2, rows=4, bgcolor=color.new(#131722, 10), border_width=1, border_color=color.new(#363A45, 50))

if showHUD and barstate.islast
    rangeTicks = currentRange / syminfo.mintick
    avgTicks   = na(avgRange) ? 0 : (avgRange / syminfo.mintick)
    pctOfAvg   = na(avgRange) ? 0 : (currentRange / avgRange) * 100
    
    statusColor = isExpansion ? color.red : color.blue
    statusText  = isExpansion ? "EXPANSION (NO FADE)" : "NORMAL"
    
    // Header
    table.cell(hud, 0, 0, "TOKYO MICROSTRUCTURE", text_color=color.white, text_size=size.small, bgcolor=color.new(#2A2E39, 0), span=2)
    
    // Metrics
    table.cell(hud, 0, 1, "Current Range:", text_color=color.gray, text_size=size.small, text_halign=text.align_left)
    table.cell(hud, 1, 1, str.tostring(rangeTicks, "#.0") + " ticks", text_color=color.white, text_size=size.small, text_halign=text.align_right)
    
    table.cell(hud, 0, 2, "15D Average:", text_color=color.gray, text_size=size.small, text_halign=text.align_left)
    table.cell(hud, 1, 2, str.tostring(avgTicks, "#.0") + " ticks (" + str.tostring(pctOfAvg, "#") + "%)", text_color=color.white, text_size=size.small, text_halign=text.align_right)
    
    // Status
    table.cell(hud, 0, 3, "London Setup:", text_color=color.gray, text_size=size.small, text_halign=text.align_left)
    table.cell(hud, 1, 3, statusText, text_color=statusColor, text_size=size.small, text_halign=text.align_right)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Tokyo morning expansion days: when I refuse the London fade

Post by PTScalper »

Pro Upgrades Explained:

Inputs & Grouping: Inputs are cleanly grouped in the indicator settings menu.

Liquidity Projections (extendHours): Once Tokyo closes, it automatically draws dotted lines extending the high and low forward. This visualizes exactly where the London/New York algorithms will target if they attempt a liquidity sweep.

Equilibrium Tracking: The dashed line constantly updates to the 50% mark of the session. If the session expands and you decide to look for a continuation play, the equilibrium acts as your premium/discount boundary for entry.

Heads Up Display (HUD): The clunky label is replaced with a sleek, non-intrusive table in the bottom right corner of the chart, tracking live ticks against the 15-day average and outputting the exact percentage of expansion.

Alert Integrations: You can now set a server-side alert on this indicator in TradingView. The moment an active candle breaches the 1.5x expansion threshold, it fires a push notification to your phone so you know the London fade is invalidated without having to stare at the chart.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply