ComFracti Fractal RSI Strategy ist eine StockSharp-Portierung des MetaTrader-Experten ComFracti. Der Algorithmus sucht mithilfe von Bill Williams-Fraktalen in zwei Zeitrahmen nach Richtungsverzerrungen und filtert die Signale mit einem schnellen RSI, der anhand täglicher Kerzen berechnet wird. Sobald ein gültiges Setup angezeigt wird, eröffnet die Strategie eine einzelne Position, schützt sie mit konfigurierbaren Stop-Loss- und Take-Profit-Abständen und kann optional beendet werden, wenn sich das Signal umkehrt oder ein Haltezeitlimit erreicht ist.
Die Standardkonfiguration repliziert den 15-minütigen Handelszeitrahmen mit einem 1-stündigen Bestätigungszeitrahmen und einer täglichen RSI-Länge von drei Perioden unter Verwendung des Kerzenöffnungspreises, genau wie beim ursprünglichen Experten.
Handelslogik
Fraktale Bias-Erkennung
Fertige Kerzen aus dem Handelszeitrahmen und dem höheren Zeitrahmen werden über ein fraktales Fenster mit fünf Balken verarbeitet.
Die Parameter Primary*Shift und Higher*Shift legen fest, wie viele Balken die Strategie auf das neueste bestätigte Fraktal überprüft. Die Standardwerte stimmen mit dem ursprünglichen Wert von 3 überein, was bedeutet, dass der Code das Fraktal auswertet, das vor drei Kerzen bestätigt wurde.
Ein Abwärts-Fraktal (Swing-Tief) ohne begleitendes Aufwärts-Fraktal wird als bullisch (+1) behandelt. Ein Aufwärts-Fraktal ohne Abwärts-Fraktal wird als bärisch (-1) behandelt.
Täglicher RSI-Filter
Ein RelativeStrengthIndex mit dem konfigurierbaren RsiPeriod (Standard 3) läuft im täglichen Zeitrahmen und verwendet den Kerzenöffnungspreis, passend zur MetaTrader-Implementierung.
Bei langen Setups muss der RSI unter 50 - RsiBuyOffset liegen; Bei kurzen Setups muss der RSI über 50 + RsiSellOffset liegen.
Eintrittsbedingungen
Kaufen: Beide Fraktal-Tracker melden +1 und der RSI-Filter ist bullisch. Die Strategie eröffnet eine Long-Position, wenn sie flach oder short ist, und sendet so genug Volumen, um auf die Long-Seite zu wechseln.
Verkaufen: Beide Fraktal-Tracker melden -1 und der RSI-Filter ist bärisch. Die Strategie eröffnet eine Short-Position, wenn sie flach oder lang ist, und sendet so genügend Volumen, um auf die Short-Seite zu wechseln.
Positionsverwaltung
Schützende Stop-Loss- und Take-Profit-Level werden unmittelbar nach der Positionsänderung auf der Grundlage von StopLossPips und TakeProfitPips multipliziert mit der Pip-Größe des Instruments berechnet.
Die Position kann geschlossen werden, wenn der Preis den Stopp oder das Ziel erreicht, wenn ExpiryMinutes abläuft oder wenn CloseOnOppositeSignal aktiviert ist und das Signal umkehrt.
Parameter
Name
Beschreibung
Standard
Volume
Bestellvolumen, das für jeden Eintrag verwendet wird.
0.1
TakeProfitPips
Gewinnzielentfernung in Pips. Zum Deaktivieren auf 0 setzen.
700
StopLossPips
Stop-Loss-Distanz in Pips. Zum Deaktivieren auf 0 setzen.
2500
ExpiryMinutes
Maximale Haltezeit in Minuten, bevor ein Ausgang erzwungen wird. 0 deaktiviert den Timer.
5555
CloseOnOppositeSignal
Schließen Sie die aktive Position, wenn das Signal in die entgegengesetzte Richtung wechselt.
false
PrimaryBuyShift
Balken zurück, um das bullische Fraktal im Handelszeitrahmen zu untersuchen.
3
HigherBuyShift
Balken zurück, um das bullische Fraktal im höheren Zeitrahmen zu untersuchen.
3
PrimarySellShift
Balken zurück, um das rückläufige Fraktal im Handelszeitrahmen zu untersuchen.
3
HigherSellShift
Balken zurück, um das rückläufige Fraktal im höheren Zeitrahmen zu untersuchen.
3
RsiBuyOffset
Für lange Setups ist ein Versatz unter 50 erforderlich.
3
RsiSellOffset
Für kurze Setups ist ein Versatz über 50 erforderlich.
3
RsiPeriod
RSI Länge im täglichen Zeitrahmen.
3
CandleType
Kerzentyp des Handelszeitrahmens.
15-Minuten-Kerzen
HigherTimeFrame
Kerzentyp für den Bestätigungszeitrahmen.
1-Stunden-Kerzen
DailyTimeFrame
Kerzentyp, der für den täglichen RSI verwendet wird.
1-Tages-Kerzen
Implementierungshinweise
Die Strategie nutzt das High-Level-Kerzenabonnement API (SubscribeCandles().Bind(...)) und verwaltet Indikatoren intern, ohne sie über Strategy.Indicators offenzulegen, wie in den Richtlinien gefordert.
Fractals werden über einen internen Helfer berechnet, der ein rollierendes Fünf-Kerzen-Fenster speichert und das Signal erst aktualisiert, nachdem ein Fraktal bestätigt wurde.
RSI-Werte werden über RelativeStrengthIndex.Process(...) mit dem Kerzeneröffnungspreis abgerufen, entsprechend dem MetaTrader PRICE_OPEN-Modus.
Es wird jeweils nur eine Position beibehalten. Marktaufträge drehen die Position bei Bedarf um, indem sie das zur Deckung eines bestehenden Risikos erforderliche Volumen hinzufügen.
Die Pip-Größe wird aus Security.PriceStep und Security.Decimals geschätzt, wobei ein 10-facher Multiplikator für Vermögenswerte mit drei oder mehr Dezimalstellen verwendet wird, wodurch die Umrechnung von MetaTrader Point in Pip reproduziert wird.
Nutzungstipps
Die fraktalen Verschiebungen müssen groß genug sein, um sicherzustellen, dass der angeforderte Kerzenindex vorhanden ist. Bei einer Verschiebung von drei benötigt der Tracker mindestens fünf fertige Kerzen pro Zeitrahmen, bevor er Signale generiert.
Wenn Sie Instrumente mit unterschiedlichen Tick-Größen handeln (z. B. Indizes oder Aktien), passen Sie TakeProfitPips und StopLossPips an die Pip-Definition des Instruments an.
Das Deaktivieren von CloseOnOppositeSignal repliziert das ursprüngliche Verhalten des Expertenberaters (es war standardmäßig deaktiviert) und verlässt sich ausschließlich auf Stopps, Ziele oder den Ablauftimer für Exits.
Die Strategie implementiert kein Martingal oder risikobasierte Größenbestimmung; Die MetaTrader-Lotberechnung basierte auf Kontomargenfunktionen, die in StockSharp nicht verfügbar sind. Verwenden Sie den Parameter Volume oder binden Sie die Strategie in einen Portfoliomanager ein, wenn eine dynamische Positionsgrößenbestimmung erforderlich ist.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ComFracti Fractal RSI: Fractal breakout with RSI filter and ATR stops.
/// </summary>
public class ComFractiFractalRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _entryPrice;
private decimal _prevHigh5;
private decimal _prevLow5;
private decimal _high1, _high2, _high3, _high4, _high5;
private decimal _low1, _low2, _low3, _low4, _low5;
private int _barCount;
public ComFractiFractalRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_barCount = 0;
_prevHigh5 = 0;
_prevLow5 = 0;
_high1 = _high2 = _high3 = _high4 = _high5 = 0;
_low1 = _low2 = _low3 = _low4 = _low5 = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_barCount = 0;
_prevHigh5 = 0;
_prevLow5 = 0;
_high1 = _high2 = _high3 = _high4 = _high5 = 0;
_low1 = _low2 = _low3 = _low4 = _low5 = 0;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
// Shift fractal window
_high5 = _high4; _high4 = _high3; _high3 = _high2; _high2 = _high1;
_high1 = candle.HighPrice;
_low5 = _low4; _low4 = _low3; _low3 = _low2; _low2 = _low1;
_low1 = candle.LowPrice;
_barCount++;
if (_barCount < 5 || atrVal <= 0)
return;
var close = candle.ClosePrice;
// Detect fractal high (center bar _high3 is highest)
var fractalUp = _high3 > _high1 && _high3 > _high2 && _high3 > _high4 && _high3 > _high5;
// Detect fractal low (center bar _low3 is lowest)
var fractalDown = _low3 < _low1 && _low3 < _low2 && _low3 < _low4 && _low3 < _low5;
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 3m || close <= _entryPrice - atrVal * 2m || fractalDown)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 3m || close >= _entryPrice + atrVal * 2m || fractalUp)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (fractalDown && rsiVal < 45)
{
_entryPrice = close;
BuyMarket();
}
else if (fractalUp && rsiVal > 55)
{
_entryPrice = close;
SellMarket();
}
}
_prevHigh5 = _high5;
_prevLow5 = _low5;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex, AverageTrueRange
class com_fracti_fractal_rsi_strategy(Strategy):
def __init__(self):
super(com_fracti_fractal_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._entry_price = 0.0
self._prev_high5 = 0.0
self._prev_low5 = 0.0
self._high1 = 0.0
self._high2 = 0.0
self._high3 = 0.0
self._high4 = 0.0
self._high5 = 0.0
self._low1 = 0.0
self._low2 = 0.0
self._low3 = 0.0
self._low4 = 0.0
self._low5 = 0.0
self._bar_count = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(com_fracti_fractal_rsi_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._bar_count = 0
self._prev_high5 = 0.0
self._prev_low5 = 0.0
self._high1 = self._high2 = self._high3 = self._high4 = self._high5 = 0.0
self._low1 = self._low2 = self._low3 = self._low4 = self._low5 = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
av = float(atr_val)
# Shift fractal window
self._high5 = self._high4
self._high4 = self._high3
self._high3 = self._high2
self._high2 = self._high1
self._high1 = float(candle.HighPrice)
self._low5 = self._low4
self._low4 = self._low3
self._low3 = self._low2
self._low2 = self._low1
self._low1 = float(candle.LowPrice)
self._bar_count += 1
if self._bar_count < 5 or av <= 0:
return
close = float(candle.ClosePrice)
# Detect fractal high (center bar _high3 is highest)
fractal_up = (self._high3 > self._high1 and self._high3 > self._high2 and
self._high3 > self._high4 and self._high3 > self._high5)
# Detect fractal low (center bar _low3 is lowest)
fractal_down = (self._low3 < self._low1 and self._low3 < self._low2 and
self._low3 < self._low4 and self._low3 < self._low5)
if self.Position > 0:
if close >= self._entry_price + av * 3.0 or close <= self._entry_price - av * 2.0 or fractal_down:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 3.0 or close >= self._entry_price + av * 2.0 or fractal_up:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_high5 = self._high5
self._prev_low5 = self._low5
return
if self.Position == 0:
if fractal_down and rv < 45:
self._entry_price = close
self.BuyMarket()
elif fractal_up and rv > 55:
self._entry_price = close
self.SellMarket()
self._prev_high5 = self._high5
self._prev_low5 = self._low5
def OnReseted(self):
super(com_fracti_fractal_rsi_strategy, self).OnReseted()
self._entry_price = 0.0
self._bar_count = 0
self._prev_high5 = 0.0
self._prev_low5 = 0.0
self._high1 = self._high2 = self._high3 = self._high4 = self._high5 = 0.0
self._low1 = self._low2 = self._low3 = self._low4 = self._low5 = 0.0
def CreateClone(self):
return com_fracti_fractal_rsi_strategy()