Page 1 of 1

Measuring slippage by session: London vs NY vs Asia sample

Posted: Tue Sep 22, 2026 10:33 am
by LondonScalper
I stopped arguing about "slippage is fine" until I split the sample by session.

Same pair, same order type, three buckets: Asia, London, New York. The histograms do not look alike. London has more events and a fatter mid; Asia has fewer trades and the occasional ugly tail; NY overlap can look like London until a US data release rewrites the right side of the chart.

Sample discipline I use
  • At least a few dozen fills per bucket before I talk about medians
  • Side-aware: buys and sells logged separately when the book is skewed
  • News minutes tagged so they do not poison the "normal session" view
Once I saw the tails by session, my size and pair choices changed more than any new entry rule. Slippage is not one number — it is a shape.

How do you bucket slippage in your own log, and did any session surprise you once the sample was honest?

When the London sample is fat enough, I sometimes split overlap minutes from pure NY afternoon. Overlap can borrow London shape or invent its own tails around US data. The goal is not a prettier chart — it is knowing which session still deserves size after costs.

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:26 pm
by PTScalper
LondonScalper wrote: Tue Sep 22, 2026 10:33 am I stopped arguing about "slippage is fine" until I split the sample by session.

Same pair, same order type, three buckets: Asia, London, New York. The histograms do not look alike. London has more events and a fatter mid; Asia has fewer trades and the occasional ugly tail; NY overlap can look like London until a US data release rewrites the right side of the chart.

Sample discipline I use
  • At least a few dozen fills per bucket before I talk about medians
  • Side-aware: buys and sells logged separately when the book is skewed
  • News minutes tagged so they do not poison the "normal session" view
Once I saw the tails by session, my size and pair choices changed more than any new entry rule. Slippage is not one number — it is a shape.

How do you bucket slippage in your own log, and did any session surprise you once the sample was honest?

When the London sample is fat enough, I sometimes split overlap minutes from pure NY afternoon. Overlap can borrow London shape or invent its own tails around US data. The goal is not a prettier chart — it is knowing which session still deserves size after costs.
Hi LondonScalper,

Bucketing slippage by session reveals that liquidity is not just about volume; it is about order book density. When looking at an honest, side-aware sample, the biggest surprise is usually the Asia session's asymmetry.

While London has a fat, normal distribution of minor slippage driven by high transaction velocity, Asia often prints zero slippage 90% of the time. But because the top-of-book is thin, that remaining 10% consists of violent, asymmetric tails. A moderate market order—or a cascading stop run—sweeps multiple price levels instantly.

The Overlap presents a different trap. It looks incredibly liquid, but the moment high-impact US macro data approaches, market makers pull their resting limit orders. The spread widens infinitesimally before the spike, turning a deep London-style book into an air pocket. For M1 or M5 price action scalping where the margin for error is incredibly tight, catching those vacuum effects in the data dictates position sizing far more than the entry setup itself.

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:26 pm
by PTScalper
MQL4 Implementation
Because MT4 overwrites the requested price with the fill price in the history tab for market orders, you cannot extract accurate slippage from OrdersHistoryTotal(). It must be logged in real-time at the exact moment of execution.

This MQL4 snippet provides a real-time trade logger that calculates exact point slippage, tags the execution session based on broker server time, and exports it to a CSV for external histogram analysis.

Code: Select all

//+------------------------------------------------------------------+
//|                                          SessionSlippageLog.mq4  |
//+------------------------------------------------------------------+
#property strict

// Adjust these to match your broker's server time GMT offset
input int LondonStartHour = 8;
input int NYStartHour = 13; // NY open / Overlap start
input int NYEndHour = 17;   // London Close / Pure NY afternoon starts here

string logFileName = "Slippage_Log.csv";

