Page 1 of 1
Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Tue Sep 22, 2026 10:54 am
by LondonScalper
Tokyo morning EURUSD can look cheap until the spread quietly fails your filter.
I used to take "small" mean-reversion ideas overnight because the chart was clean. Then I tagged trades where live spread sat above my cap at entry. Expectancy after costs was not the story the M5 candle suggested. Asia liquidity is real, but it is not London, and EURUSD is not obligated to behave like a London pair at 02:00.
Filter I enforce
1. Hard max spread at click — no discretionary "it will tighten."
2. If the filter trips, the idea goes to the journal as skip_cost, not as a missed winner.
3. Size only comes back when the quote is inside the cap for more than a single flicker.
Standing aside on a clean chart is annoying. Paying a hidden tax for the privilege of being early is worse.
Do you keep a Tokyo-specific spread cap on EURUSD, or one global number that mostly reflects London?
EURUSD overnight still gets a glance for levels I might use after London open — watching is free. Trading through a failed filter is not. The journal line skip_cost keeps those mornings from disappearing into I-should-have-taken-it folklore on Sunday.
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:07 pm
by PTScalper
LondonScalper wrote: Tue Sep 22, 2026 10:54 am
Tokyo morning EURUSD can look cheap until the spread quietly fails your filter.
I used to take "small" mean-reversion ideas overnight because the chart was clean. Then I tagged trades where live spread sat above my cap at entry. Expectancy after costs was not the story the M5 candle suggested. Asia liquidity is real, but it is not London, and EURUSD is not obligated to behave like a London pair at 02:00.
Filter I enforce
1. Hard max spread at click — no discretionary "it will tighten."
2. If the filter trips, the idea goes to the journal as
skip_cost, not as a missed winner.
3. Size only comes back when the quote is inside the cap for more than a single flicker.
Standing aside on a clean chart is annoying. Paying a hidden tax for the privilege of being early is worse.
Do you keep a Tokyo-specific spread cap on EURUSD, or one global number that mostly reflects London?
EURUSD overnight still gets a glance for levels I might use after London open — watching is free. Trading through a failed filter is not. The journal line skip_cost keeps those mornings from disappearing into I-should-have-taken-it folklore on Sunday.
Hi LondonScalper,
A global spread cap is a trap. If you calibrate your maximum spread to London’s deep liquidity (e.g., 0.3 to 0.5 pips on EURUSD), your filter will lock you out of Tokyo entirely. If you widen a global cap to accommodate Asia (e.g., 1.5 pips), you expose yourself to sloppy, toxic fills during the overlap hours when a 1.5 pip spread actually indicates severe market stress or a news event.
You need a session-specific cap. EURUSD at 02:00 GMT is essentially a different asset than EURUSD at 09:00 GMT. The algorithm should expect, and accept, a slightly wider baseline in Tokyo, but it must strictly cut off the moment that baseline stretches into illiquidity.
Your skip_cost journaling rule is bulletproof psychology. Charting platforms plot the bid (or mid) price, making historical charts look like pristine mean-reversion playgrounds. The spread is invisible in hindsight. By actively tagging skip_cost, you kill the Sunday night FOMO of "I missed a winner" and replace it with "I executed my risk-management rules perfectly."
Here is a Pine Script (v5) built to enforce this exact workflow.
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:08 pm
by PTScalper
How This Script Works
1.) The Flicker Filter: Instead of checking the spread for a single tick, it uses a rolling window. The spread must remain below your cap for $N$ consecutive bars (or ticks on lower timeframes) to prove the liquidity is real, not just a momentary quote flicker.
2.) Session Isolation: It actively isolates your defined Tokyo window.
3.) The Journal Tag: It visualizes your exact journal process. If a mock mean-reversion setup triggers but the spread fails the test, it prints an orange SKIP (skip_cost) on the chart. If the spread is healthy, it prints a green ENTRY.
(Note: In TradingView, syminfo.spread is dynamic in live real-time forward testing, but often defaults to your broker's static historical average when looking back in time. This script is designed to run live to catch those real-time spread blowouts.)
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:08 pm
by PTScalper
Pine script:
Code: Select all
//@version=5
indicator("Tokyo Spread Filter & Journal", overlay=true)
// =========================================================================
// INPUTS
// =========================================================================
grp_session = "Session & Setup"
tokyo_session = input.session("1900-0300", title="Tokyo Session (EST)", group=grp_session)
grp_spread = "Spread & Liquidity Filter"
max_spread_pips = input.float(1.2, title="Hard Max Spread (Pips)", step=0.1, group=grp_spread)
flicker_bars = input.int(3, title="Flicker Filter (Bars)", minval=1, tooltip="Spread must stay under the cap for this many consecutive bars to validate the quote.", group=grp_spread)
// =========================================================================
// SPREAD CALCULATION
// =========================================================================
// Convert mintick to standard pips (Standardizing for 5-digit brokers)
pip_multiplier = syminfo.mintick == 0.001 ? 100 : syminfo.mintick == 0.00001 ? 10000 : 1
current_spread_pips = (syminfo.spread * syminfo.mintick) * pip_multiplier
// Flicker Filter: The highest spread over the last N bars must be <= max cap
spread_is_safe = ta.highest(current_spread_pips, flicker_bars) <= max_spread_pips
// =========================================================================
// SESSION & MOCK SETUP LOGIC
// =========================================================================
in_session = not na(time(timeframe.period, tokyo_session))
// Mock Mean-Reversion Setup (Price crossing under a 20-period, 2-StdDev Lower Bollinger Band)
[_, _, lower_bb] = ta.bb(close, 20, 2)
setup_triggered = in_session and ta.crossunder(close, lower_bb)
// =========================================================================
// EXECUTION & JOURNALING LOGIC
// =========================================================================
// The setup fired, and the spread is healthy
valid_entry = setup_triggered and spread_is_safe
// The setup fired, but the spread tripped the filter (Your skip_cost rule)
skip_cost = setup_triggered and not spread_is_safe
// =========================================================================
// VISUALS & ALERTS
// =========================================================================
// Highlight the Tokyo Session
bgcolor(in_session ? color.new(color.blue, 95) : na, title="Tokyo Session Background")
// Plot the Journal Entries
plotshape(valid_entry, title="Valid Entry", shape=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, text="ENTRY")
plotshape(skip_cost, title="Skip (Cost)", shape=shape.xcross, location=location.belowbar, color=color.orange, size=size.small, text="SKIP")
// Live Alerts
alertcondition(valid_entry, title="Live Entry Alert", message="Setup valid. Spread is within cap.")
alertcondition(skip_cost, title="Spread Cap Tripped", message="Setup ignored. Spread exceeded max cap (skip_cost).")
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:10 pm
by PTScalper
Moving this logic into MetaTrader gives you a major edge over TradingView: true tick-level quotes. TradingView often interpolates or averages broker spreads on historical data, but MT4 and MT5 inspect live Ask - Bid delta on every incoming quote.
Both versions below implement:
1.) The Live Spread Calculator: Converts broker points into fractional pips (accounting for 3/5-digit pricing).
2.) The Tick Flicker Filter: Requires $N$ consecutive live ticks inside your spread cap before approving an entry. A single flash quote resets the counter immediately.
3.) Session Gating: Restricts scanning to your specified Tokyo window (in broker server time).
4.) The skip_cost Tag: Plots a green arrow on verified entries and an orange cross on skip_cost, simultaneously logging the exact spread to your Terminal's Experts / Journal tab.
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:11 pm
by PTScalper
1. MetaTrader 4 (MQL4)
Save this as a Custom Indicator in MetaEditor (File -> New -> Custom Indicator), name it Tokyo_Spread_Filter, and compile.
Code: Select all
//+------------------------------------------------------------------+
//| Tokyo_Spread_Filter_MT4.mq4 |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrLimeGreen
#property indicator_color2 clrDarkOrange
#property indicator_width1 2
#property indicator_width2 2
// Buffers
double EntryBuffer[];
double SkipCostBuffer[];
// Inputs
input string InpGroupSession = "=== Session Window (Server Time) ===";
input int InpStartHour = 0; // Tokyo Start Hour
input int InpEndHour = 8; // Tokyo End Hour
input string InpGroupSpread = "=== Spread & Flicker Filter ===";
input double InpMaxSpreadPips = 1.2; // Hard Max Spread (Pips)
input int InpFlickerTicks = 5; // Consecutive Safe Ticks Required
input string InpGroupStrategy = "=== Mean-Reversion Setup ===";
input int InpBBPeriod = 20; // Bollinger Bands Period
input double InpBBDev = 2.0; // Bollinger Bands Deviation
// State variables
static int safe_ticks_count = 0;
static datetime last_alert_bar = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, EntryBuffer);
SetIndexStyle(0, DRAW_ARROW);
SetIndexArrow(0, 233); // Wingdings Up Arrow
SetIndexLabel(0, "Valid Entry");
SetIndexBuffer(1, SkipCostBuffer);
SetIndexStyle(1, DRAW_ARROW);
SetIndexArrow(1, 251); // Wingdings X (Cross)
SetIndexLabel(1, "Skip Cost");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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 < InpBBPeriod + 1) return 0;
// 1. Calculate live spread in standard pips
double pip_size = (_Digits == 3 || _Digits == 5) ? _Point * 10.0 : _Point;
double current_spread = (Ask - Bid) / pip_size;
// 2. Flicker Filter: Quote must hold below the cap for N consecutive ticks
if(current_spread <= InpMaxSpreadPips)
safe_ticks_count++;
else
safe_ticks_count = 0;
bool spread_is_safe = (safe_ticks_count >= InpFlickerTicks);
// 3. Session Gate (Broker Server Time)
int current_hour = TimeHour(TimeCurrent());
bool in_session = (InpStartHour <= InpEndHour) ?
(current_hour >= InpStartHour && current_hour < InpEndHour) :
(current_hour >= InpStartHour || current_hour < InpEndHour);
// 4. Setup Evaluation (Triggered once per completed candle)
datetime current_bar_time = Time[0];
if(in_session && current_bar_time != last_alert_bar)
{
double bb_lower = iBands(NULL, 0, InpBBPeriod, InpBBDev, 0, PRICE_CLOSE, MODE_LOWER, 1);
// Mean-reversion condition: Bar 1 closed beneath the lower band
if(Close[1] < bb_lower && Open[1] >= bb_lower)
{
if(spread_is_safe)
{
EntryBuffer[1] = Low[1] - (15 * _Point);
PrintFormat("[ENTRY] Tokyo EURUSD setup confirmed. Spread: %.1f pips (Held for %d ticks)", current_spread, safe_ticks_count);
Alert(StringFormat("EURUSD ENTRY: Spread %.1f pips", current_spread));
}
else
{
SkipCostBuffer[1] = Low[1] - (15 * _Point);
PrintFormat("[skip_cost] Tokyo EURUSD filter tripped. Spread: %.1f pips > Cap %.1f", current_spread, InpMaxSpreadPips);
Alert(StringFormat("EURUSD skip_cost: Spread %.1f pips", current_spread));
}
last_alert_bar = current_bar_time;
}
}
return(rates_total);
}
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:11 pm
by PTScalper
2. MetaTrader 5 (MQL5)
In MT5, indicators handle dynamic arrays and calculation handles asynchronously. Save this in MetaEditor as Tokyo_Spread_Filter_MT5.mq5.
Code: Select all
//+------------------------------------------------------------------+
//| Tokyo_Spread_Filter_MT5.mq5 |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLimeGreen
#property indicator_width1 2
#property indicator_label1 "Valid Entry"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrDarkOrange
#property indicator_width2 2
#property indicator_label2 "Skip Cost"
// Buffers
double EntryBuffer[];
double SkipCostBuffer[];
// Inputs
input group "=== Session Window (Server Time) ==="
input int InpStartHour = 0; // Tokyo Start Hour
input int InpEndHour = 8; // Tokyo End Hour
input group "=== Spread & Flicker Filter ==="
input double InpMaxSpreadPips = 1.2; // Hard Max Spread (Pips)
input int InpFlickerTicks = 5; // Consecutive Safe Ticks Required
input group "=== Mean-Reversion Setup ==="
input int InpBBPeriod = 20; // Bollinger Bands Period
input double InpBBDev = 2.0; // Bollinger Bands Deviation
// State variables
int bb_handle;
static int safe_ticks_count = 0;
static datetime last_alert_bar = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, EntryBuffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_ARROW, 233); // Wingdings Up Arrow
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
SetIndexBuffer(1, SkipCostBuffer, INDICATOR_DATA);
PlotIndexSetInteger(1, PLOT_ARROW, 251); // Wingdings X (Cross)
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
bb_handle = iBands(_Symbol, _Period, InpBBPeriod, 0, InpBBDev, PRICE_CLOSE);
if(bb_handle == INVALID_HANDLE)
{
Print("Failed to create Bollinger Bands indicator handle.");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(bb_handle);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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 < InpBBPeriod + 2) return 0;
// 1. Get live tick spread
MqlTick last_tick;
if(!SymbolInfoTick(_Symbol, last_tick)) return rates_total;
double pip_size = (_Digits == 3 || _Digits == 5) ? _Point * 10.0 : _Point;
double current_spread = (last_tick.ask - last_tick.bid) / pip_size;
// 2. Flicker Filter: Spread must remain safe for consecutive ticks
if(current_spread <= InpMaxSpreadPips)
safe_ticks_count++;
else
safe_ticks_count = 0;
bool spread_is_safe = (safe_ticks_count >= InpFlickerTicks);
// 3. Session Gate (Broker Server Time)
MqlDateTime tm;
TimeToStruct(TimeCurrent(), tm);
bool in_session = (InpStartHour <= InpEndHour) ?
(tm.hour >= InpStartHour && tm.hour < InpEndHour) :
(tm.hour >= InpStartHour || tm.hour < InpEndHour);
// 4. Setup Evaluation on Completed Candle
int current_bar_idx = rates_total - 1;
datetime current_bar_time = time[current_bar_idx];
if(in_session && current_bar_time != last_alert_bar)
{
double lower_bb[1];
// Index 1 = most recently closed candle
if(CopyBuffer(bb_handle, 2, 1, 1, lower_bb) <= 0) return rates_total;
int prev_idx = rates_total - 2;
if(close[prev_idx] < lower_bb[0] && open[prev_idx] >= lower_bb[0])
{
if(spread_is_safe)
{
EntryBuffer[prev_idx] = low[prev_idx] - (15 * _Point);
PrintFormat("[ENTRY] Tokyo EURUSD confirmed. Spread: %.1f pips (Held for %d ticks)", current_spread, safe_ticks_count);
Alert(StringFormat("EURUSD ENTRY: Spread %.1f pips", current_spread));
}
else
{
SkipCostBuffer[prev_idx] = low[prev_idx] - (15 * _Point);
PrintFormat("[skip_cost] Tokyo EURUSD aborted. Spread: %.1f pips > Cap %.1f", current_spread, InpMaxSpreadPips);
Alert(StringFormat("EURUSD skip_cost: Spread %.1f pips", current_spread));
}
last_alert_bar = current_bar_time;
}
}
return(rates_total);
}
Re: Avoiding EURUSD during Tokyo morning when spreads exceed my filter
Posted: Wed Sep 23, 2026 8:12 pm
by PTScalper
Execution Notes
Adjusting to Broker Server Time: InpStartHour and InpEndHour refer to the clock shown on your MT4/MT5 Market Watch. Most FX brokers run on GMT+2 / GMT+3 (NY close 5 PM alignment). At GMT+2, Tokyo open (00:00 GMT) is 02:00 server time. Check your broker's clock to set your session window accurately.
Finding Your skip_cost Log: Open the bottom dock in MetaTrader (Ctrl + T in MT4, Ctrl + T in MT5) and select the Experts or Journal tab. Every blocked setup will show up as: