GitHub で見る

RSI アラート戦略

概要

RSI アラート戦略 は、StockSharp フレームワーク内の MetaTrader 5 "RSI アラート" エキスパート アドバイザの動作を再現します。元のボットは、売られすぎ (≤20) または買われすぎ (80 以上) レベルを大幅に超えた相対力指数 (RSI) の測定値を監視し、市場ポジションをオープンしているときにすぐにアラート通知を送信しました。変換されたバージョンでは、このイベント駆動の哲学が維持されています。つまり、完了したローソク足をリッスンし、RSI を評価し、設定されたしきい値に達したときに成行注文を送信してポジションを自動的に反転します。

取引ロジック

  1. 設定されたローソク足シリーズ (デフォルト: 1 分の時間枠) をサブスクライブし、終値を RelativeStrengthIndex インジケーターにフィードします。
  2. 不完全なローソク足を無視し、RSI インジケーターが完全に形成されるまで待ちます。これは、新しいバーごとに条件を 1 回だけ評価する MQL エキスパートを反映しています。
  3. 取引シグナルを生成します。
    • 買いシグナル – RSI ≤ OversoldLevel。この戦略は、ショートエクスポージャーをクローズし、設定されたボリュームでロングポジションをオープンします。
    • 売りシグナル – RSI ≥ OverboughtLevel。この戦略は、ロングエクスポージャーをクローズし、設定されたボリュームでショートポジションをオープンします。
  4. 注文は常に BuyMarket/SellMarket で発注されるため、未決注文、ストップロス、テイクプロフィットレベルはありません。 MetaTrader 実装では、オプションの SL/TP 入力が許可されていましたが、デフォルトでは手動管理に依存していました。 StockSharp ポートは、アラートから取引への変換に重点を置き、リスク管理を外部モジュール (たとえば、StartProtection() またはポートフォリオ レベルの制御) に任せます。

戦略はシグナル間でフラットなままです。反対のトリガーが表示されると、元の EA が連続アラートを発したときに行ったのとまったく同じように、新しい方向に入る前に既存の露出を平坦化するのに十分な量を追加して位置を逆転させます。

パラメーター

パラメータ デフォルト 説明
OrderVolume 0.01 成行注文の取引サイズ。反転する場合、この戦略は再エントリーする前に既存のポジションをカバーするために必要な金額を追加します。
RsiPeriod 30 RSI の平均期間。正の整数である必要があります。
OverboughtLevel 80 売りシグナルを発行する RSI のしきい値。攻撃性を調整するために最適化できます。
OversoldLevel 20 購入シグナルを発行する RSI のしきい値。
CandleType 1 分 TimeFrameCandle RSI の計算に使用されるキャンドル データ ソース。より高い時間枠を分析するように変更します。

すべてのパラメータは StrategyParam<T> を通じて公開されるため、StockSharp デザイナーに表示され、XML プリセットに保存でき、最適化シナリオをサポートします。

実装メモ

  • 高レベルの StockSharp API は全体で使用されます。ローソク足は SubscribeCandles() を介して取得され、RSI は subscription.Bind(indicator, callback) を介して更新されます。手動によるバッファ処理や履歴コピーは必要ありません。
  • 基本の Strategy.Volume プロパティは OrderVolume パラメータと同期されているため、ユーザーが実行時にロット サイズを変更した場合でもポジション反転が正しく機能します。
  • インライン コメントと XML ドキュメントは、プロジェクトの要件に合わせて英語で作成されます。
  • チャート出力はオプションですがサポートされています。ストラテジーがデザイナー内で実行されると、価格ローソク足、実行された取引、および RSI インジケーターの値がプロットされます。

使用のヒント

  • 自動化されたリスク管理が必要な場合は、戦略を外部のストップロス/テイクプロフィットモジュールと組み合わせます。
  • さまざまなボラティリティ体制の市場に適応する場合は、RSI のしきい値を最適化します。
  • 元のスクリプトと同様に、スイング設定のローソク足の時間枠を増やすか、スキャルピング スタイルのアラートのデフォルトの 1 分シリーズを維持します。
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>
/// RSI alert strategy converted from the original MetaTrader expert advisor.
/// Buys when RSI drops below the oversold threshold and sells when RSI rises above the overbought threshold.
/// </summary>
public class RsiAlertStrategy : Strategy
{
	private readonly StrategyParam<decimal> _orderVolume;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _overboughtLevel;
	private readonly StrategyParam<decimal> _oversoldLevel;
	private readonly StrategyParam<DataType> _candleType;

	private RelativeStrengthIndex _rsi;

	/// <summary>
	/// Order volume used for market trades.
	/// </summary>
	public decimal OrderVolume
	{
		get => _orderVolume.Value;
		set
		{
			_orderVolume.Value = value;
			Volume = value; // Keep the base strategy volume aligned with the parameter value.
		}
	}

	/// <summary>
	/// RSI averaging period.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	/// <summary>
	/// RSI level that triggers short trades.
	/// </summary>
	public decimal OverboughtLevel
	{
		get => _overboughtLevel.Value;
		set => _overboughtLevel.Value = value;
	}

	/// <summary>
	/// RSI level that triggers long trades.
	/// </summary>
	public decimal OversoldLevel
	{
		get => _oversoldLevel.Value;
		set => _oversoldLevel.Value = value;
	}

	/// <summary>
	/// Candle type supplying prices to the RSI indicator.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="RsiAlertStrategy"/> with default parameters.
	/// </summary>
	public RsiAlertStrategy()
	{
		_orderVolume = Param(nameof(OrderVolume), 0.01m)
			.SetGreaterThanZero()
			.SetDisplay("Order Volume", "Order size used for market trades", "Trading")
			;

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Number of bars for RSI calculation", "Indicator")
			;

		_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
			.SetDisplay("Overbought Level", "RSI threshold that triggers short signals", "Indicator")
			;

		_oversoldLevel = Param(nameof(OversoldLevel), 30m)
			.SetDisplay("Oversold Level", "RSI threshold that triggers long signals", "Indicator")
			;

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles that feed the RSI", "General");

		Volume = OrderVolume;
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_rsi = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		Volume = OrderVolume; // Ensure the strategy uses the configured volume on each start.

		_rsi = new RelativeStrengthIndex
		{
			Length = RsiPeriod
		};

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(_rsi, ProcessCandle)
			.Start();

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent));

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

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

		var buySignal = rsiValue <= OversoldLevel;
		var sellSignal = rsiValue >= OverboughtLevel;

		if (buySignal && Position == 0)
		{
			BuyMarket();
		}
		else if (sellSignal && Position == 0)
		{
			SellMarket();
		}
	}
}