Skip to content
All strategies

Strategies

FMZ One-Sided Recycling Grid: Wide-Step LTC Spot with Inventory Stops

Outcome: Abandoned

FmzLtcSpotOneSidedRecyclingGrid

Outcome Summary

This strategy tested whether an FMZ-style one-sided recycling grid on LTC spot could clear fees, using a 1.8% take-profit on a 0.9% grid against a 0.20% spot round trip. Over 3 iterations it never got past verification. QA found that stop_requested and the cycle bookkeeping were reset only when a new cycle started, so after any losing liquidation the 24h halt kept moving forward and the grid shut down for good. The sandbox matched this, with only 10 fills and 4 equity-moving days in 834 days. QA also flagged that the cycle trailing loss would trigger before the node stops and that per-node accounting conflicted with the single netted spot position. The strategy was abandoned without a full backtest, optimization or analyst review.

Hypothesis

Test one mechanism from 发明者量化-小小梦: resting purchases below an anchor, a separate profit-taking sell for each filled node, and replacement of that node only after its inventory is sold. Adapt to LTC Binance Spot with percentage-scaled prices, equal capital allocations, wide profit targets and mandatory inventory liquidation controls. This is a research hypothesis, not a demonstrated profitable strategy. Virtual-order activation and grid relocation are execution features of the same mechanism, not additional hypotheses.

The source contains one trading mechanism; reversing its direction does not create a distinct hypothesis. BINANCE_SPOT is under its 15% target, and cash trading preserves the source's buy-first mechanics without leveraged inventory accumulation. Long-only and single-symbol exposure remain overrepresented, but adding shorts or artificial hedge legs would change the source mechanism. corpus_concentration is empty, so LTC's individual research share cannot be verified. Unlike the existing ETH Bybit teaching grid, this experiment uses spot inventory, fill-linked recycling, wider percentage targets and a cycle-level trailing loss limit. Negative-Sharpe execution checks in the supplied successes are not evidence of profitability.

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] A 1.8% take-profit on a 0.9% grid clears the 0.20% spot round trip (0.10% maker + 0.10% taker per side), so the fee floor passes. The sandbox recorded only 10 fills and 4 equity-moving days in 834 days, so it cannot measure edge. The reported 24.8% drawdown on a book capped at 20% exposure looks like a cash-only equity artifact; check it in the full backtest. Because levels net into one position, the trade ledger……Show moreShow less

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] A 1.8% take-profit on a 0.9% grid clears the 0.20% spot round trip (0.10% maker + 0.10% taker per side), so the fee floor passes. The sandbox recorded only 10 fills and 4 equity-moving days in 834 days, so it cannot measure edge. The reported 24.8% drawdown on a book capped at 20% exposure looks like a cash-only equity artifact; check it in the full backtest. Because levels net into one position, the trade ledger undercounts round trips (L133). Compare per-level fills with total_trades before trusting per-trade economics. - [critical] Any liquidation that does not end in a profit permanently locks out the strategy. stop_requested and the cycle bookkeeping (cycle_cash, cycle_peak, cycle_equity) are reset only in _start_cycle(), but _manage() never reaches _start_cycle() while now_ns < halt_until_ns. Once _drain() finishes, it sets liquidating=False, sets anchor=0 and returns, because the halt is still active. On the next bar should_exit() returns True again. After a node stop fill this is because stop_requested is still True. After a trailing-loss exit it is because cycle_peak - (cycle_cash + 0) still exceeds the threshold, since the realized loss is now in cycle_cash. The check runs with liquidating=False, so _manage sets liquidating=True and halt_until_ns = now + cooldown again. The halt moves forward 24h on every hourly bar, never expires, and the grid never re-arms. The orphan-inventory path at line ~228 deadlocks the same way. The sandbox is consistent with this: 10 fills, 1 closed position, only 4 days with equity changes over 834 days, and a drawdown lasting 829.6 days. The hypothesis's 'stop_cooldown_hours pause' becomes a permanent shutdown, so the backtest would measure only the first cycle or few cycles. (line 214) — fix: Make the liquidation trigger edge-triggered and reset state when the drain completes. When _drain() returns True, clear stop_requested and reset cycle_cash, cycle_peak and cycle_equity (or set a 'cycle_closed' flag that should_exit honours). Then start the next cycle only after the original halt_until_ns, and never extend the halt while waiting. One option is to evaluate should_exit() only when anchor > 0 and not liquidating. Add a synthetic test in which a node stop fills and the grid re-arms after stop_cooldown_hours. - [warning] The cycle trailing loss (1.2% of cycle equity) binds long before the 6% node stop. With 20% exposure fully filled, about a 6% average adverse move liquidates the whole book; with fewer levels filled it takes a larger move. The per-node exchange stop will therefore rarely be the binding exit. This is allowed by the hypothesis ('mandatory inventory liquidation controls'), but the trailing exit is evaluated only at hourly closes and executes as a market sell. (line 117) — fix: Document which control is intended to bind, or derive cycle_trailing_loss_pct from node_stop_pct x max_exposure. - [warning] Five overlapping bracket OUO sets share one netting spot position, and reduce_only legs on a CASH account aggregate. If one node's stop and another node's target fire in the same bar, per-node qty bookkeeping (from on_order_filled) and the engine's position can diverge. The positions report will also count several level round trips as one trade. (line 152) — fix: After each fill, reconcile the sum of node qty with the cache position quantity, and liquidate or halt on a mismatch.

