Ir al contenido
← Todos los ejemplos

Ejemplo 52

Flow supertrend kalman

a trend strategy on the order-flow Supertrend. It enters when the fifteen-minute Supertrend made of what traded turns

Categoría
Host: necesita los datos y el motor de la terminal
Permisos
orders.submit
Antes de ejecutarlo
a chart in hand on the live market or a replay, whose instrument the live feed serves (aggregated prints and closed
Qué hace
asks the terminal to run the strategy on that market; once running it places orders on the account the person chose.
Cómo ejecutarlo
Add script on the Market Replay window or the title bar's script icon (replay or real time); Insert strategy in the Datasets
Lenguaje
>=0.1.2, <0.2.0
Host
>=0.1.11, <0.2.0
Necesita
features >=0.1.6, <0.2.0trade >=0.1.0, <0.2.0

Código

// 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(());
}