IMC Prosperity 4 — Trading Competition Guide
A Python-based algorithmic trading competition by IMC Trading (one of the world's top HFT firms). You build trading bots that compete in a simulated virtual marke…
Open on imc now
Connected to the competition feed. Verify dates, eligibility and prizes on the official page.
No open imc competitions in the feed right now.
The feed refreshes daily. Browse every tracked platform or check again soon.
IMC Prosperity 4 — Trading Competition Guide
What Is It?
A Python-based algorithmic trading competition by IMC Trading (one of the world's top HFT firms). You build trading bots that compete in a simulated virtual market across 5 rounds. Combines algorithmic trading + market microstructure + strategy.
2026 Key Facts
- Edition: Prosperity 4
- Prize pool: $50,000 USD
- Start: April 14, 2026
- Format: 5 rounds, each with 1 algorithmic challenge + 1 manual challenge
- Duration: Rounds 1–2 (72 hrs each), Rounds 3–5 (48 hrs each)
- Eligibility: University students worldwide
- Cost: Free
URL
prosperity.imc.com
What You Actually Build
A Python Trader class with a run() method. Each round introduces new tradeable products with different market dynamics. Your bot must:
- Read the order book (bids/asks)
- Decide what to buy/sell at what price
- Manage positions within limits
- Maximize "SeaShells" (the in-game currency = your score)
Core Concepts You Must Learn
| Concept | Why It Matters |
|---|---|
| Bid/Ask spread | How markets work. You trade inside it to profit. |
| Order book | Shows all pending orders at each price level |
| Market making | Buy at bid, sell at ask. Profit = spread. |
| Position limits | You can't hold unlimited inventory — manage risk |
| Mean reversion | Prices revert to fair value — exploit this |
| Pair trading | Two correlated assets diverge → trade the spread |
Winning Strategies — Deep Dive (From Top Solutions, Prosperity 2 & 3)
1. Market Making (Stable Assets — e.g., RainforestResin, Pearls ≈ 10,000)
Place bids just below fair value, asks just above. Simple. Reliable. Low-risk.
# If fair_value is known (stable asset):
orders.append(Order(product, fair_value - 1, buy_volume)) # bid
orders.append(Order(product, fair_value + 1, -sell_volume)) # ask
The "edge" is the distance between your trade price and true fair value. Maximize this consistently.
2. EMA Fair Value Estimation (Volatile Assets — e.g., Kelp)
When no fixed fair value exists, estimate it dynamically.
from collections import deque
class EMATrader:
def __init__(self, window=8):
self.prices = deque(maxlen=window)
self.ema = None
self.alpha = 2 / (window + 1)
def update(self, mid_price):
if self.ema is None:
self.ema = mid_price
else:
self.ema = self.alpha * mid_price + (1 - self.alpha) * self.ema
def signal(self, ask, bid):
if ask < self.ema: return "BUY"
if bid > self.ema: return "SELL"
return "HOLD"
EMA window (~8 for Kelp) is a key tunable parameter — backtest it.
3. Mean Reversion with Z-Score (Squid Ink / High-Volatility Assets)
import numpy as np
from collections import deque
class ZScoreReversion:
def __init__(self, short_window=5, long_window=20):
self.short = deque(maxlen=short_window)
self.long = deque(maxlen=long_window)
def update(self, price):
self.short.append(price)
self.long.append(price)
def z_score(self):
if len(self.long) < self.long.maxlen:
return 0
ema_short = np.mean(self.short)
ema_long = np.mean(self.long)
std_long = np.std(self.long) + 1e-9
return (ema_short - ema_long) / std_long
def signal(self, threshold=1.5):
z = self.z_score()
if z > threshold: return "SELL" # Overbought — reversion expected
if z < -threshold: return "BUY" # Oversold — reversion expected
return "HOLD"
4. Statistical / Index Arbitrage (Basket Products)
When a basket product trades at a price diverging from its components:
from sklearn.linear_model import LinearRegression
import numpy as np
# Fit weights of components to basket price
def fit_basket_weights(component_prices, basket_prices):
model = LinearRegression(fit_intercept=True)
model.fit(component_prices, basket_prices)
return model
# At runtime: compute synthetic fair value
def basket_signal(model, component_prices, basket_mid, threshold=1.5):
synthetic = model.predict(component_prices.reshape(1, -1))[0]
spread = basket_mid - synthetic
std = np.std(recent_spreads) # rolling std of spread
z = spread / (std + 1e-9)
if z > threshold: return "SELL basket"
if z < -threshold: return "BUY basket"
return "HOLD"
Alpha Animals (2nd place USA, 9th globally, Prosperity 3) used this to achieve rank 2 in Round 2.
5. Options Pricing (Volcanic Rock Vouchers)
Treat competition vouchers as call options using Black-Scholes. Compute implied volatility from market prices and exploit deviations.
from scipy.stats import norm
import numpy as np
def black_scholes_call(S, K, T, r, sigma):
"""S=spot, K=strike, T=time to expiry, r=rate (0), sigma=IV"""
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
d2 = d1 - sigma*np.sqrt(T)
return S * norm.cdf(d1) - K * np.exp(-r*T) * norm.cdf(d2)
def implied_vol(market_price, S, K, T, r=0.0, tol=1e-5):
"""Invert Black-Scholes for IV using bisection."""
lo, hi = 0.001, 5.0
for _ in range(100):
mid = (lo + hi) / 2
if black_scholes_call(S, K, T, r, mid) > market_price:
hi = mid
else:
lo = mid
if hi - lo < tol:
break
return mid
6. Counterparty Anomaly Detection (Advanced — Round 5 Prosperity 3)
When counterparty data is revealed, track individual trader win rates.
- Alpha Animals identified trader "Olivia" with a suspiciously high win rate in Squid Ink and Croissants
- Copied her trades as a regime signal → significant P&L contribution
- When you see a counterparty consistently profiting, follow them
Summary Table
| Strategy | Asset Type | Risk | Complexity |
|---|---|---|---|
| Market making | Stable (known fair value) | Low | Low |
| EMA fair value | Moderately volatile | Medium | Low |
| Z-score mean reversion | Highly volatile | Medium | Medium |
| Basket arbitrage | Index/basket products | Medium | High |
| Options pricing | Vouchers/derivatives | High | High |
| Counterparty copying | Any | Medium | Medium |
Python Skills Needed
- Classes and object-oriented Python
- Basic pandas / numpy
- Understanding of deques (rolling windows)
- Ability to write fast, stateless logic (no slow loops)
How Top Teams Approach Each Round
- Visualize first — clean and plot all price data with matplotlib; correlation heatmaps with seaborn before writing any strategy
- Backtest everything on historical data provided before deploying live
- Conservative position sizing first — many teams lost large amounts from bugs in position limit handling; test edge cases
- Beware 99% R² — suspiciously good linear regression = verify on held-out data immediately
- Implement hard risk controls — one position management bug can wipe rounds of profit (documented: 82,558 SeaShells lost in one round)
- Study prior-year repos — understand WHY those approaches worked, not just copy them
- Accept calculated risk — when trailing significantly, aggressive strategies are required for prize contention
Prosperity 3 — Round-by-Round Breakdown (Study This for P4)
Round 1: Rainforest Resin, Kelp, Squid Ink
| Product | Strategy | PnL (2nd place) |
|---|---|---|
| Rainforest Resin | Fixed fair value (~10,000) market making ±2.5 spread | ~39,000 SeaShells/round |
| Kelp | 8-period SMA as fair value; market make around deviation | ~5,000 SeaShells/round |
| Squid Ink | EMA z-score mean reversion OR volatility spike detection | ~8,000 SeaShells/round |
2nd place (Frankfurt Hedgehogs) used "Wall Mid": (best_bid + best_ask)/2 as fair value proxy with inventory flattening when position skews.
Round 2: Basket Products (Picnic Basket 1 & 2, Croissants, Jams, Djembes)
- Basket 1 = 6×Croissants + 3×Jams + 1×Djembe
- Basket 2 = 4×Croissants + 2×Jams
- Strategy: compute synthetic fair value → trade when basket diverges
Frankfurt Hedgehogs key insight: Baskets mean-revert vs synthetic value, but components do NOT move to match basket → trade baskets only, don't hedge with components.
def basket_arb(basket_mid, croissant_mid, jam_mid, djembe_mid, threshold=50):
synthetic = 6*croissant_mid + 3*jam_mid + 1*djembe_mid
spread = basket_mid - synthetic
if spread > threshold: return "SELL basket"
if spread < -threshold: return "BUY basket"
return "HOLD"
Fixed threshold (±50) outperformed z-score for this product — stability over peak performance.
Round 3: Volcanic Rock + 5 Vouchers (Call Options)
This is the options round. Every top team used Black-Scholes.
from scipy.stats import norm
import numpy as np
def black_scholes_call(S, K, T, sigma, r=0.0):
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T) + 1e-9)
d2 = d1 - sigma*np.sqrt(T)
return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
def implied_vol(market_price, S, K, T, r=0.0, tol=1e-5):
lo, hi = 0.001, 5.0
for _ in range(100):
mid = (lo + hi) / 2
if black_scholes_call(S, K, T, mid, r) > market_price: hi = mid
else: lo = mid
if hi - lo < tol: break
return (lo + hi) / 2
# Greeks for risk management
def delta(S, K, T, sigma, r=0.0):
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T) + 1e-9)
return norm.cdf(d1)
def gamma(S, K, T, sigma, r=0.0):
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T) + 1e-9)
return norm.pdf(d1) / (S * sigma * np.sqrt(T) + 1e-9)
def vega(S, K, T, sigma, r=0.0):
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T) + 1e-9)
return S * norm.pdf(d1) * np.sqrt(T)
Volatility smile exploitation (2nd place globally):
- Compute IV for each of the 5 strikes
- Plot IV vs moneyness
ln(S/K)/√T→ parabolic smile appears - Fit parabola to the smile curve
- Trade vouchers whose IV deviates from the fitted curve (bet on reversion to the smile)
Round 4: Magnificent Macarons (Cross-Island Conversion)
- Analyze local bid/ask vs foreign bid/ask accounting for transport fees + tariffs
- Sunlight regime detection — low sunlight increases production costs → shift strategy:
- Normal: two-way arbitrage
- Low sunlight: accumulate long positions, minimize exports
- Volume imbalance exploit: if
best_bid_volume > 9on local exchange, sell order at best ask guaranteed to fill
Round 5: All Products + Insider Detection
# Track counterparty win rate
class InsiderDetector:
def __init__(self, window=50):
self.trades = {} # {trader_name: deque of (buy/sell, subsequent_price_move)}
self.window = window
def update(self, trader, direction, price_before, price_after):
if trader not in self.trades:
from collections import deque
self.trades[trader] = deque(maxlen=self.window)
profitable = (direction == 'BUY' and price_after > price_before) or \
(direction == 'SELL' and price_after < price_before)
self.trades[trader].append(profitable)
def win_rate(self, trader):
if trader not in self.trades or len(self.trades[trader]) == 0:
return 0.5
return sum(self.trades[trader]) / len(self.trades[trader])
def is_insider(self, trader, threshold=0.70):
return self.win_rate(trader) > threshold
# Olivia had >70% win rate — copy her trades as regime signals
Backtesting Setup
Install the community-standard backtester:
pip install -U prosperity3bt
prosperity3bt algorithm.py 1 # all data from round 1
prosperity3bt algorithm.py 1 --vis # auto-open visualizer
prosperity3bt algorithm.py 1 2 3 # multiple rounds
P3 Visualizer: jmerle.github.io/imc-prosperity-3-visualizer/
Prosperity 4 — Pre-Start Checklist (Before April 14)
[ ] pip install prosperity3bt and run all Prosperity 3 round data
[ ] Clone and read: github.com/TimoDiehm/imc-prosperity-3 (2nd globally)
[ ] Clone and read: github.com/CarterT27/imc-prosperity-3 (9th global, 2nd USA)
[ ] Implement Black-Scholes + Greeks from scratch (you will need this)
[ ] Implement implied vol solver (Newton-Raphson or bisection)
[ ] Build EMA + z-score mean reversion detector
[ ] Build market maker with inventory management
[ ] Build insider/counterparty win-rate tracker
[ ] Study Round 1 manual challenge patterns from Prosperity 2 and 3
[ ] Understand: basket fair value from components (linear regression)
Key Resources
| Resource | URL |
|---|---|
| Frankfurt Hedgehogs — 2nd globally (code + blog) | github.com/TimoDiehm/imc-prosperity-3 |
| Alpha Animals — 9th global, 2nd USA (code) | github.com/CarterT27/imc-prosperity-3 |
| Community backtester | github.com/jmerle/imc-prosperity-3-backtester |
| IMC Prosperity 3 writeup (Matius Chong) | medium.com/@matius_chong/imc-prosperity-3-challenge-2025 |
| IMC Prosperity 3 writeup (Martin Oravec, 73rd) | medium.com/@oravec.martin01/imc-prosperity-3-be859180f133 |
| Top 100 strategies explained | medium.com/@shriyan.gosavi/how-i-placed-top-100-in-the-imc-trading-challenge |
| Official platform | prosperity.imc.com |
Career Value
- IMC actively recruits from top performers
- Converts to intern/full-time interviews at IMC Trading
- Also recognized by Jane Street, Citadel, Two Sigma recruiters
- Shows quant + engineering hybrid skillset
Preparation Checklist
- Read "what is an order book" (15 min)
- Study market making concept
- Clone a past Prosperity GitHub repo and understand the structure
- Practice: write a simple EMA-based bot
- Form team of 2–3 people with different strengths (algo, manual trading, math)