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 now
No open IMC Prosperity competitions in the feed right now.
Add the competitions calendar to your phone
Subscribe once — every open competition's deadline shows up in your native calendar and auto-updates daily as new ones open and old ones close. No account needed.
Outlook / other: add a calendar “from URL” using the copied link.
How to win on IMC Prosperity
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)