Faithful Port of FMZ 'Python ML: SVM Predicts Buy/Sell' (by Zero): Rolling Linear-SVM 3-Class Next-Bar Direction Classifier on Raw [Open, Close], Long/Short/Flat, SpreadVal=2, BTCUSD_PERP.BINANCE_CM 1H
Outcome: Abandoned
BtcCmLinearSvmNextBarDirection
Outcome Summary
This hypothesis ported an FMZ rolling linear-SVM next-bar direction classifier to the Binance COIN-M BTC perpetual at 1H, and it pre-registered a near-zero-edge prediction. After 2 iterations the backtest produced 1,408 trades averaging -0.129% per trade, with PF 0.80 and Sharpe -0.38, and the account was liquidated for a -100% return while buy-and-hold BTC rose about 3x. The analyst abandoned it at backtest review before optimization, because a zero gross edge cannot clear trading costs. The analyst also flagged implausible COIN-M daily MTM swings and conflicting liquidation dates for engine review, noting they do not change the sign of the edge.
Faithful port of the open-source FMZ Quant strategy 'Python 机器学习之 SVM 预测买卖' by Zero (https://www.fmz.com/strategy/21370; original: Bitfinex BTC_USD, 1h bars). Credit to the author. Mechanism, in our own words: on every new hourly bar, re-train a linear support-vector classifier from scratch on the recent bar history. Each training sample is one past bar i, its feature vector is the two RAW price levels [open_i, close_i] (no scaling, no returns), and its label is the direction of the NEXT bar's close change, d =……Show moreShow less
Faithful port of the open-source FMZ Quant strategy 'Python 机器学习之 SVM 预测买卖' by Zero (https://www.fmz.com/strategy/21370; original: Bitfinex BTC_USD, 1h bars). Credit to the author. Mechanism, in our own words: on every new hourly bar, re-train a linear support-vector classifier from scratch on the recent bar history. Each training sample is one past bar i, its feature vector is the two RAW price levels [open_i, close_i] (no scaling, no returns), and its label is the direction of the NEXT bar's close change, d = close_{i+1} - close_i: class UP if d > SpreadVal, class DOWN if d < -SpreadVal, class FLAT otherwise, with SpreadVal = 2 (price units, USD) exactly as in the source. The trained model then classifies the latest bar's [open, close] into UP/DOWN/FLAT, and that prediction drives a single long/short/flat position. Adaptations (only these): venue/instrument moved from Bitfinex BTC_USD spot to BTCUSD_PERP.BINANCE_CM (the Binance COIN-M inverse perpetual). It is also quoted in USD per BTC, so SpreadVal=2 keeps its original unit meaning, and it has the lowest round-trip cost in our venue set (~0.06% vs ~0.10% USD-M), which matters for a strategy with hourly turnover. It also fills the under-quota COIN-M bucket (3.2% vs >=5% target). BTC is kept despite corpus concentration only because the source strategy is a BTC_USD strategy and the user asked for a faithful port. Sizing is translated from 'half of the initial account' to 50% of current equity notional at leverage 1.0. The classifier is implemented in numpy because sklearn is not an allowed sandbox import. It is a reimplementation of sklearn's svm.LinearSVC with defaults. The source runs on FMZ's live/in-progress bar: at new-bar detection it uses the just-opened bar's [open, close] (where close is roughly the open). On our bar-close engine the equivalent point-in-time translation uses the just-CLOSED bar t as the prediction input. The training pairs are all (features of bar i, label from close_{i+1} - close_i) where bar i+1 has already closed, so nothing looks ahead. Honest note: SpreadVal=2 USD on a ~$60k-120k BTC is ~0.002%, so the FLAT class almost never occurs and the model is effectively a binary up/down classifier on price levels. Raw [open, close] levels carry essentially no information about the sign of the next hourly change. The factory's lesson L167 predicts this faithful-port family dies at fee_edge. It is proposed because the user explicitly asked for a faithful port, and our real-fee backtest decides. The prediction below is pre-registered as near-zero edge.
Iteration 2 fixes the critical QA sizing defect and changes nothing else. Signal, labels, solver and entry/exit logic are unchanged. On BINANCE_CM the inverse PnL, fees and impact settle in BTC, so get_account_equity() (the USD-stable balance) never moved and every trade was sized at ~$50k until the book was liquidated. position_size() now uses USD mark-to-market equity: the stable balance plus (the BTC balance now minus the BTC balance captured on the first bar, before any trade) times the current price. Because……Show moreShow less
Iteration 2 fixes the critical QA sizing defect and changes nothing else. Signal, labels, solver and entry/exit logic are unchanged. On BINANCE_CM the inverse PnL, fees and impact settle in BTC, so get_account_equity() (the USD-stable balance) never moved and every trade was sized at ~$50k until the book was liquidated. position_size() now uses USD mark-to-market equity: the stable balance plus (the BTC balance now minus the BTC balance captured on the first bar, before any trade) times the current price. Because the strategy is always flat at entry-sizing time, unrealized PnL is zero. The notional is clamped to min(position_frac x MTM x leverage, MTM), floored to whole $100 contracts, and the function returns 0 when MTM <= 0. The coin baseline is held in plain scalar attributes (_coin0, _coin0_set), so it survives restarts. Expected effect: the deployed notional shrinks with losses, avg_position_pct should read about 50% of MTM equity instead of ~97%, and a 1x book can no longer be liquidated. The one-bar-flat reversal and the min_bars_required override are kept as QA accepted them. Honest expectation, as pre-registered: pre-cost PnL is roughly break-even and ~1,800 round trips at ~0.06% RT cost make this a measured fee_edge falsification, not something to tune.
negative_expectancy: faithful port of FMZ 'SVM predicts buy/sell' (Zero) on BTCUSD_PERP.BINANCE_CM 1H. Over 1,408 trades, avg_trade_return_pct is -0.129% (the COIN-M floor is +0.10%), PF is 0.80 and Sharpe is -0.38. The account was liquidated (total_return -100%) and the strategy lost in every vol regime. The per-trade loss is about equal to the taker round-trip cost plus impact, so pre-cost PnL is about zero: raw price levels as SVM features carry no information about next-bar direction. This matches the hypothesis's own near-zero-edge prediction. QA's edge concern is borne out. Optimization cannot lift a zero gross edge above costs, and retuning spread_val or train_bars would not be a faithful port (lessons L120/L141). Failure code: fee_edge (first measured report). Side note: the COIN-M daily MTM series shows implausible swings (-70% then +224% on consecutive days on a 0.5x book), and liquidation_date disagrees with the daily series. The mechanism is not verified; flag it for engine review. It does not change the sign of the trade-ledger edge.
Implementation
Faithful port of FMZ 'Python ML: SVM Predicts Buy/Sell' by Zero (fmz.com/strategy/21370). On every closed 1H bar of BTCUSD_PERP.BINANCE_CM it re-trains, from scratch, a numpy linear SVM equivalent to sklearn LinearSVC defaults (squared hinge, L2, C=1, OvR, regularized intercept). Training rows are the raw [open, close] of the last 300 bars, labelled UP/DOWN/FLAT from the next bar's close change with SpreadVal=2 USD. The model classifies the just-closed bar. The strategy is long on UP, short on DOWN, and flat otherwise, holding 50% of mark-to-market USD equity in whole $100 contracts.
Verification Results
No code change needed for a faithful port. The analyst should use 0.10% + impact as the cost floor.
Cost premise mismatch. The hypothesis justifies BINANCE_CM with a ~0.06% round trip, but entries and exits use the base template's market orders (0.05% taker on each side), so the round trip is ~0.10% plus modelled impact. This does not change correctness. The pre-registered fee_edge outcome just arrives faster.
Optional: submit the opposite entry right after the exit on the same bar, if the base template allows it.
Reversals take one bar flat. should_exit closes when the prediction differs from the held side. The opposite entry can only happen on the next bar, and only if the prediction is still the same then. The source flips directly on each new bar. Previous QA accepted this. It slightly lowers exposure and adds a missed bar on every reversal.
Confirm that plain-scalar strategy state is restored in paper/live, or rebuild the baseline from the account's initial coin balance.
_coin0 (the BTC baseline) is captured on the first calculate_signal call. The docstring says it persists on restart. If a live restart does not restore it, realised coin PnL from before the restart drops out of MTM equity. Backtest is unaffected. Also, liquidation in the sandbox comes from impact folded in after the fact, which this in-engine equity cannot see. That is a harness limitation, not a strategy bug.
The sandbox is a completed fee_edge measurement, which is what the hypothesis pre-registered. 3,598 round trips, win rate 48.8%, avg_trade_return_pct -0.102%, commissions 42% of gross. Per-trade loss about equals the real round-trip cost, so pre-cost PnL is roughly zero. PF 0.71 comes from costs, not a flipped signal, so L125's polarity suspicion does not apply. The hypothesis says COIN-M round trip is ~0.06%, but the code sends MARKET orders at the 0.05% taker rate, so the real cost is ~0.10% plus impact ($44.5k……Show moreShow less
The sandbox is a completed fee_edge measurement, which is what the hypothesis pre-registered. 3,598 round trips, win rate 48.8%, avg_trade_return_pct -0.102%, commissions 42% of gross. Per-trade loss about equals the real round-trip cost, so pre-cost PnL is roughly zero. PF 0.71 comes from costs, not a flipped signal, so L125's polarity suspicion does not apply. The hypothesis says COIN-M round trip is ~0.06%, but the code sends MARKET orders at the 0.05% taker rate, so the real cost is ~0.10% plus impact ($44.5k total). The liquidated=true / -100% result is not caused by sizing. avg_position_pct is 41%, so the iteration-2 MTM fix works. Summed trade PnL is about -$76k, and the post-hoc folded impact of -$44.5k takes the equity curve below zero. The strategy's in-engine equity cannot see that folded cost. Funding is not modelled either (funding_events_available=0) while exposure is 81%, so the real result would be slightly worse. Raw price levels as SVM features carry no directional information. Treat this as falsified (L117 shape: more than 1,000 trades with pre-cost PF about 1). Do not retune thresholds.
Backtest Review
Sharpe
-0.38
Total return
-100.00%
Max drawdown
100.00%
Trades
1408
Win rate
53.6%
Profit factor
0.80
The port is faithful: the classifier is LinearSVC with defaults and uses raw [open, close] features. Labels come only from bars that have already closed, so there is no lookahead.
The sample is reliable: 1,408 closed trades (2,815 fills) from 2020-08 until liquidation. That is enough to measure a per-trade edge tightly.
Per-trade return is negative. avg_trade_return_pct is -0.129%, against a COIN-M floor of +0.10%. The code sends taker market orders, so the real round-trip cost is about 0.10% plus impact. Pre-cost PnL is roughly zero, consistent with a win rate of 0.536 and avg win $230 vs avg loss $333.
Profit factor is 0.80. Sharpe is -0.38, with a CI of -4.43 to 1.80 and PSR 0.41. Commissions were $43.7k and modelled impact another $47.0k. The strategy loses in all three vol regimes (calm Sharpe -3.7, normal -2.0).
The account was liquidated and total_return is -100%. Monthly returns were negative every month from 2020-09 to 2021-01 before the wipe-out.
Benchmark comparison: buy-and-hold BTC over 2020-08 to 2021-02 went up about 3x. The strategy's beta is -0.99 and its alpha is -2.28, so it traded against a strong trend without any compensating edge.
Side note, not a basis for the verdict: the daily series has implausible inverse-contract swings on a 0.5x book (2021-01-24 -70%, 2021-01-25 +224%, 2020-11-28/29 -20%/+25%). The report also gives two different liquidation dates: the daily series ends 2021-02-07, but liquidation_date says 2021-10-11. This looks like a COIN-M MTM or accounting anomaly. I have not verified the mechanism, and the trade ledger is negative whether or not it is real.
Iteration History
Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] Sandbox: 1,779 trades, PF 0.72, avg_trade_return_pct -0.095%. Costs are $89k commission plus $56k impact against a net loss of about $85k, so the book is roughly break-even or slightly positive BEFORE costs and dies on turnover (~1,970x). A trade is ~3.5h long, so costs sit near the per-trade move. That is consistent with the pre-registered fee_edge prediction. PF < 0.70-ish on >100 trades normally raises a polarity suspicion (L125).……Show moreShow less
Verification failed (Layer 4 — QA review) [class=code_defect]:
- [edge_concern] Sandbox: 1,779 trades, PF 0.72, avg_trade_return_pct -0.095%. Costs are $89k commission plus $56k impact against a net loss of about $85k, so the book is roughly break-even or slightly positive BEFORE costs and dies on turnover (~1,970x). A trade is ~3.5h long, so costs sit near the per-trade move. That is consistent with the pre-registered fee_edge prediction. PF < 0.70-ish on >100 trades normally raises a polarity suspicion (L125). Here the 53% win rate and positive pre-cost PnL say the shortfall is cost, not sign. Once sizing is fixed, expect a measured falsification rather than something to tune.
- [critical] Position size does not follow real equity on BINANCE_CM, and the sandbox was LIQUIDATED at leverage 1.0 (liquidated=true, 2025-04-22, total_return -100%). The strategy is meant to hold 50% of equity, so a 1x book cannot be liquidated. position_size() uses get_account_equity(), and on this venue that reads the account's USD-stable balance (the 100k seed). The inverse contract settles PnL, commissions and impact in BTC, from the separate 50-BTC seed, so that stable balance never moves. Each trade is therefore sized at a constant ~$50k (500 contracts) no matter how much has been lost. The numbers agree: avg_trade_pnl_usd -47.70 / avg_trade_return_pct -0.0954% gives ~$50k of notional deployed on every trade. avg_position_pct is 96.9% of the shrinking MTM equity, against a stated 50%. So the drawdown ends in liquidation instead of shrinking the book. This is a sizing/accounting defect, not an edge outcome (compare L148/L156: sizing capped only by a stale equity figure). (line 176) — fix: Size from mark-to-market equity in USD: the stable balance plus the BTC balance change since start times the current price (store the BTC balance seen at on_start), plus unrealized PnL. Alternatively, track realised PnL yourself from closed positions. Then clamp: contracts x 100 <= position_frac x MTM equity x leverage, and never more than MTM equity. Add a fallback that returns 0 when MTM equity is <= 0. Show in the rationale that avg_position_pct reads about 50% in the next sandbox.
- [warning] The FMZ source reverses within one bar. Here a reversal is exit on bar t, then a possible re-entry on bar t+1 if the fresh prediction still agrees. The developer disclosed this and the base template forces it. The effect is one bar flat after each flip, and flips that reverse again are lost. It does not change the mechanism. (line 164) — fix: Acceptable as disclosed. Alternatively, submit the opposite-side entry right after _submit_exit, using _submit_entry_instrument in should_exit, to match the source's same-bar reversal.
- [warning] The min_bars_required override shadows the base method (static-analysis warning). It is harmless: train_bars+2 = 302 1H bars. The deque is bounded (maxlen=train_bars+1), so the 'unbounded growth' warning is a false positive. Per-bar cost is fixed (300 rows, at most 3 small Newton solves), so it is not O(span) (L124 OK). (line 50) — fix: No change required.
- [warning] The sandbox ledger shows avg_holding_bars 0.0 alongside avg_holding_period 3h27m, and trades_count 3557 against total_trades 1779 (fills vs round trips). That looks like a known harness metrics artifact, not a strategy bug. Also funding_folded=false with 0 funding events: COIN-M funding is not in PnL, so the ~78% time-in-market carries unmodelled funding. — fix: Keep in mind at backtest review. No strategy change needed.
Outcome Summary
Raw price levels used as classifier features carry no information about next-bar direction, so hourly-turnover ports built on them die at fee_edge, as the pre-registered prediction and lesson L167 said they would. Separately, the COIN-M daily MTM swings (-70% then +224% on a 0.5x book) and the conflicting liquidation dates should go to engine review.
At backtest review the analyst chose abandon (fee_edge / negative_expectancy): gross edge was about zero, so the per-trade loss roughly equalled taker round-trip cost plus impact. Optimization could not fix this, and retuning spread_val or train_bars would break the faithful-port requirement.
A faithful port of Zero's FMZ 'SVM Predicts Buy/Sell' strategy: every hour it re-trained a linear SVM (numpy reimplementation of sklearn LinearSVC defaults) on the raw [open, close] of the last 300 bars to predict the next bar's direction (SpreadVal=2) and traded BTCUSD_PERP.BINANCE_CM 1H long/short/flat at 50% of equity, 1x leverage.
From 2020-08-11 until the account was liquidated, 1,408 trades averaged -0.129% per trade (COIN-M floor +0.10%), with profit factor 0.80, Sharpe -0.38 (CI -4.43 to 1.80), win rate 53.6% and total return -100%. Commissions were $43.7k and modelled impact another $47.0k, and the strategy lost money in calm, normal and stressed vol regimes.
Backtest and paper results are hypothetical. Trading involves risk of loss.