GitHub で見る
MACD ダイバージェンス RSI 戦略
概要
- MetaTrader エキスパート アドバイザー 「Macd diver rsi mt4」 を StockSharp のハイレベル API に移植します。
- MACD ダイバージェンス認識と組み合わせた RSI フィルターを使用して、単一のシンボルを時間反転にトレードします。
- 一度にオープンできる市場ポジションは 1 つだけです。この戦略は、新しいシグナルを発行する前にフラット状態になるのを待ちます。
信号ロジック
- 選択した時間枠からの終了したすべてのローソク足は、戦略にバインドされた 4 つのインジケーターをフィードします。
- 2 つの独立した
RelativeStrengthIndex インスタンス (売られすぎフィルターと買われすぎフィルター用) が 1 バー分サンプリングしました。
- 構成可能な高速/低速 EMA と信号長を備えた 2 つの
MovingAverageConvergenceDivergence インジケーター。
- 強気のセットアップ
- 前のバー RSI は、設定可能な売られすぎしきい値を下回っている必要があります。
- 最新の MACD 値は、動的しきい値 (現在の商品の 3 ピップに相当) を下回る局所的なディップを形成する必要があります。
- 過去のデータがスキャンされ、以前の MACD の下落とそれに関連する価格変動の安値が特定されます。乖離が確認された場合
MACD の谷が上昇する一方で価格が安値を切り下げる(通常のダイバージェンス)、または MACD の谷が下落する一方で価格が高くなる
低い (隠れた発散)、元の MQL ロジックと一致します。
- 確認され、戦略にオープンポジションがない場合、方向固有のボリュームとリスク設定で市場買いが送信されます。
- 弱気の設定は、RSI の買われすぎフィルターと MACD のピークを備えた強気のルールを反映しています。発散は次によって検証されます
以前のスイング高値と現在のスイング高値を比較します。
- エントリー直後、戦略は設定されたストップロスとテイクプロフィットの距離をピップから価格単位に変換します。
(元のポイント形式ルールを尊重して)
SetStopLoss / SetTakeProfit を通じて適用します。
パラメーター
LowerRsiPeriod、LowerRsiThreshold – inp1_Lo_RSIperiod / inp1_Ro_Value にマッピングします。
BullishFastEma、BullishSlowEma、BullishSignalSma – inp2_fastEMA / inp2_slowEMA / inp2_signalSMA にマッピングします。
BullishVolume、BullishStopLossPips、BullishTakeProfitPips – inp3_VolumeSize、inp3_StopLossPips、inp3_TakeProfitPips にマッピングします。
UpperRsiPeriod、UpperRsiThreshold – inp4_Lo_RSIperiod / inp4_Ro_Value にマッピングします。
BearishFastEma、BearishSlowEma、BearishSignalSma – inp5_fastEMA / inp5_slowEMA / inp5_signalSMA にマッピングします。
BearishVolume、BearishStopLossPips、BearishTakeProfitPips – inp6_VolumeSize、inp6_StopLossPips、inp6_TakeProfitPips にマッピングします。
CandleType – すべての計算のタイムフレーム ソース。
実装メモ
- MACD 発散閾値は現在の商品ポイント サイズから導出され、3 ピップに等しく、デフォルトの 0.0003 に一致します。
MQL バージョンで使用されます。
- ローソク足、MACD、および価格履歴は、境界付きリスト (600 要素) に保存され、発散スキャン ウィンドウを再現します。
大きな配列を割り当てる。
- この戦略は、
SubscribeCandles(...).Bind(...) を使用して単一パスですべてのインジケーターを更新し、プロセスのみが終了します
ローソク足は、元のバーごとに 1 回のブロック実行と同じです。
- ピップ距離は、
SetStopLoss と SetTakeProfit を呼び出す前に絶対価格オフセットに変換され、
MQL ソースの先頭で宣言されたポイント形式ルール。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MACD Divergence RSI strategy: RSI filter + MACD signal line crossover.
/// Buys when RSI below threshold and MACD crosses above signal.
/// Sells when RSI above threshold and MACD crosses below signal.
/// </summary>
public class MacdDivergenceRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private decimal _prevMacd;
private decimal _prevSignal;
private decimal _prevRsi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public MacdDivergenceRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = 0;
_prevSignal = 0;
_prevRsi = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = 12 }, LongMa = { Length = 26 } },
SignalMa = { Length = 9 }
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal || !rsiValue.IsFinal) return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;
var rsi = rsiValue.ToDecimal();
if (_hasPrev)
{
if (_prevMacd <= _prevSignal && macdMain > signal && rsi < 40 && Position <= 0)
BuyMarket();
else if (_prevMacd >= _prevSignal && macdMain < signal && rsi > 60 && Position >= 0)
SellMarket();
}
_prevMacd = macdMain;
_prevSignal = signal;
_prevRsi = rsi;
_hasPrev = true;
}
}
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 MovingAverageConvergenceDivergenceSignal, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class macd_divergence_rsi_strategy(Strategy):
def __init__(self):
super(macd_divergence_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._prev_macd = 0.0
self._prev_signal = 0.0
self._prev_rsi = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
def OnReseted(self):
super(macd_divergence_rsi_strategy, self).OnReseted()
self._prev_macd = 0.0
self._prev_signal = 0.0
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(macd_divergence_rsi_strategy, self).OnStarted2(time)
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = 12
macd.Macd.LongMa.Length = 26
macd.SignalMa.Length = 9
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, rsi, self._process_candle).Start()
def _process_candle(self, candle, macd_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not rsi_value.IsFinal:
return
if macd_value.Macd is None or macd_value.Signal is None:
return
macd_main = float(macd_value.Macd)
signal = float(macd_value.Signal)
rsi_val = float(rsi_value)
if self._has_prev:
if self._prev_macd <= self._prev_signal and macd_main > signal and rsi_val < 40 and self.Position <= 0:
self.BuyMarket()
elif self._prev_macd >= self._prev_signal and macd_main < signal and rsi_val > 60 and self.Position >= 0:
self.SellMarket()
self._prev_macd = macd_main
self._prev_signal = signal
self._prev_rsi = rsi_val
self._has_prev = True
def CreateClone(self):
return macd_divergence_rsi_strategy()