Die PricerEA-Strategie bildet das Verhalten des MetaTrader 4-Experten „PricerEA v1.0“ unter Verwendung des StockSharp-High-Level-API nach.
Es platziert bis zu vier ausstehende Aufträge (Kaufstopp, Verkaufsstopp, Kauflimit und Verkaufslimit) zu manuell definierten Preisniveaus. Einmal
Wenn die ausstehende Order ausgeführt wird, fügt die Strategie schützende Stop-Loss- und Take-Profit-Orders hinzu und ermöglicht optional einen Trailing Stop und
Break-Even-Anpassung, um dem ursprünglichen Expert Advisor zu folgen.
Wie es funktioniert
Ausstehende Aufträge – die Strategie liest absolute Preisniveaus aus den Eingaben und übermittelt nur die entsprechenden ausstehenden Aufträge
einmal beim Start. Der optionale Ablauf kann in Minuten konfiguriert werden.
Volumenauswahl – Benutzer können die feste manuelle Losgröße beibehalten oder in den automatischen Modus wechseln, aus dem das Volumen abgeleitet wird
der Portfoliosaldo und das MT4-Risikofaktor-Analogon.
Schutz – nachdem eine Einstiegsorder ausgeführt wurde, erstellt die Strategie Stop-Loss- und Take-Profit-Orders im konfigurierten Abstand
(ausgedrückt in Preispunkten). Wenn sowohl Trailing als auch Break-Even aktiviert sind, folgt der Stopp den ursprünglichen MQL-Bedingungen: das ist er
Der Kurs bewegt sich erst, nachdem der Preis die Break-Even-Distanz plus den anfänglichen Stopp erreicht hat.
Auftragspflege – ausstehende Aufträge werden automatisch storniert, wenn ihre Gültigkeitsdauer abläuft oder die Strategie endet.
Absolute Preise für die entsprechenden ausstehenden Bestellungen. Ein Wert von 0 deaktiviert die Bestellung.
TakeProfitPoints
Abstand vom Einstiegspreis zur Take-Profit-Order, gemessen in Preispunkten (Security.PriceStep).
StopLossPoints
Abstand vom Einstiegspreis zur Stop-Loss-Order, ebenfalls gemessen in Preispunkten.
EnableTrailingStop
Aktiviert die Trailing-Stop-Logik.
TrailingStepPoints
Minimale Bewegung (in Punkten) erforderlich, bevor der Trailing Stop verschoben wird.
EnableBreakEven
Aktiviert die Break-Even-Regel, die den Stop nach ausreichendem Gewinn über/unter den Einstiegspunkt anhebt.
BreakEvenTriggerPoints
Zusätzlicher Gewinn (Punkte) erforderlich, bevor der Stop für die Gewinnschwelle verschoben wird.
PendingExpiryMinutes
Lebensdauer der ausstehenden Bestellungen in Minuten. 0 hält sie am Leben, bis sie gefüllt oder manuell abgebrochen werden.
VolumeMode
Wählt zwischen manueller Lautstärke und automatischer Größenanpassung.
RiskFactor
Von der automatischen Größenanpassung verwendeter Risikomultiplikator (spiegelt die Eingabe MQL wider).
ManualVolume
Feste Losgröße, die verwendet wird, wenn VolumeMode auf Manual gesetzt ist.
Unterschiede zur MT4-Version
Die automatische Volumenberechnung verwendet den Portfoliosaldo StockSharp und den Wertpapiervertragsmultiplikator. Verschiedene Makler
kann unterschiedliche Formeln verwenden, daher kann der resultierende Wert geringfügig von MetaTrader abweichen.
Schutzaufträge werden über StockSharp-Helfer erteilt und respektieren die Lautstärkestufe sowie die Mindest- und Höchstlautstärke des Veranstaltungsortes.
Der Ablauf wird innerhalb der Strategie implementiert (MetaTrader basiert auf dem serverseitigen Ablauf der Bestellung).
Nutzungshinweise
Konfigurieren Sie die Preisniveaus, bevor Sie mit der Strategie beginnen. Bei Werten gleich Null ist die entsprechende Bestellung deaktiviert.
Um die MT4-Logik „Ziffern“ zu imitieren, arbeiten die punktbasierten Parameter in Security.PriceStep-Einheiten.
Kombinieren Sie die Strategie mit den Portfolio- und Protokollierungstools von StockSharp, um ausstehende Aufträge und Schutzstopps zu überwachen.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// PricerEA strategy: Bollinger Bands mean reversion with RSI filter.
/// Buys at lower band when RSI is oversold, sells at upper band when overbought.
/// </summary>
public class PricerEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private int _candlesSinceTrade;
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 int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public PricerEaStrategy()
{
_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");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for adaptive band distance", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 8)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candlesSinceTrade = SignalCooldownCandles;
var sma = new SimpleMovingAverage { Length = BbPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, rsi, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sma, decimal rsi, decimal atr)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var bandDistance = atr * 2.5m;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (Position > 0 && (close >= sma || rsi >= 50))
{
SellMarket();
_candlesSinceTrade = 0;
}
else if (Position < 0 && (close <= sma || rsi <= 50))
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (Position == 0 && _candlesSinceTrade >= SignalCooldownCandles && close <= sma - bandDistance && rsi < 30)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (Position == 0 && _candlesSinceTrade >= SignalCooldownCandles && close >= sma + bandDistance && rsi > 70)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
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 SimpleMovingAverage, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class pricer_ea_strategy(Strategy):
def __init__(self):
super(pricer_ea_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._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period", "Indicators")
self._signal_cooldown = self.Param("SignalCooldownCandles", 8) \
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading")
self._sma = None
self._rsi = None
self._atr = None
self._candles_since_trade = 0
@property
def bb_period(self):
return self._bb_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def signal_cooldown(self):
return self._signal_cooldown.Value
def OnReseted(self):
super(pricer_ea_strategy, self).OnReseted()
self._sma = None
self._rsi = None
self._atr = None
self._candles_since_trade = self.signal_cooldown
def OnStarted2(self, time):
super(pricer_ea_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = self.bb_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._atr = AverageTrueRange()
self._atr.Length = self.atr_period
self._candles_since_trade = self.signal_cooldown
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._sma, self._rsi, self._atr, self._process_candle)
subscription.Start()
def _process_candle(self, candle, sma_value, rsi_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed or not self._rsi.IsFormed or not self._atr.IsFormed:
return
close = float(candle.ClosePrice)
sma_val = float(sma_value)
rsi_val = float(rsi_value)
atr_val = float(atr_value)
band_distance = atr_val * 2.5
if self._candles_since_trade < self.signal_cooldown:
self._candles_since_trade += 1
if self.Position > 0 and (close >= sma_val or rsi_val >= 50.0):
self.SellMarket()
self._candles_since_trade = 0
elif self.Position < 0 and (close <= sma_val or rsi_val <= 50.0):
self.BuyMarket()
self._candles_since_trade = 0
elif self.Position == 0 and self._candles_since_trade >= self.signal_cooldown and close <= sma_val - band_distance and rsi_val < 30.0:
self.BuyMarket()
self._candles_since_trade = 0
elif self.Position == 0 and self._candles_since_trade >= self.signal_cooldown and close >= sma_val + band_distance and rsi_val > 70.0:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return pricer_ea_strategy()