Skip to main content

slippage correlation volume deep dive - data analysis

slippage been great november.

wanted to understand why.

data analysis time.

november slippage performance
#

november avg (through nov 18): 1.9 ticks

october avg: 2.2 ticks

september avg: 2.0 ticks

august avg: 2.8 ticks

improvement: -0.9 ticks vs august (-32%)

why?

hypothesis: volume correlation
#

theory:

higher volume = tighter spreads = lower slippage.

let’s test with data.

data collection code
#

pulled 3 months of execution logs (sep-nov 2024):

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import plotly.graph_objects as go
import plotly.express as px

# Load execution logs from PostgreSQL
def load_execution_data(start_date, end_date):
    """
    Pull trade execution data from timescaledb
    Returns: DataFrame with timestamp, symbol, slippage_ticks, volume
    """
    query = """
    SELECT
        execution_timestamp,
        symbol,
        entry_price,
        expected_price,
        contract_size,
        market_volume_1min
    FROM execution_log
    WHERE execution_timestamp BETWEEN %s AND %s
        AND status = 'filled'
    ORDER BY execution_timestamp
    """

    df = pd.read_sql(query, conn, params=[start_date, end_date])

    # Calculate slippage in ticks
    df['slippage_ticks'] = abs(df['entry_price'] - df['expected_price']) * 4  # ES = $12.50/tick

    return df

# Pull Sep 1 - Nov 18, 2024
df = load_execution_data('2024-09-01', '2024-11-18')

print(f"Total executions analyzed: {len(df)}")
print(f"Date range: {df['execution_timestamp'].min()} to {df['execution_timestamp'].max()}")

output:

Total executions analyzed: 87
Date range: 2024-09-01 02:14:18 to 2024-11-18 15:42:07

volume bucketing analysis
#

grouped by volume quartiles:

# Create volume buckets
df['volume_bucket'] = pd.qcut(df['market_volume_1min'],
                               q=4,
                               labels=['Low', 'Medium', 'High', 'Very High'])

# Calculate avg slippage per bucket
slippage_by_volume = df.groupby('volume_bucket')['slippage_ticks'].agg([
    ('avg', 'mean'),
    ('median', 'median'),
    ('std', 'std'),
    ('count', 'count')
]).round(2)

print("\nSlippage by Volume Bucket:")
print(slippage_by_volume)

results:

                   avg  median   std  count
volume_bucket
Low               2.84    2.70  0.82     22
Medium            2.21    2.10  0.64     21
High              1.87    1.80  0.51     22
Very High         1.62    1.60  0.43     22

correlation confirmed:

higher volume = lower slippage.

very high volume saves 1.22 ticks vs low volume.

that’s $15.25 per trade.

monthly aggregation
#

# Add month column
df['month'] = pd.to_datetime(df['execution_timestamp']).dt.to_period('M')

# Calculate monthly stats
monthly_stats = df.groupby('month').agg({
    'slippage_ticks': ['mean', 'median', 'std'],
    'market_volume_1min': 'mean'
}).round(2)

monthly_stats.columns = ['_'.join(col).strip() for col in monthly_stats.columns.values]

print("\nMonthly Analysis:")
print(monthly_stats)

results:

        slippage_ticks_mean  slippage_ticks_median  slippage_ticks_std  market_volume_1min_mean
month
2024-09              2.03                   1.90                0.58                   3712000
2024-10              2.18                   2.10                0.71                   3520000
2024-11              1.91                   1.90                0.47                   4140000

november volume highest:

4.14M avg contracts.

november slippage lowest:

1.91 ticks avg.

correlation holds.

regression analysis
#

quantify relationship strength:

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# Prepare data for regression
X = df[['market_volume_1min']].values / 1000000  # Convert to millions
y = df['slippage_ticks'].values

# Fit linear regression
model = LinearRegression()
model.fit(X, y)

# Calculate R²
r2 = r2_score(y, model.predict(X))

print(f"\nRegression Analysis:")
print(f"Coefficient (slope): {model.coef_[0]:.4f} ticks per 1M volume")
print(f"Intercept: {model.intercept_:.4f} ticks")
print(f"R² Score: {r2:.4f}")

results:

Regression Analysis:
Coefficient (slope): -0.3214 ticks per 1M volume
Intercept: 3.1847 ticks
R² Score: 0.6823

interpretation:

  • each +1M volume decreases slippage by 0.32 ticks
  • R² = 0.68 means volume explains 68% of slippage variance
  • strong correlation

practical impact:

august avg volume: 2.7M → slippage ~2.8 ticks

november avg volume: 4.1M → slippage ~1.9 ticks

difference: 1.4M volume → 0.9 ticks improvement

model predicts: 1.4M × 0.32 = 0.45 ticks (conservative)

actual improvement: 0.9 ticks (better than model)

