Avellaneda-Stoikov + Hawkes Processes — Market Making and Order-Flow Alpha
In short: The two canonical building blocks of academic HFT: a closed-form model for where to quote (Avellaneda-Stoikov) and a statistical model for when trades cluster (Hawkes). Together they describe the two halves of a market maker's problem — price the quotes, then time the quotes.
| Key fact | Detail |
|---|---|
| What it covers | creative coding, crypto, data science, finance/trading |
| Tools | Meta |
| Posts covered | 1 post (1 S-tier) · top: 10 institutional quant projects… |
| Creators | @heidioftheeast |
| Sources dated | Feb 2026 |
| Prompt system | Run-it-yourself prompts |
| Last verified | 2026-10-22 |
The two canonical building blocks of academic HFT: a closed-form model for where to quote (Avellaneda-Stoikov) and a statistical model for when trades cluster (Hawkes). Together they describe the two halves of a market maker's problem — price the quotes, then time the quotes.
Cloned repo: repos/avellaneda-stoikov/ (from https://github.com/fedecaccia/avellaneda-stoikov)
1. Avellaneda-Stoikov — the canonical market-making model
What it is
A 2008 paper by Marco Avellaneda and Sasha Stoikov, "High Frequency Trading in a Limit Order Book," that solves a specific problem: a market maker holds inventory q, faces a mid-price s that diffuses as Brownian motion, and must choose bid/ask quotes continuously. Where should they post to maximize terminal utility while controlling inventory risk?
The answer is two formulas — the reservation price and the optimal spread — and those two formulas are the foundation for essentially every serious MM model that followed.
How it works
The maker has a utility function (exponential, risk-averse with parameter γ). They post quotes symmetrically around a reservation price that is shifted away from mid based on current inventory. If you're long, you skew quotes lower to encourage sells. If you're short, you skew higher. The spread itself widens with volatility, time-to-horizon, and risk aversion.
Key mechanics — the two formulas
Reservation price (your private indifference price given inventory):
r(s, q, t) = s − q · γ · σ² · (T − t)
s— current midq— signed inventory (positive = long)γ— risk aversion (higher = more skew)σ²— variance of mid-price(T − t)— time remaining until horizon
Optimal bid-ask spread:
δ_ask + δ_bid = γ · σ² · (T − t) + (2/γ) · ln(1 + γ/k)
k— order-book liquidity parameter (intensity decay of the limit-order arrival functionλ(δ) = A · exp(−k·δ))A— base arrival intensity
Then you post:
- Bid at
r − (spread / 2) - Ask at
r + (spread / 2)
The first term of the spread is the inventory term (widens with risk). The second is the adverse selection term (widens when order flow is thin). This is the whole engine.
The repo — fedecaccia/avellaneda-stoikov
Cloned to repos/avellaneda-stoikov/. Minimal Python implementation, ~200 lines. Core loop from src/main.py:
# Risk aversion
gamma = 0.1
# Liquidity parameter (exponential decay of fill intensity)
k = 1.5
# Mid-price follows Brownian motion
sigma = 2
for i in range(N):
# Reservation price — skews away from inventory
r[i] = s[i] - q[i] * gamma * (sigma**2) * (T - t[i])
# Optimal half-spread
r_spread = gamma * (sigma**2) * (T - t[i]) + (2/gamma) * math.log(1 + gamma/k)
# Quotes
r_ask = r[i] + r_spread / 2
r_bid = r[i] - r_spread / 2
# Simulate Poisson fills with intensity A*exp(-k*delta)
...
The repo includes a doc/ folder with the original paper and follow-ups (Guéant-Lehalle-Tapia closed-form extension, mean-reversion variants). Good starting point, but known limitations: Brownian mid is unrealistic, k and A need live calibration, no queue-position model.
Quick start
cd ./repos/avellaneda-stoikov/
pip install numpy matplotlib
python src/main.py
Runs 100 simulated sessions and plots PnL distribution. Tweak gamma, k, sigma and watch how the spread and skew react.
Known limitations (and what the follow-ups fix)
- Brownian mid — real prices jump. Fix: use a jump-diffusion or Hawkes-modulated mid.
- Fixed
k— real liquidity is regime-dependent. Fix: rolling calibration from trade flow. - Symmetric fills — adverse selection makes them asymmetric. Fix: asymmetric
k_bid,k_ask. - No queue model — AS assumes you fill instantly at the quoted price. Fix: queue-position aware extensions (Guéant-Lehalle).
- Single asset — multi-asset version requires solving a coupled HJB. Fix: Guéant 2017.
For a modern RL extension, see javifalces/HFTFramework — reinforcement learning on top of AS for dynamic γ and k.
2. Hawkes processes — order flow is self-exciting
What it is
A Hawkes process is a point process where the arrival of an event temporarily increases the probability of more events. Classic example: earthquakes (a big one triggers aftershocks). In markets: a trade begets more trades. Order flow is demonstrably self-exciting — if you watch BTC-PERP on Hyperliquid for 10 seconds, you see this with your own eyes. Buys cluster. Sells cluster. Quiet periods are quiet.
Avellaneda-Stoikov assumes trades arrive as a plain Poisson process (constant intensity A). That assumption is wrong at HFT timescales. Replacing it with a Hawkes intensity is the single biggest realism upgrade.
How it works — the math
A univariate Hawkes process has a conditional intensity:
λ(t) = μ + Σ_{t_i < t} α · exp(−β (t − t_i))
μ— baseline intensity (exogenous flow)α— jump in intensity per event (self-excitation strength)β— decay rate (how fast excitement dies)- Branching ratio
n = α/βmust be< 1for stability.nnear 1 means the process is critical — heavy clustering, close to explosive.
For order flow, you want a bivariate or multivariate Hawkes with buy and sell streams that excite each other asymmetrically. The 4-dimensional version (bid market orders, ask market orders, bid limit orders, ask limit orders) is the standard for LOB research.
Key intuition
- Self-excitation captures momentum at the micro scale — a large buy market order raises the probability of more buy market orders over the next ~100ms.
- Cross-excitation captures the order-book reaction — a market buy raises the probability of a cancellation on the ask and a new limit ask higher up.
- Branching ratio is a regime detector.
n ≈ 0.9+= critical, clustered, dangerous to provide liquidity.n ≈ 0.5= calm. - Fitted
μ,α,βgive you an instantaneous order-flow imbalance forecast — the true signal every MM and taker wants.
Repos worth pulling
x-datainitiative/tick— production-grade Python library for Hawkes fitting. Handles MLE, EM, and sum-of-exponentials kernels. The go-to for serious work.jeremymck/High-Frequency-Data---Limit-Order-Books— pedagogical notebooks covering LOB simulation + Hawkes estimation end-to-end.sohaibelkarmi/High-Frequency-Trading-Simulator— C++ LOB with Hawkes-driven order flow, Python bindings.
Quick start with tick
from tick.hawkes import HawkesExpKern, SimuHawkesExpKernels
import numpy as np
# Fit a 2D Hawkes (buys, sells) on your trade timestamps
# timestamps = [np.array([buy_times]), np.array([sell_times])]
decays = np.array([[5.0, 5.0], [5.0, 5.0]]) # β per pair
learner = HawkesExpKern(decays, penalty='l2', C=1e3)
learner.fit(timestamps)
# adjacency[i][j] = α from stream j exciting stream i
print("Branching matrix:\n", learner.adjacency)
print("Baseline:", learner.baseline)
print("Spectral radius (stability):", np.max(np.abs(np.linalg.eigvals(learner.adjacency))))
Roll this on 1-minute windows and you have a live order-flow-clustering monitor.
3. Putting them together — the modern MM stack
The research consensus for the last ~8 years has been: replace Avellaneda-Stoikov's constant A, k with Hawkes-derived, regime-aware estimates.
The combined loop:
- Maintain a rolling Hawkes fit on trade timestamps (fit every N seconds).
- Convert the fitted intensity into a live forecast
λ̂(t)for the next fill window. - Feed
λ̂into AS as a time-varyingA. Also use branching ratio to modulateγ— get more risk-averse whenn → 1. - Skew quotes with the AS reservation price, sized with AS spread, but gated by the Hawkes regime (don't quote when
nis critical unless spread compensates). - (Optional) Train an RL agent to choose
γdynamically — that's whatjavifalces/HFTFrameworkandim1235/ISAC(Soft Actor-Critic on AS) do.
4. How this plugs into your trading-agent-team
The current trading-agent-team at ~/projects/agents/trading-agent-team/ is built around taker strategies — fast cyclers, graduated TP, ensembles across 8 coins. AS + Hawkes opens a second leg of the strategy: a maker leg that generates uncorrelated PnL from spread capture rather than directional alpha.
Concrete integration ideas:
-
Hawkes as a regime filter for the existing taker strategies. Fit a bivariate Hawkes on trade tape per coin. When branching ratio spikes above ~0.9, the fast-cycler TP logic should tighten because reversals become more likely. This is a pure overlay — no new strategy, just a kill switch / sizing knob. Lowest-risk way to start.
-
Order-flow imbalance as a feature for the Oracle Commander / Rolodex selector. Add the ratio of buy-excited to sell-excited intensity as a short-horizon feature. Should add signal to coin rotation decisions at 1-5 minute horizons.
-
Hyperliquid maker leg. Hyperliquid pays maker rebates. A disciplined AS quoter on a liquid pair (HYPE, SOL) sized small could produce steady edge and double as inventory for the taker strategies — when the maker leg accumulates a long, the taker leg can ride it out instead of fighting it. This is the pattern HL-Delta uses in
./repos/HL-Delta/. -
Challenge-game parameter sweep. AS has exactly the shape that
/challenge-gamewas built for: 3 numeric parameters (γ,k,horizon_T), a clear fitness function (Sharpe of simulated PnL), and fast evaluation. Run a tournament against replayed Hyperliquid L2 data. -
Watchdog layer for Unicron. The Hawkes branching ratio is a clean scalar "how crazy is order flow right now" number. Pipe it into the Unicron oversight watchdog (
project_unicron_oversight_spec.md) as an auto-pause trigger when it crosses a threshold.
Data requirement: All of this needs trade-level tape, not OHLCV. Hyperliquid's WebSocket gives trade ticks for free — that's the data path. For order-book state (needed for full Hawkes LOB models) you need L2 snapshots, which flowsurface in ./repos/flowsurface/ already handles in Rust.
5. Further reading
- Avellaneda & Stoikov (2008) — the original paper, in
repos/avellaneda-stoikov/doc/. - Guéant, Lehalle, Fernandez-Tapia (2013) — closed-form extension with inventory bounds.
- Bacry, Mastromatteo, Muzy (2015) — "Hawkes processes in finance," the definitive survey.
- Bacry & Muzy (2014) — Hawkes estimation of market impact.
- Cartea, Jaimungal, Penalva — Algorithmic and High-Frequency Trading (textbook). The chapter on AS is the clearest exposition out there.
- Deep Hawkes process for high-frequency market making — Journal of Banking and Financial Technology, 2024 (neural extension).
Sources
- https://github.com/fedecaccia/avellaneda-stoikov
- https://github.com/javifalces/HFTFramework
- https://github.com/im1235/ISAC
- https://github.com/x-datainitiative/tick
- https://github.com/jeremymck/High-Frequency-Data---Limit-Order-Books
- https://jheusser.github.io/2013/09/08/hawkes.html
- https://link.springer.com/article/10.1007/s42786-024-00049-8
Prompt system — run this yourself
Everything below is pasteable into Claude Code, Claude, or any agent. Use the one-shot when you want the whole result in one run; use the step prompts when you want to steer. Every step carries its own audit, and the gap audit at the end makes the agent find and fill what it missed.
Mission. Running this system turns the guide into a tested research stack: a verified Avellaneda-Stoikov (AS) quoting engine, a Hawkes order-flow model fitted and goodness-of-fit tested on real Hyperliquid trade data, and an event-driven paper backtest comparing a fixed-spread quoter, plain AS and Hawkes-modulated AS after fees, queue position and adverse selection. It also tests the lowest-risk integration: a Hawkes branching-ratio regime overlay on the existing taker strategies, run as a paired shadow. It is for a trader with a running crypto bot stack. Done means reproducible results against controls and a written gate: no real money until the paper arm beats its control after costs.
1 · Deeper, not bigger
Before running anything, make the task deeper rather than larger. Ask: what would a top professional do here that I am not asking for; what is the rawest material; which methods and tools; what, other than the model or me, proves it right. Then ask for exactly that.
- What a top professional would do (that you didn't ask for): A market-making quant would not trust the closed-form spread until it is calibrated in the right units: σ and k must be expressed per price unit and time unit consistent with the tick size, or the inventory term explodes on a 60,000-dollar asset. They would replace the finite horizon T with the Guéant-Lehalle-Fernandez-Tapia infinite-horizon approximation for a 24/7 perpetual, calibrate A and k from fill intensity versus quote depth, and judge every quoting rule by markout PnL at 1, 10 and 60 seconds rather than by raw spread captured. For Hawkes they would test fit with the time-rescaling theorem before using a branching ratio as a regime signal, and they would aggregate one taker order's multiple prints into one event.
- Rawest material to start from: 1) Avellaneda and Stoikov, 'High-frequency trading in a limit order book' (Quantitative Finance, 2008), from the repo's doc/ folder. 2) Guéant, Lehalle and Fernandez-Tapia, 'Dealing with the inventory risk' (2013). 3) Bacry, Mastromatteo and Muzy, 'Hawkes processes in finance' (2015). 4) The cloned repos: fedecaccia/avellaneda-stoikov (src/main.py), x-datainitiative/tick, javifalces/HFTFramework. 5) Raw Hyperliquid data: the trades and l2Book websocket streams recorded locally, plus any historical archive Hyperliquid publishes. 6) Hyperliquid's current fee schedule and tick and lot sizes per coin. 7) The trading-agent-team repo's taker strategy code and trade logs, for the overlay test.
- Methods and tools: Python with numpy, pandas and scipy; a websocket recorder writing trades and L2 snapshots to Parquet with exchange timestamps; tick's HawkesExpKern for exponential-kernel fits if it installs on your Python, else a hand-written exponential Hawkes log-likelihood using the recursive form, optimized with scipy.optimize.minimize under the stability constraint; time-rescaling residuals tested against Exp(1) with a Kolmogorov-Smirnov test and QQ plot; fill-intensity calibration by regressing log hit rate on quote depth; hftbacktest or a custom event-driven simulator with queue position, latency and fees; markout PnL; paired comparisons on identical data windows; bootstrap confidence intervals over days.
- What proves it right (other than you or the model): Reproduce the AS paper's simulated comparison of inventory and symmetric strategies (mean PnL, PnL std, inventory std) within sampling error using the repo's parameters. A Hawkes fit whose time-rescaled residuals pass a KS test at the 5% level on held-out windows. A paper backtest where Hawkes-modulated AS beats both plain AS and a fixed-spread control on markout-adjusted PnL after fees, with a bootstrap interval excluding zero. For the overlay, a paired shadow over the same live period showing the effect on the taker strategies' drawdown.
Rewritten prompt — ask for exactly that:
I have the Avellaneda-Stoikov repo cloned and a Hawkes guide. Act as a market-making quant and build a research stack I can trust, paper only. First read the AS paper, Guéant-Lehalle-Fernandez-Tapia, and Bacry et al. on Hawkes in finance, and verify the repo's src/main.py against the paper's formulas, including whether its spread variable is total or half spread. Then: (1) reproduce the paper's inventory-versus-symmetric simulation; (2) record Hyperliquid trades and L2 for BTC and ETH for at least 7 days, aggregating multi-fill taker orders into single events; (3) fit bivariate exponential Hawkes on buys and sells per window, check fit by time-rescaling and a KS test, and report branching ratio over time; (4) calibrate A and k from hit rate versus quote depth, in tick units; (5) backtest event-driven with queue position, latency and the real fee schedule: fixed-spread control, plain AS, and AS with Hawkes-driven A and gamma, scored on markout PnL at 1, 10 and 60 seconds; (6) run the branching-ratio overlay as a paired shadow on the existing taker bots. No real orders until the paper arm beats its control after costs, with inventory and daily-loss caps written first. Never print API keys.
2 · One-shot prompt
ROLE AND STANCE
You are a market-making quant validating two academic models before any capital touches them. Paper only. You distrust closed forms until units and calibration are checked, and you judge quoting by markouts, not spread captured.
CONTEXT
- Guide: AS reservation price r = s - q * gamma * sigma^2 * (T - t); total spread = gamma * sigma^2 * (T - t) + (2/gamma) * ln(1 + gamma/k); quotes at r +/- spread/2; fills at intensity A * exp(-k * delta).
- Repo: repos/avellaneda-stoikov/ (fedecaccia), about 200 lines, gamma 0.1, k 1.5, sigma 2, Brownian mid, 100 simulated sessions. The code comments its spread variable as a half-spread but computes the total spread formula and then divides by two; verify which is right.
- Known limits listed in the guide: Brownian mid, fixed k, symmetric fills, no queue model, single asset.
- Hawkes: lambda(t) = mu + sum alpha * exp(-beta (t - t_i)); branching ratio n = alpha/beta must be below 1; n near 0.9 means clustered, dangerous to quote. Note: in tick's HawkesExpKern the adjacency matrix is already the kernel's integral, so it is the branching ratio directly; do not divide by beta again.
- Guide's integration idea: a Hawkes branching-ratio overlay on the trading-agent-team taker strategies as a kill switch or sizing knob, lowest risk first.
- Venue: Hyperliquid perpetuals; trades and l2Book websocket streams.
HARD CONSTRAINTS
- No real orders. The gate to real money: paper arm beats both controls on markout-adjusted PnL after fees over at least 14 days of out-of-sample data, bootstrap interval excludes zero, and a 2-week live paper-quoting run (simulated fills against the real tape) agrees. Then start at the minimum order size with a per-coin inventory cap, a daily loss stop at 0.5% of the allocated account and an automatic kill switch, all written before the first order.
- Never promise returns.
- Load keys from environment only; never print, log or commit them.
- Work in tick units for prices and seconds for time; state units for every parameter.
DELIVERABLES, IN ORDER
1. verify_as.md: formulas in src/main.py checked against the paper; reproduction of the paper's inventory versus symmetric table.
2. recorder/: websocket recorder for trades and L2, Parquet output, gap detection.
3. hawkes/: event aggregation (multiple prints from one taker order at one timestamp become one event), bivariate exponential fit per 5-minute window, time-rescaling KS test, branching-ratio series.
4. calib/: A and k per side from hit rate versus depth, rolling.
5. backtest/: event-driven simulator with queue position, latency, fees; arms: fixed spread, plain AS (GLT infinite-horizon form), AS with Hawkes-driven A and gamma that rises as n approaches 1; metrics: PnL, markouts at 1, 10, 60 s, inventory std, max drawdown, fill rate.
6. overlay/: paired shadow of the taker strategies with and without a branching-ratio gate, same period.
7. gate.md: the real-money gate, caps and kill switch, plus the current pass or fail.
GAP ANALYSIS (BUILT IN)
Keep gaps.md: whether tick installs on your Python version; tie handling in timestamps; L2 snapshot frequency versus true queue dynamics; fee tier assumptions; whether the archive covers the period; claims in the guide that you could not reproduce. Fill what you can.
SELF-QUESTIONS
- Are sigma and k in tick and second units, and does the spread come out a plausible number of ticks?
- Did the Hawkes fit pass time-rescaling, or am I reading a branching ratio from a bad model?
- Are ties from one taker order inflating self-excitation?
- Does AS beat the fixed-spread control after markouts, or only before?
- Does the overlay reduce drawdown or just reduce trades?
STOP CONDITIONS
Stop and report if recorded data has gaps over 5% of the window, if no Hawkes fit passes the KS test, or if every arm loses to the fixed-spread control after costs. Otherwise stop when all seven deliverables exist.
RETURN FORMAT
Table of deliverable, path, status; the backtest metrics table per arm with bootstrap intervals; KS pass rate; overlay result; gate status; top five gaps.
3 · Step-by-step prompts
Step 1 — Ground truth: verify the repo against the paper
Goal: Make sure the formulas and code agree before anything is built on them.
Open repos/avellaneda-stoikov/. Read the AS 2008 paper in doc/ and Guéant-Lehalle-Fernandez-Tapia 2013.
1. Transcribe the paper's reservation price and spread formulas and compare with src/main.py line by line. The code comments 'optimal half-spread' but computes gamma*sigma^2*(T-t) + (2/gamma)*ln(1+gamma/k), which the paper gives as the total spread; it then posts r +/- r_spread/2. Decide which is correct and write it down with the equation number.
2. Run python src/main.py with numpy and matplotlib. Then write a reproduction script for the paper's comparison of the inventory strategy against the symmetric strategy at gamma 0.1, 0.01 and 0.5: mean PnL, PnL std, final inventory std over 1,000 simulations. Compare with the paper's table.
3. Write the GLT infinite-horizon approximations for a 24/7 perpetual where T is undefined.
4. Check whether tick installs on your Python; if not, record the error and plan a scipy fallback.
Expect: verify_as.md with line-by-line comparison, a reproduction table next to the paper's, GLT formulas, install notes.
Audit before moving on: Reproduced numbers must be within sampling error of the paper; if not, find the difference (time step, fill model, random seed count) before continuing. Any unresolved formula mismatch blocks the backtest.
Step 2 — Record Hyperliquid trades and L2
Goal: Build the raw dataset everything else is fitted on.
Write recorder/record.py: subscribe to Hyperliquid's public trades and l2Book websocket streams for BTC and ETH. Store each trade with exchange timestamp (ms), side, price, size and any trade or order identifiers the feed gives, and each L2 update with timestamp and top 20 levels. Write hourly Parquet files. Reconnect with backoff and log every disconnect with its duration.
Run it for at least 7 days on a machine that stays up. In parallel, check whether Hyperliquid publishes historical trade or L2 archives you can use to extend the window, and note format and cost.
Write recorder/check.py: per hour, count trades, count disconnect seconds, flag hours with more than 1% missing time, and report the distribution of trades per millisecond timestamp.
Record Hyperliquid's current tick size, lot size and maker and taker fees for each coin, with the doc URL and date. No API keys are needed for public streams; do not load any.
Expect: 7+ days of Parquet data, check.py report, fees_and_ticks.md.
Audit before moving on: If total gap time exceeds 5% of the window, extend recording before fitting. If many trades share a millisecond, they are likely one taker order hitting several makers; plan aggregation in step 3.
Step 3 — Fit and test the Hawkes model
Goal: Get a branching-ratio series you can trust.
Aggregate trades: prints with the same timestamp, side and taker identifier (or same ms and side if no identifier) become one event; keep summed size. Build buy and sell event-time arrays per 5-minute window.
Fit a bivariate exponential Hawkes per window. With tick: HawkesExpKern with a decay grid (for example 1, 5, 20 per second), choose decay by held-out log-likelihood, read adjacency as branching ratios and the spectral radius as overall stability. Without tick: implement the exponential Hawkes log-likelihood with the recursive formula and optimize mu, alpha, beta under the constraint spectral radius below 1.
Goodness of fit: compute the compensator between events (time-rescaling); residuals should be Exp(1). Run a KS test per window and report the pass rate at 5%. Plot QQ for a typical and a volatile window.
Output a series of spectral radius, self-excitation and cross-excitation per window, and its correlation with next-window realized volatility and spread.
Expect: hawkes/ code, fits.parquet, a KS pass-rate table, QQ plots, the branching-ratio series with a volatility correlation.
Audit before moving on: If fewer than 70% of windows pass KS, try a sum-of-exponentials kernel before using the series. Confirm you did not divide tick's adjacency by beta. A branching ratio pinned near 1 in all windows usually means ties were not aggregated.
Step 4 — Calibrate fill intensity A and k
Goal: Replace the repo's fixed A and k with values from the tape.
For each depth delta in ticks from the mid (1 to 30 ticks), estimate how often a resting order at that distance would have been hit per second: count aggregated taker events whose price reached that depth on each side, divided by time. Fit log(lambda) = log(A) - k * delta by weighted least squares per side, per hour.
Report A and k with units (per second, per tick), their rolling stability, and the asymmetry between bid and ask.
Recompute sigma in ticks per square-root second from mid changes over 1-second intervals. Then compute the AS spread in ticks with these units at gamma values that give a spread between 1 and 10 ticks, and record that gamma range.
Relate A to the Hawkes intensity: compare hourly A with the mean fitted lambda; this is the link the guide proposes for a time-varying A.
Expect: calib/ code, A and k series per side, the gamma range table, an A versus Hawkes lambda plot.
Audit before moving on: If the computed spread is thousands of ticks or below one tick for all reasonable gamma, the units are wrong; fix before step 5. Check that fits use enough events per bucket (at least 30).
Step 5 — Event-driven paper backtest with controls
Goal: Compare quoting rules after fees, queues and adverse selection.
Use hftbacktest or write an event-driven simulator on the recorded data with: a queue-position model (your order joins the back of the queue at its price level and fills only after volume ahead is traded), 50-200 ms latency for order placement and cancel, the real maker fee or rebate, and minimum order size.
Arms, identical data and parameters elsewhere:
- Control: fixed symmetric spread of N ticks, N chosen on a training period.
- Plain AS using the GLT infinite-horizon form, constant A, k, sigma from training.
- Hawkes AS: A from the rolling Hawkes intensity, gamma scaled up as spectral radius approaches 1, quoting paused above a threshold chosen on training data.
Split days into training and out-of-sample. Report per arm: PnL after fees, markouts at 1, 10 and 60 s, inventory std, max drawdown, fill rate, and bootstrap 95% intervals across out-of-sample days. Inventory cap per coin identical across arms.
Expect: backtest/ code and results.md with the arm table and intervals, plus a PnL decomposition into spread capture, inventory PnL and fees.
Audit before moving on: If any arm shows profit with negative markouts at 10 s, it is a simulator artifact or luck; check queue logic. Verify no parameter was tuned on out-of-sample days.
Step 6 — Branching-ratio overlay on the taker strategies
Goal: Test the guide's lowest-risk integration as a paired shadow.
Open the trading-agent-team repository (the guide names ~/projects/agents/trading-agent-team/; confirm the path). Identify the taker strategies, their entry and take-profit logic and their trade logs.
Build a paired shadow: replay the same signals over the recorded period twice, once as-is and once gated by the Hawkes spectral radius (for example skip entries or tighten take-profit when the radius exceeds a threshold chosen on training days). Use identical fills and fees in both.
Report per coin: trades taken, PnL after fees, max drawdown, win rate, and the distribution of the radius at entry for winners and losers. Out-of-sample days only for the final numbers.
If the live bots can run a shadow arm without placing orders, propose the code change as a patch file, not an applied change, and describe how it would log its decisions alongside the live arm.
Expect: overlay/ results.md, a patch file for a live shadow arm, no changes applied to the live repo.
Audit before moving on: If the gated arm shows lower drawdown only because it trades far less, report return per trade and per unit of exposure as well. Confirm the live repository is untouched.
Step 7 — Validate against oracles and write the gap report
Goal: Decide what passes the paper gate and what remains unknown.
1. Confirm the AS reproduction matches the paper within sampling error.
2. Confirm the Hawkes KS pass rate on held-out windows.
3. Confirm which arm, if any, beats both controls on markout-adjusted PnL after fees with a bootstrap interval excluding zero.
4. Write gate.md: paper result, then a 2-week live paper-quoting run against the real tape with simulated fills, then minimum order size with per-coin inventory cap, daily loss stop at 0.5% of the allocated account and an automatic kill switch. Mark the current status. No real orders in this session.
5. Write gaps.md: claims from the guide checked (for example 'n near 0.9 is dangerous to quote', 'replacing Poisson with Hawkes is the single biggest realism upgrade', the half-spread comment), data limits, fee assumptions, tick install outcome, untested multi-asset effects. Fix what you can now.
Expect: validation.md, gate.md with status, gaps.md.
Audit before moving on: Re-run the backtest from a clean checkout and confirm identical numbers. Grep the repo and logs for key-like strings; any hit is fixed and rotated immediately.
4 · Gap analysis and audit
Run this after the build. It makes the agent enumerate its own claims, mark what is verified, rank the gaps and fix the top ones.
You are auditing an Avellaneda-Stoikov plus Hawkes research stack you did not build. Read verify_as.md, recorder/ checks, hawkes/, calib/, backtest/results.md, overlay/results.md, gate.md.
1. List every claim: formula correctness, reproduction numbers, KS pass rates, A and k values, arm metrics, overlay effect, gate status.
2. Mark each verified, unverified or false with evidence: a script output, a plot, a table row.
3. Re-check: units are ticks and seconds throughout; ties were aggregated; tick's adjacency was not divided by beta; the simulator models queue position, latency and fees; parameters were chosen on training days only; controls ran on identical data; no real orders were sent; no key appears in code, logs or history.
4. List missing pieces: multi-asset inventory, regime changes outside the window, exchange outages, funding payments on perps.
5. Rank gaps by whether they could flip the gate decision.
6. Fix the top three now.
7. Report what you could not fix and why.
Questions the agent must ask itself before it says done:
- Is the repo's r_spread the total spread or the half-spread, and which does the paper say?
- Are sigma and k in tick and second units, giving a spread of a plausible number of ticks?
- What replaces T - t on a perpetual that never closes?
- Did I aggregate multiple prints from one taker order into one event?
- Did the Hawkes fit pass time-rescaling before I used its branching ratio?
- Did I divide tick's adjacency by beta by mistake?
- Does my simulator fill me before the queue ahead of me is traded?
- Do the arms beat the fixed-spread control on 10-second markouts, not just raw PnL?
- Did any parameter see out-of-sample data?
- Does the overlay cut drawdown per unit of exposure, or just cut exposure?
- Have I written the inventory cap, daily loss stop and kill switch before any order?
5 · What proves it right
- The AS 2008 paper's inventory versus symmetric strategy table, reproduced within sampling error from the repo's parameters.
- The time-rescaling theorem: KS test of Hawkes residuals against Exp(1) passing in at least 70% of held-out windows.
- A fixed-spread quoter and plain AS as controls on identical out-of-sample days, with bootstrap intervals on markout-adjusted PnL after fees.
- A 2-week live paper-quoting run against the real Hyperliquid tape agreeing in sign with the backtest.
- The paired taker-strategy shadow: same signals, same fills, with and without the branching-ratio gate.
6 · Failure modes
- Unit blow-up. Tell: AS spread of thousands of dollars on BTC. Fix: express sigma and k in ticks and seconds and recompute gamma range.
- Tie inflation. Tell: branching ratio near 1 everywhere. Fix: aggregate same-timestamp prints per taker order.
- Bad fit, confident signal. Tell: KS failures ignored. Fix: gate the series on KS pass; try sum-of-exponentials kernels.
- Free fills. Tell: profit with negative markouts. Fix: queue-position model, latency and fees in the simulator.
- Overfitting. Tell: great training results, flat out-of-sample. Fix: tune on training days only and report out-of-sample.
- Library rot. Tell: tick fails to build. Fix: hand-written exponential Hawkes likelihood with scipy.
- Skipping the gate. Tell: real orders before gate.md passes. Fix: kill switch and caps first, paper quoting next, minimum size last.
7 · Agent direction (unattended runs)
Run step 1 immediately and start the recorder in step 2 as a background service on day one, because every later step waits on data. Cache recorded Parquet under data/hl/ and fitted parameters under hawkes/fits/. Spawn a sub-agent for the simulator in step 5 while Hawkes fitting runs; they share only the data folder, read-only. Never edit the live trading-agent-team repository; produce patch files only. Stop and ask before any authenticated API call, before any real order, and if the recorder machine cannot stay up for 7 days. Load any key from environment only and never print it. If tick will not build after one attempt, switch to the scipy likelihood rather than debugging compilers. Return README.md linking verify_as.md, recorder/, hawkes/, calib/, backtest/results.md, overlay/results.md, gate.md and gaps.md, each with a one-line status and the gate result.
Prompt system updated 2026-10-22 · all prompt systems · JSON