Every retail trader has felt it: you get filled a little worse than the price you clicked, again and again, and you start to wonder whether it is just the market or something else. The honest answer is that you cannot know from a feeling. You can know from the data.
This is the first post in a short series where I measure the parts of retail trading execution that brokers do not publish. I build execution and arbitrage software at BJF Trading Group, and the recurring lesson across thousands of accounts is the same: your fill quality is a measurable property, not a matter of trust.
Let us measure slippage properly.
Slippage is fine. Asymmetry is the tell.
Slippage is the gap between the price you requested and the price you got. In a moving market, some of it is unavoidable and completely fair. The mistake is judging a broker by the average slippage, because an average hides the one thing that matters: the shape of the distribution.
A fair execution path slips you both ways. Sometimes worse, sometimes better (price improvement). A hostile one slips you almost always in the direction that costs you. Same average is possible in both cases. The distribution is what separates them.
Define per-trade slippage with a consistent sign
The first trick is to make the sign mean the same thing for buys and sells. Positive = filled better than requested, negative = filled worse.
import numpy as np
import pandas as pd
def signed_slippage_pips(df, pip_size=0.0001):
# direction: for buy, -1 for sell
raw = (df["fill_price"] - df["requested_price"]) / pip_size
return raw * df["direction"]
# df columns: requested_price, fill_price, direction (1), profit
df["slip"] = signed_slippage_pips(df)
Now a positive slip always means the fill helped you and a negative slip always means it hurt you, whether you were buying or selling.
The symmetry ratio
The single most useful number is the ratio of favorable to unfavorable fills.
pos = (df["slip"] > 0).sum()
neg = (df["slip"] < 0).sum()
symmetry_ratio = pos / max(neg, 1)
print(f"favorable fills: {pos}")
print(f"unfavorable fills: {neg}")
print(f"symmetry ratio: {symmetry_ratio:.2f}")
print(f"mean slip: {df['slip'].mean():.3f} pips")
Interpretation:
- Ratio near 1.0 with real positive slippage present: healthy, two-sided execution.
- Ratio well below 1.0, positive slippage almost never appearing: one-sided execution. The mean can still look small while the distribution is entirely against you.
You need a decent sample. A couple of hundred trades minimum before the ratio means anything.
Look at the histogram, not just the number
import matplotlib.pyplot as plt
plt.hist(df["slip"], bins=40)
plt.axvline(0, linestyle="--")
plt.xlabel("signed slippage (pips)")
plt.ylabel("count")
plt.title("Fill distribution")
plt.show()
A fair broker gives you something roughly centered, with a tail on both sides. A hostile one gives you a distribution that is chopped off at zero on the favorable side, with all the mass sitting in negative territory.
The part most people miss: correlate slippage with your outcome
Asymmetric execution is not just one-sided on average. It tends to get worse specifically on the trades that were about to win. So the strongest test is to condition slippage on the trade result.
winners = df[df["profit"] > 0]["slip"]
losers = df[df["profit"] <= 0]["slip"]
print(f"mean slip on winners: {winners.mean():.3f} pips")
print(f"mean slip on losers: {losers.mean():.3f} pips")
If your winners are consistently slipped harder than your losers, that is not the market being fair to everyone equally. That is a distribution being shaped around your profitability.
Why this matters more than any review
A broker can buy reviews. It cannot edit the tick-by-tick record sitting on your own machine. Your fill log is the one un-gameable source of truth about how you are actually treated, and it takes about thirty lines of Python to read it.
If you want the deeper version of this, with the broker-side mechanics behind why the distribution ends up one-sided (last look, toxic-flow handling, server-side execution filters), I wrote it up here: How brokers really fill your orders. The formal treatment of when these costs cross the line into erasing an edge is in the paper The Mathematics of Slippage.
Next in the series: simulating "last look", the short hold window where a lot of this asymmetry is actually created.
I develop arbitrage and execution software at BJF Trading Group. The open BEQI methodology for scoring broker execution from your own logs is at bjftradinggroup.com.
Top comments (0)