Diese Strategie ist eine C#-Konvertierung des MetaTrader 5 Expert Advisors "SimpleTrade (barabashkakvns Edition)". Sie vergleicht den Eröffnungspreis der aktuellen Bar mit dem Eröffnungspreis drei Bars zuvor. Wenn das aktuelle Open höher ist, geht die Strategie long; andernfalls geht sie short. Jede Position wird nur eine abgeschlossene Kerze lang gehalten und mit einer festen Stop-Loss-Distanz in Pips abgesichert.
Die StockSharp-Implementierung abonniert die ausgewählte Kerzenserie über die High-Level-API und reagiert nur auf abgeschlossene Bars, um sicherzustellen, dass Entscheidungen auf abgeschlossenen Preisdaten basieren. Positionen werden beim nächsten Bar-Übergang oder früher geschlossen, wenn das Stop-Level innerhalb der Bar-Range berührt wird.
Handelslogik
Einstieg
Bei jeder abgeschlossenen Bar den Eröffnungspreis speichern und eine rollende Geschichte der letzten vier Opens pflegen.
Wenn keine offene Position vorhanden ist und mindestens vier Eröffnungspreise verfügbar sind, das neueste Open mit dem vor drei Bars aufgezeichneten vergleichen.
Eine Long-Position eingehen, wenn das aktuelle Open über dem Open drei Bars zuvor liegt; andernfalls eine Short-Position eingehen.
Ausstieg
Jeder Trade ist durch ein Stop-Level geschützt, das als StopLossPips × Pip-Größe vom Einstiegs-Eröffnungspreis berechnet wird.
Auf der folgenden Bar wird die Position unabhängig vom Ergebnis geschlossen, um den ursprünglichen Expert Advisor zu replizieren, der einen Trade nie länger als eine Kerze hält.
Wenn das Bar-High (für Shorts) oder Low (für Longs) das Stop-Level durchdringt, versucht die Strategie, die Position sofort zum Marktpreis zu schließen.
Parameter
Parameter
Standard
Beschreibung
StopLossPips
120
Abstand vom Einstiegs-Eröffnungspreis zum Schutz-Stop, gemessen in Pips. Der Code reproduziert das MetaTrader-Verhalten, indem er den Preisschritt für Symbole mit 3 oder 5 Dezimalstellen mit 10 multipliziert.
TradeVolume
1
Order-Volumen für Market-Einstiege. Anpassen, um mit der Kontraktgröße des gehandelten Instruments übereinzustimmen.
CandleType
1-Stunden-Zeitrahmen
Gibt an, welche Kerzenserie die Strategie abonniert. Den Zeitrahmen wählen, der dem in MetaTrader verwendeten Chart entspricht.
Alle Parameter sind als StrategyParam<T>-Objekte exponiert, damit sie über die grafische Benutzeroberfläche optimiert oder geändert werden können.
Implementierungshinweise
Die rollende Geschichte von vier Eröffnungspreisen wird ohne Sammlungen gepflegt, um den Repository-Richtlinien zu entsprechen.
Stops werden nicht als separate Orders eingereicht; stattdessen prüft die Logik die Kerzen-Ranges und gibt einen Market-Ausstieg aus, wenn das Stop-Level ausgelöst worden wäre.
Da StockSharp Positionen asynchron verarbeitet, verlässt die Strategie einen bestehenden Trade, bevor ein neues Einstiegssignal ausgewertet wird. Im Live-Trading entspricht dies der ursprünglichen "Schließen dann Wiederöffnen"-Sequenz und vermeidet gleichzeitig überlappende Orders.
Die Pip-Größe wird von Security.PriceStep abgeleitet. Bei 5- oder 3-stelligen Symbolen wird der Schritt mit zehn multipliziert, damit ein Pip der MetaTrader-Definition entspricht.
Verwendungstipps
Die Strategie auf Instrumenten mit konsistenten Tick-Größen ausführen, wo pip-basierte Stops sinnvoll sind (z.B. wichtige Forex-Paare).
Den StopLossPips-Wert pro Instrument optimieren; große Werte erweitern den Schutzpuffer, während kleinere Werte die Strategie empfindlicher für Intrabar-Rauschen machen.
Sicherstellen, dass die Broker-Verbindung Kerzen-Updates mit endgültigen Zuständen sendet, damit die Strategie die korrekten Eröffnungspreise erhält.
Risiken und Einschränkungen
Trades nur eine Bar lang zu halten bedeutet, dass die Strategie stark vom gewählten Zeitrahmen abhängt. Backtesting verschiedener Kerzen-Dauern ist unerlässlich.
Die Verwendung von Kerzen-Extremen zur Emulation von Stop-Ausführungen führt in volatilen Märkten im Vergleich zu nativen Stop-Orders zu Slippage.
Die Strategie bleibt nach den ersten vier Datenbars immer im Markt (entweder long oder short), was in Seitwärtsmärkten häufige Trades erzeugen kann.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simple trade strategy converted from MetaTrader that compares the current open with the open three bars ago.
/// The logic holds positions for a single bar and protects the trade with a fixed stop distance.
/// </summary>
public class SimpleTradeStrategy : Strategy
{
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<decimal> _tradeVolume;
private readonly StrategyParam<DataType> _candleType;
private decimal _openCurrent;
private decimal _openMinus1;
private decimal _openMinus2;
private decimal _openMinus3;
private int _historyCount;
private decimal? _stopPrice;
/// <summary>
/// Stop loss distance expressed in pips.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Trade volume used for market orders.
/// </summary>
public decimal TradeVolume
{
get => _tradeVolume.Value;
set => _tradeVolume.Value = value;
}
/// <summary>
/// Candle type processed by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="SimpleTradeStrategy"/> parameters.
/// </summary>
public SimpleTradeStrategy()
{
_stopLossPips = Param(nameof(StopLossPips), 120)
.SetGreaterThanZero()
.SetDisplay("Stop Loss (pips)", "Fixed protective distance in pips", "Risk Management")
;
_tradeVolume = Param(nameof(TradeVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Order volume in lots", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Primary candle source for decisions", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_openCurrent = 0m;
_openMinus1 = 0m;
_openMinus2 = 0m;
_openMinus3 = 0m;
_historyCount = 0;
_stopPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Exit existing trades before evaluating new entries to mimic the original MQL behaviour.
if (TryCloseExistingPosition(candle))
return;
UpdateHistory(candle.OpenPrice);
// Need at least four opens to compare with the value three bars ago.
if (_historyCount < 4)
return;
ExecuteEntry(candle);
}
private bool TryCloseExistingPosition(ICandleMessage candle)
{
if (Position > 0)
{
var volume = Position;
// Close long trades at the protective stop or at the bar change.
if (_stopPrice is decimal stop && candle.LowPrice <= stop)
{
SellMarket();
}
else
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
}
_stopPrice = null;
return true;
}
if (Position < 0)
{
var volume = Math.Abs(Position);
// Close short trades at the protective stop or at the bar change.
if (_stopPrice is decimal stop && candle.HighPrice >= stop)
{
BuyMarket();
}
else
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
}
_stopPrice = null;
return true;
}
return false;
}
private void UpdateHistory(decimal currentOpen)
{
// Shift the stored opens so that _openMinus3 keeps the value three candles back.
_openMinus3 = _openMinus2;
_openMinus2 = _openMinus1;
_openMinus1 = _openCurrent;
_openCurrent = currentOpen;
if (_historyCount < 4)
_historyCount++;
}
private void ExecuteEntry(ICandleMessage candle)
{
var pipSize = CalculatePipSize();
var stopOffset = pipSize * StopLossPips;
// Enter long when the current open is above the open three bars ago, otherwise enter short.
if (_openCurrent > _openMinus3)
{
BuyMarket();
_stopPrice = candle.OpenPrice - stopOffset;
}
else
{
SellMarket();
_stopPrice = candle.OpenPrice + stopOffset;
}
}
private decimal CalculatePipSize()
{
// Reproduce the MetaTrader adjustment: multiply by ten for symbols with 3 or 5 decimals.
var step = Security?.PriceStep ?? 1m;
var decimals = Security?.Decimals;
if (decimals == 3 || decimals == 5)
step *= 10m;
return step;
}
}
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
class simple_trade_strategy(Strategy):
def __init__(self):
super(simple_trade_strategy, self).__init__()
self._sl_pips = self.Param("StopLossPips", 120)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(simple_trade_strategy, self).OnReseted()
self._opens = []
self._stop_price = None
def OnStarted2(self, time):
super(simple_trade_strategy, self).OnStarted2(time)
self._opens = []
self._stop_price = None
self._pip_size = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
self._pip_size = float(self.Security.PriceStep)
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.OnProcess).Start()
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
# Close existing position first (hold only 1 bar)
if self.Position > 0:
if self._stop_price is not None and float(candle.LowPrice) <= self._stop_price:
self.SellMarket()
else:
self.SellMarket()
self._stop_price = None
self._update_opens(float(candle.OpenPrice))
return
elif self.Position < 0:
if self._stop_price is not None and float(candle.HighPrice) >= self._stop_price:
self.BuyMarket()
else:
self.BuyMarket()
self._stop_price = None
self._update_opens(float(candle.OpenPrice))
return
self._update_opens(float(candle.OpenPrice))
if len(self._opens) < 4:
return
open_current = self._opens[-1]
open_minus3 = self._opens[-4]
stop_offset = self._pip_size * self._sl_pips.Value
if open_current > open_minus3:
self.BuyMarket()
self._stop_price = float(candle.OpenPrice) - stop_offset
else:
self.SellMarket()
self._stop_price = float(candle.OpenPrice) + stop_offset
def _update_opens(self, val):
self._opens.append(val)
if len(self._opens) > 5:
self._opens.pop(0)
def CreateClone(self):
return simple_trade_strategy()