Skip to content
All strategies

Strategies

Freqtrade 'Supertrend' by @juankysoriano (Juan Carlos Soriano), faithful port: triple-Supertrend long-only entry/exit with stepped ROI table, -26.5% trailing stoploss, on LINKUSDT.BINANCE_SPOT 1h

Outcome: Abandoned

FreqtradeSupertrendLinkSpot

Outcome Summary

This run ported the hyperopted Freqtrade 'Supertrend' strategy line for line to LINK spot on 1h bars, using six incremental Supertrend state machines plus the original ROI, stop and trailing exits. It took 894 trades from 2019 to 2026 and lost about 0.24% per trade after fees, roughly -0.04% before them, so fees were not the root cause. At backtest review, after 2 iterations, the analyst abandoned it for negative expectancy, an inverted payoff (capped wins against losses running to the deep stop) and no forecasting information in the signal; it never reached optimization. The rejection applies only to this LINK spot port, not to the original on its hyperopted pairs. A separate, unverified concern about impact-cost accounting behind the -100%/liquidation headline was passed to the operator for a ledger review.

Hypothesis

Faithful line-for-line translation of the Freqtrade open-source strategy 'Supertrend' (https://github.com/freqtrade/freqtrade-strategies/blob/f3340ce11f5bdf62f598522e64d1f5638eaa13f5/user_data/strategies/Supertrend.py, GPL-3.0, author @juankysoriano / Juan Carlos Soriano, who gets the credit). The original runs on 1h candles and goes long only. It enters when three 'buy' Supertrend indicators all read 'up' and leaves when three separate 'sell' Supertrend indicators all read 'down'. Exits also come from a stepped……Show moreShow less

Faithful line-for-line translation of the Freqtrade open-source strategy 'Supertrend' (https://github.com/freqtrade/freqtrade-strategies/blob/f3340ce11f5bdf62f598522e64d1f5638eaa13f5/user_data/strategies/Supertrend.py, GPL-3.0, author @juankysoriano / Juan Carlos Soriano, who gets the credit). The original runs on 1h candles and goes long only. It enters when three 'buy' Supertrend indicators all read 'up' and leaves when three separate 'sell' Supertrend indicators all read 'down'. Exits also come from a stepped minimal-ROI table, a -26.5% stoploss and the trailing-stop settings. The parameter values are the hyperopted defaults in buy_params/sell_params. These override the IntParameter defaults (4/14): buy (multiplier, period) = (4,8), (7,9), (1,8); sell (multiplier, period) = (1,16), (3,18), (6,18). VENUE CHOICE: the original is a long-only, unlevered Freqtrade strategy, i.e. spot. Platform routing therefore puts it on BINANCE_SPOT (CASH, 0.10% taker per side, ~0.20% RT). The instrument is LINKUSDT.BINANCE_SPOT 1-HOUR (catalog has bars from 2019-01-16 to 2026-10-01, ~67k bars). We chose LINK instead of BTC because BTC is ~44-62% of the corpus and LINK spot has no recorded use. LINK is also volatile enough that the 8.7% / 5.8% / 2.9% ROI targets are reachable within the ROI time windows. SUPERTREND DEFINITION (technical.indicators.supertrend, per freqtrade-strategies issue #30 comment 853042401), computed per (multiplier m, period p): TR = TA-Lib TRANGE (max(high-low, |high-prev_close|, |low-prev_close|)); ATR = simple moving average of TR over p bars (SMA, NOT Wilder smoothing); basic_ub = (high+low)/2 + m*ATR; basic_lb = (high+low)/2 - m*ATR. final_ub and final_lb start at 0.0. For i >= p: final_ub[i] = basic_ub[i] if (basic_ub[i] < final_ub[i-1] or close[i-1] > final_ub[i-1]) else final_ub[i-1]; final_lb[i] = basic_lb[i] if (basic_lb[i] > final_lb[i-1] or close[i-1] < final_lb[i-1]) else final_lb[i-1]. ST starts at 0.0. For i >= p: if ST[i-1]==final_ub[i-1] and close[i] <= final_ub[i] then ST=final_ub[i]; elif ST[i-1]==final_ub[i-1] and close[i] > final_ub[i] then ST=final_lb[i]; elif ST[i-1]==final_lb[i-1] and close[i] >= final_lb[i] then ST=final_lb[i]; elif ST[i-1]==final_lb[i-1] and close[i] < final_lb[i] then ST=final_ub[i]; else 0.0. Direction STX = 'down' if ST>0 and close<ST; 'up' if ST>0 and close>=ST; empty/undefined (neither up nor down) if ST<=0 or not yet warmed up. IMPLEMENTATION NOTE: the original computes all 630 hyperopt-range combinations in populate_indicators. That is only for the hyperopt search. The developer must compute ONLY the 6 used Supertrends, each as an O(1) incremental state machine (rolling TR deque for the SMA plus prev final_ub/final_lb/ST/close). Do NOT recompute over history each bar: recent sandbox_timeout deaths came from exactly that. Equality tests ST[i-1]==final_ub[i-1] should compare against the stored previous value (same float object semantics, i.e. track which band ST is on with a state flag equivalent to the equality). CAVEAT: the source does `_, stx = ftt.supertrend(...)` and its docstring says the call returns a (value, direction) tuple. If the installed `technical` version returns a DataFrame instead, the unpacking would yield column names. We translate the documented intent (the direction series), not that possible library mismatch. Performance claims of the original (hyperopted with ShortTradeDurHyperOptLoss on 2021+ data) are treated as unverified; our fee-inclusive backtest decides.

The user requested a faithful port, so all rules and the hyperopted defaults are kept exactly and no parameter is tunable: the author already hyperopted them. Venue: the strategy is long-only and unlevered, so routing puts it on BINANCE_SPOT (spot is under its 15% quota). Instrument: LINK instead of BTC to diversify the corpus. LINK has data back to 2019 and the volatility the 8.7% ROI step assumes. Holding period runs from a few hours to ~1.5 days (mid_term). The -26.5% stop at 95% stake means a full stop-out costs ~25% of equity, so the 40% drawdown floor is honest, not flattering.

negative_expectancy (fee-floor check: -0.24% vs the 0.25% spot floor; the gross figure of about -0.04% shows fees are not the cause). This rejects the faithful 1h LINKUSDT.BINANCE_SPOT port of @juankysoriano's Freqtrade 'Supertrend', with hyperopted buy (4,8)/(7,9)/(1,8), sell (1,16)/(3,18)/(6,18), ROI ladder, -26.5% stop and trailing settings. It does not reject the author's strategy on the 2021+ pairs it was hyperopted on, or Supertrend generally. Evidence: 894 closed trades, a reliable sample. Mean net trade……Show moreShow less

negative_expectancy (fee-floor check: -0.24% vs the 0.25% spot floor; the gross figure of about -0.04% shows fees are not the cause). This rejects the faithful 1h LINKUSDT.BINANCE_SPOT port of @juankysoriano's Freqtrade 'Supertrend', with hyperopted buy (4,8)/(7,9)/(1,8), sell (1,16)/(3,18)/(6,18), ROI ladder, -26.5% stop and trailing settings. It does not reject the author's strategy on the 2021+ pairs it was hyperopted on, or Supertrend generally. Evidence: 894 closed trades, a reliable sample. Mean net trade return is -0.24% and about -0.04% before commission. Gross PF excluding commission is 0.92 and net PF is 0.85. Mean trade return was negative in 7 of 8 years; only 2020 was positive. Executed-signal IC is -0.036 (t=-1.5). The payoff is inverted: wins average +3.7% because the ROI ladder caps them, while losses average -6.4% and run to the -26.5% stop. QA's concern is borne out. Optimization cannot help because the contract freezes every parameter (tunable is empty). Separate operator note: the -100% / liquidation and the impact_cost_pct of 6654% (capacity $22.58) look exaggerated. Impact appears to be folded into equity while sizing compounds on engine equity; this is unverified and needs a ledger review. The per-trade price returns already exclude impact and are negative, so the verdict does not depend on it.

Implementation

Faithful Stratmill port of @juankysoriano's Freqtrade 'Supertrend' (GPL-3.0): long-only LINK spot 1h. Enters when 3 buy Supertrends (4,8),(7,9),(1,8) all read 'up' with volume>0; exits on 3 sell Supertrends (1,16),(3,18),(6,18) all 'down' (and not entry), stepped fee-net minimal ROI {0:8.7%,372:5.8%,861:2.9%,2221:0%}, -26.5% stoploss with trailing 5% once profit > 14.4%. 95% stake, startup 199 candles.

Iteration 2 fixes the Layer-3 sandbox_timeout. Profiling showed the strategy is already O(1) per bar: the identical sandbox window (833 days, ~20k 1h bars, ending at the final-exam boundary 2026-08-21) ran locally in 155s through the same subprocess runner with host load average ~67. So the 300s overrun was host contention, not history-scaling work. The per-bar hot path is still leaner now: the six Supertrend state machines update from one pre-built tuple, and the entry, exit and score aggregation are inlined instead of using generator all()/min(). Rerun: 121s with byte-identical trading (248 trades, same per-trade return), so no rule changed. Translation semantics are unchanged from iteration 1. Platform adaptation: ROI, stop and trailing exits are evaluated at the 1h bar close and filled at market, not intra-candle. Honest note: the smoke window shows avg_trade_return_pct of -0.47% on 248 trades; the full backtest decides.

Verification Results

Keep as the faithful port. If the analyst iterates, consider a per-trade risk cap (stake fraction derived from stop distance) and limit/maker entries to cut impact.

Sizing commits 95% of equity per trade, faithful to Freqtrade's stake-all default. The -26.5% trailing stop therefore puts up to about 25% of equity at risk on a single trade, and modeled impact on a ~$95k LINK spot market order (~0.13%/fill) is larger than the 0.10% commission. Worst-case gross is ≤ 0.95x equity on a CASH account (leverage 1.0, with no short path), so the order is fillable. This is a risk/capacity concern, not a bug.

Optional: place a reduce-only stop-market order at _stop_rate and update it as the trail ratchets, so the stated stop is honored intra-bar.

ROI, the -26.5% stop and trailing exits are checked against the 1h bar CLOSE and filled at market. Freqtrade backtesting fills them intra-candle at the ROI or stop rate. The trailing high is correctly taken from bar highs, but a breach inside the candle is only acted on at the close. The developer documents this as a platform adaptation; on 1h bars the slippage against the stated stop is usually small, but it can be large in fast moves.

Make sure the paper warmup covers at least startup_candle_count (199) bars so the band state machines converge before trading.

Per-trade stop state (_trade_open_ts, _open_rate, _max_rate, _stop_rate) is scalar and is restored by persistable_state. The six _SupertrendState objects are not persisted; they are rebuilt during warmup replay via calculate_signal. Supertrend band state is path-dependent, so after a live restart a short warmup may make the bands differ from a continuous backtest for a while. This matters for live trading only.

The smoke test ran 252 closed long trades on LINK spot 1h and averaged -0.41% per trade (PF 0.80, win rate 63%, Sharpe -1.57). Before costs the result is about zero: summed PnL is about -$113k, against $48k commission and $64k folded impact. Impact therefore exceeds commission, at roughly 0.13% per fill on a 95%-of-equity stake. The 0% ROI step at 2221 minutes, together with ROI and stop exits taken at bar close rather than intra-candle, cuts winners at about breakeven fee-net, while losers run to the trailing -26.5% stop (avg loss $6.2k vs avg win $2.9k). The -100% / 'liquidated' figure and avg_position_pct of 407% are probably artifacts of folding impact into equity. The engine's CASH account cannot go below zero, and sizing reads engine equity, not impact-reduced equity. Check first in the full backtest: the gross (pre-cost) PF, impact as a share of gross, and whether the 2221-minute 0% ROI step leaves any positive per-trade edge above the spot 0.25% floor.

Backtest Review

Sharpe
0.39
Total return
-100.00%
Max drawdown
100.00%
Trades
894
Win rate
61.3%
Profit factor
0.85

Implementation matches the hypothesis: long-only and 894 entries, all fully executed. The incremental Supertrend state machines, stepped ROI, trailing stop and startup gate all follow the spec.

Reliable sample of 894 closed trades from 2019-01 to 2026-08, with clean input data (reviewed exchange outages only).

Mean per-trade pnl_pct is -0.24% net of commission, against the 0.25% BINANCE_SPOT floor. Before commission it is about -0.04%, so the gross edge is about zero to negative and fees are not the root cause. The price-only gross PF, excluding commission, is 0.92. The reported net PF is 0.85.

Negative in 7 of 8 calendar years when measured by mean trade pnl_pct: 2019 -0.52, 2020 +1.25, 2021 -0.08, 2022 -1.23, 2023 -0.14, 2024 -0.15, 2025 -0.83, 2026 -1.04. Only the 2020 LINK bull run was positive.

Payoff is structurally inverted. The win rate is 61%, but the average win is +3.7% and the average loss is -6.4%. The ROI ladder caps winners (8.7%, then 5.8%, then 2.9%, then 0% after 37h). Losers run to the -26.5% stop: the five worst trades were -20% to -26%.

Executed-signal IC is -0.036 (t=-1.5) over 1,792 observations: no forecasting information.

Alpha against LINK buy-and-hold is -116%/yr (IR -0.64) at beta 1.09.

Headline -100% / liquidated 2021-12-10 and impact_cost_pct 6654% (capacity $22.58) are inflated. Impact is folded into equity while sizing compounds on engine equity: $1.27M of impact against $604k of commission. I did not independently verify the mechanism. The per-trade price returns above do not include impact and are still negative, so the verdict does not depend on it.

Iteration History

sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (833 days of LINKUSDT.BINANCE_SPOT-1-HOUR-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 ROI ladder that caps winners (average +3.7%) while a wide -26.5% stop lets losers run (average -6.4%) inverts the payoff, so a 61% win rate can still lose money; check the win/loss asymmetry before porting hyperopted exit settings to a new pair and period.

The backtest-review analyst voted abandon for negative expectancy: -0.24% per trade against the 0.25% spot floor, with a gross edge of about zero, mean trade return negative in 7 of 8 years, and executed-signal IC of -0.036 (t=-1.5). Optimization could not help because every parameter was frozen, so the optimization, analyst, risk and promotion stages never ran.

A faithful port of @juankysoriano's Freqtrade 'Supertrend' strategy on LINKUSDT.BINANCE_SPOT 1h: go long only when three buy Supertrends all read 'up', exit when three sell Supertrends all read 'down', and also exit via a stepped ROI ladder (8.7%/5.8%/2.9%/0%), a -26.5% stoploss and trailing-stop settings.

Over 894 closed long trades (2019-01 to 2026-08), the mean net trade return was -0.24% (about -0.04% before commission), net profit factor 0.85 (gross ex-commission 0.92), win rate 61%, and arithmetic Sharpe 0.39; the headline total return was -100% with liquidation on 2021-12-10, a figure the analyst flagged as likely inflated by impact accounting.

Analysis

Supertrend

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