Eine Outside Bar entsteht, wenn die Handelsspanne einer Kerze die der vorherigen überschreitet und damit einen kurzen Volatilitätsschub erzeugt. Diese Strategie handelt gegen die Bewegung, wenn die Outside Bar in entgegengesetzter Richtung zum vorherigen Trend schließt, und erwartet eine Rückkehr zum Gleichgewicht.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 121%. Die Strategie eignet sich am besten für den Kryptomarkt.
Wenn eine Outside Bar entsteht, bestimmt der Algorithmus, ob die Kerze bullisch oder bearisch ist. Eine bullische Outside Bar nach einem Rückgang eröffnet eine Long-Position mit einem Stop unterhalb des Balken-Tiefs. Eine bearische Outside Bar nach einer Rally löst einen Short mit einem Stop oberhalb ihres Hochs aus. Trades werden beendet, wenn der Kurs anschließend durch diesen Extrempunkt bricht.
Das Setup sucht schnelle Umkehrungen nach einem erschöpfenden Impuls und eignet sich am besten in volatilen Märkten statt in stark trendenden.
Details
Einstiegskriterien: Outside Bar schließt entgegengesetzt der vorherigen Bewegung.
Long/Short: Beide.
Ausstiegskriterien: Kurs bricht Outside Bar Hoch/Tief oder Stop-Loss.
Stops: Ja, außerhalb des Musters platziert.
Standardwerte:
CandleType = 5 minute
StopLossPercent = 1
Filter:
Kategorie: Muster
Richtung: Beide
Indikatoren: Candlestick
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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>
/// Outside Bar Reversal strategy.
/// Detects outside bar patterns (higher high and lower low than previous bar).
/// Bullish outside bar = buy, bearish outside bar = sell.
/// Uses SMA for exit signals.
/// </summary>
public class OutsideBarReversalStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private ICandleMessage _prevCandle;
private int _cooldown;
/// <summary>
/// MA Period.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public OutsideBarReversalStrategy()
{
_maPeriod = Param(nameof(MAPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for SMA", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldown > 0)
{
_cooldown--;
_prevCandle = candle;
return;
}
if (_prevCandle != null)
{
// Outside bar: higher high AND lower low than previous bar
var isOutsideBar = candle.HighPrice > _prevCandle.HighPrice && candle.LowPrice < _prevCandle.LowPrice;
if (isOutsideBar)
{
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
if (Position == 0 && isBullish)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && isBearish)
{
SellMarket();
_cooldown = CooldownBars;
}
}
// Exit logic using SMA
if (Position > 0 && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
_prevCandle = candle;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class outside_bar_reversal_strategy(Strategy):
"""
Outside Bar Reversal strategy.
Detects outside bar patterns (higher high and lower low than previous bar).
Bullish outside bar = buy, bearish outside bar = sell.
Uses SMA for exit signals.
"""
def __init__(self):
super(outside_bar_reversal_strategy, self).__init__()
self._ma_period = self.Param("MAPeriod", 20).SetDisplay("MA Period", "Period for SMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_candle = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(outside_bar_reversal_strategy, self).OnReseted()
self._prev_candle = None
self._cooldown = 0
def OnStarted2(self, time):
super(outside_bar_reversal_strategy, self).OnStarted2(time)
self._prev_candle = None
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_candle = candle
return
if self._prev_candle is not None:
# Outside bar: higher high AND lower low than previous bar
is_outside_bar = candle.HighPrice > self._prev_candle.HighPrice and candle.LowPrice < self._prev_candle.LowPrice
if is_outside_bar:
is_bullish = candle.ClosePrice > candle.OpenPrice
is_bearish = candle.ClosePrice < candle.OpenPrice
if self.Position == 0 and is_bullish:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position == 0 and is_bearish:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
# Exit logic using SMA
sv = float(sma_val)
if self.Position > 0 and float(candle.ClosePrice) < sv:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position < 0 and float(candle.ClosePrice) > sv:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
self._prev_candle = candle
def CreateClone(self):
return outside_bar_reversal_strategy()