Die Crypto-SR-Strategie portiert den MetaTrader-4-Expert-Advisor "Crypto S&R" auf die StockSharp-High-Level-API. Die Implementierung behält die gestaffelte Bestätigungslogik des ursprünglichen Systems bei: einen Trendfilter auf Basis linear gewichteter gleitender Durchschnitte (LWMA), eine Momentum-Prüfung auf höherem Zeitrahmen, einen langfristigen MACD-Trendfilter und aus Fraktalen abgeleitete Unterstützungs-/Widerstandsniveaus. Orders werden per Marktausführung gesendet, und die Position wird über feste Stop-Loss-/Take-Profit-Niveaus, Break-even-Anpassungen und einen in Pips gemessenen Trailing Stop verwaltet.
Handelslogik
Analyse des primären Zeitrahmens: Die Strategie abonniert die konfigurierte Kerzenserie und speist zwei LWMAs mit dem typischen Kerzenpreis (high + low + close) / 3. Die schnelle LWMA muss über (unter) der langsamen LWMA liegen, um Longs (Shorts) zu erlauben.
Momentum auf höherem Zeitrahmen: Ein Momentum-Indikator wird auf einer zweiten Kerzenserie ausgewertet. Die absolute Entfernung der letzten drei Momentum-Werte vom neutralen Wert (100) muss die Kauf-/Verkaufsschwellen überschreiten.
Langfristiger MACD-Filter: Die Strategie hört auf einen weiteren Kerzenstrom, in dem ein MACD (12, 26, 9) berechnet wird. Long-Positionen erfordern, dass die MACD-Linie über ihrem Signal bleibt; Short-Positionen benötigen sie darunter. Der langfristige Standardzeitrahmen ist täglich, um die vom EA verwendete Monatsserie anzunähern; er kann angepasst werden, wenn echte Monatskerzen verfügbar sind.
Fraktale Unterstützung/Widerstand: Fertige Kerzen werden in einem rollierenden Puffer gespeichert. Wenn das klassische Bill-Williams-Fraktalmuster (zwei Nachbarn auf jeder Seite) erscheint, wird das entsprechende Hoch/Tief zum aktiven Widerstands- oder Unterstützungsniveau. Um das Niveau wird ein konfigurierbarer Pip-Puffer gelegt, um die horizontalen Linien des ursprünglichen Experten nachzubilden.
Einstiegsregeln:
Kauf: keine offene Long-Position, schnelle LWMA über langsamer LWMA, Momentum-Abweichung >= Kaufschwelle, bullischer MACD, die aktuelle Kerze testet die gepufferte Unterstützung und schließt über dem vorherigen Schlusskurs.
Verkauf: gespiegelte Bedingungen mit Widerstandsniveau, Momentum-Verkaufsschwelle und bärischer MACD-Bestätigung.
Risikomanagement: Jede neue Position erhält einen anfänglichen Stop-Loss und Take-Profit in Pips. Break-even-Logik kann den Stop verschieben, sobald die Triggerdistanz erreicht ist, während ein optionaler Trailing Stop dem Preis über Kerzenhochs/-tiefs folgt. Long-/Short-Exposure wird geschlossen, wenn der MACD-Filter gegen den Trade dreht.
Implementierungshinweise
Der monatliche MACD-Filter der MetaTrader-Version wird standardmäßig mit einer Tagesserie angenähert, weil StockSharp keine Kalendermonatskerzen direkt bereitstellt. Benutzer können zu einem eigenen Monatsaggregator wechseln, wenn die Datenquelle dies unterstützt.
Orders werden mit Marktanfragen geschlossen, wenn Schutzlevel verletzt werden. Das spiegelt die OrderClose-Aufrufe in MQL wider und vermeidet die Abhängigkeit von börsenseitigen Stop-Orders.
Alle Indikatorbindungen erfolgen über die High-Level-Abonnement-API; direkte Aufrufe von GetValue sind nicht erforderlich.
Parameter
Name
Beschreibung
Standard
FastMaPeriod
Länge der schnellen LWMA im primären Zeitrahmen.
6
SlowMaPeriod
Länge der langsamen LWMA im primären Zeitrahmen.
85
MomentumPeriod
Momentum-Periode im höheren Zeitrahmen.
14
MomentumBuyThreshold
Minimale absolute Momentum-Abweichung von 100, um Long-Einstiege zu erlauben.
0.3
MomentumSellThreshold
Minimale absolute Momentum-Abweichung von 100, um Short-Einstiege zu erlauben.
0.3
MacdFastPeriod
Länge der schnellen EMA für den langfristigen MACD-Filter.
12
MacdSlowPeriod
Länge der langsamen EMA für den langfristigen MACD-Filter.
26
MacdSignalPeriod
Länge der Signal-EMA für den langfristigen MACD-Filter.
9
StopLossPips
Harte Stop-Loss-Distanz in Pips.
20
TakeProfitPips
Feste Take-Profit-Distanz in Pips.
50
TrailingStopPips
Trailing-Stop-Distanz in Pips (0 deaktiviert den Trail).
40
UseBreakEven
Ob der Stop nach einem Gewinntrigger auf Break-even verschoben wird.
true
BreakEvenTriggerPips
Gewinn in Pips, der vor Break-even-Anpassungen erforderlich ist.
30
BreakEvenOffsetPips
Offset beim Verschieben des Stops auf Break-even.
30
FractalWindowLength
Anzahl fertiger Kerzen, die zur Bestätigung fraktaler Hochs und Tiefs gehalten werden.
7
FractalBufferPips
Zusätzlicher Puffer um Fraktalniveaus in Pips.
10
TradeVolume
Volumen jeder Marktorder.
1
CandleType
Primäre Kerzenserie für LWMA- und Fraktallogik.
Zeitrahmen 15m
HigherCandleType
Höherer Zeitrahmen für den Momentum-Filter.
Zeitrahmen 1h
LongTermCandleType
Zeitrahmen für den MACD-Trendfilter.
Zeitrahmen 1d
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 CryptoSrStrategy : 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 CryptoSrStrategy()
{
_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 crypto_sr_strategy(Strategy):
def __init__(self):
super(crypto_sr_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(crypto_sr_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(crypto_sr_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 crypto_sr_strategy()