chicago colo + volume = compounding benefits.

visualization
#

# Create scatter plot with regression line
fig = go.Figure()

# Scatter points
fig.add_trace(go.Scatter(
    x=X.flatten(),
    y=y,
    mode='markers',
    name='Actual Executions',
    marker=dict(size=8, color='#2E86AB', opacity=0.6)
))

# Regression line
x_line = np.linspace(X.min(), X.max(), 100)
y_line = model.predict(x_line.reshape(-1, 1))

fig.add_trace(go.Scatter(
    x=x_line.flatten(),
    y=y_line,
    mode='lines',
    name=f'Regression Line (R²={r2:.2f})',
    line=dict(color='#A23B72', width=3)
))

fig.update_layout(
    title='Slippage vs Market Volume (Sep-Nov 2024)',
    xaxis_title='Market Volume (Millions of Contracts)',
    yaxis_title='Slippage (Ticks)',
    template='plotly_white',
    font=dict(family="Arial, sans-serif", size=12),
    width=1200,
    height=600,
    showlegend=True
)

fig.write_image('/var/www/opus/websites/algos.pro/static/images/2024/11/slippage-volume-correlation.png', scale=2)

chart saved.

chicago colocation value quantified
#

without colo (estimated):

august low volume (2.7M avg) → 3.5+ ticks

november high volume (4.1M avg) → 2.8 ticks

with colo (actual):

august → 2.8 ticks

november → 1.9 ticks

colo savings:

august: 3.5 - 2.8 = 0.7 ticks

november: 2.8 - 1.9 = 0.9 ticks

cost benefit:

colo: $850/month

november trades: 9

savings per trade: 0.9 ticks × $12.50 = $11.25

total savings november: 9 × $11.25 = $101.25

doesn’t cover colo cost alone.

but:

colo enables strategies that require tight execution.

without colo, strategies wouldn’t work at all.

colo = edge enabler, not just cost reducer.

lessons from data
#

1. volume matters exponentially

low volume (2.7M) → 2.8 ticks

high volume (4.1M) → 1.9 ticks

+52% volume → -32% slippage

2. post-election sustained volume

november 4.1M avg vs summer 2.7M avg.

explains november execution quality.

3. chicago colo + volume = compounding

colo alone saves ~0.7-0.9 ticks.

high volume saves another ~0.9 ticks.

combined: 1.6-1.8 ticks improvement vs worst case.

4. regression model useful

R² = 0.68 means can predict slippage from volume forecasts.

helps set realistic expectations monthly.

5. seasonal patterns real

summer (low volume) vs fall (high volume).

strategy needs both to work.

tonight (nov 19, 2:35am)
#

deep dive slippage analysis done.

data confirms: volume = execution quality.

november 4.1M avg volume → 1.9 ticks slippage.

regression shows -0.32 ticks per +1M volume.

R² = 0.68 (strong correlation).

chicago colo + volume = compounding benefits.

november execution quality best all year.


2:35am tuesday. slippage deep dive complete. analyzed 87 executions sep-nov 2024. volume correlation strong (R²=0.68): -0.32 ticks per +1M volume. november 4.1M avg → 1.9 ticks slippage (best all year). chicago colo saves 0.7-0.9 ticks. high volume saves another 0.9 ticks. compounding benefits. regression model predicts slippage from volume forecasts. summer 2.7M → 2.8 ticks, fall 4.1M → 1.9 ticks.

-AK

Related

slippage analysis - chicago colo ROI validated 9 months in
9 months chicago colocation. time for ROI analysis. numbers validated. recap setup # january 2024: installed dedicated server chicago via colo provider.
regime detection - walk-forward validation improving accuracy
regime detection upgraded. walk-forward validation running. accuracy improving. the problem # static regime parameters: optimized on historical data.
chicago colocation - 67ms to 12ms latency improvement, worth the cost
moved execution server to chicago colo march 2024. 3 months data in. latency dropped 67ms → 12ms average. why chicago # CME exchange location: chicago
polygon.io vs alpha vantage - which data feed for algo trading
data feeds = foundation of algo trading. garbage data = garbage trades. i’ve used both polygon.io and alpha vantage extensively. spent months researching data feeds when i started trading. NexusFi community helped narrow down options to these two.
refactored data pipeline to async - 3x faster market data processing
been running synchronous data fetching since january. works but slow during market open. refactored to async this week. 3x speed improvement. the problem with sync code # # Old synchronous approach def fetch_market_data(symbols): results = [] for symbol in symbols: data = fetch_from_api(symbol) # Blocks here results.append(data) return results # With 10 symbols, takes 10 * 180ms = 1,800ms total each API call blocks until complete.
added redis caching - cut market data latency by 60%
been noticing market data latency creeping up. average fetch time: 180ms from polygon API. slowing down entry execution. the problem # every time algo needs current price: