Стратегия ICT Bread and Butter Sell-Setup
Стратегия отслеживает максимумы и минимумы сессий Лондона, Нью-Йорка и Азии и торгует заранее определённые сетапы.
Детали
- Условия входа:
- NY Short: цена делает новый максимум выше лондонского и свеча закрывается медвежьей в сессии NY.
- London Close Buy: между 10:30 и 13:00 цена закрывается ниже минимума Лондона.
- Asia Short: во время азиатской сессии цена закрывается выше азиатского максимума.
- Long/Short: обе стороны.
- Условия выхода:
- Для каждой сделки используются стоп-лосс и тейк-профит в тиках.
- Стопы: Да.
- Значения по умолчанию:
ShortStopTicks= 10ShortTakeTicks= 20BuyStopTicks= 10BuyTakeTicks= 20AsiaStopTicks= 10AsiaTakeTicks= 15CandleType= TimeSpan.FromMinutes(1).TimeFrame().
- Фильтры:
- Категория: Price action
- Направление: Обе
- Индикаторы: Price action
- Стопы: Да
- Сложность: Базовая
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ICT Bread and Butter Sell-Setup strategy.
/// Tracks the London (02:00-08:20 UTC), New York (08:20-16:00 UTC) and Asia (19:00-02:00 UTC) session ranges.
/// NY short: during the NY session a bearish candle whose high exceeds the London session high.
/// London close buy: between 10:30 and 13:00 a close below the London session low.
/// Asia short: during the Asia session a close above the Asia session high so far.
/// Every setup has its own stop loss and take profit in ticks; an opposite setup reverses the position.
/// </summary>
public class IctBreadAndButterSellSetupStrategy : Strategy
{
private static readonly TimeSpan _londonStart = new(2, 0, 0);
private static readonly TimeSpan _nyStart = new(8, 20, 0);
private static readonly TimeSpan _nyEnd = new(16, 0, 0);
private static readonly TimeSpan _asiaStart = new(19, 0, 0);
private static readonly TimeSpan _londonCloseStart = new(10, 30, 0);
private static readonly TimeSpan _londonCloseEnd = new(13, 0, 0);
private readonly StrategyParam<int> _shortStopTicks;
private readonly StrategyParam<int> _shortTakeTicks;
private readonly StrategyParam<int> _buyStopTicks;
private readonly StrategyParam<int> _buyTakeTicks;
private readonly StrategyParam<int> _asiaStopTicks;
private readonly StrategyParam<int> _asiaTakeTicks;
private readonly StrategyParam<DataType> _candleType;
private decimal? _londonHigh;
private decimal? _londonLow;
private decimal? _asiaHigh;
private bool _inLondon;
private bool _inAsia;
private decimal? _stopPrice;
private decimal? _takePrice;
/// <summary>
/// Stop loss ticks for NY short entry.
/// </summary>
public int ShortStopTicks
{
get => _shortStopTicks.Value;
set => _shortStopTicks.Value = value;
}
/// <summary>
/// Take profit ticks for NY short entry.
/// </summary>
public int ShortTakeTicks
{
get => _shortTakeTicks.Value;
set => _shortTakeTicks.Value = value;
}
/// <summary>
/// Stop loss ticks for London close buy.
/// </summary>
public int BuyStopTicks
{
get => _buyStopTicks.Value;
set => _buyStopTicks.Value = value;
}
/// <summary>
/// Take profit ticks for London close buy.
/// </summary>
public int BuyTakeTicks
{
get => _buyTakeTicks.Value;
set => _buyTakeTicks.Value = value;
}
/// <summary>
/// Stop loss ticks for Asia sell entry.
/// </summary>
public int AsiaStopTicks
{
get => _asiaStopTicks.Value;
set => _asiaStopTicks.Value = value;
}
/// <summary>
/// Take profit ticks for Asia sell entry.
/// </summary>
public int AsiaTakeTicks
{
get => _asiaTakeTicks.Value;
set => _asiaTakeTicks.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IctBreadAndButterSellSetupStrategy()
{
_shortStopTicks = Param(nameof(ShortStopTicks), 10)
.SetNotNegative()
.SetDisplay("Short Stop Ticks", "Stop loss ticks for NY short entry", "Risk Management");
_shortTakeTicks = Param(nameof(ShortTakeTicks), 20)
.SetNotNegative()
.SetDisplay("Short Take Profit Ticks", "Take profit ticks for NY short entry", "Risk Management");
_buyStopTicks = Param(nameof(BuyStopTicks), 10)
.SetNotNegative()
.SetDisplay("Buy Stop Ticks", "Stop loss ticks for London close buy", "Risk Management");
_buyTakeTicks = Param(nameof(BuyTakeTicks), 20)
.SetNotNegative()
.SetDisplay("Buy Take Profit Ticks", "Take profit ticks for London close buy", "Risk Management");
_asiaStopTicks = Param(nameof(AsiaStopTicks), 10)
.SetNotNegative()
.SetDisplay("Asia Stop Ticks", "Stop loss ticks for Asia sell entry", "Risk Management");
_asiaTakeTicks = Param(nameof(AsiaTakeTicks), 15)
.SetNotNegative()
.SetDisplay("Asia Take Profit Ticks", "Take profit ticks for Asia sell entry", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_londonHigh = null;
_londonLow = null;
_asiaHigh = null;
_inLondon = false;
_inAsia = false;
_stopPrice = null;
_takePrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var tod = candle.OpenTime.TimeOfDay;
var high = candle.HighPrice;
var low = candle.LowPrice;
var close = candle.ClosePrice;
var inLondon = tod >= _londonStart && tod < _nyStart;
var inNy = tod >= _nyStart && tod < _nyEnd;
var inAsia = tod >= _asiaStart || tod < _londonStart;
if (inLondon)
{
if (!_inLondon)
{
_londonHigh = high;
_londonLow = low;
}
else
{
_londonHigh = Math.Max(_londonHigh ?? high, high);
_londonLow = Math.Min(_londonLow ?? low, low);
}
}
_inLondon = inLondon;
// The Asia breakout is measured against the range before this candle.
var prevAsiaHigh = _inAsia && inAsia ? _asiaHigh : null;
if (inAsia)
_asiaHigh = prevAsiaHigh is decimal h ? Math.Max(h, high) : high;
_inAsia = inAsia;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (CheckExits(high, low))
return;
var step = Security?.PriceStep ?? 1m;
if (step <= 0)
step = 1m;
var nyShort = inNy && _londonHigh is decimal lh && high > lh && close < candle.OpenPrice;
var londonCloseBuy = tod >= _londonCloseStart && tod <= _londonCloseEnd && _londonLow is decimal ll && close < ll;
var asiaShort = inAsia && prevAsiaHigh is decimal ah && close > ah;
if (nyShort && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
SetLevels(close, false, ShortStopTicks * step, ShortTakeTicks * step);
}
else if (londonCloseBuy && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
SetLevels(close, true, BuyStopTicks * step, BuyTakeTicks * step);
}
else if (asiaShort && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
SetLevels(close, false, AsiaStopTicks * step, AsiaTakeTicks * step);
}
}
private void SetLevels(decimal entry, bool isLong, decimal stop, decimal take)
{
_stopPrice = stop > 0 ? (isLong ? entry - stop : entry + stop) : null;
_takePrice = take > 0 ? (isLong ? entry + take : entry - take) : null;
}
private bool CheckExits(decimal high, decimal low)
{
if (Position > 0)
{
if ((_stopPrice is decimal sl && low <= sl) || (_takePrice is decimal tp && high >= tp))
{
SellMarket(Position);
_stopPrice = null;
_takePrice = null;
return true;
}
}
else if (Position < 0)
{
if ((_stopPrice is decimal sl && high >= sl) || (_takePrice is decimal tp && low <= tp))
{
BuyMarket(-Position);
_stopPrice = null;
_takePrice = null;
return true;
}
}
return false;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
LONDON_START = TimeSpan(2, 0, 0)
NY_START = TimeSpan(8, 20, 0)
NY_END = TimeSpan(16, 0, 0)
ASIA_START = TimeSpan(19, 0, 0)
LONDON_CLOSE_START = TimeSpan(10, 30, 0)
LONDON_CLOSE_END = TimeSpan(13, 0, 0)
class ict_bread_and_butter_sell_setup_strategy(Strategy):
"""
ICT Bread and Butter Sell-Setup strategy.
Tracks the London (02:00-08:20 UTC), New York (08:20-16:00 UTC) and Asia (19:00-02:00 UTC) session ranges.
NY short: during the NY session a bearish candle whose high exceeds the London session high.
London close buy: between 10:30 and 13:00 a close below the London session low.
Asia short: during the Asia session a close above the Asia session high so far.
Every setup has its own stop loss and take profit in ticks; an opposite setup reverses the position.
"""
def __init__(self):
super(ict_bread_and_butter_sell_setup_strategy, self).__init__()
self._short_stop_ticks = self.Param("ShortStopTicks", 10).SetNotNegative().SetDisplay("Short Stop Ticks", "Stop loss ticks for NY short entry", "Risk Management")
self._short_take_ticks = self.Param("ShortTakeTicks", 20).SetNotNegative().SetDisplay("Short Take Profit Ticks", "Take profit ticks for NY short entry", "Risk Management")
self._buy_stop_ticks = self.Param("BuyStopTicks", 10).SetNotNegative().SetDisplay("Buy Stop Ticks", "Stop loss ticks for London close buy", "Risk Management")
self._buy_take_ticks = self.Param("BuyTakeTicks", 20).SetNotNegative().SetDisplay("Buy Take Profit Ticks", "Take profit ticks for London close buy", "Risk Management")
self._asia_stop_ticks = self.Param("AsiaStopTicks", 10).SetNotNegative().SetDisplay("Asia Stop Ticks", "Stop loss ticks for Asia sell entry", "Risk Management")
self._asia_take_ticks = self.Param("AsiaTakeTicks", 15).SetNotNegative().SetDisplay("Asia Take Profit Ticks", "Take profit ticks for Asia sell entry", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._london_high = None
self._london_low = None
self._asia_high = None
self._in_london = False
self._in_asia = False
self._stop_price = None
self._take_price = None
def OnReseted(self):
super(ict_bread_and_butter_sell_setup_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(ict_bread_and_butter_sell_setup_strategy, self).OnStarted2(time)
self._reset_state()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
tod = candle.OpenTime.TimeOfDay
high = candle.HighPrice
low = candle.LowPrice
close = candle.ClosePrice
in_london = tod >= LONDON_START and tod < NY_START
in_ny = tod >= NY_START and tod < NY_END
in_asia = tod >= ASIA_START or tod < LONDON_START
if in_london:
if not self._in_london or self._london_high is None:
self._london_high = high
self._london_low = low
else:
self._london_high = max(self._london_high, high)
self._london_low = min(self._london_low, low)
self._in_london = in_london
# The Asia breakout is measured against the range before this candle.
prev_asia_high = self._asia_high if self._in_asia and in_asia else None
if in_asia:
self._asia_high = high if prev_asia_high is None else max(prev_asia_high, high)
self._in_asia = in_asia
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._check_exits(high, low):
return
step = self.Security.PriceStep if self.Security is not None and self.Security.PriceStep is not None else Decimal(1)
if step <= 0:
step = Decimal(1)
ny_short = in_ny and self._london_high is not None and high > self._london_high and close < candle.OpenPrice
london_close_buy = tod >= LONDON_CLOSE_START and tod <= LONDON_CLOSE_END and self._london_low is not None and close < self._london_low
asia_short = in_asia and prev_asia_high is not None and close > prev_asia_high
if ny_short and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._set_levels(close, False, self._short_stop_ticks.Value * step, self._short_take_ticks.Value * step)
elif london_close_buy and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._set_levels(close, True, self._buy_stop_ticks.Value * step, self._buy_take_ticks.Value * step)
elif asia_short and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._set_levels(close, False, self._asia_stop_ticks.Value * step, self._asia_take_ticks.Value * step)
def _set_levels(self, entry, is_long, stop, take):
if stop > 0:
self._stop_price = entry - stop if is_long else entry + stop
else:
self._stop_price = None
if take > 0:
self._take_price = entry + take if is_long else entry - take
else:
self._take_price = None
def _check_exits(self, high, low):
if self.Position > 0:
if (self._stop_price is not None and low <= self._stop_price) or (self._take_price is not None and high >= self._take_price):
self.SellMarket(self.Position)
self._stop_price = None
self._take_price = None
return True
elif self.Position < 0:
if (self._stop_price is not None and high >= self._stop_price) or (self._take_price is not None and low <= self._take_price):
self.BuyMarket(-self.Position)
self._stop_price = None
self._take_price = None
return True
return False
def CreateClone(self):
return ict_bread_and_butter_sell_setup_strategy()