Implementation

Long-only grid on LTC Binance Spot that rebuys each level only after that level's coins are sold. Five post-only limit buys sit grid_spacing_pct apart below an anchor price. Each buy is placed only when price comes within activation_distance_pct of it and is cancelled when price moves more than deactivation_distance_pct away. Each filled level gets its own exit orders at the exchange: a take_profit_pct limit sell and a node_stop_pct stop. A level is placed again only after its coins are sold. When nothing is held, the grid moves to a new anchor if price drifts move_distance_pct from the old one or after idle_reset_hours. Three events sell all holdings and pause new buys for stop_cooldown_hours: a cycle loss of cycle_trailing_loss_pct of cycle equity from its peak, a level held for 72h, or any level's stop filling. Each level is 4% of NAV and total exposure is capped at 20%.

Implements the FMZ grid that re-places each level only after its fill is sold, on spot (long-only, CASH, leverage 1). Iteration 3: the previous submission's code field held a placeholder string instead of the source, which caused the Layer-1 syntax error. This version restores the full strategy source. It also fixes the iteration-2 Layer-1.5 failure: every fixed value in optimization_plan now appears in parameters with the same value and type, including leverage=1.0. The strategy logic is unchanged. Note: levels filled at the same time net into one spot position, so the positions report may count several level round-trips as one trade.

Verification Results

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] A 1.8% take-profit on a 0.9% grid clears the 0.20% spot round trip (0.10% maker + 0.10% taker per side), so the fee floor passes. The sandbox recorded only 10 fills and 4 equity-moving days in 834 days, so it cannot measure edge. The reported 24.8% drawdown on a book capped at 20% exposure looks like a cash-only equity artifact; check it in the full backtest. Because levels net into one position, the trade ledger undercounts round……Show moreShow less

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] A 1.8% take-profit on a 0.9% grid clears the 0.20% spot round trip (0.10% maker + 0.10% taker per side), so the fee floor passes. The sandbox recorded only 10 fills and 4 equity-moving days in 834 days, so it cannot measure edge. The reported 24.8% drawdown on a book capped at 20% exposure looks like a cash-only equity artifact; check it in the full backtest. Because levels net into one position, the trade ledger undercounts round trips (L133). Compare per-level fills with total_trades before trusting per-trade economics. - [critical] Any liquidation that does not end in a profit permanently locks out the strategy. stop_requested and the cycle bookkeeping (cycle_cash, cycle_peak, cycle_equity) are reset only in _start_cycle(), but _manage() never reaches _start_cycle() while now_ns < halt_until_ns. Once _drain() finishes, it sets liquidating=False, sets anchor=0 and returns, because the halt is still active. On the next bar should_exit() returns True again. After a node stop fill this is because stop_requested is still True. After a trailing-loss exit it is because cycle_peak - (cycle_cash + 0) still exceeds the threshold, since the realized loss is now in cycle_cash. The check runs with liquidating=False, so _manage sets liquidating=True and halt_until_ns = now + cooldown again. The halt moves forward 24h on every hourly bar, never expires, and the grid never re-arms. The orphan-inventory path at line ~228 deadlocks the same way. The sandbox is consistent with this: 10 fills, 1 closed position, only 4 days with equity changes over 834 days, and a drawdown lasting 829.6 days. The hypothesis's 'stop_cooldown_hours pause' becomes a permanent shutdown, so the backtest would measure only the first cycle or few cycles. (line 214) — fix: Make the liquidation trigger edge-triggered and reset state when the drain completes. When _drain() returns True, clear stop_requested and reset cycle_cash, cycle_peak and cycle_equity (or set a 'cycle_closed' flag that should_exit honours). Then start the next cycle only after the original halt_until_ns, and never extend the halt while waiting. One option is to evaluate should_exit() only when anchor > 0 and not liquidating. Add a synthetic test in which a node stop fills and the grid re-arms after stop_cooldown_hours. - [warning] The cycle trailing loss (1.2% of cycle equity) binds long before the 6% node stop. With 20% exposure fully filled, about a 6% average adverse move liquidates the whole book; with fewer levels filled it takes a larger move. The per-node exchange stop will therefore rarely be the binding exit. This is allowed by the hypothesis ('mandatory inventory liquidation controls'), but the trailing exit is evaluated only at hourly closes and executes as a market sell. (line 117) — fix: Document which control is intended to bind, or derive cycle_trailing_loss_pct from node_stop_pct x max_exposure. - [warning] Five overlapping bracket OUO sets share one netting spot position, and reduce_only legs on a CASH account aggregate. If one node's stop and another node's target fire in the same bar, per-node qty bookkeeping (from on_order_filled) and the engine's position can diverge. The positions report will also count several level round trips as one trade. (line 152) — fix: After each fill, reconcile the sum of node qty with the cache position quantity, and liquidate or halt on a mismatch.

