Die Above Below MA Rejoin-Strategie ist eine StockSharp-Umsetzung des MetaTrader 4-Expertenberaters „AboveBelowMA“. Das ursprüngliche Skript überwacht den 15-Minuten-Chart von GBP/USD und vergleicht den aktuellen Preis mit einem exponentiellen gleitenden Durchschnitt (EMA) über eine Periode, der anhand des typischen Preises berechnet wird. Wenn der Preis auf der entgegengesetzten Seite eines steigenden oder fallenden Durchschnitts handelt, versucht die Strategie, diese Abweichung abzuschwächen und sich wieder der zugrunde liegenden Richtung von EMA anzuschließen. Dieser Port hält die Signalstruktur intakt und nutzt gleichzeitig StockSharp High-Level-APIs (SubscribeCandles + Bind).
Handelslogik
Abonnieren Sie den konfigurierten Kerzentyp (standardmäßig 15 Minuten) und geben Sie einen exponentiellen gleitenden Durchschnitt ein, der den typischen Preis (High + Low + Close) / 3 verwendet.
Verfolgen Sie die neuesten und vorherigen EMA-Werte, um die kurzfristige Steigung zu verstehen. Eine bullische Tendenz erfordert einen Anstieg des EMA, während eine bärische Tendenz einen Rückgang erfordert.
Long-Setup: Wenn die Kerze mindestens eine Preisstufe unter EMA öffnet, unter EMA schließt und der vorherige EMA-Wert niedriger als der aktuelle EMA-Wert ist, schließen Sie alle Short-Positionen und bereiten Sie sich auf den Kauf vor. Wenn keine Position mehr vorhanden ist, erteilen Sie eine Marktkauforder.
Short-Setup: Wenn die Kerze mindestens eine Preisstufe über EMA öffnet, über EMA schließt und der vorherige EMA-Wert höher ist als der aktuelle EMA-Wert, schließen Sie alle Long-Engagements und bereiten Sie den Verkauf vor. Wenn die Position flach ist, erteilen Sie einen Marktverkaufsauftrag.
Aufträge werden nur für fertige Kerzen erteilt, um vorzeitige Signale bei teilweise geformten Balken zu vermeiden.
Positionsgrößenbestimmung
Die Größe der MetaTrader-Version wird mit AccountFreeMargin / 10000 gehandelt, die auf 5 Lots begrenzt ist. Die Implementierung von StockSharp bietet ein äquivalentes Verhalten: Wenn UseDynamicVolume aktiviert ist, dividiert die Strategie den aktuellen Portfoliowert durch BalanceToVolumeDivider (Standard: 10000).
Die berechnete Größe ist durch MaxVolume begrenzt und spiegelt die feste 5-Lot-Obergrenze des Expertenberaters wider. Wenn die dynamische Größenanpassung deaktiviert ist, wird der Parameter InitialVolume als festes Volumen verwendet.
Alle Volumina sind an den Volumenschritt des Instruments und die minimalen/maximalen Volumenbeschränkungen angepasst, um eine Ablehnung durch den Broker oder Simulator zu vermeiden.
Parameter
Parameter
Beschreibung
EmaLength
Periode des exponentiellen gleitenden Durchschnitts (standardmäßig 1, passend zu EA).
CandleType
Zeitrahmen, der zum Erstellen der Kerzen verwendet wird, die den EMA versorgen (Standard 15 Minuten).
InitialVolume
Das Bestellvolumen wurde korrigiert, wenn die dynamische Größenanpassung deaktiviert ist.
UseDynamicVolume
Ermöglicht die portfoliobasierte Positionsgrößenbestimmung (Balance / BalanceToVolumeDivider).
BalanceToVolumeDivider
Auf den Portfoliowert angewendeter Teiler, um AccountFreeMargin / 10000 zu emulieren.
MaxVolume
Maximales Auftragsvolumen, das die Strategie zulässt.
Notizen
Die Strategie verwendet ClosePosition(), bevor ein Trade in die entgegengesetzte Richtung eröffnet wird, und entspricht der MetaTrader-Logik, die gegensätzliche Orders über CheckOrders schließt.
Da Signale an fertigen Kerzen ausgewertet werden, können Einträge etwas später erfolgen als bei der Tick-basierten MetaTrader-Version. Diese Änderung verbessert die Stabilität beim Ausführen von Backtests oder beim Live-Handel mit Kerzendaten.
Stellen Sie sicher, dass das ausgewählte Wertpapier aussagekräftige PriceStep-, VolumeStep- und Portfoliobewertungsinformationen bereitstellt, damit der dynamische Volumenblock wie erwartet funktioniert.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Above/Below MA Rejoin strategy.
/// Buys when price is below a rising EMA (pullback in uptrend).
/// Sells when price is above a falling EMA (pullback in downtrend).
/// </summary>
public class AboveBelowMaRejoinStrategy : Strategy
{
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevEma;
private decimal _prevClose;
private bool _hasPrev;
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AboveBelowMaRejoinStrategy()
{
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Period", "EMA lookback period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0m;
_prevClose = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevEma = emaValue;
_prevClose = close;
_hasPrev = true;
return;
}
var emaRising = emaValue > _prevEma;
var emaFalling = emaValue < _prevEma;
// Price rejoins from below in uptrend - buy
if (emaRising && _prevClose < _prevEma && close >= emaValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Price rejoins from above in downtrend - sell
else if (emaFalling && _prevClose > _prevEma && close <= emaValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevEma = emaValue;
_prevClose = close;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class above_below_ma_rejoin_strategy(Strategy):
"""Above/Below MA Rejoin strategy.
Buys when price rejoins from below a rising EMA (pullback in uptrend).
Sells when price rejoins from above a falling EMA (pullback in downtrend)."""
def __init__(self):
super(above_below_ma_rejoin_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Period", "EMA lookback period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_ema = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaLength(self):
return self._ema_length.Value
def OnReseted(self):
super(above_below_ma_rejoin_strategy, self).OnReseted()
self._prev_ema = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(above_below_ma_rejoin_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
if not self._has_prev:
self._prev_ema = ema_val
self._prev_close = close
self._has_prev = True
return
ema_rising = ema_val > self._prev_ema
ema_falling = ema_val < self._prev_ema
# Price rejoins from below in uptrend - buy
if ema_rising and self._prev_close < self._prev_ema and close >= ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Price rejoins from above in downtrend - sell
elif ema_falling and self._prev_close > self._prev_ema and close <= ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_ema = ema_val
self._prev_close = close
def CreateClone(self):
return above_below_ma_rejoin_strategy()