GitHub で見る

ダイバージェンス + EMA + RSI 閉じる購入のみ

概要

この戦略は、MetaTrader の「ダイバージェンス + ema + rsi 終値買いのみ」エキスパート アドバイザーを StockSharp の高レベルの API に移植します。 5 分足ローソクに基づいて機能し、時間 および データを参照して、トレンドの一致と売られ過ぎの状態を確認します。オーダーはロングのみとなります。エントリーには、強気の MACD ヒストグラムの発散が必要です。これは、タイトな売られすぎバンド内の 1 時間ごとの確率的クロスオーバーと、日次の上昇する EMA 構造によって確認されます。イグジットは、フレームワークによって管理されるオプションのストップロスおよびテイクプロフィット保護と組み合わせた固定の RSI オーバーシュートに依存します。

取引ロジック

  1. より長い時間枠のトレンド フィルター

    • 上昇トレンドを確実にするには、日次 EMA(9) が EMA(20) を上回る必要があります。
    • 直近の5分間終値は日足のEMA(9)を下回って、戻りからのロングエントリーが試みられるようにする必要があります。
  2. 時間ごとの確率的確認

    • 最新の完了した時間ごとの確率的 %K 値は、StochasticLowerBound (デフォルト 0) と StochasticUpperBound (デフォルト 40) の間になければなりません。
    • %K は最後の時間足で %D を上回っている必要があります (現在の %K > %D で、前の %K ≤ 以前の %D)。
  3. MACD 分岐トリガー (5 分)

    • MACD ヒストグラム (MACD ラインからシグナル ラインを引いたもの) は、5 分足の終値が前のローソク足と比較して低い安値を設定する間に、少なくとも MacdThreshold 改善する必要があります。これは、元の EA で使用された強気ダイバージェンスに近似します。
  4. エントリー実行

    • すべてのフィルターが一致し、ロングポジションがない場合、戦略は市場買いを送信します。予期しないショートポジションが存在する場合は、ロングを反転する前に、要求されたボリュームが増加してそれを中和します。
  5. 退出ルール

    • 保護的な RSI 出口は、5 分足 RSI が RsiExitLevel (デフォルト 77) を超えたときにロングを閉じます。
    • StartProtection は、対応するパラメータが正の場合は常に、ピップから価格距離に変換されたストップロスとテイクプロフィットの両方のレベルをアクティブにします。
  6. 注文管理

    • 約定の重複を避けるため、新しい成行買い注文を送信する前に、アクティブな注文はすべてキャンセルされます。
    • 音量のデフォルトは TradeVolume パラメータで、最適化のために調整できます。

パラメーター

名前 説明 デフォルト
CandleType MACD、RSI、および実行の主なタイムフレーム。 5分キャンドル
HourTimeFrame 確率的フィルターで使用される時間枠。 1時間
DayTimeFrame EMA のトレンド確認の日次時間枠。 1日
MacdFastPeriod / MacdSlowPeriod / MacdSignalPeriod プライマリタイムフレームの MACD 構造。 6/13/5
MacdThreshold 発散を受け入れるための最小の MACD ヒストグラムの増加。 0.0003
DailyFastPeriod / DailySlowPeriod 毎日の EMA 期間。 9/20
StochasticKPeriod / StochasticDPeriod / StochasticSlowing 時間ごとの確率的構成。 30/5/9
StochasticUpperBound / StochasticLowerBound 許容される時間単位の %K 範囲。 40/0
RsiPeriod プライマリ タイムフレームの長さは RSI です。 7
RsiExitLevel RSI の値は強制的に長時間終了します。 77
TradeVolume 購入の基本注文サイズ。 0.01
StopLossPips ストップロス距離 (ピップ単位) (0 は無効)。 100
TakeProfitPips 利益確定距離 (ピップ単位) (0 を無効にします)。 200

注意事項

  • この戦略は、構成されたプライマリ時間枠、時間単位のシリーズ、日単位のシリーズという 3 つのデータ ストリームをサブスクライブします。各ストリームは、実装を簡潔かつイベント駆動型に保つために、Bind/BindEx を介して独自のインジケーター セットを駆動します。
  • インジケーター値は、元の EA のシフト パラメーターを反映するために、完成したキャンドルでのみ処理されます。
  • MACD 発散検出では、ソース MQL ファイルからビルダーが生成したロジックのシンプルかつ堅牢な近似値として、前のバーの終値とヒストグラム値を使用します。
  • ストップロスとテイクプロフィットは、ブローカーの約定との同期を維持するために StartProtection によって処理され、手動で注文を複製することなくバックテストやライブ取引をサポートします。
using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Divergence EMA RSI Close Buy Only" MetaTrader expert.
/// Long-only strategy: buys when price pulls back below fast EMA with RSI oversold,
/// exits when RSI reaches overbought level.
/// </summary>
public class DivergenceEmaRsiCloseBuyOnlyStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiEntry;
	private readonly StrategyParam<decimal> _rsiExit;

	private ExponentialMovingAverage _ema;
	private RelativeStrengthIndex _rsi;
	private decimal? _prevRsi;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal RsiEntry
	{
		get => _rsiEntry.Value;
		set => _rsiEntry.Value = value;
	}

	public decimal RsiExit
	{
		get => _rsiExit.Value;
		set => _rsiExit.Value = value;
	}

	public DivergenceEmaRsiCloseBuyOnlyStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for signals", "General");

		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend filter", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period for entry/exit", "Indicators");

		_rsiEntry = Param(nameof(RsiEntry), 35m)
			.SetDisplay("RSI Entry", "RSI level to enter long", "Signals");

		_rsiExit = Param(nameof(RsiExit), 65m)
			.SetDisplay("RSI Exit", "RSI level to exit long", "Signals");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_ema = new ExponentialMovingAverage { Length = EmaPeriod };
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		_prevRsi = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_ema, _rsi, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _ema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal rsiValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_ema.IsFormed || !_rsi.IsFormed)
		{
			_prevRsi = rsiValue;
			return;
		}

		if (_prevRsi is null)
		{
			_prevRsi = rsiValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;
		var close = candle.ClosePrice;

		// Exit: RSI crosses above exit level
		if (Position > 0 && _prevRsi.Value < RsiExit && rsiValue >= RsiExit)
		{
			SellMarket(Position);
		}

		// Entry: RSI crosses below entry level and price is near/below EMA (buy the dip)
		if (Position <= 0 && _prevRsi.Value > RsiEntry && rsiValue <= RsiEntry && close <= emaValue * 1.005m)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));

			BuyMarket(volume);
		}

		_prevRsi = rsiValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_ema = null;
		_rsi = null;
		_prevRsi = null;

		base.OnReseted();
	}
}