Ir al contenido
← Todos los ejemplos

Ejemplo 50

Sweep fade managed

a managed order-flow trade, written to use what a complex strategy needs: an entry that carries its own stop and target, a part of the

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 bars)
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 window (backtest).
Lenguaje
>=0.1.2, <0.2.0
Host
>=0.1.9, <0.2.0
Necesita
features >=0.1.4, <0.2.0trade >=0.1.0, <0.2.0

Código

// Purpose: a managed order-flow trade, written to use what a complex strategy needs: an entry that carries its own stop and target, a part of the
// position taken off on the way, the stop brought to break-even once it has, a time limit, and a rest between trades.
//
//   SETUP    the bar that just closed went THROUGH the edge of the last `lookback` bars' range and closed back inside it, with the aggressors
//            pushing into the edge (buying into a high that did not hold, selling into a low that did not): a failed break.
//   ENTRY    against the break, at the market. The stop rests `pad` dollars beyond the bar's extreme; the distance from the price to it is the
//            trade's risk, R, remembered from the entry (`at_entry`).
//   MANAGE   at `first_r` R in favour, half of the position is closed and the stop is moved to the entry price;
//            the rest runs to the target, `final_r` R, or is closed after `max_minutes`.
//   REST     no new trade for `rest_minutes` after one closes.
//
// HONEST NOTE ON ITS EDGE: IT HAS NONE THAT WAS FOUND. This setup was studied on the twenty days of BTCUSDT prints recorded on this machine.
// As written here (the 8-hour range, the stop 5 dollars past the bar), over those twenty days it would have taken 251 trades and made +0.5 basis
// points a trade before fees and LOST 10 a trade after them (taker 5 bp and 1 bp of slippage, maker 2 bp): its risk is a few dollars, and a
// round trip costs more than the move it catches. A variant with a wide stop made +13 bp a trade net on the first twelve days and lost 23 on the
// eight kept aside. It is here to show how a managed trade is written, and to be studied and changed -- not to be trusted with money.
// 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)
// 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.9, <0.2.0";
requires "features" ">=0.1.4, <0.2.0";
requires "trade" ">=0.1.0, <0.2.0";

strategy sweep_fade(lookback: Int, pad: Decimal, first_r: Decimal, final_r: Decimal, max_minutes: Decimal, rest_minutes: Decimal, size: Quantity) version "1.0.0" {
    // The last closed bar, and the range of the `lookback` bars before it.
    let px = features.price(features.Source.AggTrades);
    let close = features.bar_close();
    let high = features.bar_high();
    let low = features.bar_low();
    let range_high = features.highest_high(lookback, 1);
    let range_low = features.lowest_low(lookback, 1);
    let delta = features.bar_delta(features.Source.AggTrades);

    // True on the one step where a new bar has closed -- a bar is looked at once.
    let new_bar = close != prev(close);
    let failed_up = high > range_high && close < range_high && delta > 0;
    let failed_down = low < range_low && close > range_low && delta < 0;
    let rested = features.flat_minutes() >= rest_minutes;

    // Where the stop goes, and the risk that makes.
    let short_stop = high + pad;
    let long_stop = low - pad;

    // 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 short_risk = at_entry(short_stop - px);
    let long_risk = at_entry(px - long_stop);
    let whole = features.position_fraction() > 0.75;
    let aged = features.position_minutes() >= max_minutes;

    // Out of time.
    rule long_timed_out when exposure_is(Exposure.Open) && held > 0 && aged
        => order(Side.Sell, Intent.Close, OrderType.Market, Sizing.Fixed(size));
    rule short_timed_out when exposure_is(Exposure.Open) && held < 0 && aged
        => order(Side.Buy, Intent.Close, OrderType.Market, Sizing.Fixed(size));

    // The first target: half off, once.
    rule long_first when exposure_is(Exposure.Open) && held > 0 && whole && px >= entry + first_r * long_risk
        => order(Side.Sell, Intent.Reduce, OrderType.Market, Sizing.PercentOfPosition(percent(50)));
    rule short_first when exposure_is(Exposure.Open) && held < 0 && whole && px <= entry - first_r * short_risk
        => order(Side.Buy, Intent.Reduce, OrderType.Market, Sizing.PercentOfPosition(percent(50)));

    // What is left cannot lose: the stop to the entry price, once.
    rule long_safe when exposure_is(Exposure.Open) && held > 0 && !whole && features.stop_price() < entry
        => protect(Protect.StopLoss(entry));
    rule short_safe when exposure_is(Exposure.Open) && held < 0 && !whole && features.stop_price() > entry
        => protect(Protect.StopLoss(entry));

    // The entries, each with its stop beyond the bar's extreme and its target `final_r` risks away.
    rule fade_high when exposure_is(Exposure.Flat) && new_bar && failed_up && rested
        => order(Side.Sell, Intent.Open, OrderType.Market, Sizing.Fixed(size), Protect.Bracket(px - final_r * (short_stop - px), short_stop));
    rule fade_low when exposure_is(Exposure.Flat) && new_bar && failed_down && rested
        => order(Side.Buy, Intent.Open, OrderType.Market, Sizing.Fixed(size), Protect.Bracket(px + final_r * (px - long_stop), long_stop));
    flatten_on_stop;
}

fn main() -> Result<Unit, Error> {
    // The 8-hour range; the stop 5 dollars past the bar; half off at 1 R; the rest to 3 R or four hours; half an hour between trades.
    let run = trade.run(sweep_fade(480, 5.0, 1.0, 3.0, 240.0, 30.0, qty(0.02)))?;
    print(run.name + " on " + run.target + ": " + run.state);
    return Ok(());
}