Diese Strategie portiert den 1 MINUTE SCALPER MetaTrader 4 Expert Advisor in die StockSharp High-Level-API. Sie behält die
mehrschichtige Trendbestätigung, das Multi-Timeframe-Momentum und den Langzeit-MACD-Filter des Original-Roboters bei, während
die Risikokontrollen an StockSharp's positionszentriertes Modell angepasst werden.
Kernlogik
Trend-Stack – dreizehn linear gewichtete gleitende Durchschnitte (LWMA 3/5/8/10/12/15/30/35/40/45/50/55/200) müssen in
strenger Reihenfolge ausgerichtet sein. Long-Trades erfordern, dass jeder kürzere Durchschnitt über dem nächsten liegt,
während Shorts die Bedingung umkehren.
Primäres Trend-Gate – ein zusätzlicher schneller LWMA (Standard 6) muss für Longs über dem langsamen LWMA (Standard 85)
bleiben und für Shorts darunter, was die schnell-vs-langsam-Prüfung des EA widerspiegelt.
Kerzenstruktur – Einträge werden nur ausgelöst, wenn die Überlappungsmuster aus dem Skript vorhanden sind: Für Longs muss
das Tief vor zwei Bars unter dem vorherigen Hoch liegen, für Shorts muss das vorherige Tief unter dem Hoch von vor zwei Bars
fallen.
Momentum-Filter – ein 14-Perioden-Momentum-Indikator, berechnet auf einem höheren Zeitrahmen (Standard 15-Minuten-
Kerzen), muss bei mindestens einem der letzten drei Werte um mindestens die konfigurierten Schwellenwerte von 100 abweichen.
Dies reproduziert die MomLevelB/MomLevelS-Vergleiche.
Monatlicher MACD-Bias – ein MACD, der auf dem ausgewählten MACD-Zeitrahmen aufgebaut ist (standardmäßig 30-Tage-Kerzen
als Proxy für monatliche Daten), muss die Hauptlinie über der Signallinie für Longs oder darunter für Shorts zeigen.
Trade-Management
Anfangsschutz – Stop-Loss- und Take-Profit-Abstände werden in Instrument-Schritten (Punkten) ausgedrückt. Wenn eine
Position öffnet, wandelt die Strategie diese Schrittzählungen in absolute Preise um, indem sie Security.PriceStep verwendet.
Break-Even-Bewegung – nachdem sich der Preis um BreakEvenTriggerSteps zugunsten bewegt hat, wird der Stop auf den
Einstieg plus BreakEvenOffsetSteps verschoben (für Shorts gilt die gespiegelte Logik). Das Flag wird einmal pro Position
ausgelöst.
Schritt-Trailing – wenn TrailingStopSteps positiv ist, folgt der Stop dem höchsten (oder niedrigsten) Preis seit dem
Einstieg um die angegebene Anzahl von Schritten.
Geld-Trailing – sobald der schwebende Gewinn MoneyTrailTarget (Währung) überschreitet, verfolgt die Strategie den
Spitzen-PnL und schließt die Position, wenn der Rückgang MoneyTrailStop entspricht.
Geld-/Prozentziele – optionale absolute oder prozentuale Take-Profit-Ziele schließen alle Positionen, wenn der schwebende
PnL die konfigurierten Schwellenwerte überschreitet. Das Prozentziel verwendet den beim Start der Strategie erfassten
Anfangs-Portfoliowert.
Eigenkapital-Stop – die Strategie überwacht das maximale Eigenkapital (Portfoliowert plus offener PnL). Wenn der Drawdown
von diesem Höchststand EquityRiskPercent überschreitet, werden alle Positionen abgebaut und die AccountEquityHigh()-
Schutzmaßnahme des EA repliziert.
Parameter
Parameter
Beschreibung
Volume
Ordervolumen für neue Einträge. Wird zur absoluten aktuellen Position hinzugefügt, sodass Umkehrungen die Exposition sofort wechseln.
FastMaPeriod / SlowMaPeriod
LWMA-Längen für den primären Trendfilter.
MomentumPeriod
Länge des Momentum-Indikators auf höherem Zeitrahmen.
MomentumBuyThreshold / MomentumSellThreshold
Minimale absolute Abweichung von 100, die für Long-/Short-Momentum-Bestätigung erforderlich ist.
Trailing-Logik für den schwebenden Gewinn konfigurieren.
UseEquityStop, EquityRiskPercent
Drawdown-Stop aktivieren und den maximalen Drawdown-Prozentsatz definieren.
CandleType
Primäre Arbeitskerzen (Standard 1 Minute).
MomentumCandleType
Kerzen auf höherem Zeitrahmen für den Momentum-Indikator (Standard 15 Minuten).
MacdCandleType
Kerzen für den MACD-Trendfilter (Standard 30 Tage ≈ monatlich).
Unterschiede zum MT4-Expert
StockSharp verwendet Nettopositionen, daher pflegt die Strategie immer eine einzelne aggregierte Position anstelle mehrerer
Tickets bis zu Max_Trades. Umkehrungen schließen das bestehende Exposure, bevor sie in die entgegengesetzte Richtung öffnen.
PercentTakeProfit bezieht sich auf den beim Start erfassten Portfoliowert statt des sich ständig ändernden
AccountBalance(), das MetaTrader verwendet, was geräuschvolle Ziele vermeidet, wenn externe Trades das Guthaben ändern.
Die geldbasierte Ausstiegslogik (Take_Profit_In_Money und TRAIL_PROFIT_IN_MONEY2) arbeitet mit dem Live-PnL, der aus dem
durchschnittlichen Eintrittspreis der Strategie berechnet wird. Dies entspricht dem EA-Verhalten, aber innerhalb des
StockSharp-Schutzrahmens.
Die Plattform muss Kerzen-Feeds für die ausgewählten Zeitrahmen liefern (CandleType, MomentumCandleType,
MacdCandleType). Stellen Sie sicher, dass die verwendeten Adapter die angeforderten Auflösungen unterstützen.
Stimmen Sie die Schwellenwerte auf Ihr Instrument und Ihre Session ab. Enge Spreads oder hochvolatile Paare können breitere
Schrittabstände oder größere Momentum-Schwellenwerte erfordern, um Rauschen zu reduzieren.
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>
/// One-minute scalper strategy using fast/slow WMA crossover.
/// Buys on bullish crossover, sells on bearish crossover.
/// </summary>
public class OneMinuteScalperStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private WeightedMovingAverage _fast;
private WeightedMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Fast WMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow WMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="OneMinuteScalperStrategy"/> class.
/// </summary>
public OneMinuteScalperStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast WMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 85)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow WMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit 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();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new WeightedMovingAverage { Length = FastPeriod };
_slow = new WeightedMovingAverage { 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;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// WMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 60;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 60;
}
_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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class one_minute_scalper_strategy(Strategy):
def __init__(self):
super(one_minute_scalper_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20).SetGreaterThanZero().SetDisplay("Fast Period", "Fast WMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 85).SetGreaterThanZero().SetDisplay("Slow Period", "Slow WMA period", "Indicator")
self._sl_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 500).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
def OnReseted(self):
super(one_minute_scalper_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
def OnStarted2(self, time):
super(one_minute_scalper_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
self._fast = WeightedMovingAverage()
self._fast.Length = self._fast_period.Value
self._slow = WeightedMovingAverage()
self._slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(tf(5))
sub.Bind(self._fast, self._slow, self.OnProcess).Start()
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
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 = candle.ClosePrice
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
step = float(self.Security.PriceStep)
# Check SL/TP
if self.Position > 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close <= self._entry_price - self._sl_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close >= self._entry_price + self._tp_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close >= self._entry_price + self._sl_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close <= self._entry_price - self._tp_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
# WMA crossover
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 = 60
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 = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return one_minute_scalper_strategy()