← All examples
Example 52
Flow supertrend kalman
a trend strategy on the order-flow Supertrend. It enters when the fifteen-minute Supertrend made of what traded turns
- Category
- Host: needs the terminal's data and engine
- Permissions
- orders.submit
- Before you run it
- a chart in hand on the live market or a replay, whose instrument the live feed serves (aggregated prints and closed
- What it does
- asks the terminal to run the strategy on that market; once running it places orders on the account the person chose.
- How to run it
- Add script on the Market Replay window or the title bar's script icon (replay or real time); Insert strategy in the Datasets
- Language
>=0.1.2, <0.2.0- Host
>=0.1.11, <0.2.0- Needs
- features >=0.1.6, <0.2.0trade >=0.1.0, <0.2.0
Source
// Purpose: a trend strategy on the order-flow Supertrend. It enters when the fifteen-minute Supertrend made of what traded turns // (`flow_supertrend_side`: hung from each bar's VWAP, as wide as the core of its volume, turning only with the aggressors behind the // close), and only in the direction of a Kalman trend on the hour -- and only when the market is calm enough that the stop beyond // the last swing is not a wide one. The target is `reward` times the risk (1:2 to 1:3), and once the trade is a risk in favour its // stop trails `trail_atr` fifteen-minute ranges behind the last closed minute. // // SETUP the 15-minute flow Supertrend turns: up for a long, down for a short. // FILTER the 60-minute Kalman trend slopes the same way (`kalman_slope`); // the 15-minute range is not among the widest it has been (`volatility_rank` <= `max_rank`, 0 the calmest of the last // `vol_lookback` bars, 100 the wildest); // the stop is not wide: at most `max_risk_atr` 15-minute ranges from the price. // STOP past the last confirmed 15-minute swing low (for a long; high for a short), `pad_atr` ranges beyond it. // TARGET `reward` times the risk, set with the stop as one bracket. // TRAIL from 1 R in favour, on each closed minute, the stop moves to `trail_atr` ranges behind the close -- never back. // EXIT also when the Supertrend turns against the trade. // // HONEST NOTE: written to the specification and checked that it compiles and hands over a strategy; its edge has not been measured. // Backtest it on the Datasets window over several months, with fees, and on a stretch it was not tuned on, before trusting it. // Category: host // Permissions: orders.submit // Preconditions: a chart in hand on the live market or a replay, whose instrument the live feed serves (aggregated prints and closed // bars); or a dataset holding aggTrades and 1-minute klines (Datasets window). // Side effects: asks the terminal to run the strategy on that market; once running it places orders on the account the person chose. // Run: Add script on the Market Replay window or the title bar's script icon (replay or real time); Insert strategy in the Datasets // window (backtest). lang ">=0.1.2, <0.2.0"; host "ttt" ">=0.1.11, <0.2.0"; requires "features" ">=0.1.6, <0.2.0"; requires "trade" ">=0.1.0, <0.2.0"; strategy flow_supertrend_kalman( st_minutes: Int, st_period: Int, st_factor: Decimal, trend_minutes: Int, smoothness: Int, atr_period: Int, vol_lookback: Int, max_rank: Decimal, max_risk_atr: Decimal, swing_strength: Int, pad_atr: Decimal, reward: Decimal, trail_atr: Decimal, size: Quantity ) version "1.0.0" { let px = features.price(features.Source.AggTrades); // True on the one step where a minute has closed: the trail moves once a minute, not on every print. let close = features.bar_close(); let new_bar = close != prev(close); // The setup: the flow Supertrend on the lower timeframe turns. Its side changes when a 15-minute bar closes, so a turn is true // for one step. let side = features.flow_supertrend_side(st_minutes, st_period, st_factor); let turned_up = side > 0 && prev(side) < 0; let turned_down = side < 0 && prev(side) > 0; // The trend it has to agree with: a Kalman trend of the closes on the higher timeframe. let slope = features.kalman_slope(trend_minutes, smoothness); // How wide the market is: the 15-minute range, and where it sits among its recent values. let atr = features.atr(st_minutes, atr_period); let rank = features.volatility_rank(st_minutes, atr_period, vol_lookback); // The stops: past the last confirmed swing, a pad of the range beyond it -- and the risk each makes. let long_stop = features.swing_low(st_minutes, swing_strength) - pad_atr * atr; let short_stop = features.swing_high(st_minutes, swing_strength) + pad_atr * atr; let long_risk = px - long_stop; let short_risk = short_stop - px; // Calm enough, and a stop that is not a wide one. let calm = rank <= max_rank; let long_fits = calm && long_risk > 0 && long_risk <= max_risk_atr * atr; let short_fits = calm && short_risk > 0 && short_risk <= max_risk_atr * atr; // The open trade: its side, its price, and the risk it was taken with -- held from the entry, so that it is still the same // after the stop that defined it has been moved. let held = features.position_sign(); let entry = features.entry_price(); let risk_long = at_entry(long_risk); let risk_short = at_entry(short_risk); let long_trail = close - trail_atr * atr; let short_trail = close + trail_atr * atr; // The trail: from one risk in favour, the stop follows the close, never back. rule trail_long when exposure_is(Exposure.Open) && held > 0 && new_bar && px >= entry + risk_long && long_trail > features.stop_price() => protect(Protect.StopLoss(long_trail)); rule trail_short when exposure_is(Exposure.Open) && held < 0 && new_bar && px <= entry - risk_short && short_trail < features.stop_price() => protect(Protect.StopLoss(short_trail)); // The trend turned against the trade: out. rule long_out when exposure_is(Exposure.Open) && held > 0 && turned_down => order(Side.Sell, Intent.Close, OrderType.Market, Sizing.Fixed(size)); rule short_out when exposure_is(Exposure.Open) && held < 0 && turned_up => order(Side.Buy, Intent.Close, OrderType.Market, Sizing.Fixed(size)); // The entries: a turn with the trend, in a market calm enough, the stop past the swing, the target `reward` risks away. rule go_long when exposure_is(Exposure.Flat) && turned_up && slope > 0 && long_fits => order(Side.Buy, Intent.Open, OrderType.Market, Sizing.Fixed(size), Protect.Bracket(px + reward * long_risk, long_stop)); rule go_short when exposure_is(Exposure.Flat) && turned_down && slope < 0 && short_fits => order(Side.Sell, Intent.Open, OrderType.Market, Sizing.Fixed(size), Protect.Bracket(px - reward * short_risk, short_stop)); flatten_on_stop; } fn main() -> Result<Unit, Error> { // The 15-minute flow Supertrend (10 bars, 3 ranges); the hour's Kalman trend (smoothness 10); 14-bar ranges ranked over the last // day (96 bars), trading only under the 80th percentile, with a stop no wider than 2.5 ranges; swings of 3 bars a side, the stop // a fifth of a range past it; the target 2.5 risks away (between 1:2 and 1:3); the trail 2 ranges behind once 1 R in favour. let run = trade.run(flow_supertrend_kalman(15, 10, 3.0, 60, 10, 14, 96, 80.0, 2.5, 3, 0.2, 2.5, 2.0, qty(0.01)))?; print(run.name + " on " + run.target + ": " + run.state); return Ok(()); }