Diese Strategie repliziert den CompassLine-Experten, indem sie zwei komplementäre Filter zusammenführt:
Linie folgen – ein Ausbruchspfad der Bänder um Bollinger, optional um ATR verschoben. Wenn der Preis außerhalb der Bänder schließt, verlängert sich die Spur in Richtung des Ausbruchs und zieht sich nie zurück, solange der Trend anhält.
Kompass – eine logistische Transformation des Medianpreises im Verhältnis zum höchsten Hoch und niedrigsten Tief über dem Fenster des gleitenden Durchschnitts. Das Rohsignal wird doppelt geglättet (dreieckige Mittelung), um einen stabilen bullischen/bärischen Zustand zu erzeugen.
Eine Position wird nur eröffnet, wenn beide Filter mit dem Trend übereinstimmen. Optionale Zeitfilterung und Schutzstopps spiegeln die MQL-Logik wider.
Einzelheiten
Eintrittskriterien:
Die Folgelinie muss bei Long-Positionen nach oben (aktueller Schlusskurs über dem oberen Band) oder bei Shorts nach unten (aktueller Schlusskurs unter dem unteren Band) zeigen. Die Verschiebung um ATR kann mit UseAtrFilter umgeschaltet werden.
Der Kompassstatus (basierend auf CompassPeriod) muss nach der doppelten Glättungsphase für Long-Positionen positiv oder für Short-Positionen negativ sein.
Der Handel wird nur ausgeführt, wenn der optionale Sitzungsfilter (UseTimeFilter mit Session in HHmm-HHmm) dies zulässt.
Lang/Kurz: Beide Richtungen werden unterstützt.
Ausstiegskriterien:
CloseMode = None behält die Position bei, bis ein Gegeneinstieg oder ein Schutzstopp erfolgt.
CloseMode = BothIndicators wird geschlossen, wenn sowohl „Linie folgen“ als auch „Kompass“ gleichzeitig die Richtung umkehren.
CloseMode = FollowLineOnly wird beendet, wenn Follow Line gegen die Position kippt.
CloseMode = CompassOnly wird beendet, wenn der Kompass die Polarität ändert.
Stopps: Die Distanzen TakeProfit und StopLoss (in Sicherheitsschritten) werden nach jeder Eingabe angewendet, wenn sie größer als Null sind.
Die Compass-Glättung verwendet ein dreieckiges Fenster gleich rund(CompassPeriod / 3), was der ursprünglichen Indikatorimplementierung sehr nahe kommt.
Sitzungszeichenfolgen wie 0930-1600 beschränken den Handel auf das angegebene Fenster, während die Indikatorzustände weiterhin außerhalb der Sitzung aktualisiert werden.
Bei Schutzanordnungen werden die High-Level-Helfer von StockSharp wiederverwendet, sodass die Logik mit den Portfolio-Risikomanagementmodulen kompatibel ist.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Compass Line strategy: BB + RSI trend filter.
/// Buys when close < lower BB and RSI < 45.
/// Sells when close > upper BB and RSI > 55.
/// </summary>
public class CompassLineStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<int> _rsiPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BbPeriod
{
get => _bbPeriod.Value;
set => _bbPeriod.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public CompassLineStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BbPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
decimal? prevClose = null;
decimal? prevLower = null;
decimal? prevUpper = null;
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, rsi, (candle, bbVal, rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bbv = (BollingerBandsValue)bbVal;
if (bbv.UpBand is not decimal upper || bbv.LowBand is not decimal lower)
return;
if (rsiVal.IsEmpty)
return;
var rsiDec = rsiVal.GetValue<decimal>();
var close = candle.ClosePrice;
if (prevClose.HasValue && prevLower.HasValue && prevUpper.HasValue)
{
var crossBelowLower = prevClose.Value > prevLower.Value && close <= lower;
var crossAboveUpper = prevClose.Value < prevUpper.Value && close >= upper;
if (crossBelowLower && rsiDec < 45m && Position <= 0)
BuyMarket();
else if (crossAboveUpper && rsiDec > 55m && Position >= 0)
SellMarket();
}
prevClose = close;
prevLower = lower;
prevUpper = upper;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bb);
DrawOwnTrades(area);
}
}
}
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 BollingerBands, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class compass_line_strategy(Strategy):
def __init__(self):
super(compass_line_strategy, self).__init__()
self._bb_period = self.Param("BbPeriod", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._bb = None
self._rsi = None
self._prev_close = None
self._prev_lower = None
self._prev_upper = None
@property
def bb_period(self):
return self._bb_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
def OnReseted(self):
super(compass_line_strategy, self).OnReseted()
self._bb = None
self._rsi = None
self._prev_close = None
self._prev_lower = None
self._prev_upper = None
def OnStarted2(self, time):
super(compass_line_strategy, self).OnStarted2(time)
self._bb = BollingerBands()
self._bb.Length = self.bb_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.BindEx(self._bb, self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, bb_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._bb.IsFormed or not self._rsi.IsFormed:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
rsi = float(rsi_value)
close = float(candle.ClosePrice)
if self._prev_close is not None and self._prev_lower is not None and self._prev_upper is not None:
cross_below_lower = self._prev_close > self._prev_lower and close <= lower
cross_above_upper = self._prev_close < self._prev_upper and close >= upper
if cross_below_lower and rsi < 45.0 and self.Position <= 0:
self.BuyMarket()
elif cross_above_upper and rsi > 55.0 and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_lower = lower
self._prev_upper = upper
def CreateClone(self):
return compass_line_strategy()