Strategy file: microPriceMM.js Market: futures
Description
Stoikov (2017) §2 weighted mid-price (microprice) with optional tape trade-flow fusion. OFI-driven quoting with VAP break-even exits. Futures.
How it works
Stoikov (2018) defined the microprice as the conditional expectation of the future mid-price given the current order-book state, derived as a Markov-chain limit: microprice = bid + (ask - bid)·g(I, S) where I is order-book imbalance and S the spread state. Empirically the microprice is a much better predictor of the next mid-print than the simple weighted mid (bid·ask_size + ask·bid_size) / total_size), because it correctly accounts for the path-dependent dynamics of imbalance regeneration. The strategy anchors its quotes to the microprice instead of the mid, biasing toward the side the book imbalance predicts will move first. On futures venues with high microstructure quality this materially reduces adverse selection.
Capital & Period
Order sizing and candle timeframe.
| Key | Type | Default | Description |
|---|---|---|---|
PERIOD |
select | 5 |
Candle timeframe Gunbot feeds the strategy. 1-3 min suits very liquid spot or perp; 5 min is the balanced default; 15 min reduces noise on thinner pairs at the cost of slower adaptation. |
TRADING_LIMIT |
range (range 10..5000) | 500 |
Order size in QUOTE currency (e.g. USDT) per buy attempt. Sets per-quote notional; raise to commit more per fill, lower to keep risk smaller per trade. Futures: scaled by leverage in the runtime; pick a notional you are happy holding flat-to-flat. |
MP_TL |
range (range 10..5000) | 500 |
Strategy-specific TL override. When set, takes precedence over TRADING_LIMIT for THIS strategy only — lets you run different sizes per pair from the GUI without touching the global TL. |
MP_CAPITAL_ALLOC |
range (range 100..100000) | 5000 |
Hard cap on capital this strategy is allowed to commit on this pair. Drives circuit breakers (daily-loss = % of this) and exposure math. Set to the maximum quote balance you want this pair to ever consume. |
Allocation
How much of THIS pair’s wallet the strategy may use, what it must start with, and the hard config gate. Trading is BLOCKED until Wallet allocation % is set AND Allocation confirmed is ON. Optional grid splits an order into laddered post-only rungs for better fills.
| Key | Type | Default | Description |
|---|---|---|---|
ALLOC_PCT |
range (range 1..100) | 25 |
Percentage of THIS pair’s wallet balance the strategy may deploy. Effective cap = min(wallet × this %, the absolute Capital allocation). Every order is clamped to it and can never exceed it. REQUIRED — trading is blocked until this is set (>0) and Allocation confirmed is ON. |
ALLOC_CONFIRMED |
boolean | False |
Explicit acknowledgement that the allocation above is correct for this pair. The strategy will NOT place any entry order until this is ON. A clear "ALLOCATION CONFIGURED" line is logged once it is; otherwise an "ALLOCATION NOT CONFIGURED — refusing to trade" line is logged each cycle. |
ALLOC_SPLIT_TOL |
range (range 0..100) | 15 |
How far the starting base/quote split may deviate from what this strategy needs before it refuses to start. Long-only strategies want mostly quote/cash; two-sided market-makers want ~50/50 base/quote; futures want free margin. Mismatch beyond this % blocks trading (unless Enforce start inventory is OFF). |
ALLOC_ENFORCE_SPLIT |
boolean | True |
When ON, the strategy refuses to trade until the starting base/quote split is within tolerance of what it needs (archetype-aware). When OFF, a mismatch is logged as a warning but trading proceeds. |
ALLOC_AUTO_REBALANCE |
boolean | True |
Two-sided market-makers only. ON by default: if the pair starts off the target base/quote split, the strategy places a single bounded market order on start to reach it (e.g. buys ~half the allocation into base for a 50/50 maker), then begins normal trading. Set to OFF to instead stay blocked and log the exact amount to buy/sell manually. Long-only and futures strategies ignore this. |
ALLOC_RESERVE_PCT |
range (range 0..50) | 0 |
A buffer, as % of wallet, kept BELOW the allocation cap and never deployed. Use to leave headroom for fees/slippage. Effective cap = min(wallet × allocation %, absolute cap) − wallet × this %. |
MP_GRID |
boolean | False |
When ON, an entry order is split into several laddered post-only rungs across a price band instead of one order — often gets better average fills. Cumulative size is still clamped to the allocation. OFF = single order. |
MP_GRID_LEVELS |
range (range 2..10) | 3 |
Number of laddered rungs to split an entry into when "Split entries into a grid" is ON. More rungs = finer fills but more orders. |
MP_GRID_SPAN_PCT |
range (range 0.1..5) | 0.5 |
Price band width, as % from the reference price, across which the grid rungs are spread. e.g. 0.5 places rungs from the reference price down to 0.5% below it (for buys). |
Microprice Model
Stoikov §2 weighted mid-price quote anchor + book-imbalance-driven adaptive half-spread.
| Key | Type | Default | Description |
|---|---|---|---|
MP_BASE_HALF |
range (range 0.5..30) | 3 |
Half-spread (bps) when imbalance is neutral — the floor under your quoted spread. Wider = safer/lower fill rate; tighter = more fills but more adverse-selection risk. 3 bps is reasonable on BTC/ETH perp; raise on thinner pairs. |
MP_MAX_HALF |
range (range 3..80) | 15 |
Cap on the adaptive half-spread when imbalance is extreme. Prevents quotes from drifting absurdly wide on transient book pressure. Default 15 bps; raise on volatile pairs where the model legitimately wants wider quotes under stress. |
MP_OFI_INT |
range (range 0..5) | 1.5 |
How strongly quotes lean in the direction of microprice drift (informed-flow follow). Higher = more aggressive direction-of-flow following; lower = closer to neutral mid-anchored. 1.5 is a balanced default. |
MP_MICRO_EMA |
range (range 0.05..0.95) | 0.3 |
Smoothing weight on the microprice EMA. Higher α = faster reaction to current book imbalance (noisier signal). Lower α = smoother but laggier. 0.3 balances responsiveness with stability. |
MP_MICRO_HIST |
range (range 5..200) | 30 |
Number of recent microprice samples retained for diagnostics. Has no effect on the quoting decision itself; raise only if you want a longer history visible in the sidebar. |
MP_QUOTE_WITHOUT_SIGNAL |
boolean | False |
When OFF (default), the strategy refuses to quote if there is no real orderbook and no trade tape — avoiding trading on a dead signal (microprice collapses to mid). When ON, it falls back to quoting a wide fixed spread even without book/tape. Keep OFF unless you accept fixed-spread quoting with no microstructure edge. |
Live Trade Tape (TFI fusion)
Optional augmentation: trade-flow imbalance from the live tape blended into the microprice drift signal.
| Key | Type | Default | Description |
|---|---|---|---|
MP_USE_TAPE |
boolean | False |
When ON, pulls real trade arrivals from the shared tape module and computes trade-flow imbalance (TFI) over a rolling window. TFI is fused into the microdrift signal as an orthogonal informed-flow indicator. Auto-falls-back to book-only when tape unavailable. |
MP_TFI_WINDOW_MS |
range (range 1000..30000) | 5000 |
Rolling window for trade-flow imbalance computation. Shorter (1-3 s) = more reactive but noisier; longer (10-30 s) = smoother but laggier. 5 s suits 1-min candles on BTC/ETH perp. |
MP_TFI_WEIGHT |
range (range 0..1) | 0.5 |
Blend ratio: final microDrift = (1-w)·book + w·TFI. 0.0 = book-only (legacy). 1.0 = tape-only. 0.5 weights both equally. Lower if your exchange has noisy public-trade aggregation; raise to lean on real tape over book. |
Exits & Inventory
VAP-scratch exit logic and inventory caps.
| Key | Type | Default | Description |
|---|---|---|---|
MP_SCRATCH_EPS |
range (range 0..20) | 1 |
Minimum bps above VAP (or break-even) required before an exit is allowed. Acts as a fee+slippage cushion. Raise to require fatter scratches; lower to scratch closer to flat. 1 bps suits low-fee perp. |
MP_SCRATCH_TRIG |
range (range 0..30) | 3 |
Additional bps beyond ε before microprice-cross triggers an exit. Higher = waits for stronger reversion confirmation; lower = exits earlier with weaker signal. |
MP_MAX_POS_Q |
range (range 0.5..20) | 3 |
Maximum position size measured in TL units (q = position·mid / TL). Hit cap → reduces 50% at market. 3 means up to 3× a single TL of inventory. |
MP_STALE_CYCLES |
range (range 1..30) | 3 |
How many cycles a working quote may sit unfilled before being cancelled and re-priced. Lower = more aggressive re-quoting (more order-management churn); higher = orders allowed to rest longer. |
Rebates & Display
Maker rebate accounting and sidebar precision.
| Key | Type | Default | Description |
|---|---|---|---|
MP_MAKER_REBATE |
range (range -2..5) | 0.02 |
Per-side maker rebate (bps). Used only for projected-rebate display in the sidebar. Set to your exchange's actual maker rebate (e.g. Bybit -0.025% = -2.5 bps when displayed; convention: positive = rebate paid TO you). |
MP_SP |
range (range 0..8) | 4 |
Decimal places shown for prices in the sidebar. 4 suits low-priced pairs (DOGE, SHIB); 1-2 for BTC/ETH. |
Runtime & Exchange
Logging, fees and the cross-exchange/safety toggles.
| Key | Type | Default | Description |
|---|---|---|---|
LOG_LEVEL |
select | NORMAL |
Controls how much the strategy writes to Gunbot logs. SILENT keeps only errors and circuit-breaker messages. NORMAL writes one summary line per cycle plus order events — recommended for live trading. DEBUG adds full internal model state. |
WARMUP_CYCLES |
range (range 1..60) | 5 |
Cycles to wait before the strategy starts placing orders. Lets candle history, OU/ADF fits, and tape caches reach a stable estimate. 5 is fine on liquid pairs; raise to 15-30 on illiquid pairs or longer candle periods. |
MP_FEE |
range (range 0..0.2) | 0.05 |
Taker fee for your exchange tier, as a percentage. Used in P&L bookkeeping and fee-aware exit-price math. Pull the exact number from your exchange fee schedule (VIP/maker tier) for accurate fees. |
MP_MAX_DD |
range (range 1..30) | 5 |
Peak-to-trough equity drawdown that pauses the strategy. Hits → strategy stops placing new orders until manual reset. Tighter (3-5%) for conservative, wider (10-20%) for higher-risk venues. |
MP_MAX_EXP |
range (range 10..95) | 70 |
Hard cap on capital deployed at any moment. Above this, new entry orders are blocked. Lower = more idle cash buffer; higher = more capital working but tighter liquidation risk on futures. |
MP_DAILY_LOSS |
range (range 0.5..10) | 2 |
Daily loss budget as a % of CAPITAL_ALLOC. When today's PnL falls below this threshold, the strategy halts for the remainder of the UTC day. Resets at next-day rollover. |
BE_GUARD |
boolean | True |
When ON, blocks any sell/close at a price BELOW the position break-even while holding a long. Wraps sellMarket, sellLimit, sellLimitPostOnly, closeMarket and closeLimit. Set false to disable (e.g. when you intentionally allow stop-loss exits below BE). |
NO_POST_ONLY |
boolean | False |
When ON, every post-only order is routed as a regular limit order instead. Auto-enabled for PancakeSwap and Aster (DEXes with no post-only flag). Turn ON manually for any exchange that rejects post-only with an error in your logs. |
NO_CLOSE_MARKET |
boolean | False |
When ON, position closes are routed through opposite-side market orders instead of closeMarket(). Auto-enabled when closeMarket is unavailable in the runtime. Use only if your exchange/build does not implement the close API. |
MP_TRACE |
boolean | False |
When ON, writes a structured JSONL audit trail to gunbot_logs/quantroduction/ |
VERBOSE_LOGS |
boolean | False |
When ON, the full Quantroduction × Gunbot dashboard (every config value + state snapshot) re-emits every VERBOSE_INTERVAL_MIN minutes for forensic audit. When OFF (default), the dashboard only fires once per Gunbot restart per pair. |
VERBOSE_INTERVAL_MIN |
range (range 5..240) | 30 |
How often the dashboard re-emits when VERBOSE_LOGS is ON. Lower = more frequent / noisier; higher = quieter. Has no effect when VERBOSE_LOGS is OFF. |
BE_GUARD_BLOCK_MARKET_SELLS |
boolean | True |
Default ON (legacy). Set OFF to enable SOFT BE_GUARD: market sells and closeMarket pass through (treated as urgent / stop-loss). Only limit sells below break-even remain blocked. Prevents BE_GUARD from silently swallowing stop-loss exits. |
SCRATCH_LIVENESS_MIN |
range (range 0..120) | 0 |
When >0: if the pair holds inventory and hasn't filled in N minutes AND the bid is at break-even+1bp, force a market exit to rotate capital. 0 = disabled. Typical: 30. |
CONSEC_RESET_CYCLES |
range (range 60..2880) | 480 |
After this many cycles without any order activity, auto-reset consecutiveLosses to 0. Default 480 cycles ≈ 2h at 15s/cycle. Prevents a 3-loss streak from killing the pair for the entire session. |
DRIFT_ATR_FRAC |
range (range 0..0.5) | 0 |
When >0: scale drift-requote threshold to this fraction of the recent 10-candle high-low range (clamped 2-100 bps). 0 = use fixed *_STALE_DRIFT_BPS. Typical: 0.05 = 5% of recent range. Adapts drift detection to per-pair volatility. |
SKEW_QTY_MAX |
range (range 1..5) | 2.5 |
Maximum ask:bid qty ratio when inventory is heavily skewed. 2.5 means a heavily-bagged pair quotes up to 2.5x ask qty vs bid qty to drain inventory faster. Set 1.0 to disable (symmetric quoting). |
SKEW_QTY_TARGET |
range (range 0.1..0.9) | 0.5 |
Target inventory fraction of pair equity. 0.5 = 50/50 balanced base/quote. Skew kicks in proportionally as actual exposure deviates from target. |
PORTFOLIO_INCLUDE |
boolean | True |
When ON (default), this pair participates in the shared PORTFOLIO_EXP_BUDGET — its exposure counts toward portfolio total and bids pause when budget is exceeded. When OFF, the pair stands alone (use PAIR_EXP_BUDGET for own cap). |
PORTFOLIO_EXP_BUDGET |
range (range 0..1) | 0 |
Cap on total portfolio inventory as fraction of total allocated equity (sum across PORTFOLIO_INCLUDE pairs). 0 = disabled. Typical: 0.6 = 60% inventory cap across the included portfolio. When exceeded, bids pause but exits remain active. |
PAIR_EXP_BUDGET |
range (range 0..1) | 0 |
This pair's own exposure cap as fraction of pair equity (inventory / pair allocated capital). Applies independently of portfolio budget. 0 = disabled. Typical: 0.2 = 20% per-pair cap. |
DISABLE_BREAKER_WINDDOWN |
boolean | False |
When OFF (default), an active breaker (3 consecutive losses or daily loss limit) actively frees capital: cancels open orders and scratch-sells inventory IF profitable (bid >= BE+1bp). When ON, legacy halt-and-hold behaviour. |
TRACE_ALL |
boolean | False |
Master switch for the Quantroduction tracer. When ON, writes detailed per-cycle JSONL to gunbot_logs/quantroduction/ AND emits a verbose console summary. Equivalent to setting every |
Safety & Tuning (v1.0-beta)
Universal safety + tuning knobs added in v1.0-beta. These were previously hidden from the chart page even though the strategy reads them. Setting any of these here will be applied per-pair.
| Key | Type | Default | Description |
|---|---|---|---|
MIN_ORDER_QUOTE |
range (range 1..100) | 5 |
Floor on order size in quote currency to avoid exchange dust rejections. Match to your exchange's minimum notional. Default 5 USDT. |
MP_ASK_CLAMP_BUFFER_BPS |
range (range 0..50) | 2 |
When BE_GUARD is on and the strategy computes a sub-BE ask, the clamp snaps the ask up to break-even + this many bps. Default 2 = ask sits 2 bps above BE. Larger = more profitable but slower fills. |
MP_DISABLE_ASK_CLAMP |
boolean | False |
Default OFF (clamp active). Set ON to bypass the break-even-aware ask snap; ask remains at the strategy's raw computed value. Use only if you want the ask to occasionally sit below BE. |
MP_PERIOD |
string | 1 |
Candle period in minutes used for this strategy's indicators. Common values: '1', '5', '15'. Some strategies need a long history to warm up indicators. |
MP_STALE_DRIFT_BPS |
range (range 1..50) | 8 |
Cancel and requote when an on-book order has drifted more than N bps from the current computed quote. Default 8. Lower = more cancels (higher fee burn); higher = more stale quotes. ATR-scaled override available via DRIFT_ATR_FRAC. |
MP_DEEPEN_LEVELS |
range (range 1..5) | 1 |
How many orderbook levels to use in the weighted-mid microprice. 1 (default) is the L1 weighted-mid - simple and fast. 2 or 3 uses deeper levels with geometric (1/2^k) weight decay - closer to the full Stoikov 2018 §3 microprice, smoother signal on thin top-of-book. |
STRICT_LITERATURE |
boolean | False |
Master switch. When ON, the strategy disables every operator-grade safety override (BE_GUARD, cross-protection floors, BE ask clamps, drift-ATR scaling, asymmetric sizing, scratch liveness, breaker wind-down) so it runs as faithful as we can make it to the cited academic paper. Use this for paper-comparison backtests or academic research. WARNING: in strict mode the strategy can take real losses (papers prove optimality only in expectation, not per-trade). |
NO_CLOSE_MARKET |
toggle | False |
When true, the strategy NEVER falls back to a market sell to close a held inventory — only post-only limits. Use to prevent any taker fee on exits. Default false (allow market close when necessary). |
QUANTRODUCTION_TRACE |
toggle | False |
When true, this single pair writes detailed cycle events to gunbot_logs/quantroduction/ |
RESET_BREAKER_ONCE |
toggle | False |
One-shot: set true and Gunbot will clear all tripped risk breakers (consec_losses, daily_loss, max_dd) on this pair on the next cycle, then re-arm them. The setting auto-clears itself after firing. Use when a breaker tripped on a now-stale condition. |
RESET_STATS_ONCE |
toggle | False |
One-shot: set true and Gunbot will clear customStratStore counters (wins, losses, totalPnL, peakEquity, maxDD, dailyPnL, dailyLossLimit) on this pair on the next cycle. The setting auto-clears itself after firing. Useful after a recovery / regime change. |
Laddered Quoting
Spread each side of the quote into a stack of post-only rungs instead of one full-size order.
| Key | Type | Default | Description |
|---|---|---|---|
MP_LAYERS |
range (range 1..8) | 4 |
Number of laddered post-only rungs per side per cycle. The microprice tilt is preserved across rungs. |
MP_LAYER_SPAN_BPS |
range (range 0..50) | 8 |
Spread of the rung ladder around the microprice anchor. |
Portfolio & Runtime (per-pair overrides)
Per-pair runtime knobs. Override any of these on a single pair without changing the strategy defaults.
| Key | Type | Default | Description |
|---|---|---|---|
SPREAD_PNL_JUMP_GUARD |
range (range 0.1..1) | 0.5 |
Realized-PnL deltas larger than this fraction of pair equity are treated as deposits/withdrawals/data-glitches and skipped. Default 0.5 means a single delta over 50% of equity is ignored. Lower for tighter glitch detection on small accounts. |
References & further reading
- Stoikov, S. (2018). The micro-price: a high-frequency estimator of future prices. Quantitative Finance 18(12), 1959–1966.
- Cartea, Á., Donnelly, R. & Jaimungal, S. (2018). Enhancing trading strategies with order book signals. Applied Mathematical Finance 25(1), 1–35.
- Easley, D., López de Prado, M. & O'Hara, M. (2012). Flow toxicity and liquidity in a high-frequency world. Review of Financial Studies 25(5), 1457–1493.
Configuration playbook
- Full Tier 1-3 stack: see
OPERATOR_GUIDE.mdquick-start - Standalone pair (not in portfolio):
"PORTFOLIO_INCLUDE": false, "PAIR_EXP_BUDGET": 0.20 - Clear stuck breaker:
"RESET_BREAKER_ONCE": true - Clear historical loss counters:
"RESET_STATS_ONCE": true(preserves total PnL) - Enable JSONL tracer:
"TRACE_ALL": true - Soft BE_GUARD:
"BE_GUARD": true, "BE_GUARD_BLOCK_MARKET_SELLS": false