Skip to content
All strategies

Strategies

FMZ 2014 Depth-Reach Quasi-Market-Maker (by 小草, fmz.com/strategy/1088), Faithful Port: Long-Only Full-Inventory Maker Quotes ±10bp Around the Touch, Cancel-and-Replace Every Bar, No Stop (SOLUSDT.BINANCE USD-M, 1-Minute Bars, Post-Only Maker Orders)

Outcome: Abandoned

FmzDepthReachQuasiMarketMakerSol1m

Outcome Summary

This strategy ported a 2014 FMZ order-book-depth market-making bot to 1-minute SOLUSDT perpetuals, quoting ±10bp around the touch with all its inventory and no stop, even though the hypothesis itself called this class a fee graveyard. Across 3 iterations it never got past verification. The sandbox backtest went to -100% with liquidation, 2,311 trades and a 0% win rate, because sizing let exposure reach about 252% of equity and the market impact per trade outweighed the 20bp spread. QA also flagged a trade ledger that doesn't reconcile and warned that the touch-fill model doesn't capture adverse selection. The run was abandoned as a code defect before the backtest review, optimization, analyst and risk stages.

Hypothesis

Port of 小草's 2014 'simple Bitcoin high-frequency bot' (FMZ strategy 1088). The strategy is by that author. Classification: (a) a concrete, tradeable strategy. Original rules, in our words: every 3.5 seconds the bot reads 20 levels of order-book depth. Its buy price is one tick above the bid level where cumulative bid size first passes 8 coins. Its sell price is one tick below the ask level where cumulative ask size first passes 8 coins. If the sell price minus the buy price is 1.5 price units or less, it moves……Show moreShow less

Port of 小草's 2014 'simple Bitcoin high-frequency bot' (FMZ strategy 1088). The strategy is by that author. Classification: (a) a concrete, tradeable strategy. Original rules, in our words: every 3.5 seconds the bot reads 20 levels of order-book depth. Its buy price is one tick above the bid level where cumulative bid size first passes 8 coins. Its sell price is one tick below the ask level where cumulative ask size first passes 8 coins. If the sell price minus the buy price is 1.5 price units or less, it moves both quotes 10 units further out. It then cancels every resting order and posts two limit orders: a sell of all coins held and a buy using all cash minus a small buffer, each only if it is larger than 0.02 coins. There is no stop-loss and no cost-basis logic. Port decisions: (1) Data. The catalog has no historical L2 depth: the order_book_delta and quote_tick folders hold only one or two snapshots from 2026-04/05. On a modern liquid perp, 8 coins of size sit at or next to the touch, so the original code's own 1.5-unit branch fires on essentially every tick. The quotes therefore become touch -10 and touch +10 units. At the ~10,000 BTC price in the author's example, 10 units = 10bp and 1.5 units = 1.5bp. We keep those defaults as relative values, using the last 1-minute close as the touch. (2) Cadence. 3.5 seconds becomes one update per 1-minute bar close. This is a representation compromise. (3) Venue. Binance spot charges 0.10% maker, which is more than the whole 20bp quote width, so spot cannot work. We use Binance USD-M (0.02% maker, 0.04% round trip), long-only at 1x, to keep the original cash/coin inventory behaviour. Hyperliquid's 1m history is only about 3 days, too short to validate on. (4) Instrument. SOL instead of BTC, because BTC is the most over-used series in the corpus. (5) Sizing. Full position, as in the original. Flat state: all cash with a resting bid, expected about 45-60% of the time. Honest prior: this is sub-hour passive mean reversion on a liquid major, which is the fee-graveyard class.

