デュアル Supertrend MACD 戦略
デュアル Supertrend MACD 戦略は、2つの Supertrend インジケーターと MACD フィルターを組み合わせます。 価格が両方の Supertrend ラインより上にあり、MACD ヒストグラムが正の場合にロングポジションを建てます。 価格が両方のラインより下にあり、ヒストグラムが負の場合にショートポジションが発生します。 いずれかの Supertrend が方向を転換するか、MACD ヒストグラムがゼロを越えたときにポジションを閉じます。
詳細
- データ: 価格ローソク足。
- エントリー条件:
- ロング:
Close > Supertrend1 && Close > Supertrend2 && MACD Histogram > 0 - ショート:
Close < Supertrend1 && Close < Supertrend2 && MACD Histogram < 0
- ロング:
- エグジット条件:
- ロング:
Close < Supertrend1 || Close < Supertrend2 || MACD Histogram < 0 - ショート:
Close > Supertrend1 || Close > Supertrend2 || MACD Histogram > 0
- ロング:
- ストップ: デフォルトなし。
- デフォルト値:
MacdFast= 12MacdSlow= 26MacdSignal= 9OscillatorMaType= ExponentialSignalMaType= ExponentialAtrPeriod1= 10Factor1= 3.0AtrPeriod2= 20Factor2= 5.0TradeDirection= "Both"
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 設定可能
- インジケーター: Supertrend, MACD
- 複雑さ: 中級
- リスクレベル: 中
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>
/// Dual Supertrend MACD strategy.
/// The MACD line is the fast minus the slow moving average of the close (OscillatorMaType) and the histogram is the MACD line minus
/// its signal average (SignalMaType). Long: close above both Supertrend lines and a positive histogram. Short: close below both lines
/// and a negative histogram. A long closes when the close falls below either line or the histogram turns negative, a short when the
/// close rises above either line or the histogram turns positive. TradeDirection limits the sides that may be opened.
/// </summary>
public class DualSupertrendMacdStrategy : Strategy
{
/// <summary>
/// Moving average types of the MACD.
/// </summary>
public enum MaTypes
{
/// <summary>
/// Simple moving average.
/// </summary>
Simple,
/// <summary>
/// Exponential moving average.
/// </summary>
Exponential,
}
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<MaTypes> _oscillatorMaType;
private readonly StrategyParam<MaTypes> _signalMaType;
private readonly StrategyParam<int> _atrPeriod1;
private readonly StrategyParam<decimal> _factor1;
private readonly StrategyParam<int> _atrPeriod2;
private readonly StrategyParam<decimal> _factor2;
private readonly StrategyParam<string> _tradeDirection;
private readonly StrategyParam<DataType> _candleType;
private IIndicator _signalMa;
/// <summary>
/// Fast MACD period.
/// </summary>
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>
/// Slow MACD period.
/// </summary>
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>
/// Signal MACD period.
/// </summary>
public int MacdSignal
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>
/// Moving average type of the MACD line.
/// </summary>
public MaTypes OscillatorMaType
{
get => _oscillatorMaType.Value;
set => _oscillatorMaType.Value = value;
}
/// <summary>
/// Moving average type of the signal line.
/// </summary>
public MaTypes SignalMaType
{
get => _signalMaType.Value;
set => _signalMaType.Value = value;
}
/// <summary>
/// ATR period of the first Supertrend.
/// </summary>
public int AtrPeriod1
{
get => _atrPeriod1.Value;
set => _atrPeriod1.Value = value;
}
/// <summary>
/// Factor of the first Supertrend.
/// </summary>
public decimal Factor1
{
get => _factor1.Value;
set => _factor1.Value = value;
}
/// <summary>
/// ATR period of the second Supertrend.
/// </summary>
public int AtrPeriod2
{
get => _atrPeriod2.Value;
set => _atrPeriod2.Value = value;
}
/// <summary>
/// Factor of the second Supertrend.
/// </summary>
public decimal Factor2
{
get => _factor2.Value;
set => _factor2.Value = value;
}
/// <summary>
/// Sides that may be opened: Long, Short or Both.
/// </summary>
public string TradeDirection
{
get => _tradeDirection.Value;
set => _tradeDirection.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DualSupertrendMacdStrategy()
{
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast MACD period", "MACD");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow MACD period", "MACD");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "Signal MACD period", "MACD");
_oscillatorMaType = Param(nameof(OscillatorMaType), MaTypes.Exponential)
.SetDisplay("Oscillator MA Type", "Moving average type of the MACD line", "MACD");
_signalMaType = Param(nameof(SignalMaType), MaTypes.Exponential)
.SetDisplay("Signal MA Type", "Moving average type of the signal line", "MACD");
_atrPeriod1 = Param(nameof(AtrPeriod1), 10)
.SetGreaterThanZero()
.SetDisplay("ATR Period 1", "ATR period of the first Supertrend", "Supertrend");
_factor1 = Param(nameof(Factor1), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Factor 1", "Factor of the first Supertrend", "Supertrend");
_atrPeriod2 = Param(nameof(AtrPeriod2), 20)
.SetGreaterThanZero()
.SetDisplay("ATR Period 2", "ATR period of the second Supertrend", "Supertrend");
_factor2 = Param(nameof(Factor2), 5.0m)
.SetGreaterThanZero()
.SetDisplay("Factor 2", "Factor of the second Supertrend", "Supertrend");
_tradeDirection = Param(nameof(TradeDirection), "Both")
.SetDisplay("Trade Direction", "Sides that may be opened: Long, Short or Both", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
private static IIndicator CreateMa(MaTypes type, int length)
{
return type == MaTypes.Simple
? new SimpleMovingAverage { Length = length }
: new ExponentialMovingAverage { Length = length };
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = CreateMa(OscillatorMaType, MacdFast);
var slowMa = CreateMa(OscillatorMaType, MacdSlow);
_signalMa = CreateMa(SignalMaType, MacdSignal);
var superTrend1 = new SuperTrend { Length = AtrPeriod1, Multiplier = Factor1 };
var superTrend2 = new SuperTrend { Length = AtrPeriod2, Multiplier = Factor2 };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(fastMa, slowMa, superTrend1, superTrend2, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, superTrend1);
DrawIndicator(area, superTrend2);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue fastValue, IIndicatorValue slowValue, IIndicatorValue st1Value, IIndicatorValue st2Value)
{
if (candle.State != CandleStates.Finished)
return;
if (!fastValue.IsFormed || !slowValue.IsFormed)
return;
var macd = fastValue.GetValue<decimal>() - slowValue.GetValue<decimal>();
var signalValue = _signalMa.Process(new DecimalIndicatorValue(_signalMa, macd, candle.OpenTime) { IsFinal = true });
if (!signalValue.IsFormed || !st1Value.IsFormed || !st2Value.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var histogram = macd - signalValue.GetValue<decimal>();
var st1 = st1Value.GetValue<decimal>();
var st2 = st2Value.GetValue<decimal>();
var close = candle.ClosePrice;
var direction = TradeDirection;
var allowLong = direction.EqualsIgnoreCase("Both") || direction.EqualsIgnoreCase("Long");
var allowShort = direction.EqualsIgnoreCase("Both") || direction.EqualsIgnoreCase("Short");
var longEntry = close > st1 && close > st2 && histogram > 0;
var shortEntry = close < st1 && close < st2 && histogram < 0;
var longExit = close < st1 || close < st2 || histogram < 0;
var shortExit = close > st1 || close > st2 || histogram > 0;
if (Position > 0)
{
if (!longExit)
return;
if (shortEntry && allowShort)
SellMarket(Volume + Position);
else
SellMarket(Position);
}
else if (Position < 0)
{
if (!shortExit)
return;
if (longEntry && allowLong)
BuyMarket(Volume - Position);
else
BuyMarket(-Position);
}
else if (longEntry && allowLong)
BuyMarket(Volume);
else if (shortEntry && allowShort)
SellMarket(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
from StockSharp.Algo.Indicators import SimpleMovingAverage, ExponentialMovingAverage, SuperTrend, DecimalIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class MaTypes:
"""Moving average types of the MACD."""
Simple = 0
Exponential = 1
class dual_supertrend_macd_strategy(Strategy):
"""
Dual Supertrend MACD strategy.
The MACD line is the fast minus the slow moving average of the close (OscillatorMaType) and the histogram is the MACD line minus
its signal average (SignalMaType). Long: close above both Supertrend lines and a positive histogram. Short: close below both lines
and a negative histogram. A long closes when the close falls below either line or the histogram turns negative, a short when the
close rises above either line or the histogram turns positive. TradeDirection limits the sides that may be opened.
"""
def __init__(self):
super(dual_supertrend_macd_strategy, self).__init__()
self._macd_fast = self.Param("MacdFast", 12).SetGreaterThanZero().SetDisplay("MACD Fast", "Fast MACD period", "MACD")
self._macd_slow = self.Param("MacdSlow", 26).SetGreaterThanZero().SetDisplay("MACD Slow", "Slow MACD period", "MACD")
self._macd_signal = self.Param("MacdSignal", 9).SetGreaterThanZero().SetDisplay("MACD Signal", "Signal MACD period", "MACD")
self._oscillator_ma_type = self.Param("OscillatorMaType", MaTypes.Exponential).SetDisplay("Oscillator MA Type", "Moving average type of the MACD line", "MACD")
self._signal_ma_type = self.Param("SignalMaType", MaTypes.Exponential).SetDisplay("Signal MA Type", "Moving average type of the signal line", "MACD")
self._atr_period1 = self.Param("AtrPeriod1", 10).SetGreaterThanZero().SetDisplay("ATR Period 1", "ATR period of the first Supertrend", "Supertrend")
self._factor1 = self.Param("Factor1", 3.0).SetGreaterThanZero().SetDisplay("Factor 1", "Factor of the first Supertrend", "Supertrend")
self._atr_period2 = self.Param("AtrPeriod2", 20).SetGreaterThanZero().SetDisplay("ATR Period 2", "ATR period of the second Supertrend", "Supertrend")
self._factor2 = self.Param("Factor2", 5.0).SetGreaterThanZero().SetDisplay("Factor 2", "Factor of the second Supertrend", "Supertrend")
self._trade_direction = self.Param("TradeDirection", "Both").SetDisplay("Trade Direction", "Sides that may be opened: Long, Short or Both", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._signal_ma = None
@property
def candle_type(self):
return self._candle_type.Value
@staticmethod
def _create_ma(ma_type, length):
ma = SimpleMovingAverage() if ma_type == MaTypes.Simple else ExponentialMovingAverage()
ma.Length = length
return ma
def OnStarted2(self, time):
super(dual_supertrend_macd_strategy, self).OnStarted2(time)
fast_ma = self._create_ma(self._oscillator_ma_type.Value, self._macd_fast.Value)
slow_ma = self._create_ma(self._oscillator_ma_type.Value, self._macd_slow.Value)
self._signal_ma = self._create_ma(self._signal_ma_type.Value, self._macd_signal.Value)
super_trend1 = SuperTrend()
super_trend1.Length = self._atr_period1.Value
super_trend1.Multiplier = Decimal(self._factor1.Value)
super_trend2 = SuperTrend()
super_trend2.Length = self._atr_period2.Value
super_trend2.Multiplier = Decimal(self._factor2.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(fast_ma, slow_ma, super_trend1, super_trend2, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, super_trend1)
self.DrawIndicator(area, super_trend2)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_value, slow_value, st1_value, st2_value):
if candle.State != CandleStates.Finished:
return
if not fast_value.IsFormed or not slow_value.IsFormed:
return
macd = fast_value.GetValue[Decimal](None) - slow_value.GetValue[Decimal](None)
signal_input = DecimalIndicatorValue(self._signal_ma, macd, candle.OpenTime)
signal_input.IsFinal = True
signal_value = self._signal_ma.Process(signal_input)
if not signal_value.IsFormed or not st1_value.IsFormed or not st2_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
histogram = macd - signal_value.GetValue[Decimal](None)
st1 = st1_value.GetValue[Decimal](None)
st2 = st2_value.GetValue[Decimal](None)
close = candle.ClosePrice
direction = str(self._trade_direction.Value).lower()
allow_long = direction == "both" or direction == "long"
allow_short = direction == "both" or direction == "short"
long_entry = close > st1 and close > st2 and histogram > 0
short_entry = close < st1 and close < st2 and histogram < 0
long_exit = close < st1 or close < st2 or histogram < 0
short_exit = close > st1 or close > st2 or histogram > 0
if self.Position > 0:
if not long_exit:
return
if short_entry and allow_short:
self.SellMarket(self.Volume + self.Position)
else:
self.SellMarket(self.Position)
elif self.Position < 0:
if not short_exit:
return
if long_entry and allow_long:
self.BuyMarket(self.Volume - self.Position)
else:
self.BuyMarket(-self.Position)
elif long_entry and allow_long:
self.BuyMarket(self.Volume)
elif short_entry and allow_short:
self.SellMarket(self.Volume)
def CreateClone(self):
return dual_supertrend_macd_strategy()