DecEMA-Strategie
Strategie, die den DecEMA-Indikator verwendet, um die Trendrichtung zu verfolgen. Der Indikator wendet zehn aufeinanderfolgende exponentielle Glättungen an und kombiniert sie zu einem gleitenden Durchschnitt mit geringer Verzögerung. Die Strategie vergleicht die letzten drei DecEMA-Werte. Wenn die Linie nach oben dreht und der neueste Wert den vorherigen überschreitet, kauft sie und schließt jede Short-Position. Wenn die Linie nach unten dreht und der neueste Wert unter dem vorherigen liegt, verkauft sie und schließt jede Long-Position.
Details
- Einstiegskriterien:
- Long: DecEMA-Steigung dreht nach oben und aktueller Wert > vorheriger Wert
- Short: DecEMA-Steigung dreht nach unten und aktueller Wert < vorheriger Wert
- Long/Short: Beide
- Ausstiegskriterien:
- Long: Steigung dreht nach unten
- Short: Steigung dreht nach oben
- Stops: Keine
- Standardwerte:
EmaPeriod= 3Length= 15BuyPosOpen= trueSellPosOpen= trueBuyPosClose= trueSellPosClose= trueCandleType= TimeSpan.FromHours(8).TimeFrame()
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: DecEMA
- Stops: Nein
- Komplexität: Mittel
- Zeitrahmen: Mittelfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// Strategy based on DecEMA indicator slope.
/// Buys when the indicator turns upward and sells when it turns downward.
/// </summary>
public class DecEmaStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _length;
private readonly StrategyParam<DataType> _candleType;
private decimal _prev;
private decimal _prevPrev;
private int _count;
private readonly StrategyParam<bool> _buyOpen, _sellOpen, _buyClose, _sellClose;
private Order _pending;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int Length { get => _length.Value; set => _length.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public bool BuyPosOpen { get => _buyOpen.Value; set => _buyOpen.Value = value; }
public bool SellPosOpen { get => _sellOpen.Value; set => _sellOpen.Value = value; }
public bool BuyPosClose { get => _buyClose.Value; set => _buyClose.Value = value; }
public bool SellPosClose { get => _sellClose.Value; set => _sellClose.Value = value; }
public DecEmaStrategy()
{
_buyOpen = Param(nameof(BuyPosOpen), true);
_sellOpen = Param(nameof(SellPosOpen), true);
_buyClose = Param(nameof(BuyPosClose), true);
_sellClose = Param(nameof(SellPosClose), true);
_emaPeriod = Param(nameof(EmaPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Base EMA Period", "Length for initial EMA", "Parameters");
_length = Param(nameof(Length), 15)
.SetGreaterThanZero()
.SetDisplay("Smoothing Length", "Smoothing length for DecEMA", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prev = default;
_prevPrev = default;
_count = default;
_pending = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_count = 0;
_pending = null;
var decema = new DecemaIndicator
{
EmaPeriod = EmaPeriod,
Length = Length
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(decema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, decema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal decema)
{
if (candle.State != CandleStates.Finished)
return;
_count++;
if (_count <= 2)
{
_prevPrev = _prev;
_prev = decema;
return;
}
var buy = _prev < _prevPrev && decema > _prev;
var sell = _prev > _prevPrev && decema < _prev;
if (IsFormedAndOnlineAndAllowTrading() && (_pending is null || _pending.State is OrderStates.Done or OrderStates.Failed))
{
if (buy)
{
if (Position < 0m && SellPosClose) _pending = BuyMarket(-Position + (BuyPosOpen ? Volume : 0m));
else if (Position == 0m && BuyPosOpen) _pending = BuyMarket(Volume);
}
else if (sell)
{
if (Position > 0m && BuyPosClose) _pending = SellMarket(Position + (SellPosOpen ? Volume : 0m));
else if (Position == 0m && SellPosOpen) _pending = SellMarket(Volume);
}
}
_prevPrev = _prev;
_prev = decema;
}
private class DecemaIndicator : DecimalLengthIndicator
{
public int EmaPeriod { get; set; } = 3;
private readonly ExponentialMovingAverage _baseEma = new();
private decimal _ema1, _ema2, _ema3, _ema4, _ema5;
private decimal _ema6, _ema7, _ema8, _ema9, _ema10;
public override void Reset()
{
base.Reset();
_baseEma.Length = EmaPeriod;
_baseEma.Reset();
_ema1 = _ema2 = _ema3 = _ema4 = _ema5 = 0m;
_ema6 = _ema7 = _ema8 = _ema9 = _ema10 = 0m;
}
protected override IIndicatorValue OnProcess(IIndicatorValue input)
{
var ema0 = _baseEma.Process(input).ToDecimal();
var alpha = 2m / (1m + Length);
_ema1 = alpha * ema0 + (1 - alpha) * _ema1;
_ema2 = alpha * _ema1 + (1 - alpha) * _ema2;
_ema3 = alpha * _ema2 + (1 - alpha) * _ema3;
_ema4 = alpha * _ema3 + (1 - alpha) * _ema4;
_ema5 = alpha * _ema4 + (1 - alpha) * _ema5;
_ema6 = alpha * _ema5 + (1 - alpha) * _ema6;
_ema7 = alpha * _ema6 + (1 - alpha) * _ema7;
_ema8 = alpha * _ema7 + (1 - alpha) * _ema8;
_ema9 = alpha * _ema8 + (1 - alpha) * _ema9;
_ema10 = alpha * _ema9 + (1 - alpha) * _ema10;
var value = 10m * _ema1 - 45m * _ema2 + 120m * _ema3 - 210m * _ema4 + 252m * _ema5
- 210m * _ema6 + 120m * _ema7 - 45m * _ema8 + 10m * _ema9 - _ema10;
IsFormed = _baseEma.IsFormed;
return new DecimalIndicatorValue(this, value, input.Time);
}
}
}
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, OrderStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class dec_ema_strategy(Strategy):
def __init__(self):
super(dec_ema_strategy, self).__init__()
self._buy_open = self.Param("BuyPosOpen", True)
self._sell_open = self.Param("SellPosOpen", True)
self._buy_close = self.Param("BuyPosClose", True)
self._sell_close = self.Param("SellPosClose", True)
self._pending = None
self._ema_period = self.Param("EmaPeriod", 3) \
.SetDisplay("Base EMA Period", "Length for initial EMA", "Parameters")
self._length = self.Param("Length", 15) \
.SetDisplay("Smoothing Length", "Smoothing length for DecEMA", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev = 0.0
self._prev_prev = 0.0
self._count = 0
self._pending = None
self._base_ema = None
self._ema1 = 0.0
self._ema2 = 0.0
self._ema3 = 0.0
self._ema4 = 0.0
self._ema5 = 0.0
self._ema6 = 0.0
self._ema7 = 0.0
self._ema8 = 0.0
self._ema9 = 0.0
self._ema10 = 0.0
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def Length(self):
return self._length.Value
@Length.setter
def Length(self, value):
self._length.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(dec_ema_strategy, self).OnStarted2(time)
self._count = 0
self._base_ema = ExponentialMovingAverage()
self._base_ema.Length = self.EmaPeriod
self._ema1 = 0.0
self._ema2 = 0.0
self._ema3 = 0.0
self._ema4 = 0.0
self._ema5 = 0.0
self._ema6 = 0.0
self._ema7 = 0.0
self._ema8 = 0.0
self._ema9 = 0.0
self._ema10 = 0.0
self.SubscribeCandles(self.CandleType) \
.Bind(self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
t = candle.OpenTime
ema_result = process_float(self._base_ema, close, t, True)
if not self._base_ema.IsFormed:
return
ema0 = float(ema_result)
alpha = 2.0 / (1.0 + float(self.Length))
self._ema1 = alpha * ema0 + (1.0 - alpha) * self._ema1
self._ema2 = alpha * self._ema1 + (1.0 - alpha) * self._ema2
self._ema3 = alpha * self._ema2 + (1.0 - alpha) * self._ema3
self._ema4 = alpha * self._ema3 + (1.0 - alpha) * self._ema4
self._ema5 = alpha * self._ema4 + (1.0 - alpha) * self._ema5
self._ema6 = alpha * self._ema5 + (1.0 - alpha) * self._ema6
self._ema7 = alpha * self._ema6 + (1.0 - alpha) * self._ema7
self._ema8 = alpha * self._ema7 + (1.0 - alpha) * self._ema8
self._ema9 = alpha * self._ema8 + (1.0 - alpha) * self._ema9
self._ema10 = alpha * self._ema9 + (1.0 - alpha) * self._ema10
decema = (10.0 * self._ema1 - 45.0 * self._ema2 + 120.0 * self._ema3
- 210.0 * self._ema4 + 252.0 * self._ema5 - 210.0 * self._ema6
+ 120.0 * self._ema7 - 45.0 * self._ema8 + 10.0 * self._ema9
- self._ema10)
self._count += 1
if self._count <= 2:
self._prev_prev = self._prev
self._prev = decema
return
buy = self._prev < self._prev_prev and decema > self._prev
sell = self._prev > self._prev_prev and decema < self._prev
if self.IsFormedAndOnlineAndAllowTrading() and (self._pending is None or self._pending.State in (OrderStates.Done, OrderStates.Failed)):
if buy:
if self.Position < 0 and self._sell_close.Value:
self._pending = self.BuyMarket(-self.Position + (self.Volume if self._buy_open.Value else 0))
elif self.Position == 0 and self._buy_open.Value:
self._pending = self.BuyMarket(self.Volume)
elif sell:
if self.Position > 0 and self._buy_close.Value:
self._pending = self.SellMarket(self.Position + (self.Volume if self._sell_open.Value else 0))
elif self.Position == 0 and self._sell_open.Value:
self._pending = self.SellMarket(self.Volume)
self._prev_prev = self._prev
self._prev = decema
def OnReseted(self):
super(dec_ema_strategy, self).OnReseted()
self._prev = 0.0
self._prev_prev = 0.0
self._count = 0
self._base_ema = None
self._ema1 = 0.0
self._ema2 = 0.0
self._ema3 = 0.0
self._ema4 = 0.0
self._ema5 = 0.0
self._ema6 = 0.0
self._ema7 = 0.0
self._ema8 = 0.0
self._ema9 = 0.0
self._ema10 = 0.0
def CreateClone(self):
return dec_ema_strategy()