ScalpWiz 9001 ist ein mehrschichtiges Ausbruchs-Scalping-System, das das Verhalten des gleichnamigen MetaTrader-Experten repliziert. Die Strategie misst, wie weit die neueste Kerze über den Bollinger-Bänder-Umschlag hinausschließt und, wenn die Volatilität scharf expandiert, setzt sie ein Grid von ausstehenden Stop-Orders über oder unter dem Markt ein. Das originale Geldverwaltungsmodul wird beibehalten: Jede ausstehende Order kann entweder ein festes Lot oder einen konfigurierbaren Prozentsatz des Kontokapitals riskieren.
Sobald eine der Stop-Orders ausgeführt wird, werden die verbleibenden Orders storniert, während die aktive Position mit einem traditionellen Stop-Loss, Take-Profit und einer Trailing-Komponente geschützt wird, die erst nach dem Erreichen eines zusätzlichen Puffers mit dem Trailing beginnt. Die Strategie ist für Hochfrequenz-Scalping auf niedrigeren Zeitrahmen gedacht, kann aber auf jedem von StockSharp unterstützten Instrument ausgeführt werden.
Signallogik
Den konfigurierten Zeitrahmen abonnieren und 20-Perioden-Bollinger-Bänder mit dem Abweichungsfaktor BandsDeviation (Standard 2) berechnen.
Prüfen, wie weit der Schlusskurs vom oberen oder unteren Band entfernt ist. Wenn der Schluss das Band um mindestens den vierten Level-Abstand überschreitet (Level3Pips in Preis umgerechnet), bereitet sich die Strategie darauf vor, die Bewegung zu faden:
Schluss über dem oberen Band → Sell-Stop-Orders unterhalb des Marktes platzieren.
Schluss unter dem unteren Band → Buy-Stop-Orders oberhalb des Marktes platzieren.
Vier ausstehende Orders werden mit zunehmenden Abständen platziert (Level0Pips … Level3Pips). Jede Order verwendet entweder das feste Volumen oder den der Schicht zugewiesenen Risikoprozentsatz. Orders verfallen nach ExpirationMinutes, wenn sie unberührt bleiben.
Wenn eine Einstiegsorder ausgeführt wird, werden alle ausstehenden Orders storniert. Die ausgeführte Position wird mit Stop-Loss (StopLossPips), Take-Profit (TakeProfitPips) und Trailing-Parametern (TrailingStopPips, TrailingStepPips) verwaltet. Trailing bewegt den Schutz-Stop nur, wenn der Preis mindestens TrailingStopPips + TrailingStepPips vom Einstieg entfernt ist.
Ausstiege werden mit Marktorders ausgeführt, sobald der Trailing-Stop oder das Gewinnziel auf einer abgeschlossenen Kerze erreicht wird.
Parameter
Candle Type – Zeitrahmen für Bollinger-Berechnungen.
Bands Period / Bands Deviation – Bollinger-Konfiguration.
Stop Loss (pips) – Schutz-Stop-Abstand in Pips.
Take Profit (pips) – Gewinnziel-Abstand in Pips.
Trailing Stop (pips) – Trailing-Stop-Abstand, der der Bewegung nach dem Extra-Puffer folgt.
Trailing Step (pips) – Zusätzlicher Abstand, der vor der Aktivierung des Trailings erforderlich ist.
Expiration (minutes) – Lebensdauer ausstehender Stop-Orders. Auf 0 setzen, um Orders unbegrenzt zu halten.
Management Mode – Zwischen FixedVolume und RiskPercent wählen.
Level 0-3 Value – Festes Lot oder Risikoprozentsatz für jede ausstehende Schicht.
Level 0-3 Pips – Einstiegsoffsets für jede ausstehende Schicht.
Geldverwaltung
Wenn ManagementMode gleich RiskPercent ist, berechnet die Strategie das Ordervolumen aus dem Kontokapital und dem konfigurierten Stop-Loss-Abstand:
Wenn Markt-Metadaten (Preisschritt, Schrittpreis oder Volumenschritt) nicht verfügbar sind, fällt die Ordergröße aus Sicherheitsgründen auf null zurück. Mit FixedVolume werden die Schichtwerte direkt verwendet und auf den Instrumenten-Volumenschritt und -grenzen gerundet.
Trailing und Schutz
Stop-Loss und Take-Profit werden mit Pip-Abständen relativ zum tatsächlichen Ausführungspreis initialisiert.
Die Trailing-Logik spiegelt die MetaTrader-Implementierung wider: Der Stop wird erst bewegt, wenn der Preis TrailingStop + TrailingStep vorrückt, und hält danach einen Abstand von TrailingStop.
Ausstiege werden als Marktorders ausgegeben, was die Kompatibilität mit Handelsplätzen sicherstellt, die keine serverseitigen Schutzorders unterstützen.
Praktische Hinweise
Die Pip-Abstände entsprechend der Tick-Größe des Instruments konfigurieren. Bei fünfstelligen FX-Symbolen entspricht jeder Pip zehn Preisschritten und die Strategie passt sich automatisch durch Inspektion der Wertpapier-Dezimalstellen an.
Da die Strategie von Stop-Orders abhängt, broker-spezifische Stop-Level-Anforderungen prüfen und Level-Abstände bei Bedarf anpassen.
Risikoprozent-Sizing erfordert eine gültige Portfolio-Bewertung und Sicherheitsschritt-Metadaten; andernfalls wird das Ordervolumen zu null ausgewertet.
Die Strategie operiert auf abgeschlossenen Kerzen und reagiert daher einmal pro Balken, was das Rauschen im Vergleich zum ursprünglichen tick-basierten Experten glättet.
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;
/// <summary>
/// Bollinger Bands breakout scalping strategy.
/// Buys when price breaks below lower band (mean reversion) and sells when price breaks above upper band.
/// Uses stop-loss and take-profit for risk management.
/// </summary>
public class ScalpWiz9001Strategy : Strategy
{
private readonly StrategyParam<int> _bandsPeriod;
private readonly StrategyParam<decimal> _bandsDeviation;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _takeProfitPips;
private BollingerBands _bollinger;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Bollinger Bands lookback period.
/// </summary>
public int BandsPeriod
{
get => _bandsPeriod.Value;
set => _bandsPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BandsDeviation
{
get => _bandsDeviation.Value;
set => _bandsDeviation.Value = value;
}
/// <summary>
/// Stop loss distance in price steps.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take profit distance in price steps.
/// </summary>
public int TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public ScalpWiz9001Strategy()
{
_bandsPeriod = Param(nameof(BandsPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bands Period", "Bollinger Bands period", "Indicator");
_bandsDeviation = Param(nameof(BandsDeviation), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Bands Deviation", "Bollinger Bands deviation", "Indicator");
_stopLossPips = Param(nameof(StopLossPips), 100)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 150)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bollinger = null;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bollinger = new BollingerBands
{
Length = BandsPeriod,
Width = BandsDeviation
};
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.BindEx(_bollinger, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var bb = (BollingerBandsValue)value;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower)
return;
if (!_bollinger.IsFormed)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
// Check SL/TP for existing positions
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPips > 0 && close <= _entryPrice - StopLossPips * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 5;
return;
}
if (TakeProfitPips > 0 && close >= _entryPrice + TakeProfitPips * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 5;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPips > 0 && close >= _entryPrice + StopLossPips * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 5;
return;
}
if (TakeProfitPips > 0 && close <= _entryPrice - TakeProfitPips * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 5;
return;
}
}
// Entry signals
if (Position == 0)
{
// Buy when price touches lower band (mean reversion up)
if (close <= lower)
{
BuyMarket();
_entryPrice = close;
_cooldown = 5;
}
// Sell when price touches upper band (mean reversion down)
else if (close >= upper)
{
SellMarket();
_entryPrice = close;
_cooldown = 5;
}
}
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class scalp_wiz9001_strategy(Strategy):
def __init__(self):
super(scalp_wiz9001_strategy, self).__init__()
self._bands_period = self.Param("BandsPeriod", 20) \
.SetDisplay("Bands Period", "Bollinger Bands period", "Indicator")
self._bands_deviation = self.Param("BandsDeviation", 1.5) \
.SetDisplay("Bands Deviation", "Bollinger Bands deviation", "Indicator")
self._stop_loss_pips = self.Param("StopLossPips", 100) \
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 150) \
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk")
self._bollinger = None
self._entry_price = 0.0
self._cooldown = 0
@property
def bands_period(self):
return self._bands_period.Value
@property
def bands_deviation(self):
return self._bands_deviation.Value
@property
def stop_loss_pips(self):
return self._stop_loss_pips.Value
@property
def take_profit_pips(self):
return self._take_profit_pips.Value
def OnReseted(self):
super(scalp_wiz9001_strategy, self).OnReseted()
self._bollinger = None
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(scalp_wiz9001_strategy, self).OnStarted2(time)
self._bollinger = BollingerBands()
self._bollinger.Length = self.bands_period
self._bollinger.Width = self.bands_deviation
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.BindEx(self._bollinger, self._process_candle).Start()
def _process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
upper = bb_value.UpBand
lower = bb_value.LowBand
if upper is None or lower is None:
return
if not self._bollinger.IsFormed:
return
if self._cooldown > 0:
self._cooldown -= 1
return
close = float(candle.ClosePrice)
upper_val = float(upper)
lower_val = float(lower)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
sl_pips = self.stop_loss_pips
tp_pips = self.take_profit_pips
# Check SL/TP for existing long position
if self.Position > 0 and self._entry_price > 0:
if sl_pips > 0 and close <= self._entry_price - sl_pips * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 5
return
if tp_pips > 0 and close >= self._entry_price + tp_pips * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 5
return
elif self.Position < 0 and self._entry_price > 0:
if sl_pips > 0 and close >= self._entry_price + sl_pips * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 5
return
if tp_pips > 0 and close <= self._entry_price - tp_pips * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 5
return
# Entry signals
if self.Position == 0:
if close <= lower_val:
self.BuyMarket()
self._entry_price = close
self._cooldown = 5
elif close >= upper_val:
self.SellMarket()
self._entry_price = close
self._cooldown = 5
def CreateClone(self):
return scalp_wiz9001_strategy()