// Call this function immediately after a successful OrderSend() 
// or when detecting a pending order trigger.
void LogTradeExecution(int ticket, double requestedPrice, double filledPrice, int cmd)
{
    if(ticket <= 0) return;

    int fileHandle = FileOpen(logFileName, FILE_READ|FILE_WRITE|FILE_CSV|FILE_ANSI, ",");
    if(fileHandle == INVALID_HANDLE)
    {
        Print("Failed to open slippage log file. Error: ", GetLastError());
        return;
    }

    // Move to end of file to append new records
    FileSeek(fileHandle, 0, SEEK_END);

    // Write headers if the file is newly created
    if(FileSize(fileHandle) == 0)
    {
        FileWrite(fileHandle, "Ticket", "Time", "Symbol", "Side", "Session", "Requested", "Filled", "Slippage_Points");
    }

    string side = (cmd == OP_BUY) ? "Buy" : "Sell";
    string session = GetSession(TimeCurrent());
    double slippage = 0;

    // Calculate slippage in points (positive = bad slippage, negative = positive slippage)
    if(cmd == OP_BUY)
        slippage = (filledPrice - requestedPrice) / Point;
    else if(cmd == OP_SELL)
        slippage = (requestedPrice - filledPrice) / Point;

    FileWrite(fileHandle,
              IntegerToString(ticket),
              TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES|TIME_SECONDS),
              Symbol(),
              side,
              session,
              DoubleToString(requestedPrice, Digits),
              DoubleToString(filledPrice, Digits),
              DoubleToString(slippage, 1));

    FileClose(fileHandle);
}

// Determines the session bucket based on execution time
string GetSession(datetime time)
{
    int hour = TimeHour(time);

    if(hour >= LondonStartHour && hour < NYStartHour) return "London";
    if(hour >= NYStartHour && hour < NYEndHour) return "Overlap";
    if(hour >= NYEndHour && hour < 22) return "New York";
    
    return "Asia"; // Catch-all for 22:00 to 08:00 server time
}

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:26 pm
by PTScalper
To isolate the "news minutes" you mentioned, you can either integrate an economic calendar API directly into the MQL4 script to flag rows dynamically, or simply pass this CSV into a backend database and cross-reference the execution timestamps against a historical news dataset.

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:27 pm
by PTScalper
How can I automate tagging high-impact macroeconomic news minutes in my trading logs using C# or a Python script to keep the session data clean?

Python with the pandas library is the most efficient way to handle this, as its time-series manipulation capabilities make windowed cross-referencing trivial.

This script pulls high-impact events from a public JSON feed, normalizes the timezone differences between your broker's server and the economic calendar, and tags any trade executed within a configurable window (e.g., ±15 minutes) of a relevant data release.

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:28 pm
by PTScalper
Python News-Tagging Script

Code: Select all

import pandas as pd
import requests

def fetch_economic_calendar():
    # Forex Factory provides a free, public JSON feed for the current week
    url = "https://nfs.faireconomy.media/ff_calendar_thisweek.json"
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
    
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    
    # Load into a DataFrame and filter for High impact events
    df = pd.DataFrame(response.json())
    high_impact = df[df['impact'] == 'High'].copy()
    
    # The 'date' field includes the timezone offset (e.g., 2026-09-23T08:30:00-04:00)
    # Convert it to a standardized UTC datetime
    high_impact['datetime_utc'] = pd.to_datetime(high_impact['date'], utc=True)
    
    return high_impact

def tag_trade_logs(csv_path, output_path, broker_utc_offset=3, window_minutes=15):
    # Load your MT4 slippage log
    trades = pd.read_csv(csv_path)
    
    # 1. Timezone Normalization
    # MT4 server time is typically EET (UTC+2 in winter, UTC+3 in summer)
    # We must subtract the offset and localize to UTC to match the news calendar
    trades['Time_UTC'] = pd.to_datetime(trades['Time']) - pd.Timedelta(hours=broker_utc_offset)
    trades['Time_UTC'] = trades['Time_UTC'].dt.tz_localize('UTC')
    
    news_df = fetch_economic_calendar()
    
    def apply_tag(row):
        trade_time = row['Time_UTC']
        symbol = str(row['Symbol']) # e.g., "EURUSD"
        
        # 2. Currency Parsing
        # Split symbol into base and quote (EUR and USD)
        base_ccy, quote_ccy = symbol[:3], symbol[3:6]
        
        # Filter the high-impact calendar for events affecting these specific currencies
        relevant_news = news_df[news_df['country'].isin([base_ccy, quote_ccy, 'ALL'])]
        
        # 3. Proximity Check
        for _, event in relevant_news.iterrows():
            time_diff_minutes = abs((trade_time - event['datetime_utc']).total_seconds()) / 60
            
            if time_diff_minutes <= window_minutes:
                return f"News: {event['title']} ({event['country']})"
                
        return "Normal"

    # Apply the tagging logic row by row
    trades['Execution_Context'] = trades.apply(apply_tag, axis=1)
    
    # Clean up and export
    trades = trades.drop(columns=['Time_UTC'])
    trades.to_csv(output_path, index=False)
    print(f"Tagged log saved to {output_path}")