Iteration History

Verification failed (Layer 1.5 — hypothesis/config consistency) [class=hypothesis_mismatch]: - optimization_plan fixes leverage at 1.0

Verification failed (Layer 1 — static analysis): - Syntax error: invalid decimal literal (<unknown>, line 1) (line 1)

Outcome Summary

Liquidation and cooldown triggers should fire once and reset when they fire, with all cycle state cleared once the drain completes, and a synthetic test should confirm the grid re-arms after the cooldown before a backtest is spent.

After 3 iterations it was abandoned in the verification loop because it failed Layer 4 QA review with a critical code defect. Any liquidation that did not end in profit moved the stop-cooldown halt forward on every hourly bar, so the grid locked itself out permanently and never re-armed.

It adapted an FMZ one-sided recycling grid to LTC on Binance Spot. The grid rests percentage-spaced buy orders below an anchor, gives each filled node its own profit-taking sell, and re-arms a node only after that node's inventory is sold, with mandatory node stops, a cycle trailing loss and holding-time controls.

No full backtest or optimization was run. The only evidence is the QA sandbox: 10 fills, 1 closed position, 4 days with equity changes in 834 days, a reported 24.8% drawdown and a drawdown lasting 829.6 days.

Abandon Reason

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] A 1.8% take-profit on a 0.9% grid clears the 0.20% spot round trip (0.10% maker + 0.10% taker per side), so the fee floor passes. The sandbox recorded only 10 fills and 4 equity-moving days in 834 days, so it cannot measure edge. The reported 24.8% drawdown on a book capped at 20% exposure looks like a cash-only equity artifact; check it in the full backtest. Because levels net into one position, the trade ledger……Show moreShow less

verification_loop: Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] A 1.8% take-profit on a 0.9% grid clears the 0.20% spot round trip (0.10% maker + 0.10% taker per side), so the fee floor passes. The sandbox recorded only 10 fills and 4 equity-moving days in 834 days, so it cannot measure edge. The reported 24.8% drawdown on a book capped at 20% exposure looks like a cash-only equity artifact; check it in the full backtest. Because levels net into one position, the trade ledger undercounts round trips (L133). Compare per-level fills with total_trades before trusting per-trade economics. - [critical] Any liquidation that does not end in a profit permanently locks out the strategy. stop_requested and the cycle bookkeeping (cycle_cash, cycle_peak, cycle_equity) are reset only in _start_cycle(), but _manage() never reaches _start_cycle() while now_ns < halt_until_ns. Once _drain() finishes, it sets liquidating=False, sets anchor=0 and returns, because the halt is still active. On the next bar should_exit() returns True again. After a node stop fill this is because stop_requested is still True. After a trailing-loss exit it is because cycle_peak - (cycle_cash + 0) still exceeds the threshold, since the realized loss is now in cycle_cash. The check runs with liquidating=False, so _manage sets liquidating=True and halt_until_ns = now + cooldown again. The halt moves forward 24h on every hourly bar, never expires, and the grid never re-arms. The orphan-inventory path at line ~228 deadlocks the same way. The sandbox is consistent with this: 10 fills, 1 closed position, only 4 days with equity changes over 834 days, and a drawdown lasting 829.6 days. The hypothesis's 'stop_cooldown_hours pause' becomes a permanent shutdown, so the backtest would measure only the first cycle or few cycles. (line 214) — fix: Make the liquidation trigger edge-triggered and reset state when the drain completes. When _drain() returns True, clear stop_requested and reset cycle_cash, cycle_peak and cycle_equity (or set a 'cycle_closed' flag that should_exit honours). Then start the next cycle only after the original halt_until_ns, and never extend the halt while waiting. One option is to evaluate should_exit() only when anchor > 0 and not liquidating. Add a synthetic test in which a node stop fills and the grid re-arms after stop_cooldown_hours. - [warning] The cycle trailing loss (1.2% of cycle equity) binds long before the 6% node stop. With 20% exposure fully filled, about a 6% average adverse move liquidates the whole book; with fewer levels filled it takes a larger move. The per-node exchange stop will therefore rarely be the binding exit. This is allowed by the hypothesis ('mandatory inventory liquidation controls'), but the trailing exit is evaluated only at hourly closes and executes as a market sell. (line 117) — fix: Document which control is intended to bind, or derive cycle_trailing_loss_pct from node_stop_pct x max_exposure. - [warning] Five overlapping bracket OUO sets share one netting spot position, and reduce_only legs on a CASH account aggregate. If one node's stop and another node's target fire in the same bar, per-node qty bookkeeping (from on_order_filled) and the engine's position can diverge. The positions report will also count several level round trips as one trade. (line 152) — fix: After each fill, reconcile the sum of node qty with the cache position quantity, and liquidate or halt on a mismatch.

Analysis

网格变形策略之单边网格 (注释版)

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