Стратегия "IU Bigger Than Range"
Стратегия пробоя, открывающая сделки, когда тело свечи больше предыдущего диапазона за заданный период.
Система сравнивает тело текущей свечи с диапазоном между максимальными и минимальными значениями цены открытия/закрытия за период. При превышении диапазона открывается сделка в направлении свечи, стопы задаются выбранным методом.
Детали
- Условия входа: тело свечи больше предыдущего диапазона; направление по телу свечи.
- Лонг/Шорт: оба направления.
- Условия выхода: достижение стоп-лосса или тейк-профита.
- Стопы: предыдущая свеча, ATR или уровни свинга.
- Значения по умолчанию:
LookbackPeriod= 22RiskToReward= 3StopLossMethod= PreviousHighLowAtrLength= 14AtrFactor= 2mSwingLength= 10CandleType= TimeSpan.FromMinutes(1)
- Фильтры:
- Категория: Пробой
- Направление: Оба
- Индикаторы: Highest, Lowest, ATR
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Любой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Breakout strategy that enters when the candle body exceeds the previous range.
/// </summary>
public class IuBiggerThanRangeStrategy : Strategy
{
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<int> _riskToReward;
private readonly StrategyParam<decimal> _atrFactor;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRangeSize;
private decimal _prevCandleHigh;
private decimal _prevCandleLow;
private decimal _stopPrice;
private decimal _targetPrice;
private decimal _entryPrice;
private int _barCount;
/// <summary>
/// Lookback period for range calculation.
/// </summary>
public int LookbackPeriod
{
get => _lookbackPeriod.Value;
set => _lookbackPeriod.Value = value;
}
/// <summary>
/// Risk to reward ratio.
/// </summary>
public int RiskToReward
{
get => _riskToReward.Value;
set => _riskToReward.Value = value;
}
/// <summary>
/// ATR multiplier factor.
/// </summary>
public decimal AtrFactor
{
get => _atrFactor.Value;
set => _atrFactor.Value = value;
}
/// <summary>
/// Type of candles to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="IuBiggerThanRangeStrategy"/> class.
/// </summary>
public IuBiggerThanRangeStrategy()
{
_lookbackPeriod = Param(nameof(LookbackPeriod), 22)
.SetDisplay("Lookback Period", "Length for range calculation.", "Parameters");
_riskToReward = Param(nameof(RiskToReward), 3)
.SetDisplay("Risk To Reward", "Risk to reward ratio.", "Parameters");
_atrFactor = Param(nameof(AtrFactor), 2m)
.SetDisplay("ATR Factor", "ATR multiplier.", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
.SetDisplay("Candle Type", "Type of candles.", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRangeSize = 0m;
_prevCandleHigh = 0m;
_prevCandleLow = 0m;
_stopPrice = 0m;
_targetPrice = 0m;
_entryPrice = 0m;
_barCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRangeSize = 0m;
_prevCandleHigh = 0m;
_prevCandleLow = 0m;
_stopPrice = 0m;
_targetPrice = 0m;
_entryPrice = 0m;
_barCount = 0;
var atr = new AverageTrueRange { Length = LookbackPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
_barCount++;
var rangeSize = candle.HighPrice - candle.LowPrice;
var candleBody = Math.Abs(candle.ClosePrice - candle.OpenPrice);
if (_barCount < LookbackPeriod)
{
_prevRangeSize = rangeSize;
_prevCandleHigh = candle.HighPrice;
_prevCandleLow = candle.LowPrice;
return;
}
// Exit logic first
if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.ClosePrice >= _targetPrice)
{
SellMarket();
_stopPrice = 0m;
_targetPrice = 0m;
_entryPrice = 0m;
}
}
else if (Position < 0)
{
if (candle.HighPrice >= _stopPrice || candle.ClosePrice <= _targetPrice)
{
BuyMarket();
_stopPrice = 0m;
_targetPrice = 0m;
_entryPrice = 0m;
}
}
// Entry logic
var isBodyStrong = candleBody >= _prevRangeSize && candleBody >= atrValue * 0.8m;
if (Position == 0 && isBodyStrong)
{
if (candle.ClosePrice > candle.OpenPrice && candle.ClosePrice > _prevCandleHigh)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_stopPrice = _entryPrice - atrValue * AtrFactor;
_targetPrice = _entryPrice + (_entryPrice - _stopPrice) * RiskToReward;
}
else if (candle.ClosePrice < candle.OpenPrice && candle.ClosePrice < _prevCandleLow)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_stopPrice = _entryPrice + atrValue * AtrFactor;
_targetPrice = _entryPrice - (_stopPrice - _entryPrice) * RiskToReward;
}
}
_prevRangeSize = rangeSize;
_prevCandleHigh = candle.HighPrice;
_prevCandleLow = candle.LowPrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class iu_bigger_than_range_strategy(Strategy):
def __init__(self):
super(iu_bigger_than_range_strategy, self).__init__()
self._lookback_period = self.Param("LookbackPeriod", 22) \
.SetDisplay("Lookback Period", "Length for range calculation", "Parameters")
self._risk_to_reward = self.Param("RiskToReward", 3) \
.SetDisplay("Risk To Reward", "Risk to reward ratio", "Parameters")
self._atr_factor = self.Param("AtrFactor", 2.0) \
.SetDisplay("ATR Factor", "ATR multiplier", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(120))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_range_size = 0.0
self._prev_candle_high = 0.0
self._prev_candle_low = 0.0
self._stop_price = 0.0
self._target_price = 0.0
self._entry_price = 0.0
self._bar_count = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(iu_bigger_than_range_strategy, self).OnReseted()
self._prev_range_size = 0.0
self._prev_candle_high = 0.0
self._prev_candle_low = 0.0
self._stop_price = 0.0
self._target_price = 0.0
self._entry_price = 0.0
self._bar_count = 0
def OnStarted2(self, time):
super(iu_bigger_than_range_strategy, self).OnStarted2(time)
atr = AverageTrueRange()
atr.Length = self._lookback_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
self._bar_count += 1
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
atr_v = float(atr_val)
range_size = high - low
candle_body = abs(close - open_p)
lookback = self._lookback_period.Value
if self._bar_count < lookback:
self._prev_range_size = range_size
self._prev_candle_high = high
self._prev_candle_low = low
return
rr = self._risk_to_reward.Value
factor = float(self._atr_factor.Value)
if self.Position > 0:
if low <= self._stop_price or close >= self._target_price:
self.SellMarket()
self._stop_price = 0.0
self._target_price = 0.0
self._entry_price = 0.0
elif self.Position < 0:
if high >= self._stop_price or close <= self._target_price:
self.BuyMarket()
self._stop_price = 0.0
self._target_price = 0.0
self._entry_price = 0.0
is_body_strong = candle_body >= self._prev_range_size and candle_body >= atr_v * 0.8
if self.Position == 0 and is_body_strong:
if close > open_p and close > self._prev_candle_high:
self.BuyMarket()
self._entry_price = close
self._stop_price = self._entry_price - atr_v * factor
self._target_price = self._entry_price + (self._entry_price - self._stop_price) * rr
elif close < open_p and close < self._prev_candle_low:
self.SellMarket()
self._entry_price = close
self._stop_price = self._entry_price + atr_v * factor
self._target_price = self._entry_price - (self._stop_price - self._entry_price) * rr
self._prev_range_size = range_size
self._prev_candle_high = high
self._prev_candle_low = low
def CreateClone(self):
return iu_bigger_than_range_strategy()