# Example Usage:
# tag_trade_logs("Slippage_Log.csv", "Slippage_Log_Tagged.csv", broker_utc_offset=3, window_minutes=15)

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:28 pm
by PTScalper
Critical Implementation Details

Timezone Alignment: This is the most common point of failure. The script assumes your broker operates on UTC+3 (Summer DST). If you apply this to logs generated in December, you must dynamically adjust the broker_utc_offset to 2.

Asset Mapping: The script simply splits EURUSD into EUR and USD. If you trade spot gold (XAUUSD) or equities, you will need to add a hardcoded override that maps those specific symbols to check for USD macroeconomic events.

Deep Historical Data: The endpoint used above only returns the current week's data, which is perfect for continuous weekly logging. If you are parsing years of historical execution logs in bulk, you will need a historical dataset. You can pull historical macroeconomic events using the Finnhub Economic Calendar API or load a static CSV exported from an economic calendar provider.

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:28 pm
by PTScalper
To compare slippage between Normal and News environments across different trading sessions, you need to reduce the specific news tags (e.g., "News: NFP (USD)") into a binary "News" category, calculate the summary statistics using .groupby(), and plot a normalized density histogram.

Because you will have significantly fewer news trades than normal trades, a standard count-based histogram will dwarf the news data. Using seaborn.displot with stat='density' normalizes the y-axis, allowing you to directly compare the shape and tails of both environments regardless of sample size.

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:29 pm
by PTScalper
Python Analysis Script

Code: Select all

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

def analyze_slippage(csv_path):
    # Load the tagged execution log
    df = pd.read_csv(csv_path)

    # 1. Standardize the Environment column
    # Converts specific tags like "News: FOMC (USD)" into a broader "News" category
    df['Environment'] = df['Execution_Context'].apply(
        lambda x: 'Normal' if x == 'Normal' else 'News'
    )

    # 2. Calculate Medians and Summary Statistics
    # Group by Session and Environment to isolate the metrics
    summary_stats = df.groupby(['Session', 'Environment'])['Slippage_Points'].agg(
        Trade_Count='count',
        Median_Slippage='median',
        Mean_Slippage='mean',
        Max_Adverse_Tail='max'
    ).round(2).reset_index()

    print("--- Slippage Summary by Session ---")
    print(summary_stats.to_string(index=False))
    print("\n")

    # 3. Generate Comparative Histograms
    sns.set_theme(style="darkgrid")
    
    # Create a faceted grid with one plot per session
    g = sns.displot(
        data=df,
        x='Slippage_Points',
        hue='Environment',
        col='Session',         # Creates a separate chart for Asia, London, and NY Overlap
        kind='hist',
        stat='density',        # Normalizes the area under the curve to 1 for visual comparison
        common_norm=False,     # Calculates density independently for News vs Normal
        bins=30,
        alpha=0.6,
        height=5,
        aspect=1.2,
        palette={'Normal': '#3498db', 'News': '#e74c3c'}
    )

    # Format the charts
    g.set_axis_labels("Slippage (Points)", "Density")
    g.set_titles(col_template="{col_name} Session")
    plt.subplots_adjust(top=0.85)
    g.fig.suptitle('Slippage Shape: Normal vs News Environments', fontsize=16)
    
    # Display the plot
    plt.show()

# Example Usage:
# analyze_slippage("Slippage_Log_Tagged.csv")

Re: Measuring slippage by session: London vs NY vs Asia sample

Posted: Wed Sep 23, 2026 7:29 pm
by PTScalper
Key Data Operations

df.groupby(['Session', 'Environment']): This creates a multi-index grouping so that you can view the exact median and worst-case tail (Max_Adverse_Tail) for an event like the NY Overlap during a news release versus standard NY Overlap flow.

stat='density' & common_norm=False: This is the most critical setting for the histogram. If you have 500 normal overlap trades and 30 news trades, a standard histogram makes the news tail invisible. Density scaling forces both histograms to share the same visual weight, exposing exactly how the mid thins out and the tail fattens during a data release.

Outlier Filtering (Optional): If a single extreme flash-crash event stretches your x-axis so far that the mid becomes unreadable, you can truncate the visualization data without deleting the underlying log by passing a filtered dataframe to the plot: data=df[df['Slippage_Points'] < df['Slippage_Points'].quantile(0.99)].