Strategie zur IBS-Umkehr im durchschnittlichen Hoch-Tief-Bereich
Diese Strategie sucht nach Mean Reversion, nachdem der Preis unterhalb einer dynamischen Schwelle geblieben ist, die aus der durchschnittlichen Hoch-Tief-Spanne abgeleitet wird. Sie berechnet den gleitenden Durchschnitt der Balkenspanne, das höchste Hoch und das niedrigste Tief über den Beobachtungszeitraum. Eine Kaufschwelle wird als höchstes Hoch minus 2,5-facher Durchschnittsspanne definiert. Wenn der Preis für eine bestimmte Anzahl von Balken unter diesem Niveau bleibt und die intrabarbezeichnete Stärke (IBS) innerhalb des Handelsfensters unter einem bestimmten Limit liegt, wird eine Long-Position eröffnet. Die Position wird geschlossen, wenn der Schlusskurs das Hoch des vorherigen Balkens überschreitet.
Details
- Einstiegskriterien:
- Der Preis ist
BarsBelowThreshold Balken lang unter der Kaufschwelle geblieben.
- IBS <
IbsBuyThreshold.
- Zeit zwischen
StartTime und EndTime.
- Long/Short: Nur Long.
- Ausstiegskriterien:
- Schlusskurs überschreitet das Hoch des vorherigen Balkens.
- Stops: Keine.
- Standardwerte:
Length = 20
BarsBelowThreshold = 2
IbsBuyThreshold = 0.2
- Filter:
- Kategorie: Mean Reversion
- Richtung: Long
- Indikatoren: SMA, Highest, Lowest
- Stops: Nein
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Niedrig
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>
/// Average high-low range with IBS reversal strategy.
/// Uses Highest/Lowest channel with EMA filter and cooldown.
/// Buys on breakout above channel with uptrend, sells on breakdown below with downtrend.
/// </summary>
public class AverageHighLowRangeIbsReversalStrategy : Strategy
{
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevHighest;
private decimal _prevLowest;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// Channel lookback length.
/// </summary>
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
/// <summary>
/// EMA trend filter period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AverageHighLowRangeIbsReversalStrategy()
{
_channelLength = Param(nameof(ChannelLength), 20)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Lookback for Highest/Lowest", "Indicators");
_emaLength = Param(nameof(EmaLength), 40)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 350)
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");
_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();
_prevHighest = 0;
_prevLowest = 0;
_barIndex = 0;
_lastTradeBar = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = ChannelLength };
var lowest = new Lowest { Length = ChannelLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal highestValue, decimal lowestValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;
// Breakout above previous highest with uptrend
var breakUp = _prevHighest > 0 && candle.ClosePrice > _prevHighest && candle.ClosePrice > emaValue;
// Breakdown below previous lowest with downtrend
var breakDown = _prevLowest > 0 && candle.ClosePrice < _prevLowest && candle.ClosePrice < emaValue;
if (breakUp && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (breakDown && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevHighest = highestValue;
_prevLowest = lowestValue;
}
}
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 Highest, Lowest, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class average_high_low_range_ibs_reversal_strategy(Strategy):
def __init__(self):
super(average_high_low_range_ibs_reversal_strategy, self).__init__()
self._channel_length = self.Param("ChannelLength", 20) \
.SetDisplay("Channel Length", "Lookback for Highest/Lowest", "Indicators")
self._ema_length = self.Param("EmaLength", 40) \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 350) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._bar_index = 0
self._last_trade_bar = 0
@property
def channel_length(self):
return self._channel_length.Value
@channel_length.setter
def channel_length(self, value):
self._channel_length.Value = value
@property
def ema_length(self):
return self._ema_length.Value
@ema_length.setter
def ema_length(self, value):
self._ema_length.Value = value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
@cooldown_bars.setter
def cooldown_bars(self, value):
self._cooldown_bars.Value = value
@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(average_high_low_range_ibs_reversal_strategy, self).OnReseted()
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._bar_index = 0
self._last_trade_bar = 0
def OnStarted2(self, time):
super(average_high_low_range_ibs_reversal_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self.channel_length
lowest = Lowest()
lowest.Length = self.channel_length
ema = ExponentialMovingAverage()
ema.Length = self.ema_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, ema, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, highest_value, lowest_value, ema_value):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
cooldown_ok = self._bar_index - self._last_trade_bar > self.cooldown_bars
break_up = self._prev_highest > 0 and candle.ClosePrice > self._prev_highest and candle.ClosePrice > ema_value
break_down = self._prev_lowest > 0 and candle.ClosePrice < self._prev_lowest and candle.ClosePrice < ema_value
if break_up and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif break_down and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_highest = float(highest_value)
self._prev_lowest = float(lowest_value)
def CreateClone(self):
return average_high_low_range_ibs_reversal_strategy()