Bad ticks: the single quote that ruins a test
Occasionally a feed produces a quote that is plainly wrong: a price 50 pips off for one tick, or a bid higher than the ask. These bad ticks can appear in live feeds and in stored history.
In a chart they show as a long spike on a single bar. In a backtest they can trigger stops or targets that never existed in the real market, or create a massive winner that skews the whole result.
One fake tick in a test of ten thousand trades can swing the equity curve visibly. A strategy that appears to make steady money may owe a big chunk of its profit to a handful of errors.
Cleaning is the answer. Filter out quotes where the price jumps beyond a threshold and immediately returns, or where the spread is negative or absurdly wide. Then inspect the largest winners and losers in a test by hand.
If the best trade in the whole history looks suspicious, it probably is.
Another trick is comparing the high of each bar with the average of the neighbouring bars. A high that exceeds the average by many times the typical range deserves a closer look before it gets to influence a decision.
Has a single bad data point ever turned out to explain a great backtest result?
Bad ticks: the single quote that ruins a test
Bad ticks: the single quote that ruins a test
It’s Fairman 
Re: Bad ticks: the single quote that ruins a test
Hi Fairman,Fairman wrote: Mon Nov 02, 2026 2:37 pm Bad ticks: the single quote that ruins a test
Occasionally a feed produces a quote that is plainly wrong: a price 50 pips off for one tick, or a bid higher than the ask. These bad ticks can appear in live feeds and in stored history.
In a chart they show as a long spike on a single bar. In a backtest they can trigger stops or targets that never existed in the real market, or create a massive winner that skews the whole result.
One fake tick in a test of ten thousand trades can swing the equity curve visibly. A strategy that appears to make steady money may owe a big chunk of its profit to a handful of errors.
Cleaning is the answer. Filter out quotes where the price jumps beyond a threshold and immediately returns, or where the spread is negative or absurdly wide. Then inspect the largest winners and losers in a test by hand.
If the best trade in the whole history looks suspicious, it probably is.
Another trick is comparing the high of each bar with the average of the neighbouring bars. A high that exceeds the average by many times the typical range deserves a closer look before it gets to influence a decision.
Has a single bad data point ever turned out to explain a great backtest result?
In professional quantitative finance and algorithmic trading, the excerpt you shared hits on one of the most insidious and career-defining traps in backtesting: phantom alpha generated by data artifacts.
To answer your concluding question directly: Yes, absolutely. In fact, experienced quants assume that any backtest showing extraordinary, outlier-driven returns is guilty until proven innocent. It is surprisingly common for a seemingly institutional-grade trading strategy to collapse into mediocrity—or outright losses—once a single anomalous tick or data error is excised.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
Why Single Data Points Have Such Disproportionate Impact
In backtesting engines, execution logic is literal and unforgiving. If a historical feed records a single erroneous quote where the bid crosses above the ask, or where a flash crash-style spike occurs for 200 milliseconds, the backtester will happily assume your limit or stop order filled at that exact mythical price.
This creates several systemic distortions:
The "Hero Trade" Distortion: A strategy may execute 10,000 mundane trades yielding a flat equity curve, punctuated by one trade that caught a phantom 300-pip spike. That single trade accounts for 150% of the strategy's total net profit.
False Confidence in Risk Metrics: A corrupted backtest distorts critical risk metrics like the Sharpe ratio, Sortino ratio, and Maximum Drawdown. A strategy looks artificially stable because its variance is masked by an unrepeatable windfall error.
Overfitting to Noise: If you optimize strategy parameters (like moving average lengths or stop-loss thresholds) on dirty data, your optimizer will accidentally tune your model to exploit the data errors themselves, ensuring failure in live deployment.
In backtesting engines, execution logic is literal and unforgiving. If a historical feed records a single erroneous quote where the bid crosses above the ask, or where a flash crash-style spike occurs for 200 milliseconds, the backtester will happily assume your limit or stop order filled at that exact mythical price.
This creates several systemic distortions:
The "Hero Trade" Distortion: A strategy may execute 10,000 mundane trades yielding a flat equity curve, punctuated by one trade that caught a phantom 300-pip spike. That single trade accounts for 150% of the strategy's total net profit.
False Confidence in Risk Metrics: A corrupted backtest distorts critical risk metrics like the Sharpe ratio, Sortino ratio, and Maximum Drawdown. A strategy looks artificially stable because its variance is masked by an unrepeatable windfall error.
Overfitting to Noise: If you optimize strategy parameters (like moving average lengths or stop-loss thresholds) on dirty data, your optimizer will accidentally tune your model to exploit the data errors themselves, ensuring failure in live deployment.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
Professional Methods for Detecting and Neutralizing Bad Ticks
Institutional trading desks and hedge funds do not rely solely on manual inspection; they build rigorous data-cleaning pipelines. Standard defenses against bad ticks include:ry ticket dependent on data anomalies.
The Hampel Filter & Median Absolute Deviation (MAD): Instead of standard deviation (which is easily warped by extreme outliers), quants use rolling MAD filters. If a price deviates from the rolling median by more than $N$ times the MAD, the tick is flagged and scrubbed or interpolated.
Cross-Feed Arbitration: Comparing feeds simultaneously across multiple vendors (e.g., matching a broker's feed against Thomson Reuters, Bloomberg, or consolidated tape data). If Vendor A shows a spike that Vendors B and C do not see, Vendor A's tick is discarded as a feed glitch.
Volume and Liquidity Gatekeeping: In many markets, price spikes occur on zero volume or during illiquid market micro-sessions (like the late-night Asian drift or pre-market liquidity vacuums). Requiring a minimum volume threshold or validating ticks against order book depth (Level 2 data) eliminates phantom spikes.
The "Leave-One-Out" Stress Test: A standard diagnostic on any trading desk is running the backtest while intentionally stripping out the top 5% or top 1% of winning trades. If the equity curve turns flat or downward-sloping, the strategy has no genuine economic edge; it is merely a lottery ticket dependent on data anomalies.
Institutional trading desks and hedge funds do not rely solely on manual inspection; they build rigorous data-cleaning pipelines. Standard defenses against bad ticks include:ry ticket dependent on data anomalies.
The Hampel Filter & Median Absolute Deviation (MAD): Instead of standard deviation (which is easily warped by extreme outliers), quants use rolling MAD filters. If a price deviates from the rolling median by more than $N$ times the MAD, the tick is flagged and scrubbed or interpolated.
Cross-Feed Arbitration: Comparing feeds simultaneously across multiple vendors (e.g., matching a broker's feed against Thomson Reuters, Bloomberg, or consolidated tape data). If Vendor A shows a spike that Vendors B and C do not see, Vendor A's tick is discarded as a feed glitch.
Volume and Liquidity Gatekeeping: In many markets, price spikes occur on zero volume or during illiquid market micro-sessions (like the late-night Asian drift or pre-market liquidity vacuums). Requiring a minimum volume threshold or validating ticks against order book depth (Level 2 data) eliminates phantom spikes.
The "Leave-One-Out" Stress Test: A standard diagnostic on any trading desk is running the backtest while intentionally stripping out the top 5% or top 1% of winning trades. If the equity curve turns flat or downward-sloping, the strategy has no genuine economic edge; it is merely a lottery ticket dependent on data anomalies.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
Implementing a Hampel filter is one of the most robust ways to scrub bad ticks, flash crashes, and feed artifacts out of high-frequency or daily price series.
Unlike standard moving averages and standard deviation filters—which are heavily distorted by extreme outliers (because a single massive spike pulls the mean and standard deviation toward itself)—the Hampel filter relies on Rolling Median and Median Absolute Deviation (MAD). This makes it immune to the very spikes it is trying to catch.
Unlike standard moving averages and standard deviation filters—which are heavily distorted by extreme outliers (because a single massive spike pulls the mean and standard deviation toward itself)—the Hampel filter relies on Rolling Median and Median Absolute Deviation (MAD). This makes it immune to the very spikes it is trying to catch.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
Python Implementation
Here is a clean, vectorized Python implementation using pandas and numpy. This function identifies outliers and replaces them with the rolling median (or leaves them as NaN for interpolation).
Here is a clean, vectorized Python implementation using pandas and numpy. This function identifies outliers and replaces them with the rolling median (or leaves them as NaN for interpolation).
Code: Select all
import numpy as np
import pandas as pd
def hampel_filter(series: pd.Series, window_size: int = 5, n_sigmas: float = 3.0) -> pd.Series:
"""
Applies a Hampel filter to a pandas Series to detect and replace outliers.
Parameters:
- series: pd.Series of prices or returns.
- window_size: Total window size for rolling median (e.g., 5 or 10 ticks/bars).
- n_sigmas: Threshold multiplier for MAD (default 3.0, corresponding roughly to 3 sigma).
Returns:
- pd.Series with outliers replaced by the rolling median.
"""
# Copy series to avoid modifying original data in-place
filtered_series = series.copy()
# Calculate rolling median
rolling_median = series.rolling(window=window_size, min_periods=1, center=True).median()
# Calculate rolling Median Absolute Deviation (MAD)
# MAD = median(|X - median(X)|)
difference = (series - rolling_median).abs()
rolling_mad = difference.rolling(window=window_size, min_periods=1, center=True).median()
# Scaling factor for MAD to make it asymptotically consistent with standard deviation for normal distributions
# 1 / Phi^(-1)''(3/4) ≈ 1.4826
threshold = n_sigmas * 1.4826 * rolling_mad
# Identify outliers where the absolute difference exceeds the threshold
outlier_mask = difference > threshold
# Replace outliers with the rolling median (or np.nan if you prefer custom interpolation)
filtered_series[outlier_mask] = rolling_median[outlier_mask]
return filtered_series
# --- Example Usage ---
np.random.seed(42)
time_index = pd.date_range("2026-01-01 09:30:00", periods=100, freq="S")
prices = 100 + np.cumsum(np.random.randn(100) * 0.1)
# Inject synthetic bad ticks (outliers and a crossed quote/spike)
prices[25] = 150.0 # Massive upward spike
prices[72] = 50.0 # Massive downward flash crash
price_series = pd.Series(prices, index=time_index)
cleaned_series = hampel_filter(price_series, window_size=7, n_sigmas=3.0)
# Check how many points were corrected
print(f"Outliers detected and corrected: {price_series.ne(cleaned_series).sum()}")Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
[bKey Mechanics to Tune[/b]
window_size: Determines how many neighboring points are looked at to establish the local median. For tick data, a smaller window (e.g., 5 to 11 ticks) captures rapid micro-structure spikes. For bar data (1-minute or 5-minute bars), a window of 10 to 20 bars is typically appropriate.
n_sigmas (Threshold): Setting this to 3.0 captures points roughly 3 standard deviations away from the local median. Dropping it to 2.5 catches more aggressive anomalies, but risks clipping legitimate high-volatility momentum moves (like economic data releases).
The Constant $1.4826$: This scaling factor is mathematically required so that the MAD behaves like standard deviation ($\sigma$) when the underlying data is normally distributed.
window_size: Determines how many neighboring points are looked at to establish the local median. For tick data, a smaller window (e.g., 5 to 11 ticks) captures rapid micro-structure spikes. For bar data (1-minute or 5-minute bars), a window of 10 to 20 bars is typically appropriate.
n_sigmas (Threshold): Setting this to 3.0 captures points roughly 3 standard deviations away from the local median. Dropping it to 2.5 catches more aggressive anomalies, but risks clipping legitimate high-volatility momentum moves (like economic data releases).
The Constant $1.4826$: This scaling factor is mathematically required so that the MAD behaves like standard deviation ($\sigma$) when the underlying data is normally distributed.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
In electronic trading and backtesting engines, a crossed market ($\text{Bid} > \text{Ask}$) or a locked market ($\text{Bid} = \text{Ask}$) represents a complete breakdown of market microstructure logic. Outside of brief arbitrage windows or inverted venue order routing (which are rarely accessible to non-HFT retail execution), crossed quotes in historical data feeds almost always stem from timestamp desynchronization between exchanges, venue feed latency, or data provider errors.
When running backtests, crossed markets, zero-volume quotes, and abnormal spreads can artificially fill trades at prices that never existed in the real order book.
When running backtests, crossed markets, zero-volume quotes, and abnormal spreads can artificially fill trades at prices that never existed in the real order book.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
1. Inverted & Zero-Spread Rejection (Crossed/Locked Markets)Rule:
If $\text{Bid} \ge \text{Ask}$, flag and discard the tick immediately.
Why: In backtesting, if a strategy places a buy limit order when the feed is crossed, the engine fills the buy at the lower ask or higher bid depending on implementation, generating instant, unearned profit on paper.
Treatment: Discard the bad quote entirely, or set both bid and ask to NaN and forward-fill from the last valid uncrossed quote.
If $\text{Bid} \ge \text{Ask}$, flag and discard the tick immediately.
Why: In backtesting, if a strategy places a buy limit order when the feed is crossed, the engine fills the buy at the lower ask or higher bid depending on implementation, generating instant, unearned profit on paper.
Treatment: Discard the bad quote entirely, or set both bid and ask to NaN and forward-fill from the last valid uncrossed quote.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Bad ticks: the single quote that ruins a test
2. Dynamic Spread Thresholds ($Z$-Score / Rolling MAD)Rule:
Discard any tick where $\text{Ask} - \text{Bid} > \text{Threshold}_{\text{max}}$ or $\text{Ask} - \text{Bid} \le 0$.
Implementation: Compute a rolling median and Median Absolute Deviation (MAD) of the spread over a moving window (e.g., 500 ticks or 15 minutes).
If the current spread exceeds:
$$\text{Spread} > \text{Median}(\text{Spread}) + k \times \text{MAD}(\text{Spread})$$
(typically $k = 3.0$ or $4.0$), mark the quote as invalid.
Why: Flash illiquidity or data glitches can cause spreads to explode from 0.5 pips to 100 pips for a single tick. Executing stops during an artificial spread blowout skews drawdown numbers.
Discard any tick where $\text{Ask} - \text{Bid} > \text{Threshold}_{\text{max}}$ or $\text{Ask} - \text{Bid} \le 0$.
Implementation: Compute a rolling median and Median Absolute Deviation (MAD) of the spread over a moving window (e.g., 500 ticks or 15 minutes).
If the current spread exceeds:
$$\text{Spread} > \text{Median}(\text{Spread}) + k \times \text{MAD}(\text{Spread})$$
(typically $k = 3.0$ or $4.0$), mark the quote as invalid.
Why: Flash illiquidity or data glitches can cause spreads to explode from 0.5 pips to 100 pips for a single tick. Executing stops during an artificial spread blowout skews drawdown numbers.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.