Iteration 3 fixes the Layer-3 sandbox timeout only. Order churn was the per-bar cost: a 5bp drift tolerance on SOL 1m bars cancelled and replaced the full-size quotes on most bars, which could mean tens of thousands of orders in the window. Drift requotes now fire only on a cadence tied to the bar timestamp (minute % requote_every_min == 0, the same across restarts) and need at least 10bp of drift (one full quote width). Requotes after a fill or a missing quote still happen immediately. Quote logic, sizing and signal are unchanged. Honest prior from the hypothesis: this is passive sub-hour mean reversion in the fee-graveyard class, and the backtest's touch-fill model likely flatters maker fills (lesson L31).

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Even with sizing fixed, a 20bp-wide quote pair on 1m SOL has ~0.04% maker round trip and relies on the backtest's touch-fill model filling passive quotes. Adverse selection is not modelled, so any positive result is likely flattering. The hypothesis itself calls this the fee-graveyard class. - [critical] Gross exposure goes over equity at leverage 1.0, and the account was liquidated. In the sandbox, avg_position_pct……Show moreShow less

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Even with sizing fixed, a 20bp-wide quote pair on 1m SOL has ~0.04% maker round trip and relies on the backtest's touch-fill model filling passive quotes. Adverse selection is not modelled, so any positive result is likely flattering. The hypothesis itself calls this the fee-graveyard class. - [critical] Gross exposure goes over equity at leverage 1.0, and the account was liquidated. In the sandbox, avg_position_pct is 252% with config leverage 1.0, and the account hit liquidated=true on 2026-07-27 with total_return -100%. `cash = equity*lev*(1-buffer) - coins*close` is recomputed after every fill from the venue balance. Nothing in it caps gross notional independently: no check against notional already committed or resting, and no hard ceiling of gross <= equity x leverage. A long-only 1x book with this design cannot be liquidated unless exposure has gone above 100%. That makes this a sizing/accounting defect, not an edge outcome. (line 131) — fix: Cap the BUY quantity so (existing long qty + resting buy qty) x price <= equity x leverage x (1 - buffer), using mark-to-market equity rather than the raw wallet balance. Assert the cap before every submit. Before posting the replacement bid, confirm the cancel of the previous bid was processed (no open BUY in cache.orders_open) so two bids cannot both fill. - [critical] The impact/capacity limit is blown by sizing. total_impact_usd is $624,541 across 2,311 trades, about $270 per trade. That is almost exactly the average loss of $298.58, and it is why the win rate is exactly 0% on a design that sells 20bp above where it buys. Every quote commits 100% (in practice ~250%) of equity to a single 1-minute SOL fill. The modelled market impact of that clip is far larger than the 20bp quote width, so each round trip is structurally negative before any signal question comes up. Per the fail_class rules, a capacity limit blown by position sizing is a code_defect. (line 142) — fix: Clip each quote to a capacity-aware fraction of equity. Size it from recent 1m volume, e.g. <= a small % of bar notional volume, so modelled impact stays well under the 10bp half-width. Report the resulting per-trade impact in the rationale. - [warning] The trade ledger does not reconcile. avg_trade_return_pct is -0.0000333% while avg_trade_pnl_usd is -$298.58 and total_return is -100% (lessons L140/L116). Per-trade economics cannot be compared to the 0.04% maker round trip until the denominator is the notional actually deployed. Also, trades_count (6,040) differs from total_trades (2,311). (line 139) — fix: After fixing sizing, check that the ledger books each fill against its real notional before any fee-floor comparison. - [warning] The requote cadence is calendar-anchored (bar ts minute % 5), which is correct. But drift requotes need >=10bp of movement and happen only every 5 minutes. The original cancels and replaces every loop, so quotes can sit up to one full quote-width stale. This is a documented compromise for wall-clock reasons, so it is only a warning. (line 97) — fix: Once sizing is fixed and the order count drops, consider a tighter tolerance (e.g. 5bp) on the calendar grid. - [warning] min_bars_required override shadows the base method. It is harmless here because there are no indicators, but it is flagged by static analysis. (line 51) — fix: Keep it only if the base contract allows it.

Implementation

Long-only full-inventory quasi market maker (port of FMZ 1088): post-only GTC bid at touch-10bp with all cash, post-only ask at touch+10bp for all coins held, cancel-and-replace on fills or on a 5-minute calendar cadence when the target drifts >=10bp. No stop.

