Die Manuelle EA-Strategie ist eine Eins-zu-eins-StockSharp-High-Level-API-Konvertierung des MetaTrader 4-Expertenberaters Manual_EA.mq4 (Ordner MQL/8159). Das ursprüngliche System gibt nach eigenem Ermessen Kauf- oder Verkaufsaufträge aus, wenn der Stochastic-Oszillator extreme Zonen verlässt. Der StockSharp-Port behält die gleiche 5-3-3-Oszillatorkonfiguration bei, gleicht das bestehende Risiko automatisch aus, bevor die nächste Marktorder platziert wird, und stellt die gängigen Geldverwaltungsoptionen durch Strategieparameter offen.
Handelslogik
Die Strategie abonniert die CandleType-Serie (Standard: 15-Minuten-Kerzen) und speist die Schlusskurse in einen Stochastic-Oszillator ein, der wie folgt konfiguriert ist:
%K Lookback = KPeriod (Standard 5 Balken)
%K Verlangsamung = Slowing (Standard 3 Balken)
%D Glättung = DPeriod (Standard 3 Balken)
Signale werden anhand des Endwerts der %D-Linie (Signal) jeder fertigen Kerze ausgewertet. Zur Erkennung von Bahnübergängen werden zwei aufeinanderfolgende Messwerte verglichen.
Langer Eintrag – Wenn der vorherige %D-Wert unter oder gleich OversoldLevel (Standard 10) war und der letzte Wert über diesen Schwellenwert steigt. Die Strategie neutralisiert zunächst jegliches Short-Engagement und kauft dann Volume + |short position| nach Marktorder.
Kurzer Eintrag – Wenn der vorherige %D-Wert über oder gleich OverboughtLevel (Standard 90) war und der letzte Wert unter diesen Schwellenwert fällt. Jede bestehende Long-Position wird geschlossen, bevor Volume + |long position| zum Marktpreis verkauft wird.
Schutzanordnungen werden über StartProtection abgewickelt. Ein positiver StopLoss und/oder TakeProfit (gemessen in Preispunkten) aktiviert das automatische Risikomanagement. Wenn Sie einen Parameter auf 0 setzen, wird der entsprechende Schutz deaktiviert.
Der Port vermeidet bewusst Indikatorpufferzugriffsmuster und unvollendete Kerzenlogik und entspricht den Best Practices von StockSharp auf hoher Ebene API.
Parameter
Parameter
Beschreibung
Standard
CandleType
Zeitrahmen (als DataType), der zum Aufbau von Kerzen und zum Antreiben des Oszillators verwendet wird.
15-minütiger Zeitrahmen
KPeriod
Lookback-Länge der Zeile Stochastic %K.
5
DPeriod
Glättungslänge der Signalleitung Stochastic %D.
3
Slowing
Zusätzliche Glättung wird auf %K angewendet, bevor %D berechnet wird.
3
OverboughtLevel
Obergrenze, die Short-Einträge auslöst, wenn sie um %D nach unten überschritten wird.
90
OversoldLevel
Untere Grenze, die lange Einträge auslöst, wenn sie um %D nach oben überschritten wird.
10
StopLoss
Abstand in Preispunkten für den schützenden Stop-Loss (0 = deaktiviert).
100
TakeProfit
Abstand in Preispunkten für das Take-Profit-Ziel (0 = deaktiviert).
100
Volume
Bestellgröße, die mit jedem neuen Signal (Lots) gesendet wird. Vorhandene Gegenpositionen werden zunächst verrechnet.
0,1
Zusätzliche Hinweise
Die Strategie verwendet SubscribeCandles zusammen mit BindEx, um StochasticOscillatorValue-Updates zu streamen und sicherzustellen, dass die Indikatorwerte endgültig sind, bevor Handelsentscheidungen getroffen werden.
Bei der Diagrammvisualisierung werden automatisch die ausgewählten Kerzenserien, der Stochastic-Oszillator und eigene Trades dargestellt, wenn ein Diagrammbereich verfügbar ist.
Da %D Kreuzungen bei aufeinanderfolgenden fertigen Kerzen ausgewertet werden, entspricht das Verhalten der MQL-Implementierung, die MODE_SIGNAL-Werte bei Schicht 1 und 2 verglichen hat.
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;
public class ManualEaStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
private bool _hasPrev;
private int _cooldown;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ManualEaStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 9).SetDisplay("RSI Period", "RSI lookback", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 20).SetDisplay("EMA Period", "EMA filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ema, ProcessCandle).Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
}
private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsi;
return;
}
if (_prevRsi <= 20 && rsi > 20 && close > ema && Position == 0)
{
BuyMarket();
_cooldown = 2;
}
else if (_prevRsi >= 80 && rsi < 80 && close < ema && Position == 0)
{
SellMarket();
_cooldown = 2;
}
_prevRsi = rsi;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class manual_ea_strategy(Strategy):
def __init__(self):
super(manual_ea_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 9).SetDisplay("RSI Period", "RSI lookback", "Indicators")
self._ema_period = self.Param("EmaPeriod", 20).SetDisplay("EMA Period", "EMA filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_rsi = 0.0; self._has_prev = False; self._cooldown = 0
@property
def rsi_period(self): return self._rsi_period.Value
@property
def ema_period(self): return self._ema_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(manual_ea_strategy, self).OnReseted()
self._prev_rsi = 0.0; self._has_prev = False; self._cooldown = 0
def OnStarted2(self, time):
super(manual_ea_strategy, self).OnStarted2(time)
self._has_prev = False; self._cooldown = 0
rsi = RelativeStrengthIndex(); rsi.Length = self.rsi_period
ema = ExponentialMovingAverage(); ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, ema, self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(2, UnitTypes.Percent),
stopLoss=Unit(1, UnitTypes.Percent)
)
def process_candle(self, candle, rsi, ema):
if candle.State != CandleStates.Finished: return
close = float(candle.ClosePrice)
rsi_val = float(rsi); ema_val = float(ema)
if not self._has_prev:
self._prev_rsi = rsi_val; self._has_prev = True; return
if self._cooldown > 0:
self._cooldown -= 1; self._prev_rsi = rsi_val; return
if self._prev_rsi <= 20 and rsi_val > 20 and close > ema_val and self.Position == 0:
self.BuyMarket(); self._cooldown = 2
elif self._prev_rsi >= 80 and rsi_val < 80 and close < ema_val and self.Position == 0:
self.SellMarket(); self._cooldown = 2
self._prev_rsi = rsi_val
def CreateClone(self): return manual_ea_strategy()