Die Bobnaley-Strategie reproduziert den MetaTrader 5 Expertenberater „bobnaley“ unter Verwendung des StockSharp hohen Levels API. Es kombiniert einen einfachen Trendfilter für gleitende Durchschnitte mit dem stochastischen Oszillator, um nach Umkehrmöglichkeiten zu suchen. Der ursprüngliche Gutachter bewertete die Tick-Preise; Der Port verwendet fertige Kerzen und behält die Regeln für die Auftragsverwaltung bei.
Wie es funktioniert
Indikatoren
Ein einfacher gleitender Durchschnitt mit der konfigurierten Periode filtert die vorherrschende Richtung.
Ein stochastischer Oszillator (Haupt- und Signallinien) identifiziert überverkaufte und überkaufte Situationen. Für Signale wird nur die Hauptleitung benötigt; Die Signalleitung wird der Vollständigkeit halber berechnet.
Eintrittsbedingungen
Die Strategie wartet, bis die aktuelle Kerze fertig ist und alle Indikatoren gebildet sind.
Bei Long-Einstiegen muss der gleitende Durchschnitt während der letzten drei Stichproben streng fallen, während der Preis über dem letzten Durchschnitt schließt. Gleichzeitig muss die stochastische Hauptlinie unter dem überverkauften Niveau liegen und ihr vorheriger Wert muss höher sein als der davor, was die ursprüngliche EA-Anforderung stochVal[1] > stochVal[2] widerspiegelt.
Short-Einstiege sind das Spiegelbild: Der gleitende Durchschnitt muss in den letzten drei Stichproben steigen, während der Preis darunter schließt, und die stochastische Hauptlinie muss über dem überkauften Niveau liegen, während ihr vorheriger Wert niedriger als der frühere ist.
Neue Trades werden nur eröffnet, wenn derzeit keine Position aktiv ist, wodurch der PositionSelect-Schutz von MetaTrader repliziert wird.
Risikomanagement
Wenn eine Position eröffnet wird, verlässt sich die Strategie auf den Schutzdienst von StockSharp, um einen Take-Profit und einen Stop-Loss in absoluten Preiseinheiten zu platzieren. Diese Abstände stimmen mit den MetaTrader-Eingaben überein (standardmäßig 0,007 und 0,0035).
Vor jeder Entscheidung wird der Portfoliowert mit dem Parameter Minimum Balance verglichen, der den Free-Margin-Filter (ACCOUNT_FREEMARGIN > 5000) des Originalcodes widerspiegelt. Wenn der Kontowert bekannt ist und unter dem Schwellenwert liegt, wird die Eingabe übersprungen.
Volumenhandhabung
Bestellungen verwenden einen festen Base Volume-Parameter. Dies reproduziert die Chargeneinstellung, die das MetaTrader-Skript nach Anwendung seiner eigenen Rundungsroutine verwendet hat.
Parameter
Kategorie
Name
Beschreibung
Standard
Allgemein
Kerzentyp
Kerzendatentyp, der für Indikatorberechnungen verwendet wird.
Zeitrahmen von 5 Minuten
Handel
Grundvolumen
Auf jede neue Position wird ein festes Auftragsvolumen angewendet.
5
Indikatoren
MA-Zeitraum
Länge des einfachen gleitenden Durchschnitts.
76
Indikatoren
Stochastic Zeitraum
Rückblick auf die stochastische Hauptlinie.
5
Indikatoren
Stochastic %K
Glättungslänge für die %K-Linie.
3
Indikatoren
Stochastic %D
Glättungslänge für die %D-Linie.
3
Indikatoren
Stochastic Überverkauft
Schwellenwert, der den überverkauften Bereich für die Hauptlinie definiert.
30
Indikatoren
Stochastic Überkauft
Schwellenwert, der den überkauften Bereich für die Hauptlinie definiert.
70
Risikomanagement
Nehmen Sie Gewinn mit
Abstand zwischen Einstiegspreis und Take-Profit in Preiseinheiten.
0,007
Risikomanagement
Stop-Loss
Abstand zwischen Einstiegspreis und Stop-Loss in Preiseinheiten.
0,0035
Risikomanagement
Mindestguthaben
Mindestportfoliowert erforderlich, bevor eine neue Bestellung gesendet werden kann.
5000
Notizen
Der ursprüngliche Experte verwendete Bid/Ask-Kurse; In StockSharp wird der Kerzenschluss als Proxy für den Ausführungspreis verwendet.
Es werden keine Trailing-Exits implementiert – der Handel wird nur durch die Schutzaufträge geschlossen.
Stochastic-Berechnungen folgen den Standardeinstellungen von MetaTrader (5/3/3), können aber über die bereitgestellten Parameter optimiert werden.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Bobnaley strategy: EMA trend with ATR volatility filter.
/// </summary>
public class BobnaleyStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public BobnaleyStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
decimal? prevClose = null;
decimal? prevEma = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, (candle, emaVal, atrVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevClose.HasValue && prevEma.HasValue)
{
var crossUp = prevClose.Value <= prevEma.Value && close > emaVal;
var crossDown = prevClose.Value >= prevEma.Value && close < emaVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevClose = close;
prevEma = emaVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
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 ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class bobnaley_strategy(Strategy):
def __init__(self):
super(bobnaley_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._ema_period = self.Param("EmaPeriod", 14) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period", "Indicators")
self._prev_close = None
self._prev_ema = None
@property
def candle_type(self):
return self._candle_type.Value
@property
def ema_period(self):
return self._ema_period.Value
@property
def atr_period(self):
return self._atr_period.Value
def OnReseted(self):
super(bobnaley_strategy, self).OnReseted()
self._prev_close = None
self._prev_ema = None
def OnStarted2(self, time):
super(bobnaley_strategy, self).OnStarted2(time)
self._prev_close = None
self._prev_ema = None
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, 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, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._prev_close is not None and self._prev_ema is not None:
cross_up = self._prev_close <= self._prev_ema and close > float(ema_val)
cross_down = self._prev_close >= self._prev_ema and close < float(ema_val)
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_ema = float(ema_val)
def CreateClone(self):
return bobnaley_strategy()