Color XMACDローソク足戦略
この戦略は「ColorXMACDCandle」エキスパートアドバイザーのStockSharp実装です。MACDインジケーターを使用し、ヒストグラムまたはシグナルラインの色変化をエントリーシグナルとして解釈します。
アイデア
戦略はMACDコンポーネントの傾きを分析します:
- ヒストグラムモード – 前のバーよりも高い新しいヒストグラムバーは強気モメンタムの増加を示します。前のバーよりも低い新しいバーは弱気モメンタムを示します。
- シグナルラインモード – MACDシグナルラインの傾きを代わりに使用します。上向きの傾きは買いシグナルとして機能し、下向きの傾きは売りシグナルとして機能します。
選択されたコンポーネントが上向きに転じ、以前は上昇していなかった場合、ショートポジションを閉じてロングポジションを開くことができます。コンポーネントが下向きに転じ、以前は下落していなかった場合、ロングポジションを閉じてショートポジションを開くことができます。
ポジションの開閉の動作は個別のパラメーターで制御され、ユーザーは各アクションを独立して有効または無効にすることができます。
パラメーター
Mode– シグナルのソース:HistogramまたはSignalLine。FastPeriod– MACDの高速EMA期間。SlowPeriod– MACDの低速EMA期間。SignalPeriod– MACDシグナルスムージング期間。EnableBuyOpen– ロングポジションの開始を許可する。EnableSellOpen– ショートポジションの開始を許可する。EnableBuyClose– ロングポジションの決済を許可する。EnableSellClose– ショートポジションの決済を許可する。CandleType– 計算用のローソク足タイプ。
取引ルール
- 選択したローソク足シリーズを購読してMACDインジケーターを計算する。
- 選択したモードに応じてヒストグラムまたはシグナルラインの傾きを追跡する。
- 傾きが上向きに転じたとき、ショートポジションを閉じ(許可されている場合)、任意でロングポジションを開く。
- 傾きが下向きに転じたとき、ロングポジションを閉じ(許可されている場合)、任意でショートポジションを開く。
この戦略にはストップロスやテイクプロフィットのメカニズムは含まれていません。必要に応じてリスク管理を別途追加できます。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that reacts to slope changes of the MACD histogram.
/// Buys when histogram slope turns up, sells when it turns down.
/// </summary>
public class ColorXMacdCandleStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _signalMa;
private decimal? _prevHist;
private decimal? _prevPrevHist;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorXMacdCandleStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "MACD");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "MACD");
_signalPeriod = Param(nameof(SignalPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Period", "Signal line period", "MACD");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type for calculations", "Common");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_signalMa = null;
_prevHist = null;
_prevPrevHist = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergence();
macd.ShortMa.Length = FastPeriod;
macd.LongMa.Length = SlowPeriod;
_signalMa = new ExponentialMovingAverage { Length = SignalPeriod };
Indicators.Add(_signalMa);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFormed)
return;
var macdLine = macdValue.GetValue<decimal>();
var signalResult = _signalMa.Process(macdValue);
if (!signalResult.IsFormed)
return;
var signalLine = signalResult.GetValue<decimal>();
var hist = macdLine - signalLine;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevPrevHist = _prevHist;
_prevHist = hist;
return;
}
if (_prevHist is decimal ph && _prevPrevHist is decimal pph)
{
var wasRising = ph > pph;
var nowRising = hist > ph;
// Histogram slope turns up -> buy
if (!wasRising && nowRising && Position <= 0)
BuyMarket();
// Histogram slope turns down -> sell
else if (wasRising && !nowRising && Position >= 0)
SellMarket();
}
_prevPrevHist = _prevHist;
_prevHist = hist;
}
}
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 MovingAverageConvergenceDivergence, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_xmacd_candle_strategy(Strategy):
def __init__(self):
super(color_xmacd_candle_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) \
.SetDisplay("Fast Period", "Fast EMA period", "MACD")
self._slow_period = self.Param("SlowPeriod", 26) \
.SetDisplay("Slow Period", "Slow EMA period", "MACD")
self._signal_period = self.Param("SignalPeriod", 9) \
.SetDisplay("Signal Period", "Signal line period", "MACD")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type for calculations", "Common")
self._signal_ma = None
self._prev_hist = None
self._prev_prev_hist = None
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def signal_period(self):
return self._signal_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_xmacd_candle_strategy, self).OnReseted()
self._signal_ma = None
self._prev_hist = None
self._prev_prev_hist = None
def OnStarted2(self, time):
super(color_xmacd_candle_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.fast_period
macd.LongMa.Length = self.slow_period
self._signal_ma = ExponentialMovingAverage()
self._signal_ma.Length = self.signal_period
self.Indicators.Add(self._signal_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(macd, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, macd)
self.DrawOwnTrades(area)
def process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFormed:
return
macd_line = float(macd_value)
signal_result = self._signal_ma.Process(macd_value)
if not signal_result.IsFormed:
return
signal_line = float(signal_result)
hist = macd_line - signal_line
if self._prev_hist is not None and self._prev_prev_hist is not None:
was_rising = self._prev_hist > self._prev_prev_hist
now_rising = hist > self._prev_hist
if not was_rising and now_rising and self.Position <= 0:
self.BuyMarket()
elif was_rising and not now_rising and self.Position >= 0:
self.SellMarket()
self._prev_prev_hist = self._prev_hist
self._prev_hist = hist
def CreateClone(self):
return color_xmacd_candle_strategy()