Killer Sell 2.0 ist ein reiner Short-MetaTrader-4-Expertenberater, der Einstiege nach ausgedehnten überkauften Readings timed und Gewinne sichert, wenn der Momentum in überverkauftes Gebiet schwenkt. Dieser Port schreibt die ursprüngliche Logik auf Basis der StockSharp High-Level-Strategie-API um. Die gesamte Indikatorverarbeitung ist ereignisgesteuert über SubscribeCandles().BindEx(...), und Money-Management-Regeln sind innerhalb der Strategieklasse gekapselt.
Handelslogik
Die konvertierte Logik folgt der ursprünglichen Signalkette und verwendet das Nettopositionsmodell von StockSharp. Jede abgeschlossene Kerze des konfigurierten Zeitrahmens führt folgende Schritte aus:
Datenvorbereitung. Die Strategie aktualisiert einen MACD (12/120/9), Williams %R (Periode 350 für beide Filter) und zwei Stochastik-Oszillatoren (10/1/3 für Einstieg, 90/7/1 für Ausstiege). Indikatorwerte werden nur konsumiert, wenn der neue Balken fertig und die Eingaben vollständig gebildet sind.
Einstiegsfilter. Ein Short-Setup ist gültig, wenn alle folgenden Bedingungen erfüllt sind:
Williams %R steigt über −10, was einen überkauften Markt signalisiert.
Die MACD-Hauptlinie ist größer als 0.0014.
Der Einstiegs-Stochastik %K kreuzt unter das konfigurierbare Einstiegsniveau (Standard 90). Die Kreuzungserkennung erfolgt auf aufeinanderfolgenden %K-Lesungen.
Orderplatzierung. Sobald die Filter übereinstimmen, sendet die Strategie einen Marktverkauf mit der aktuellen Martingale-Lot-Größe. Orders erhalten einen Take-Profit N Pips entfernt (Standard 100 Pips) über StartProtection.
Ausstiegsverwaltung. Während ein Short-Exposure besteht, berechnet die Strategie das arithmetische Mittel des Gewinns offener Tickets in Pips. Abhängig vom Momentum:
Wenn der durchschnittliche Gewinn unter 10 Pips liegt und Williams %R unter −80 fällt, werden alle Shorts sofort geschlossen.
Wenn der durchschnittliche Gewinn über 15 Pips liegt und der Exit-Stochastik %K unter 12 fällt, wird die Position zur Gewinnmitnahme geschlossen.
Money Management
Killer Sell 2.0 verwendet eine Martingale-Leiter ähnlich dem originalen EA. Die StockSharp-Implementierung führt eine interne Liste offener Short-Lots, um die Per-Ticket-Berechnungen von MetaTrader nachzuahmen:
Der erste Trade verwendet InitialVolume (Standard 0.05 Lots).
Nach einem profitablen oder Breakeven-Zyklus wird das Volumen auf die anfängliche Lot-Größe zurückgesetzt.
Nach einem Verlustzyklus wird der nächste Auftrag mit MartingaleMultiplier (Standard ×1.2) multipliziert. Ein Sicherheitsdeckel MaxVolume verhindert unkontrolliertes Wachstum.
Der Helfer verfolgt auch realisiertes PnL bei Fills, um zu entscheiden, ob der vorherige Zyklus profitabel war.
Parameter
Parameter
Beschreibung
CandleType
Primärer Zeitrahmen, der jeden Indikator versorgt.
EntryWprPeriod / ExitWprPeriod
Williams %R-Längen für Einstiegs- und Ausstiegsbestätigungen.
Überverkaufte Grenze, die vor Gewinnmitnahme geprüft wird.
EntryWprThreshold / ExitWprThreshold
Williams %R-Schwellenwerte für Einstiege/Ausstiege.
LossExitPips / ProfitExitPips
Durchschnittliche Gewinngrenzen (in Pips) für defensive und Zielausstiege.
TakeProfitPips
Schützender Take-Profit für jede Verkaufsorder.
InitialVolume
Volumen des ersten Martingale-Schritts.
MartingaleMultiplier
Faktor nach Verlusten.
MaxVolume
Absolutes Cap für die nächste Lot-Größe.
Konvertierungshinweise
MetaTrader führt einzelne Tickets; StockSharp arbeitet mit einer Nettoposition. Die Strategie speichert daher jeden gefüllten Short (Volumen + Preis), um durchschnittliche Gewinnberechnungen zu reproduzieren und Martingale-Resets zu evaluieren.
Der MT4-"Martingale"-Block exponierte viele zusätzliche Modi (fest, prozentuales Risiko, 1326, Fibonacci usw.). Die ursprüngliche Konfiguration verwendete den einfachen Martingale-Zweig; nur dieses Verhalten wird hier repliziert.
Der Notfall-Stop-Loss war im Quellprojekt deaktiviert. Der Port spiegelt diese Einrichtung, indem nur ein Take-Profit angehängt und andere Ausstiege intern behandelt werden.
Verwendungstipps
Fügen Sie die Strategie einem Portfolio und Wertpapier hinzu, dann setzen Sie denselben Zeitrahmen wie in den MT4-Backtests (die Standardwerte gehen von H1 aus).
Stellen Sie sicher, dass Marktdaten abgeschlossene Kerzen liefern; Indikatoren verlassen sich auf CandleStates.Finished-Ereignisse.
Überprüfen Sie die Kontohebel und erlaubten Lot-Größen. Der Standard-Martingale-Deckel (5 Lots) sollte an Ihre Broker-Anforderungen angepasst werden.
Testen Sie gründlich — Martingale-Strategien verstärken das Risiko, wenn Märkte stark gegen den Short-Bias tendieren.
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 KillerSell20Strategy : 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 KillerSell20Strategy()
{
_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 killer_sell20_strategy(Strategy):
def __init__(self):
super(killer_sell20_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(killer_sell20_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(killer_sell20_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 killer_sell20_strategy()