Die EMA Pullback-Strategie ist eine High-Level-Portierung des MetaTrader „Ema“-Expertenberaters. Es beobachtet ein Paar exponentieller gleitender Durchschnitte (EMA), wobei die Perioden 5 und 10 anhand der mittleren Kerzenpreise berechnet werden. Wenn ein bullischer oder bärischer Crossover auftritt, wartet die Strategie darauf, dass der Preis in Richtung des Extrems der vorherigen Kerze zurückkehrt, bevor sie in die Richtung des Crossovers eintritt. Feste Take-Profit- und Stop-Loss-Werte, gemessen in Preispunkten, steuern das Risiko, sobald die Position geöffnet ist.
Handelslogik
Abonnieren Sie die konfigurierte Kerzenserie (Standard: 5-Minuten-Zeitrahmen) und berechnen Sie zwei EMAs zum Medianpreis (high + low) / 2.
Erkennen Sie einen bullischen Crossover, wenn der schnelle EMA den langsamen EMA kreuzt, oder einen bärischen Crossover, wenn der schnelle EMA den langsamen EMA kreuzt.
Aktivieren Sie einen Pullback-Einstieg, nachdem der Crossover erfolgt ist:
Warten Sie bei einem Long-Setup, bis der Schlusskurs auf das vorherige Kerzenhoch abzüglich des MoveBackPoints-Versatzes zurückgeht, während der schnelle EMA um mindestens zwei Preispunkte über dem langsamen EMA bleibt.
Warten Sie bei einem kurzen Setup, bis der Schlusskurs zum vorherigen Kerzentief zuzüglich des MoveBackPoints-Versatzes zurückkehrt, während der langsame EMA um mindestens zwei Preispunkte über dem schnellen EMA bleibt.
Wenn die Pullback-Bedingung erfüllt ist, senden Sie eine Marktorder mit dem konfigurierten Handelsvolumen.
Berechnen Sie beim Einstieg die statischen Take-Profit- und Stop-Loss-Werte mithilfe der Einstellungen TakeProfitPoints und StopLossPoints, umgewandelt in absolute Preisabweichungen vom Einstiegspreis.
Beobachten Sie jede fertige Kerze und schließen Sie die Position, sobald entweder das Take-Profit- oder Stop-Loss-Niveau durch das Hoch/Tief der Kerze berührt wird.
Parameter
Name
Standard
Beschreibung
TradeVolume
0.1
Für jede Marktorder verwendetes Volumen.
FastLength
5
Periode des schnellen EMA, angewendet auf Durchschnittspreise.
SlowLength
10
Zeitraum der langsamen EMA angewendet auf mittlere Preise.
MoveBackPoints
3
Rückzugsdistanz in Preispunkten, gemessen vom Extrem der vorherigen Kerze.
TakeProfitPoints
5
Take-Profit-Distanz, in Preispunkten.
StopLossPoints
20
Stop-Loss-Distanz, in Preispunkten.
CandleType
5m
Zeitrahmen für Kerzenabonnements und Indikatorberechnungen.
Notizen
Es werden nur vollständig ausgebildete Kerzen verarbeitet, um vorzeitige Signale zu vermeiden.
Die Strategie gleicht die Eigenschaft Strategy.Volume beim Start automatisch mit dem Parameter TradeVolume aus.
Alle Berechnungen basieren auf dem Instrument PriceStep, um punktbasierte Entfernungen in absolute Preise umzurechnen.
Die Strategie eröffnet jeweils höchstens eine Position und erfordert einen neuen EMA-Crossover, bevor ein weiterer Trade vorbereitet wird.
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>
/// EMA Pullback strategy - fast/slow EMA crossover with pullback entry.
/// After a bullish crossover, waits for a pullback to fast EMA to enter long.
/// After a bearish crossover, waits for a pullback to fast EMA to enter short.
/// </summary>
public class EmaPullbackStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _prevClose;
private bool _hasPrev;
private bool _bullishCross;
private bool _bearishCross;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public EmaPullbackStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 8)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _prevClose = 0m; _hasPrev = false; _bullishCross = false; _bearishCross = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
_bullishCross = false;
_bearishCross = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_prevClose = close;
_hasPrev = true;
return;
}
// Detect crossovers
if (_prevFast <= _prevSlow && fast > slow)
{
_bullishCross = true;
_bearishCross = false;
}
else if (_prevFast >= _prevSlow && fast < slow)
{
_bearishCross = true;
_bullishCross = false;
}
// Pullback entry: after bullish cross, wait for close to touch fast EMA
if (_bullishCross && fast > slow && _prevClose > _prevFast && close <= fast && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_bullishCross = false;
}
// Pullback entry: after bearish cross, wait for close to touch fast EMA
else if (_bearishCross && fast < slow && _prevClose < _prevFast && close >= fast && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_bearishCross = false;
}
// Exit on opposite crossover
else if (Position > 0 && fast < slow)
{
SellMarket();
}
else if (Position < 0 && fast > slow)
{
BuyMarket();
}
_prevFast = fast;
_prevSlow = slow;
_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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ema_pullback_strategy(Strategy):
def __init__(self):
super(ema_pullback_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 8) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_close = 0.0
self._has_prev = False
self._bullish_cross = False
self._bearish_cross = False
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ema_pullback_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_close = 0.0
self._has_prev = False
self._bullish_cross = False
self._bearish_cross = False
def OnStarted2(self, time):
super(ema_pullback_strategy, self).OnStarted2(time)
self._has_prev = False
self._bullish_cross = False
self._bearish_cross = False
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self.process_candle).Start()
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast)
slow_val = float(slow)
close = float(candle.ClosePrice)
if not self._has_prev:
self._prev_fast = fast_val
self._prev_slow = slow_val
self._prev_close = close
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val:
self._bullish_cross = True
self._bearish_cross = False
elif self._prev_fast >= self._prev_slow and fast_val < slow_val:
self._bearish_cross = True
self._bullish_cross = False
if self._bullish_cross and fast_val > slow_val and self._prev_close > self._prev_fast and close <= fast_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._bullish_cross = False
elif self._bearish_cross and fast_val < slow_val and self._prev_close < self._prev_fast and close >= fast_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._bearish_cross = False
elif self.Position > 0 and fast_val < slow_val:
self.SellMarket()
elif self.Position < 0 and fast_val > slow_val:
self.BuyMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
self._prev_close = close
def CreateClone(self):
return ema_pullback_strategy()