Die Aussie Surfer Ltd Strategy ist eine StockSharp High-Level-API-Portierung des MetaTrader 5-Expertenberaters „Aussie Surfer Ltd“ (MQL-Ordner 43278). Die Strategie kombiniert schnelle Bollinger-Bandumkehrungen mit einem Alligator-Trendfilter, um die im ursprünglichen EA verwendete diskretionäre Einrichtung zu automatisieren. Trades werden mit dem für die Strategie konfigurierten Primärinstrument getätigt und standardmäßig anhand einer 15-minütigen Kerzenserie ausgewertet.
Indikatoren und Daten
Bollinger Bänder (Schlusskurs, Standardlänge 5, Breite 2,5) – erkennen, wann sich der Markt vorübergehend außerhalb der Bänder ausdehnt und wieder hineinschnappt.
Geglätteter gleitender Durchschnitt (Länge 21) – reproduziert die „Zähne“-Linie Alligator, um die Trendverlangsamung zu beurteilen.
Medianpreis jeder Kerze ((Hoch + Tief) / 2) – speist die Alligator-Berechnung, sodass die Steigung mit der ursprünglichen Implementierung übereinstimmt.
Die Strategie abonniert einen einzelnen Kerzenstrom. Die Indikatorwerte werden nur von fertigen Kerzen bestimmt, wodurch sichergestellt wird, dass Signale auf der Grundlage bestätigter Daten generiert werden.
Handelslogik
Eintrag einrichten
Wenn die vorherige Kerze über dem unteren Bollinger-Band öffnete und die aktuelle Kerze unter dem vor zwei Balken beobachteten Bandwert öffnete, wird eine Long-Position eröffnet (nachdem jegliches Short-Engagement abgeflacht wurde). Dies stellt die EA-Logik wieder her, bei der der Preis das untere Band durchbricht und sofort wieder hinein springt.
Wenn die vorherige Kerze unterhalb des oberen Bollinger-Bandes öffnete und die aktuelle Kerze über dem vor zwei Balken beobachteten Bandwert öffnete, wird eine Short-Position eröffnet (nachdem jegliches Long-Engagement abgeflacht wurde).
Alligator-basierter Exit
Die Zahnlinie Alligator wird ein und zwei Balken zurück überwacht. Eine Long-Position wird immer dann aufgelöst, wenn die Steigung nach unten geht (der Wert vor zwei Balken ist größer als der Wert vor einem Balken). Eine Short-Position wird geschlossen, wenn der Hang nach oben dreht.
Risikoschichten
Bei der Eingabe werden ein fester Pip-Stop-Loss und ein Take-Profit angewendet. Beide sind optional und können deaktiviert werden, indem ihr Pip-Abstand auf Null gesetzt wird.
Ein optionaler Trailing-Stop richtet den Stop-Loss neu auf das Hoch (für Long-Positionen) oder das Tief (für Short-Positionen) der zuvor abgeschlossenen Kerze abzüglich/plus der konfigurierten Pip-Distanz aus. Die Trailing-Logik ist nur aktiv, wenn der Stop-Loss aktiviert ist und EnableTrailingStop auf true gesetzt ist.
Risikomanagement
Stop-Loss – wandelt den konfigurierten Pip-Abstand mithilfe der Wertpapierpreisstufe in Preiseinheiten um.
Take-Profit – wird einmal bei der Eingabe berechnet und statisch gehalten, bis entweder erreicht oder die Position durch eine andere Regel geschlossen wird.
Trailing Stop – erhöht den Stop-Loss, wenn bei der vorherigen Kerze ein günstigeres Hoch (für Long-Positionen) oder Tief (für Short-Positionen) erscheint.
Umkehrabwicklung – Wenn ein Signal eintrifft, während eine entgegengesetzte Position offen ist, sendet die Strategie eine Marktorder in der Größe, um das neue Engagement in einer einzigen Transaktion vollständig umzukehren und aufzubauen.
Parameter
Parameter
Beschreibung
Standard
OrderVolume
Basishandelsgröße in Lots oder Kontrakten.
0.30
StopLossPips
Schutzstoppabstand in Pips. 0 deaktiviert den Stopp.
46
TakeProfitPips
Gewinnzielentfernung in Pips. 0 deaktiviert das Ziel.
0
EnableTrailingStop
Aktiviert Pip-basiertes Trailing, wenn ein Stop-Loss aktiv ist.
true
BollingerPeriod
Länge des Bollinger Bands-Fensters.
5
BollingerDeviation
Standardabweichungsmultiplikator für die Bänder.
2.5
TeethPeriod
Geglättete gleitende Durchschnittslänge für die Zahnlinie Alligator.
21
CandleType
Für Berechnungen verwendete Kerzenserie (standardmäßig 15-Minuten-Zeitrahmen).
15m Kerzen
Alle numerischen Parameter umfassen Optimierungsmetadaten, sodass sie über den Strategy Analyzer optimiert werden können.
Implementierungshinweise
Es werden nur fertige Kerzen verarbeitet; Unvollendete Daten werden ignoriert, um die zeitgesteuerte MetaTrader-Ausführung nachzuahmen, die zu Beginn jedes neuen Balkens ausgeführt wurde.
Die Trailing-Logik erfordert eine positive Stop-Loss-Distanz. Bei der Initialisierung wird eine Ausnahme ausgelöst, wenn die Trailing-Option ohne Stopp aktiviert ist.
Indikatorinstanzen werden automatisch gezeichnet, wenn ein Diagrammbereich verfügbar ist, um zu überprüfen, ob der Port StockSharp mit der Vorlage MetaTrader übereinstimmt.
Nutzung
Laden Sie die Strategie in ein StockSharp-Terminal oder eine Backtesting-Umgebung.
Konfigurieren Sie die Handelssicherheit und passen Sie die Parameter (insbesondere Pip-Abstände) an die Vertragsspezifikationen des Brokers an.
Starten Sie die Strategie. Es abonniert die konfigurierte Kerzenserie, wertet Einträge zu jeder fertigen Kerze aus und verwaltet die Position anhand der beschriebenen Regeln.
Stellen Sie beim Live-Handel sicher, dass der Broker Marktaufträge unterstützt und dass das Symbol PriceStep verfügbar ist, damit die Pip-Umrechnungen korrekt sind.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Aussie Surfer Ltd" MetaTrader expert.
/// Uses Bollinger Band reversals with an SMA slope filter for entries.
/// </summary>
public class AussieSurferLtdStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private readonly StrategyParam<int> _smaPeriod;
private ExponentialMovingAverage _bandEma;
private ExponentialMovingAverage _slopeEma;
private decimal? _prevSma;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerWidth
{
get => _bollingerWidth.Value;
set => _bollingerWidth.Value = value;
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public AussieSurferLtdStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(120).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe", "General");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Bollinger Bands window", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 2.5m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Width", "Standard deviation multiplier", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period for slope filter", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bandEma = new ExponentialMovingAverage { Length = BollingerPeriod };
_slopeEma = new ExponentialMovingAverage { Length = SmaPeriod };
_prevSma = null;
_prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_bandEma, _slopeEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bandEma);
DrawIndicator(area, _slopeEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal bandValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bandEma.IsFormed || !_slopeEma.IsFormed)
{
_prevClose = candle.ClosePrice;
_prevSma = smaValue;
return;
}
var close = candle.ClosePrice;
var bandOffset = bandValue * (BollingerWidth / 100m);
var upperBand = bandValue + bandOffset;
var lowerBand = bandValue - bandOffset;
if (_prevSma is null || _prevClose is null)
{
_prevSma = smaValue;
_prevClose = close;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
// SMA slope (uptrend or downtrend)
var smaRising = smaValue > _prevSma.Value;
var smaFalling = smaValue < _prevSma.Value;
// Long: price was below lower band and crosses back above, SMA falling (reversal)
var longSignal = _prevClose.Value < lowerBand && close >= lowerBand && smaFalling;
// Short: price was above upper band and crosses back below, SMA rising (reversal)
var shortSignal = _prevClose.Value > upperBand && close <= upperBand && smaRising;
if (longSignal)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (shortSignal)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
// Exit at opposite band or SMA reversal
if (Position > 0 && (close >= upperBand || (smaFalling && _prevSma.Value > smaValue)))
{
SellMarket(Position);
}
else if (Position < 0 && (close <= lowerBand || (smaRising && _prevSma.Value < smaValue)))
{
BuyMarket(Math.Abs(Position));
}
_prevSma = smaValue;
_prevClose = close;
}
/// <inheritdoc />
protected override void OnReseted()
{
_bandEma = null;
_slopeEma = null;
_prevSma = null;
_prevClose = null;
base.OnReseted();
}
}
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 aussie_surfer_ltd_strategy(Strategy):
def __init__(self):
super(aussie_surfer_ltd_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(120)))
self._bollinger_period = self.Param("BollingerPeriod", 20)
self._bollinger_width = self.Param("BollingerWidth", 2.5)
self._sma_period = self.Param("SmaPeriod", 21)
self._prev_sma = None
self._prev_close = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
@BollingerWidth.setter
def BollingerWidth(self, value):
self._bollinger_width.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
def OnReseted(self):
super(aussie_surfer_ltd_strategy, self).OnReseted()
self._prev_sma = None
self._prev_close = None
def OnStarted2(self, time):
super(aussie_surfer_ltd_strategy, self).OnStarted2(time)
self._prev_sma = None
self._prev_close = None
band_ema = ExponentialMovingAverage()
band_ema.Length = self.BollingerPeriod
slope_ema = ExponentialMovingAverage()
slope_ema.Length = self.SmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(band_ema, slope_ema, self._process_candle).Start()
def _process_candle(self, candle, band_value, sma_value):
if candle.State != CandleStates.Finished:
return
band_val = float(band_value)
sma_val = float(sma_value)
close = float(candle.ClosePrice)
band_offset = band_val * (float(self.BollingerWidth) / 100.0)
upper_band = band_val + band_offset
lower_band = band_val - band_offset
if self._prev_sma is None or self._prev_close is None:
self._prev_sma = sma_val
self._prev_close = close
return
sma_rising = sma_val > self._prev_sma
sma_falling = sma_val < self._prev_sma
# Long: price was below lower band and crosses back above, SMA falling (reversal)
long_signal = self._prev_close < lower_band and close >= lower_band and sma_falling
# Short: price was above upper band and crosses back below, SMA rising (reversal)
short_signal = self._prev_close > upper_band and close <= upper_band and sma_rising
if long_signal:
if self.Position <= 0:
self.BuyMarket()
elif short_signal:
if self.Position >= 0:
self.SellMarket()
# Exit at opposite band or SMA reversal
if self.Position > 0 and (close >= upper_band or (sma_falling and self._prev_sma > sma_val)):
self.SellMarket()
elif self.Position < 0 and (close <= lower_band or (sma_rising and self._prev_sma < sma_val)):
self.BuyMarket()
self._prev_sma = sma_val
self._prev_close = close
def CreateClone(self):
return aussie_surfer_ltd_strategy()