Long EMA 高度エグジット戦略
Long EMA 高度エグジット戦略は、短期移動平均が中期移動平均を上回るクロスが発生し、価格が長期移動平均の上にある場合にエントリーするロング専用戦略です。エグジットは、MACDの下向きクロス、選択した移動平均を下回る価格の終値、MAの下向きクロス、トレーリングストップ、またはATRベースのボラティリティフィルターによってトリガーされます。
詳細
- データ: 価格ローソク足。
- エントリー条件:
- ロング: 短期MAが中期MAを上回るクロスし、価格が長期MAの上。
- エグジット条件: MACDの下向きクロス、選択したMAを下回る価格、短期MAが中期MAを下回るクロス、オプションのトレーリングストップ。
- ストップ: オプションのトレーリングストップ。
- デフォルト値:
MaType= EMAEntryConditionType= CrossoverLongTermPeriod= 200ShortTermPeriod= 5MidTermPeriod= 10EnableMacdExit= trueMacdCandleType= TimeSpan.FromDays(7).TimeFrame()MacdFastLength= 12MacdSlowLength= 26MacdSignalLength= 9UseTrailingStop= falseTrailingStopPercent= 15UseMaCloseExit= falseMaCloseExitPeriod= 50UseMaCrossExit= trueUseVolatilityFilter= falseAtrPeriod= 14AtrMultiplier= 1.5CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: ロングのみ
- インジケーター: MA, MACD, ATR
- 複雑さ: 中
- リスクレベル: 中
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>
/// Long EMA advanced exit strategy.
/// Long only: enters when the short MA crosses above (or, with the Above condition, is above) the medium MA while price is above the long MA.
/// Exits when the MACD on the higher MacdCandleType timeframe crosses below its signal line, when price closes below the MaCloseExitPeriod MA,
/// when the short MA crosses below the medium MA, when a candle range exceeds AtrMultiplier ATRs, or on a percent trailing stop; each exit can be switched off.
/// </summary>
public class LongEmaAdvancedExitStrategy : Strategy
{
/// <summary>
/// Moving average types.
/// </summary>
public enum MaTypes
{
/// <summary>
/// Exponential moving average.
/// </summary>
EMA,
/// <summary>
/// Simple moving average.
/// </summary>
SMA,
}
/// <summary>
/// Entry condition types.
/// </summary>
public enum EntryConditions
{
/// <summary>
/// Short MA crosses above the medium MA.
/// </summary>
Crossover,
/// <summary>
/// Short MA is above the medium MA.
/// </summary>
Above,
}
private readonly StrategyParam<MaTypes> _maType;
private readonly StrategyParam<EntryConditions> _entryConditionType;
private readonly StrategyParam<int> _longTermPeriod;
private readonly StrategyParam<int> _shortTermPeriod;
private readonly StrategyParam<int> _midTermPeriod;
private readonly StrategyParam<bool> _enableMacdExit;
private readonly StrategyParam<DataType> _macdCandleType;
private readonly StrategyParam<int> _macdFastLength;
private readonly StrategyParam<int> _macdSlowLength;
private readonly StrategyParam<int> _macdSignalLength;
private readonly StrategyParam<bool> _useTrailingStop;
private readonly StrategyParam<decimal> _trailingStopPercent;
private readonly StrategyParam<bool> _useMaCloseExit;
private readonly StrategyParam<int> _maCloseExitPeriod;
private readonly StrategyParam<bool> _useMaCrossExit;
private readonly StrategyParam<bool> _useVolatilityFilter;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevShort;
private decimal? _prevMid;
private decimal? _prevMacd;
private decimal? _prevSignal;
private MovingAverageConvergenceDivergenceSignal _macd;
/// <summary>
/// Moving average type.
/// </summary>
public MaTypes MaType
{
get => _maType.Value;
set => _maType.Value = value;
}
/// <summary>
/// Entry condition type.
/// </summary>
public EntryConditions EntryConditionType
{
get => _entryConditionType.Value;
set => _entryConditionType.Value = value;
}
/// <summary>
/// Long-term MA period.
/// </summary>
public int LongTermPeriod
{
get => _longTermPeriod.Value;
set => _longTermPeriod.Value = value;
}
/// <summary>
/// Short-term MA period.
/// </summary>
public int ShortTermPeriod
{
get => _shortTermPeriod.Value;
set => _shortTermPeriod.Value = value;
}
/// <summary>
/// Medium-term MA period.
/// </summary>
public int MidTermPeriod
{
get => _midTermPeriod.Value;
set => _midTermPeriod.Value = value;
}
/// <summary>
/// Exit on a MACD cross down.
/// </summary>
public bool EnableMacdExit
{
get => _enableMacdExit.Value;
set => _enableMacdExit.Value = value;
}
/// <summary>
/// Candle type of the MACD exit.
/// </summary>
public DataType MacdCandleType
{
get => _macdCandleType.Value;
set => _macdCandleType.Value = value;
}
/// <summary>
/// MACD fast length.
/// </summary>
public int MacdFastLength
{
get => _macdFastLength.Value;
set => _macdFastLength.Value = value;
}
/// <summary>
/// MACD slow length.
/// </summary>
public int MacdSlowLength
{
get => _macdSlowLength.Value;
set => _macdSlowLength.Value = value;
}
/// <summary>
/// MACD signal length.
/// </summary>
public int MacdSignalLength
{
get => _macdSignalLength.Value;
set => _macdSignalLength.Value = value;
}
/// <summary>
/// Use the percent trailing stop.
/// </summary>
public bool UseTrailingStop
{
get => _useTrailingStop.Value;
set => _useTrailingStop.Value = value;
}
/// <summary>
/// Trailing stop percent.
/// </summary>
public decimal TrailingStopPercent
{
get => _trailingStopPercent.Value;
set => _trailingStopPercent.Value = value;
}
/// <summary>
/// Exit when price closes below the exit MA.
/// </summary>
public bool UseMaCloseExit
{
get => _useMaCloseExit.Value;
set => _useMaCloseExit.Value = value;
}
/// <summary>
/// Exit MA period.
/// </summary>
public int MaCloseExitPeriod
{
get => _maCloseExitPeriod.Value;
set => _maCloseExitPeriod.Value = value;
}
/// <summary>
/// Exit when the short MA crosses below the medium MA.
/// </summary>
public bool UseMaCrossExit
{
get => _useMaCrossExit.Value;
set => _useMaCrossExit.Value = value;
}
/// <summary>
/// Exit when a candle range exceeds the ATR threshold.
/// </summary>
public bool UseVolatilityFilter
{
get => _useVolatilityFilter.Value;
set => _useVolatilityFilter.Value = value;
}
/// <summary>
/// ATR period.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// ATR multiplier of the volatility exit.
/// </summary>
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public LongEmaAdvancedExitStrategy()
{
_maType = Param(nameof(MaType), MaTypes.EMA)
.SetDisplay("MA Type", "Moving average type", "Indicators");
_entryConditionType = Param(nameof(EntryConditionType), EntryConditions.Crossover)
.SetDisplay("Entry Condition", "Crossover or Above", "Entry");
_longTermPeriod = Param(nameof(LongTermPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("Long MA", "Long-term MA period", "Indicators");
_shortTermPeriod = Param(nameof(ShortTermPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Short MA", "Short-term MA period", "Indicators");
_midTermPeriod = Param(nameof(MidTermPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Medium MA", "Medium-term MA period", "Indicators");
_enableMacdExit = Param(nameof(EnableMacdExit), true)
.SetDisplay("MACD Exit", "Exit on a MACD cross down", "Exit");
_macdCandleType = Param(nameof(MacdCandleType), TimeSpan.FromDays(7).TimeFrame())
.SetDisplay("MACD Candle Type", "Candle type of the MACD exit", "Exit");
_macdFastLength = Param(nameof(MacdFastLength), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "MACD fast length", "Exit");
_macdSlowLength = Param(nameof(MacdSlowLength), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "MACD slow length", "Exit");
_macdSignalLength = Param(nameof(MacdSignalLength), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "MACD signal length", "Exit");
_useTrailingStop = Param(nameof(UseTrailingStop), false)
.SetDisplay("Use Trailing Stop", "Use the percent trailing stop", "Risk");
_trailingStopPercent = Param(nameof(TrailingStopPercent), 15m)
.SetNotNegative()
.SetDisplay("Trailing Stop %", "Trailing stop percent", "Risk");
_useMaCloseExit = Param(nameof(UseMaCloseExit), false)
.SetDisplay("MA Close Exit", "Exit when price closes below the exit MA", "Exit");
_maCloseExitPeriod = Param(nameof(MaCloseExitPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Exit MA Period", "Exit MA period", "Exit");
_useMaCrossExit = Param(nameof(UseMaCrossExit), true)
.SetDisplay("MA Cross Exit", "Exit when the short MA crosses below the medium MA", "Exit");
_useVolatilityFilter = Param(nameof(UseVolatilityFilter), false)
.SetDisplay("Volatility Exit", "Exit when a candle range exceeds the ATR threshold", "Exit");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "Exit");
_atrMultiplier = Param(nameof(AtrMultiplier), 1.5m)
.SetNotNegative()
.SetDisplay("ATR Multiplier", "ATR multiplier of the volatility exit", "Exit");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType), (Security, MacdCandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevShort = null;
_prevMid = null;
_prevMacd = null;
_prevSignal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevShort = null;
_prevMid = null;
_prevMacd = null;
_prevSignal = null;
var shortMa = CreateMa(ShortTermPeriod);
var midMa = CreateMa(MidTermPeriod);
var longMa = CreateMa(LongTermPeriod);
var exitMa = CreateMa(MaCloseExitPeriod);
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(shortMa, midMa, longMa, exitMa, atr, ProcessCandle)
.Start();
_macd = new MovingAverageConvergenceDivergenceSignal();
_macd.Macd.ShortMa.Length = MacdFastLength;
_macd.Macd.LongMa.Length = MacdSlowLength;
_macd.SignalMa.Length = MacdSignalLength;
// The weekly MACD needs months of history, so it is processed manually to keep it from blocking entries until it forms.
SubscribeCandles(MacdCandleType)
.Bind(ProcessMacd)
.Start();
if (UseTrailingStop && TrailingStopPercent > 0)
StartProtection(new Unit(), new Unit(TrailingStopPercent, UnitTypes.Percent), isStopTrailing: true, useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, shortMa);
DrawIndicator(area, midMa);
DrawIndicator(area, longMa);
DrawOwnTrades(area);
}
}
private IIndicator CreateMa(int length)
{
return MaType == MaTypes.SMA
? new SimpleMovingAverage { Length = length }
: new ExponentialMovingAverage { Length = length };
}
private void ProcessMacd(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var macdValue = _macd.Process(candle);
if (!macdValue.IsFormed || macdValue is not IMovingAverageConvergenceDivergenceSignalValue { Macd: decimal macd, Signal: decimal signal })
return;
var crossDown = _prevMacd is decimal prevMacd && _prevSignal is decimal prevSignal && prevMacd >= prevSignal && macd < signal;
_prevMacd = macd;
_prevSignal = signal;
if (crossDown && EnableMacdExit && Position > 0 && IsFormedAndOnlineAndAllowTrading())
SellMarket(Position);
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue shortValue, IIndicatorValue midValue, IIndicatorValue longValue, IIndicatorValue exitValue, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!shortValue.IsFormed || !midValue.IsFormed)
return;
var shortMa = shortValue.GetValue<decimal>();
var midMa = midValue.GetValue<decimal>();
var prevShort = _prevShort;
var prevMid = _prevMid;
_prevShort = shortMa;
_prevMid = midMa;
if (prevShort is not decimal ps || prevMid is not decimal pm)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var crossUp = ps <= pm && shortMa > midMa;
var crossDown = ps >= pm && shortMa < midMa;
if (Position > 0)
{
var exit = (UseMaCrossExit && crossDown)
|| (UseMaCloseExit && exitValue.IsFormed && close < exitValue.GetValue<decimal>())
|| (UseVolatilityFilter && atrValue.IsFormed && candle.HighPrice - candle.LowPrice > atrValue.GetValue<decimal>() * AtrMultiplier);
if (exit)
SellMarket(Position);
return;
}
if (Position < 0 || !longValue.IsFormed)
return;
var entry = EntryConditionType == EntryConditions.Crossover ? crossUp : shortMa > midMa;
if (entry && close > longValue.GetValue<decimal>())
BuyMarket(Volume);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import (ExponentialMovingAverage, SimpleMovingAverage, AverageTrueRange,
MovingAverageConvergenceDivergenceSignal, CandleIndicatorValue)
from StockSharp.Algo.Strategies import Strategy
class long_ema_advanced_exit_strategy(Strategy):
"""
Long EMA advanced exit strategy.
Long only: enters when the short MA crosses above (or, with the Above condition, is above) the medium MA while price is above the long MA.
Exits when the MACD on the higher MacdCandleType timeframe crosses below its signal line, when price closes below the MaCloseExitPeriod MA,
when the short MA crosses below the medium MA, when a candle range exceeds AtrMultiplier ATRs, or on a percent trailing stop; each exit can be switched off.
MaType: EMA or SMA. EntryConditionType: Crossover or Above.
"""
def __init__(self):
super(long_ema_advanced_exit_strategy, self).__init__()
self._ma_type = self.Param("MaType", "EMA").SetDisplay("MA Type", "Moving average type", "Indicators")
self._entry_condition_type = self.Param("EntryConditionType", "Crossover").SetDisplay("Entry Condition", "Crossover or Above", "Entry")
self._long_term_period = self.Param("LongTermPeriod", 200).SetGreaterThanZero().SetDisplay("Long MA", "Long-term MA period", "Indicators")
self._short_term_period = self.Param("ShortTermPeriod", 5).SetGreaterThanZero().SetDisplay("Short MA", "Short-term MA period", "Indicators")
self._mid_term_period = self.Param("MidTermPeriod", 10).SetGreaterThanZero().SetDisplay("Medium MA", "Medium-term MA period", "Indicators")
self._enable_macd_exit = self.Param("EnableMacdExit", True).SetDisplay("MACD Exit", "Exit on a MACD cross down", "Exit")
self._macd_candle_type = self.Param("MacdCandleType", DataType.TimeFrame(TimeSpan.FromDays(7))).SetDisplay("MACD Candle Type", "Candle type of the MACD exit", "Exit")
self._macd_fast_length = self.Param("MacdFastLength", 12).SetGreaterThanZero().SetDisplay("MACD Fast", "MACD fast length", "Exit")
self._macd_slow_length = self.Param("MacdSlowLength", 26).SetGreaterThanZero().SetDisplay("MACD Slow", "MACD slow length", "Exit")
self._macd_signal_length = self.Param("MacdSignalLength", 9).SetGreaterThanZero().SetDisplay("MACD Signal", "MACD signal length", "Exit")
self._use_trailing_stop = self.Param("UseTrailingStop", False).SetDisplay("Use Trailing Stop", "Use the percent trailing stop", "Risk")
self._trailing_stop_percent = self.Param("TrailingStopPercent", 15.0).SetNotNegative().SetDisplay("Trailing Stop %", "Trailing stop percent", "Risk")
self._use_ma_close_exit = self.Param("UseMaCloseExit", False).SetDisplay("MA Close Exit", "Exit when price closes below the exit MA", "Exit")
self._ma_close_exit_period = self.Param("MaCloseExitPeriod", 50).SetGreaterThanZero().SetDisplay("Exit MA Period", "Exit MA period", "Exit")
self._use_ma_cross_exit = self.Param("UseMaCrossExit", True).SetDisplay("MA Cross Exit", "Exit when the short MA crosses below the medium MA", "Exit")
self._use_volatility_filter = self.Param("UseVolatilityFilter", False).SetDisplay("Volatility Exit", "Exit when a candle range exceeds the ATR threshold", "Exit")
self._atr_period = self.Param("AtrPeriod", 14).SetGreaterThanZero().SetDisplay("ATR Period", "ATR period", "Exit")
self._atr_multiplier = self.Param("AtrMultiplier", 1.5).SetNotNegative().SetDisplay("ATR Multiplier", "ATR multiplier of the volatility exit", "Exit")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._macd = None
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.candle_type), (self.Security, self._macd_candle_type.Value)]
def _reset_state(self):
self._prev_short = None
self._prev_mid = None
self._prev_macd = None
self._prev_signal = None
def OnReseted(self):
super(long_ema_advanced_exit_strategy, self).OnReseted()
self._reset_state()
def _create_ma(self, length):
ma = SimpleMovingAverage() if str(self._ma_type.Value) == "SMA" else ExponentialMovingAverage()
ma.Length = length
return ma
def OnStarted2(self, time):
super(long_ema_advanced_exit_strategy, self).OnStarted2(time)
self._reset_state()
short_ma = self._create_ma(self._short_term_period.Value)
mid_ma = self._create_ma(self._mid_term_period.Value)
long_ma = self._create_ma(self._long_term_period.Value)
exit_ma = self._create_ma(self._ma_close_exit_period.Value)
atr = AverageTrueRange()
atr.Length = self._atr_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(short_ma, mid_ma, long_ma, exit_ma, atr, self._process_candle).Start()
self._macd = MovingAverageConvergenceDivergenceSignal()
self._macd.Macd.ShortMa.Length = self._macd_fast_length.Value
self._macd.Macd.LongMa.Length = self._macd_slow_length.Value
self._macd.SignalMa.Length = self._macd_signal_length.Value
# The weekly MACD needs months of history, so it is processed manually to keep it from blocking entries until it forms.
self.SubscribeCandles(self._macd_candle_type.Value).Bind(self._process_macd).Start()
if self._use_trailing_stop.Value and self._trailing_stop_percent.Value > 0:
self.StartProtection(Unit(), Unit(Decimal(self._trailing_stop_percent.Value), UnitTypes.Percent), isStopTrailing=True, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, short_ma)
self.DrawIndicator(area, mid_ma)
self.DrawIndicator(area, long_ma)
self.DrawOwnTrades(area)
def _process_macd(self, candle):
if candle.State != CandleStates.Finished:
return
macd_value = self._macd.Process(CandleIndicatorValue(self._macd, candle))
if not macd_value.IsFormed or macd_value.Macd is None or macd_value.Signal is None:
return
macd = macd_value.Macd
signal = macd_value.Signal
cross_down = self._prev_macd is not None and self._prev_signal is not None and self._prev_macd >= self._prev_signal and macd < signal
self._prev_macd = macd
self._prev_signal = signal
if cross_down and self._enable_macd_exit.Value and self.Position > 0 and self.IsFormedAndOnlineAndAllowTrading():
self.SellMarket(self.Position)
def _process_candle(self, candle, short_value, mid_value, long_value, exit_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not short_value.IsFormed or not mid_value.IsFormed:
return
short_ma = short_value.GetValue[Decimal](None)
mid_ma = mid_value.GetValue[Decimal](None)
prev_short = self._prev_short
prev_mid = self._prev_mid
self._prev_short = short_ma
self._prev_mid = mid_ma
if prev_short is None or prev_mid is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
cross_up = prev_short <= prev_mid and short_ma > mid_ma
cross_down = prev_short >= prev_mid and short_ma < mid_ma
if self.Position > 0:
exit_signal = (self._use_ma_cross_exit.Value and cross_down) \
or (self._use_ma_close_exit.Value and exit_value.IsFormed and close < exit_value.GetValue[Decimal](None)) \
or (self._use_volatility_filter.Value and atr_value.IsFormed
and candle.HighPrice - candle.LowPrice > atr_value.GetValue[Decimal](None) * Decimal(self._atr_multiplier.Value))
if exit_signal:
self.SellMarket(self.Position)
return
if self.Position < 0 or not long_value.IsFormed:
return
entry = cross_up if str(self._entry_condition_type.Value) == "Crossover" else short_ma > mid_ma
if entry and close > long_value.GetValue[Decimal](None):
self.BuyMarket(self.Volume)
def CreateClone(self):
return long_ema_advanced_exit_strategy()