Diese Strategie reproduziert das Verhalten des ursprünglichen MetaTrader-Experten stochSell. Sie hört auf einen einzelnen Kerzenstream und wartet auf eine dreifache stochastische Bestätigung kombiniert mit einem Volatilitätsfilter, bevor eine anfängliche Market-Sell-Order gesendet wird. Unmittelbar nach dem Short-Einstieg wird eine Leiter ausstehender Sell-Stops eingesetzt, um die Bewegung zu skalieren, wenn der Preis weiter fällt.
Handelslogik
Volatilitätsfilter – eine Average True Range (ATR) mit konfigurierbarer Länge muss unter dem angegebenen Schwellenwert bleiben.
Langsame stochastische Bestätigung – der längste stochastische Oszillator muss unter dem langfristigen Überverkauf-Niveau bleiben, bevor Trades erlaubt sind.
Kreuzungsbestätigung – sowohl der mittlere als auch der schnelle stochastische Oszillator müssen während derselben abgeschlossenen Kerze durch den Überverkauf-Trigger nach unten kreuzen.
Positionsprüfung – neue Einstiege werden nur dann platziert, wenn die Strategie keine aktiven Orders hat und die Position flat ist.
Sobald alle Bedingungen erfüllt sind, sendet die Strategie eine Market-Sell-Order mit dem konfigurierten Volumen und plant sofort eine Reihe von Sell-Stop-Orders gemäß den Grid-Einstellungen. Ausstehende Orders sind optional und können deaktiviert werden, indem der Grid-Order-Zähler auf null gesetzt wird.
Ausstiegsregeln
Gewinnziel – wenn der Short-Korb den gewünschten Gewinn in Pips akkumuliert (berechnet aus dem volumengewichteten Einstiegspreis), kauft die Strategie die gesamte Position zurück und entfernt alle verbleibenden ausstehenden Orders.
Manueller Stop – Grid-Orders respektieren eine konfigurierbare Lebensdauer. Wenn eine Stop-Order ohne Ausführung abläuft, wird sie automatisch storniert.
Vollständiges Schließen – jeder Kauftrade, der die Position auf null zurückbringt, löscht die internen Einstiegsstatistiken und storniert das ausstehende Grid.
Grid-Verwaltung
Ausstehende Orders werden unterhalb des Referenzpreises mit dem Start-Offset und Schritt in Pips platziert.
Jede ausstehende Order verwendet den Grid-Volumen-Multiplikator, wodurch die Korbgröße vom anfänglichen Market-Einstieg abweichen kann.
Die Ablaufzeit (in Minuten) wird auf jede ausstehende Order angewendet; null deaktiviert das Timeout.
Parameter
Name
Beschreibung
CandleType
Primärer Zeitrahmen für jeden Indikator und jede Handelsentscheidung.
AtrPeriod / AtrThreshold
Volatilitätsfilter, der steuert, wann die Strategie handeln darf.
FastKPeriod, FastDPeriod, FastSlowing
Konfiguration des schnellen stochastischen Oszillators.
MediumKPeriod, MediumDPeriod, MediumSlowing
Konfiguration des mittleren stochastischen Oszillators.
SlowKPeriod, SlowDPeriod, SlowSlowing
Konfiguration des langsamen stochastischen Oszillators.
OversoldLevel
Niveau, durch das die schnellen und mittleren stochastischen Werte nach unten kreuzen müssen.
LongTermOversoldLevel
Obere Grenze für den langsamen Stochastik beim Einstieg.
ProfitTargetPips
Nettogewinn in Pips zum Schließen des Short-Korbs.
GridOrdersCount
Anzahl der nach dem Einstieg erstellten ausstehenden Sell-Stops.
GridStartOffsetPips
Offset in Pips zwischen Einstiegspreis und erster ausstehender Order.
GridStepPips
Abstand in Pips zwischen aufeinanderfolgenden ausstehenden Orders.
GridVolume
Volumen für jede ausstehende Order.
GridExpirationMinutes
Lebensdauer ausstehender Orders in Minuten.
MarketVolume
Volumen für den anfänglichen Market-Verkauf.
Hinweise
Indikatorwerte werden über die High-Level-BindEx-API verarbeitet und nur fertige Kerzen lösen Handelsentscheidungen aus.
Die Positionsverfolgungslogik hält einen volumengewichteten Einstiegspreis, um das Rohgewinnziel in Pips zu übersetzen.
Um die Skalierung zu deaktivieren, setzen Sie den Grid-Order-Zähler einfach auf null; die Strategie verlässt sich dann immer noch auf die stochastische Bestätigung und den ATR-Filter für einzelne Trades.
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 StochSellStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public StochSellStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class stoch_sell_strategy(Strategy):
def __init__(self):
super(stoch_sell_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(stoch_sell_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(stoch_sell_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return stoch_sell_strategy()