Verification Results

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Even with sizing fixed, a 20bp-wide quote pair on 1m SOL has ~0.04% maker round trip and relies on the backtest's touch-fill model filling passive quotes. Adverse selection is not modelled, so any positive result is likely flattering. The hypothesis itself calls this the fee-graveyard class. - [critical] Gross exposure goes over equity at leverage 1.0, and the account was liquidated. In the sandbox, avg_position_pct is 252% with……Show moreShow less

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Even with sizing fixed, a 20bp-wide quote pair on 1m SOL has ~0.04% maker round trip and relies on the backtest's touch-fill model filling passive quotes. Adverse selection is not modelled, so any positive result is likely flattering. The hypothesis itself calls this the fee-graveyard class. - [critical] Gross exposure goes over equity at leverage 1.0, and the account was liquidated. In the sandbox, avg_position_pct is 252% with config leverage 1.0, and the account hit liquidated=true on 2026-07-27 with total_return -100%. `cash = equity*lev*(1-buffer) - coins*close` is recomputed after every fill from the venue balance. Nothing in it caps gross notional independently: no check against notional already committed or resting, and no hard ceiling of gross <= equity x leverage. A long-only 1x book with this design cannot be liquidated unless exposure has gone above 100%. That makes this a sizing/accounting defect, not an edge outcome. (line 131) — fix: Cap the BUY quantity so (existing long qty + resting buy qty) x price <= equity x leverage x (1 - buffer), using mark-to-market equity rather than the raw wallet balance. Assert the cap before every submit. Before posting the replacement bid, confirm the cancel of the previous bid was processed (no open BUY in cache.orders_open) so two bids cannot both fill. - [critical] The impact/capacity limit is blown by sizing. total_impact_usd is $624,541 across 2,311 trades, about $270 per trade. That is almost exactly the average loss of $298.58, and it is why the win rate is exactly 0% on a design that sells 20bp above where it buys. Every quote commits 100% (in practice ~250%) of equity to a single 1-minute SOL fill. The modelled market impact of that clip is far larger than the 20bp quote width, so each round trip is structurally negative before any signal question comes up. Per the fail_class rules, a capacity limit blown by position sizing is a code_defect. (line 142) — fix: Clip each quote to a capacity-aware fraction of equity. Size it from recent 1m volume, e.g. <= a small % of bar notional volume, so modelled impact stays well under the 10bp half-width. Report the resulting per-trade impact in the rationale. - [warning] The trade ledger does not reconcile. avg_trade_return_pct is -0.0000333% while avg_trade_pnl_usd is -$298.58 and total_return is -100% (lessons L140/L116). Per-trade economics cannot be compared to the 0.04% maker round trip until the denominator is the notional actually deployed. Also, trades_count (6,040) differs from total_trades (2,311). (line 139) — fix: After fixing sizing, check that the ledger books each fill against its real notional before any fee-floor comparison. - [warning] The requote cadence is calendar-anchored (bar ts minute % 5), which is correct. But drift requotes need >=10bp of movement and happen only every 5 minutes. The original cancels and replaces every loop, so quotes can sit up to one full quote-width stale. This is a documented compromise for wall-clock reasons, so it is only a warning. (line 97) — fix: Once sizing is fixed and the order count drops, consider a tighter tolerance (e.g. 5bp) on the calendar grid. - [warning] min_bars_required override shadows the base method. It is harmless here because there are no indicators, but it is flagged by static analysis. (line 51) — fix: Keep it only if the base contract allows it.

Iteration History

sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (30 days of SOLUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL). This almost always means per-bar work that scales with history — e.g. rescanning the full funding/supplementary series, or rebuilding a list and calling min()/sorted() inside calculate_signal()/on_bar() on every bar. Precompute sorted timestamp arrays ONCE in __init__ and use bisect, or cache lookups keyed by timestamp, so per-bar cost is O(log n) not O(n).

Outcome Summary

A passive maker port has to cap gross notional, counting both held and resting orders, at equity × leverage, and size each quote from recent bar volume so impact stays well below the quote half-width; otherwise every round trip loses money whether or not the edge is real.

After 3 iterations it failed Layer 4 QA verification (class code_defect) and was abandoned in a verification loop. The critical issues were gross exposure above equity at 1x leverage, which let a long-only book be liquidated, and full-equity quotes whose modelled impact (~$270 per trade) was far larger than the 20bp quote width.

