ダブル MACD
ダブル MACDは異なる速度の2つのMACDインジケーターを使用します。両方のMACDが方向一致した時のみポジションを開設します。
最初のMACDは高速で素早く反応します。2番目は低速で、取引前にトレンドを確認します。
詳細
- データ: 価格ローソク足。
- エントリー条件:
- ロング: 両方のMACDラインがシグナルラインを上回る。
- ショート: 両方のMACDラインがシグナルラインを下回る。
- エグジット条件: 反対のシグナルまたはストップ。
- ストップ: オプションのストップロス。
- デフォルト値:
FastLength1= 12SlowLength1= 26SignalLength1= 9MaType1= EmaFastLength2= 24SlowLength2= 52SignalLength2= 9MaType2= EmaStopLossPercent= 2CandleType= tf(5)
- フィルター:
- カテゴリ: トレンド
- 方向: ロングとショート
- インジケーター: MACD
- ストップ: あり
- 複雑さ: 基本
- 時間軸: イントラデイ (5m)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Double MACD strategy.
/// Two MACDs of different speeds are built from moving averages of the selected types: each MACD line is the fast average of the
/// close minus the slow one, and its signal line is an average of the same type over the MACD line. The strategy goes long when both
/// MACD lines are above their signal lines and short when both are below, reversing an opposite position. A percent stop loss limits
/// the loss.
/// </summary>
public class DoubleMacdStrategy : Strategy
{
/// <summary>
/// Moving average types of the MACDs.
/// </summary>
public enum MaTypes
{
/// <summary>
/// Exponential moving average.
/// </summary>
Ema,
/// <summary>
/// Simple moving average.
/// </summary>
Sma,
/// <summary>
/// Weighted moving average.
/// </summary>
Wma,
/// <summary>
/// Smoothed moving average.
/// </summary>
Smma,
}
private readonly StrategyParam<int> _fastLength1;
private readonly StrategyParam<int> _slowLength1;
private readonly StrategyParam<int> _signalLength1;
private readonly StrategyParam<MaTypes> _maType1;
private readonly StrategyParam<int> _fastLength2;
private readonly StrategyParam<int> _slowLength2;
private readonly StrategyParam<int> _signalLength2;
private readonly StrategyParam<MaTypes> _maType2;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private IIndicator _signal1;
private IIndicator _signal2;
/// <summary>
/// Fast period of the first MACD.
/// </summary>
public int FastLength1
{
get => _fastLength1.Value;
set => _fastLength1.Value = value;
}
/// <summary>
/// Slow period of the first MACD.
/// </summary>
public int SlowLength1
{
get => _slowLength1.Value;
set => _slowLength1.Value = value;
}
/// <summary>
/// Signal period of the first MACD.
/// </summary>
public int SignalLength1
{
get => _signalLength1.Value;
set => _signalLength1.Value = value;
}
/// <summary>
/// Moving average type of the first MACD.
/// </summary>
public MaTypes MaType1
{
get => _maType1.Value;
set => _maType1.Value = value;
}
/// <summary>
/// Fast period of the second MACD.
/// </summary>
public int FastLength2
{
get => _fastLength2.Value;
set => _fastLength2.Value = value;
}
/// <summary>
/// Slow period of the second MACD.
/// </summary>
public int SlowLength2
{
get => _slowLength2.Value;
set => _slowLength2.Value = value;
}
/// <summary>
/// Signal period of the second MACD.
/// </summary>
public int SignalLength2
{
get => _signalLength2.Value;
set => _signalLength2.Value = value;
}
/// <summary>
/// Moving average type of the second MACD.
/// </summary>
public MaTypes MaType2
{
get => _maType2.Value;
set => _maType2.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DoubleMacdStrategy()
{
_fastLength1 = Param(nameof(FastLength1), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Length 1", "Fast period of the first MACD", "MACD 1");
_slowLength1 = Param(nameof(SlowLength1), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Length 1", "Slow period of the first MACD", "MACD 1");
_signalLength1 = Param(nameof(SignalLength1), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Length 1", "Signal period of the first MACD", "MACD 1");
_maType1 = Param(nameof(MaType1), MaTypes.Ema)
.SetDisplay("MA Type 1", "Moving average type of the first MACD", "MACD 1");
_fastLength2 = Param(nameof(FastLength2), 24)
.SetGreaterThanZero()
.SetDisplay("Fast Length 2", "Fast period of the second MACD", "MACD 2");
_slowLength2 = Param(nameof(SlowLength2), 52)
.SetGreaterThanZero()
.SetDisplay("Slow Length 2", "Slow period of the second MACD", "MACD 2");
_signalLength2 = Param(nameof(SignalLength2), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Length 2", "Signal period of the second MACD", "MACD 2");
_maType2 = Param(nameof(MaType2), MaTypes.Ema)
.SetDisplay("MA Type 2", "Moving average type of the second MACD", "MACD 2");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_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)];
}
private static IIndicator CreateMa(MaTypes type, int length)
{
return type switch
{
MaTypes.Sma => new SimpleMovingAverage { Length = length },
MaTypes.Wma => new WeightedMovingAverage { Length = length },
MaTypes.Smma => new SmoothedMovingAverage { Length = length },
_ => new ExponentialMovingAverage { Length = length },
};
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast1 = CreateMa(MaType1, FastLength1);
var slow1 = CreateMa(MaType1, SlowLength1);
var fast2 = CreateMa(MaType2, FastLength2);
var slow2 = CreateMa(MaType2, SlowLength2);
_signal1 = CreateMa(MaType1, SignalLength1);
_signal2 = CreateMa(MaType2, SignalLength2);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(fast1, slow1, fast2, slow2, ProcessCandle)
.Start();
StartProtection(new Unit(), StopLossPercent > 0 ? new Unit(StopLossPercent, UnitTypes.Percent) : new Unit(), useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue fast1Value, IIndicatorValue slow1Value, IIndicatorValue fast2Value, IIndicatorValue slow2Value)
{
if (candle.State != CandleStates.Finished)
return;
if (!fast1Value.IsFormed || !slow1Value.IsFormed || !fast2Value.IsFormed || !slow2Value.IsFormed)
return;
var macd1 = fast1Value.GetValue<decimal>() - slow1Value.GetValue<decimal>();
var macd2 = fast2Value.GetValue<decimal>() - slow2Value.GetValue<decimal>();
var signal1Value = _signal1.Process(new DecimalIndicatorValue(_signal1, macd1, candle.OpenTime) { IsFinal = true });
var signal2Value = _signal2.Process(new DecimalIndicatorValue(_signal2, macd2, candle.OpenTime) { IsFinal = true });
if (!signal1Value.IsFormed || !signal2Value.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var signal1 = signal1Value.GetValue<decimal>();
var signal2 = signal2Value.GetValue<decimal>();
var bullish = macd1 > signal1 && macd2 > signal2;
var bearish = macd1 < signal1 && macd2 < signal2;
if (bullish && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (bearish && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
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, WeightedMovingAverage, SmoothedMovingAverage, DecimalIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class MaTypes:
"""Moving average types of the MACDs."""
Ema = 0
Sma = 1
Wma = 2
Smma = 3
class double_macd_strategy(Strategy):
"""
Double MACD strategy.
Two MACDs of different speeds are built from moving averages of the selected types: each MACD line is the fast average of the
close minus the slow one, and its signal line is an average of the same type over the MACD line. The strategy goes long when both
MACD lines are above their signal lines and short when both are below, reversing an opposite position. A percent stop loss limits
the loss.
"""
def __init__(self):
super(double_macd_strategy, self).__init__()
self._fast_length1 = self.Param("FastLength1", 12).SetGreaterThanZero().SetDisplay("Fast Length 1", "Fast period of the first MACD", "MACD 1")
self._slow_length1 = self.Param("SlowLength1", 26).SetGreaterThanZero().SetDisplay("Slow Length 1", "Slow period of the first MACD", "MACD 1")
self._signal_length1 = self.Param("SignalLength1", 9).SetGreaterThanZero().SetDisplay("Signal Length 1", "Signal period of the first MACD", "MACD 1")
self._ma_type1 = self.Param("MaType1", MaTypes.Ema).SetDisplay("MA Type 1", "Moving average type of the first MACD", "MACD 1")
self._fast_length2 = self.Param("FastLength2", 24).SetGreaterThanZero().SetDisplay("Fast Length 2", "Fast period of the second MACD", "MACD 2")
self._slow_length2 = self.Param("SlowLength2", 52).SetGreaterThanZero().SetDisplay("Slow Length 2", "Slow period of the second MACD", "MACD 2")
self._signal_length2 = self.Param("SignalLength2", 9).SetGreaterThanZero().SetDisplay("Signal Length 2", "Signal period of the second MACD", "MACD 2")
self._ma_type2 = self.Param("MaType2", MaTypes.Ema).SetDisplay("MA Type 2", "Moving average type of the second MACD", "MACD 2")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._signal1 = None
self._signal2 = None
@property
def candle_type(self):
return self._candle_type.Value
@staticmethod
def _create_ma(ma_type, length):
if ma_type == MaTypes.Sma:
ma = SimpleMovingAverage()
elif ma_type == MaTypes.Wma:
ma = WeightedMovingAverage()
elif ma_type == MaTypes.Smma:
ma = SmoothedMovingAverage()
else:
ma = ExponentialMovingAverage()
ma.Length = length
return ma
def OnStarted2(self, time):
super(double_macd_strategy, self).OnStarted2(time)
ma_type1 = self._ma_type1.Value
ma_type2 = self._ma_type2.Value
fast1 = self._create_ma(ma_type1, self._fast_length1.Value)
slow1 = self._create_ma(ma_type1, self._slow_length1.Value)
fast2 = self._create_ma(ma_type2, self._fast_length2.Value)
slow2 = self._create_ma(ma_type2, self._slow_length2.Value)
self._signal1 = self._create_ma(ma_type1, self._signal_length1.Value)
self._signal2 = self._create_ma(ma_type2, self._signal_length2.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(fast1, slow1, fast2, slow2, self._process_candle).Start()
stop_percent = Decimal(self._stop_loss_percent.Value)
stop_loss = Unit(stop_percent, UnitTypes.Percent) if stop_percent > 0 else Unit()
self.StartProtection(Unit(), stop_loss, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_signal(self, indicator, value, candle):
input_value = DecimalIndicatorValue(indicator, value, candle.OpenTime)
input_value.IsFinal = True
return indicator.Process(input_value)
def _process_candle(self, candle, fast1_value, slow1_value, fast2_value, slow2_value):
if candle.State != CandleStates.Finished:
return
if not fast1_value.IsFormed or not slow1_value.IsFormed or not fast2_value.IsFormed or not slow2_value.IsFormed:
return
macd1 = fast1_value.GetValue[Decimal](None) - slow1_value.GetValue[Decimal](None)
macd2 = fast2_value.GetValue[Decimal](None) - slow2_value.GetValue[Decimal](None)
signal1_value = self._process_signal(self._signal1, macd1, candle)
signal2_value = self._process_signal(self._signal2, macd2, candle)
if not signal1_value.IsFormed or not signal2_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
signal1 = signal1_value.GetValue[Decimal](None)
signal2 = signal2_value.GetValue[Decimal](None)
bullish = macd1 > signal1 and macd2 > signal2
bearish = macd1 < signal1 and macd2 < signal2
if bullish and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif bearish and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return double_macd_strategy()