DecEMA戦略
DecEMAインジケーターを使用してトレンドの方向を追う戦略。このインジケーターは10回の連続した指数平滑化を適用して組み合わせ、遅延の少ない移動平均を作成します。戦略は直近3つのDecEMA値を比較します。ラインが上向きになり最新値が前の値を超えると、買いを行い任意のショートポジションを決済します。ラインが下向きになり最新値が前の値を下回ると、売りを行い任意のロングポジションを決済します。
詳細
- エントリー条件:
- ロング: DecEMAの傾きが上向きになり現在値 > 前値
- ショート: DecEMAの傾きが下向きになり現在値 < 前値
- ロング/ショート: 両方
- エグジット条件:
- ロング: 傾きが下向きに転換
- ショート: 傾きが上向きに転換
- ストップ: なし
- デフォルト値:
EmaPeriod= 3Length= 15BuyPosOpen= trueSellPosOpen= trueBuyPosClose= trueSellPosClose= trueCandleType= TimeSpan.FromHours(8).TimeFrame()
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: DecEMA
- ストップ: いいえ
- 複雑さ: 中級
- 時間軸: 中期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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;
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 DecEmaStrategy()
{
_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(4).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;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_count = 0;
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;
}
// Slope reversal detection
if (_prev < _prevPrev && decema > _prev && Position <= 0)
{
// Was falling, now turning up -> buy
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (_prev > _prevPrev && decema < _prev && Position >= 0)
{
// Was rising, now turning down -> sell
if (Position > 0) SellMarket();
SellMarket();
}
_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
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._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(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
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
@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
if self._prev < self._prev_prev and decema > self._prev and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev > self._prev_prev and decema < self._prev and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
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()