Konvertiert vom ursprünglichen MetaTrader 4-Experten „Billy_expert.mq4“.
Long-Only-Momentum-Strategie, die auf vier aufeinanderfolgende absteigende Hochs wartet und vor dem Einstieg eröffnet.
Verwendet zwei stochastische Oszillatoren (schnell im Handelszeitrahmen, langsam in einem höheren Zeitrahmen), um zu bestätigen, dass sich die Dynamik nach oben verschiebt.
Konzipiert für Spot-FX-Paare, kann aber auf jedes Instrument angewendet werden, das minutenbasierte Kerzen bereitstellt.
Signallogik
Preisaktionsfilter
Bewerten Sie fertige Kerzen im ersten Zeitrahmen.
Erfordert vier aufeinanderfolgende Kerzen, bei denen sowohl das Hoch als auch die Eröffnung sinken. Dadurch werden die MT4-Prüfungen High[0] < High[1] < High[2] < High[3] und Open[0] < Open[1] < Open[2] < Open[3] neu erstellt.
Das Muster deutet auf eine erschöpfte Abwärtsbewegung hin und bereitet die Strategie auf einen Umkehrhandel vor.
Bestätigung des Oszillators
Berechnen Sie einen schnellen stochastischen Oszillator im Handelszeitrahmen und einen langsamen stochastischen Oszillator im Bestätigungszeitrahmen.
Fordern Sie für jeden Oszillator, dass die %K-Linie sowohl bei der aktuellen als auch bei der vorherigen abgeschlossenen Kerze (%K(0) > %D(0) und %K(1) > %D(1)) über der %D-Linie liegt.
Der Handel wird nur dann ausgelöst, wenn beide Oszillatoren gleichzeitig eine Aufwärtsdynamik bestätigen.
Auftragsverwaltung
Einträge: Marktkäufe in der Größe des Strategieparameters Volume (wenn eine Short-Position vorhanden ist, wird diese automatisch geschlossen und rückgängig gemacht).
Stop-Loss: Fester Abstand unter dem Füllpreis mithilfe des Parameters Stop Loss (pts). Ein Wert von 0 deaktiviert den Stopp.
Take Profit: Fester Abstand über dem Füllpreis mithilfe des Parameters Take Profit (pts). Ein Wert von 0 deaktiviert das Ziel.
Positionsobergrenze: Max Orders begrenzt, wie viele lange Einträge gleichzeitig aktiv sein können. Da StockSharp eine Nettoposition behält, nähert sich die Strategie dem MT4-Verhalten an, indem sie zählt, wie viele Volume-Blöcke derzeit geöffnet sind.
Trailing Stop: Das ursprüngliche EA hat eine Trailing Stop-Eingabe deklariert, diese jedoch nicht implementiert. In der konvertierten Version wird außerdem die abschließende Logik für die Parität weggelassen.
Parameter
Name
Beschreibung
Standard
Trading Candle
Primärer Zeitrahmen für Preismuster und schnelle Stochastik.
1 Minute
Slow Stochastic Candle
Für die Bestätigungsstochastik wird ein höherer Zeitrahmen verwendet.
5 Minuten
Stochastic Length
Lookback-Fenster für %K.
5
%K Smoothing
Auf die %K-Linie angewendete Glättung.
3
%D Period
Auf die %D-Linie angewendete Glättung.
3
Slowing
Zusätzlicher Glättungsfaktor für %K.
3
Stop Loss (pts)
Stop-Loss-Distanz in Preisschritten.
0
Take Profit (pts)
Nehmen Sie die Gewinndistanz in Preisschritten.
12
Max Orders
Maximal gleichzeitige lange Einträge.
1
Nutzungshinweise
Legen Sie die Eigenschaft Volume fest, bevor Sie mit der Strategie beginnen. StockSharp ist standardmäßig 0, was die Auftragserteilung blockieren würde.
Die Preisstufe wird ab Security.PriceStep gelesen (fällt auf Security.Step oder 1 zurück). Stellen Sie sicher, dass die Metadaten Ihres Instruments korrekt konfiguriert sind, um präzise Stopp-/Zielwerte zu erhalten.
Wenn der Bestätigungszeitrahmen vom Handelszeitrahmen abweicht, wird die zuletzt abgeschlossene langsame Kerze wiederverwendet, bis eine neue erscheint, die dem Verhalten des ursprünglichen MT4-Skripts entspricht.
Der EA schaffte keine Ausstiege über den Stop-Loss und die Gewinnmitnahme hinaus auf Brokerseite. Die Konvertierung spiegelt dieses Verhalten wider, indem bei Erreichen der Niveaus schützende Marktaufträge gesendet werden.
Da StockSharp Positionen aggregiert, funktioniert Max Orders > 1 am besten, wenn jeder Eintrag dieselbe Volume-Größe verwendet.
Unterschiede zur MT4-Version
Sicherheitsprüfung auf fehlende Preisschrittinformationen mit einer Protokollwarnung, anstatt stillschweigend Point zu verwenden.
Es wurden Schutzklauseln hinzugefügt, um sicherzustellen, dass die Strategie nur dann gehandelt wird, wenn alle erforderlichen Daten (Preisverlauf und beide stochastischen Oszillatoren) verfügbar sind.
Die Strategie läuft nur auf fertigen Kerzen, während MT4 Ticks verarbeitet, aber durch die Taktzeit gedrosselt wird. Durch diese Änderung werden doppelte Auswertungen vermieden und die Logik bleibt deterministisch.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Long-only reversal strategy that looks for consecutive descending highs
/// and enters when RSI confirms oversold conditions with momentum turning up.
/// </summary>
public class BillyExpertReversalStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private decimal _prevHigh1, _prevHigh2, _prevHigh3;
private int _barCount;
private decimal _prevRsi;
private bool _hasPrevRsi;
private decimal _entryPrice;
public BillyExpertReversalStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "Length for RSI indicator.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh1 = 0;
_prevHigh2 = 0;
_prevHigh3 = 0;
_barCount = 0;
_prevRsi = 50;
_hasPrevRsi = false;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh1 = 0;
_prevHigh2 = 0;
_prevHigh3 = 0;
_barCount = 0;
_prevRsi = 50;
_hasPrevRsi = false;
_entryPrice = 0;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_barCount++;
var high = candle.HighPrice;
var close = candle.ClosePrice;
// Check descending highs pattern (3 consecutive lower highs)
var descendingHighs = _barCount >= 4 &&
high < _prevHigh1 &&
_prevHigh1 < _prevHigh2 &&
_prevHigh2 < _prevHigh3;
// RSI turning up from oversold
var rsiBullish = _hasPrevRsi && _prevRsi < 40 && rsiValue > _prevRsi;
// Manage long position
if (Position > 0)
{
// Exit on take-profit, stop-loss, or RSI overbought
if (_entryPrice > 0 && close >= _entryPrice * 1.015m)
{
SellMarket();
}
else if (_entryPrice > 0 && close <= _entryPrice * 0.985m)
{
SellMarket();
}
else if (rsiValue > 75)
{
SellMarket();
}
}
// Manage short position (exit only, this is mostly long-only)
if (Position < 0)
{
if (rsiValue < 30)
{
BuyMarket();
}
}
// Entry: descending highs (selling exhaustion) + RSI confirms reversal
if (Position == 0)
{
if (descendingHighs && rsiBullish)
{
_entryPrice = close;
BuyMarket();
}
// Also allow short on ascending lows pattern with overbought RSI
else if (_barCount >= 4 && rsiValue > 70 && _prevRsi > 70)
{
_entryPrice = close;
SellMarket();
}
}
// Update history
_prevHigh3 = _prevHigh2;
_prevHigh2 = _prevHigh1;
_prevHigh1 = high;
_prevRsi = rsiValue;
_hasPrevRsi = true;
}
}
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
class billy_expert_reversal_strategy(Strategy):
def __init__(self):
super(billy_expert_reversal_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "Length for RSI indicator", "Indicators")
self._prev_high1 = 0.0
self._prev_high2 = 0.0
self._prev_high3 = 0.0
self._bar_count = 0
self._prev_rsi = 50.0
self._has_prev_rsi = False
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
def OnStarted2(self, time):
super(billy_expert_reversal_strategy, self).OnStarted2(time)
self._prev_high1 = 0.0
self._prev_high2 = 0.0
self._prev_high3 = 0.0
self._bar_count = 0
self._prev_rsi = 50.0
self._has_prev_rsi = False
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
self._bar_count += 1
high = float(candle.HighPrice)
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
# Check descending highs pattern (3 consecutive lower highs)
descending_highs = (self._bar_count >= 4 and
high < self._prev_high1 and
self._prev_high1 < self._prev_high2 and
self._prev_high2 < self._prev_high3)
# RSI turning up from oversold
rsi_bullish = self._has_prev_rsi and self._prev_rsi < 40 and rsi_val > self._prev_rsi
# Manage long position
if self.Position > 0:
if self._entry_price > 0 and close >= self._entry_price * 1.015:
self.SellMarket()
elif self._entry_price > 0 and close <= self._entry_price * 0.985:
self.SellMarket()
elif rsi_val > 75:
self.SellMarket()
# Manage short position (exit only)
if self.Position < 0:
if rsi_val < 30:
self.BuyMarket()
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_high3 = self._prev_high2
self._prev_high2 = self._prev_high1
self._prev_high1 = high
self._prev_rsi = rsi_val
self._has_prev_rsi = True
return
# Entry
if self.Position == 0:
if descending_highs and rsi_bullish:
self._entry_price = close
self.BuyMarket()
elif self._bar_count >= 4 and rsi_val > 70 and self._prev_rsi > 70:
self._entry_price = close
self.SellMarket()
# Update history
self._prev_high3 = self._prev_high2
self._prev_high2 = self._prev_high1
self._prev_high1 = high
self._prev_rsi = rsi_val
self._has_prev_rsi = True
def OnReseted(self):
super(billy_expert_reversal_strategy, self).OnReseted()
self._prev_high1 = 0.0
self._prev_high2 = 0.0
self._prev_high3 = 0.0
self._bar_count = 0
self._prev_rsi = 50.0
self._has_prev_rsi = False
self._entry_price = 0.0
def CreateClone(self):
return billy_expert_reversal_strategy()