A faithful long-only port of 小草's 2014 FMZ quasi-market-maker (strategy 1088): post-only maker quotes 10bp either side of the last 1-minute close on SOLUSDT USD-M, cancelled and replaced on each bar, using all inventory and no stop-loss.

No formal backtest or optimization report exists. The QA sandbox run lost 100% (the account was liquidated on 2026-07-27) over 2,311 trades with a 0% win rate, a -$298.58 average trade, about 252% average position size at 1.0x leverage, and $624,541 of total modelled impact.

Abandon Reason

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Even with sizing fixed, a 20bp-wide quote pair on 1m SOL has ~0.04% maker round trip and relies on the backtest's touch-fill model filling passive quotes. Adverse selection is not modelled, so any positive result is likely flattering. The hypothesis itself calls this the fee-graveyard class. - [critical] Gross exposure goes over equity at leverage 1.0, and the account was liquidated. In the sandbox, avg_position_pct……Show moreShow less

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Even with sizing fixed, a 20bp-wide quote pair on 1m SOL has ~0.04% maker round trip and relies on the backtest's touch-fill model filling passive quotes. Adverse selection is not modelled, so any positive result is likely flattering. The hypothesis itself calls this the fee-graveyard class. - [critical] Gross exposure goes over equity at leverage 1.0, and the account was liquidated. In the sandbox, avg_position_pct is 252% with config leverage 1.0, and the account hit liquidated=true on 2026-07-27 with total_return -100%. `cash = equity*lev*(1-buffer) - coins*close` is recomputed after every fill from the venue balance. Nothing in it caps gross notional independently: no check against notional already committed or resting, and no hard ceiling of gross <= equity x leverage. A long-only 1x book with this design cannot be liquidated unless exposure has gone above 100%. That makes this a sizing/accounting defect, not an edge outcome. (line 131) — fix: Cap the BUY quantity so (existing long qty + resting buy qty) x price <= equity x leverage x (1 - buffer), using mark-to-market equity rather than the raw wallet balance. Assert the cap before every submit. Before posting the replacement bid, confirm the cancel of the previous bid was processed (no open BUY in cache.orders_open) so two bids cannot both fill. - [critical] The impact/capacity limit is blown by sizing. total_impact_usd is $624,541 across 2,311 trades, about $270 per trade. That is almost exactly the average loss of $298.58, and it is why the win rate is exactly 0% on a design that sells 20bp above where it buys. Every quote commits 100% (in practice ~250%) of equity to a single 1-minute SOL fill. The modelled market impact of that clip is far larger than the 20bp quote width, so each round trip is structurally negative before any signal question comes up. Per the fail_class rules, a capacity limit blown by position sizing is a code_defect. (line 142) — fix: Clip each quote to a capacity-aware fraction of equity. Size it from recent 1m volume, e.g. <= a small % of bar notional volume, so modelled impact stays well under the 10bp half-width. Report the resulting per-trade impact in the rationale. - [warning] The trade ledger does not reconcile. avg_trade_return_pct is -0.0000333% while avg_trade_pnl_usd is -$298.58 and total_return is -100% (lessons L140/L116). Per-trade economics cannot be compared to the 0.04% maker round trip until the denominator is the notional actually deployed. Also, trades_count (6,040) differs from total_trades (2,311). (line 139) — fix: After fixing sizing, check that the ledger books each fill against its real notional before any fee-floor comparison. - [warning] The requote cadence is calendar-anchored (bar ts minute % 5), which is correct. But drift requotes need >=10bp of movement and happen only every 5 minutes. The original cancels and replaces every loop, so quotes can sit up to one full quote-width stale. This is a documented compromise for wall-clock reasons, so it is only a warning. (line 97) — fix: Once sizing is fixed and the order count drops, consider a tighter tolerance (e.g. 5bp) on the calendar grid. - [warning] min_bars_required override shadows the base method. It is harmless here because there are no indicators, but it is flagged by static analysis. (line 51) — fix: Keep it only if the base contract allows it.

Backtest and paper results are hypothetical. Trading involves risk of loss.