Tokyo morning expansion days: when I refuse the London fade
Re: Tokyo morning expansion days: when I refuse the London fade
This Elite version utilizes your C# environment to seamlessly project the Premium and Discount matrices into the London session using native time-based rectangles (so they never warp based on the bar index). It implements the automated BSL/SSL sweep detection, updating the dynamic WPF-style HUD instantly when liquidity is purged.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Tokyo morning expansion days: when I refuse the London fade
Elite Ctrader version:
Code: Select all
using System;
using System.Collections.Generic;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class AsianMicrostructureELITE : Indicator
{
// =========================================================================
// INPUTS & CONFIGURATION
// =========================================================================
[Parameter("Session Start (HH:mm)", DefaultValue = "00:00", Group = "Session Parameters")]
public string SessionStart { get; set; }
[Parameter("Session End (HH:mm)", DefaultValue = "08:00", Group = "Session Parameters")]
public string SessionEnd { get; set; }
[Parameter("London Projection Length (Hours)", DefaultValue = 6, Group = "Session Parameters")]
public int ExtendHours { get; set; }
[Parameter("Average Lookback (Days)", DefaultValue = 15, Group = "Expansion Logic")]
public int Lookback { get; set; }
[Parameter("Expansion Multiplier", DefaultValue = 1.5, Group = "Expansion Logic")]
public double Multiplier { get; set; }
[Parameter("Normal Color", DefaultValue = "#2962FF", Group = "Aesthetics")]
public string NormalColorHex { get; set; }
[Parameter("Expansion Color", DefaultValue = "#FF5252", Group = "Aesthetics")]
public string ExpandColorHex { get; set; }
[Parameter("Premium Color", DefaultValue = "#FF5252", Group = "Aesthetics")]
public string PremiumColorHex { get; set; }
[Parameter("Discount Color", DefaultValue = "#2962FF", Group = "Aesthetics")]
public string DiscountColorHex { get; set; }
[Parameter("Line Color", DefaultValue = "#787B86", Group = "Aesthetics")]
public string LineColorHex { get; set; }
[Parameter("Show Data Dashboard", DefaultValue = true, Group = "Aesthetics")]
public bool ShowHUD { get; set; }
// =========================================================================
// STATE VARIABLES
// =========================================================================
private TimeSpan _startTime;
private TimeSpan _endTime;
private List<double> _pastRanges;
private bool _inSession;
private bool _alertTriggered;
private bool _bslSwept;
private bool _sslSwept;
private double _sessionHigh;
private double _sessionLow;
private DateTime _sessionStartTime;
private DateTime _sessionEndTime;
private Color _normalColor;
private Color _expandColor;
private Color _premColor;
private Color _discColor;
private Color _lineColor;
// HUD UI Elements
private Border _hudContainer;
private TextBlock _txtCurrentRange;
private TextBlock _txtAvgRange;
private TextBlock _txtStatus;
private TextBlock _txtLiquidity;
protected override void Initialize()
{
TimeSpan.TryParse(SessionStart, out _startTime);
TimeSpan.TryParse(SessionEnd, out _endTime);
_pastRanges = new List<double>();
_normalColor = Color.FromHex(NormalColorHex);
_expandColor = Color.FromHex(ExpandColorHex);
_premColor = Color.FromArgb(20, Color.FromHex(PremiumColorHex)); // 20 Alpha for shading
_discColor = Color.FromArgb(20, Color.FromHex(DiscountColorHex)); // 20 Alpha for shading
_lineColor = Color.FromHex(LineColorHex);
if (ShowHUD)
{
InitializeHUD();
}
}
public override void Calculate(int index)
{
var barTime = Bars.OpenTimes[index];
var timeOfDay = barTime.TimeOfDay;
bool isInside = IsTimeInSession(timeOfDay);
// ---------------------------------------------------------
// 1. SESSION TRANSITIONS & DATA LOGGING
// ---------------------------------------------------------
if (isInside && !_inSession)
{
_inSession = true;
_alertTriggered = false;
_bslSwept = false;
_sslSwept = false;
_sessionStartTime = barTime;
_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;
_sessionEndTime = barTime;
double finalRange = _sessionHigh - _sessionLow;
double sessionEq = _sessionLow + (finalRange / 2);
// Store range for AAR math
_pastRanges.Add(finalRange);
if (_pastRanges.Count > Lookback)
{
_pastRanges.RemoveAt(0);
}
// Project Forward Matrices into London (Time-based rendering)
DateTime projectionEnd = _sessionEndTime.AddHours(ExtendHours);
string ticks = _sessionStartTime.Ticks.ToString();
var premBox = Chart.DrawRectangle("PremBox_" + ticks, _sessionEndTime, _sessionHigh, projectionEnd, sessionEq, _premColor);
premBox.IsFilled = true;
premBox.Color = Color.Transparent; // Hide border
var discBox = Chart.DrawRectangle("DiscBox_" + ticks, _sessionEndTime, sessionEq, projectionEnd, _sessionLow, _discColor);
discBox.IsFilled = true;
discBox.Color = Color.Transparent; // Hide border
var extH = Chart.DrawTrendLine("ExtH_" + ticks, _sessionEndTime, _sessionHigh, projectionEnd, _sessionHigh, Color.FromHex(PremiumColorHex));
extH.LineStyle = LineStyle.Solid;
var extL = Chart.DrawTrendLine("ExtL_" + ticks, _sessionEndTime, _sessionLow, projectionEnd, _sessionLow, Color.FromHex(DiscountColorHex));
extL.LineStyle = LineStyle.Solid;
}
// ---------------------------------------------------------
// 2. ACTIVE SESSION DRAWING (BOX & QUARTILES)
// ---------------------------------------------------------
if (_inSession)
{
double currentRange = _sessionHigh - _sessionLow;
double avgRange = _pastRanges.Count > 0 ? _pastRanges.Average() : 0;
double sessionEq = _sessionLow + (currentRange / 2);
double session75 = _sessionLow + (currentRange * 0.75);
double session25 = _sessionLow + (currentRange * 0.25);
bool isExpansion = (avgRange > 0 && currentRange > (avgRange * Multiplier));
Color activeColor = isExpansion ? _expandColor : _normalColor;
string ticks = _sessionStartTime.Ticks.ToString();
// Draw Main Box
var box = Chart.DrawRectangle("AsiaBox_" + ticks, _sessionStartTime, _sessionHigh, barTime, _sessionLow, activeColor);
box.IsFilled = true;
box.Color = Color.FromArgb(40, activeColor);
// Draw Internal Quartiles
Chart.DrawTrendLine("AsiaEq_" + ticks, _sessionStartTime, sessionEq, barTime, sessionEq, _lineColor).LineStyle = LineStyle.Lines;
Chart.DrawTrendLine("Asia75_" + ticks, _sessionStartTime, session75, barTime, session75, _lineColor).LineStyle = LineStyle.Dots;
Chart.DrawTrendLine("Asia25_" + ticks, _sessionStartTime, session25, barTime, session25, _lineColor).LineStyle = LineStyle.Dots;
// Real-time Push Alert
if (IsLastBar && isExpansion && !_alertTriggered)
{
Print($"[{Symbol.Name}] Tokyo Expansion Triggered. London fades invalidated.");
Chart.DrawStaticText("AlertTxt", "⚠️ EXPANSION TRIGGERED (NO FADE)", VerticalAlignment.Top, HorizontalAlignment.Center, _expandColor);
_alertTriggered = true;
}
if (IsLastBar && ShowHUD) UpdateHUD(currentRange, avgRange, isExpansion);
}
else if (IsLastBar)
{
Chart.RemoveObject("AlertTxt"); // Clean up static alert text after session closes
}
// ---------------------------------------------------------
// 3. LONDON LIQUIDITY PURGE DETECTION
// ---------------------------------------------------------
bool inLondon = (!isInside && _sessionEndTime != default && barTime <= _sessionEndTime.AddHours(ExtendHours));
if (inLondon)
{
// Buy-Side Liquidity Purge
if (Bars.HighPrices[index] > _sessionHigh && !_bslSwept)
{
_bslSwept = true;
var txt = Chart.DrawText("BSL_" + index, "BSL", index, Bars.HighPrices[index], Color.FromHex(PremiumColorHex));
txt.VerticalAlignment = VerticalAlignment.Bottom;
if (IsLastBar) Print($"[{Symbol.Name}] BSL Purged in London Session.");
}
// Sell-Side Liquidity Purge
if (Bars.LowPrices[index] < _sessionLow && !_sslSwept)
{
_sslSwept = true;
var txt = Chart.DrawText("SSL_" + index, "SSL", index, Bars.LowPrices[index], Color.FromHex(DiscountColorHex));
txt.VerticalAlignment = VerticalAlignment.Top;
if (IsLastBar) Print($"[{Symbol.Name}] SSL Purged in London Session.");
}
// Update HUD regarding sweep statuses while in London
if (IsLastBar && ShowHUD)
{
double currentRange = _sessionHigh - _sessionLow;
double avgRange = _pastRanges.Count > 0 ? _pastRanges.Average() : 0;
bool isExpansion = (avgRange > 0 && currentRange > (avgRange * Multiplier));
UpdateHUD(currentRange, avgRange, isExpansion);
}
}
}
private bool IsTimeInSession(TimeSpan time)
{
if (_startTime < _endTime)
return time >= _startTime && time < _endTime;
return time >= _startTime || time < _endTime;
}
// =========================================================================
// NATIVE UI DASHBOARD (HUD)
// =========================================================================
private void InitializeHUD()
{
var panel = new StackPanel { Orientation = Orientation.Vertical, Margin = new Thickness(10) };
panel.AddChild(new TextBlock { Text = "MICROSTRUCTURE [ELITE]", ForegroundColor = Color.White, FontWeight = FontWeight.ExtraBold, Margin = new Thickness(0, 0, 0, 10) });
_txtCurrentRange = new TextBlock { ForegroundColor = Color.LightGray, Margin = new Thickness(0, 0, 0, 5) };
_txtAvgRange = new TextBlock { ForegroundColor = Color.LightGray, Margin = new Thickness(0, 0, 0, 10) };
_txtStatus = new TextBlock { FontWeight = FontWeight.Bold, Margin = new Thickness(0, 0, 0, 5) };
_txtLiquidity = new TextBlock { FontWeight = FontWeight.Bold };
panel.AddChild(_txtCurrentRange);
panel.AddChild(_txtAvgRange);
panel.AddChild(_txtStatus);
panel.AddChild(_txtLiquidity);
_hudContainer = new Border
{
BackgroundColor = Color.FromArgb(220, 19, 23, 34),
BorderColor = Color.FromArgb(255, 54, 58, 69),
BorderThickness = new Thickness(1),
CornerRadius = 3,
Margin = new Thickness(20),
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Bottom,
Child = panel
};
Chart.AddControl(_hudContainer);
}
private void UpdateHUD(double currentRange, double avgRange, bool isExpansion)
{
double pipsCurrent = Math.Round(currentRange / Symbol.PipSize, 1);
double pipsAvg = Math.Round(avgRange / Symbol.PipSize, 1);
double pctOfAvg = avgRange > 0 ? (currentRange / avgRange) * 100 : 0;
_txtCurrentRange.Text = $"Current Range: {pipsCurrent} pips";
_txtAvgRange.Text = $"15D Average: {pipsAvg} pips ({Math.Round(pctOfAvg)}%)";
// Validity Status
if (isExpansion)
{
_txtStatus.Text = "Setup Validity: EXPANSION (NO FADE)";
_txtStatus.ForegroundColor = _expandColor;
}
else
{
_txtStatus.Text = "Setup Validity: NORMAL / ACCUMULATION";
_txtStatus.ForegroundColor = _normalColor;
}
// Liquidity Sweep Status
if (_bslSwept && _sslSwept)
{
_txtLiquidity.Text = "London Liquidity: Both Sides Purged";
_txtLiquidity.ForegroundColor = Color.MediumPurple;
}
else if (_bslSwept)
{
_txtLiquidity.Text = "London Liquidity: BSL Purged (High Taken)";
_txtLiquidity.ForegroundColor = Color.FromHex(PremiumColorHex);
}
else if (_sslSwept)
{
_txtLiquidity.Text = "London Liquidity: SSL Purged (Low Taken)";
_txtLiquidity.ForegroundColor = Color.FromHex(DiscountColorHex);
}
else
{
_txtLiquidity.Text = "London Liquidity: Intact";
_txtLiquidity.ForegroundColor = Color.Gray;
}
}
}
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
-
LondonScalper
- Posts: 701
- Joined: Sat Sep 05, 2026 7:54 am
Re: Tokyo morning expansion days: when I refuse the London fade
Quantifying against a 10-day AAR is the missing piece in what I had been doing by eye. "Looks expanded" is how casual fades sneak back onto the ticket. Clean unfilled displacement with defended higher-lows is expansion; overlapping micro sweeps are the fadeable box. Your DXY filter for the euro/sterling pair is fair — if Asia only drifted 25 pips on EURUSD while USDJPY ran a hundred, London mean-reversion on Europe can still be a separate trade.PTScalper wrote:If the Tokyo range exceeds 1.5x of its 10-day Average Asian Range before London opens, the fade is completely off the table. Pair that with clean M15 displacement and shallow pullbacks. Enforce no-fade strictly on JPY crosses and AUD/NZD; for EURUSD/GBPUSD check whether DXY was the real expander.
Desk rule from tomorrow's open: measure Asia range vs 10-day AAR at 07:00 UTC; above 1.5x = fade veto on JPY crosses and AUD/NZD; EUR/GBP only if DXY was quiet. Continuation or sideways digest both beat a lazy fade into a blown Asia extreme.
Do you also veto when Asia is under 1.5x AAR but the last two hours before London print one-way displacement candles, or is the AAR gate alone enough?
Re: Tokyo morning expansion days: when I refuse the London fade
Hi LondonScalper,LondonScalper wrote: Tue Sep 22, 2026 9:56 pmQuantifying against a 10-day AAR is the missing piece in what I had been doing by eye. "Looks expanded" is how casual fades sneak back onto the ticket. Clean unfilled displacement with defended higher-lows is expansion; overlapping micro sweeps are the fadeable box. Your DXY filter for the euro/sterling pair is fair — if Asia only drifted 25 pips on EURUSD while USDJPY ran a hundred, London mean-reversion on Europe can still be a separate trade.PTScalper wrote:If the Tokyo range exceeds 1.5x of its 10-day Average Asian Range before London opens, the fade is completely off the table. Pair that with clean M15 displacement and shallow pullbacks. Enforce no-fade strictly on JPY crosses and AUD/NZD; for EURUSD/GBPUSD check whether DXY was the real expander.
Desk rule from tomorrow's open: measure Asia range vs 10-day AAR at 07:00 UTC; above 1.5x = fade veto on JPY crosses and AUD/NZD; EUR/GBP only if DXY was quiet. Continuation or sideways digest both beat a lazy fade into a blown Asia extreme.
Do you also veto when Asia is under 1.5x AAR but the last two hours before London print one-way displacement candles, or is the AAR gate alone enough?
The AAR gate alone is never enough. You must absolutely veto the fade if the final two hours print one-way displacement.
Statistical averages like the AAR measure the container, but raw price action dictates the intent. If the Asian session flatlines for six hours and then violently breaks out during the Frankfurt transition, the total range might still sit comfortably under your 1.5x AAR threshold. But stepping in front of that late momentum is stepping in front of a freight train.
Here is why the 15-minute candlestick structure leading into the open overrides the session average:
Early Order Flow: One-way displacement immediately preceding London usually represents real institutional volume stepping in early, not the exhausted, low-liquidity drift that characterizes a fadeable Asian extreme.
Velocity Over Distance: Mean-reversion relies on exhaustion. A slow, overlapping, low-momentum grind that takes eight hours to bleed to 1.3x AAR is a prime fade candidate. A tight consolidation that suddenly prints three consecutive full-bodied 15-minute candles to reach just 0.9x AAR is an active breakout. The speed of the move invalidates the fade.
Structural Intent: If that late displacement shatters local market structure and closes cleanly beyond a prior daily pivot without an immediate wick rejection, the narrative has shifted. You are no longer fading an Asian range; you are fading the first leg of a new directional move.
The AAR filter is your baseline permission slip, but the raw 15-minute chart is the final judge. If the candles leading into 07:00 UTC are closing full and heavy on their extremes without wicks, the fade is permanently off the table for that session.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.