GitHub で見る

戦略 RSI Martingale

概要

RSI Martingale は、MetaTrader 5 エキスパート アドバイザー RSI&Martingale1.5 のポートです。この戦略は、相対強度指数 (RSI) が構成可能なルックバック ウィンドウ内で極値に達するまで待機することで、勢いの反転を検索します。極端な値が現れると、予想される平均回帰の方向に取引が開始され、RSI が 50 正中線を横切るか、固定のストップ/テイク目標に達したときに取引を終了します。マーチンゲール モジュールは、オプションで、取引に負けた後にボリュームを増やして反対方向にポジションを再開できます。毎日の損益制限と時間ごとのフィルターにより、リスクの高いセッション中または資本保全目標を達成した後に取引を一時停止することができます。

戦略ロジック

RSI の極端な例

  • インジケーター – 選択したローソク式に基づいて計算された単一の RSI。取引を検討する前に、インジケーターを作成する必要があります (十分な履歴データ)。
  • 最小検出 – 最新の RSI 値が、設定された Bars For Extremes ウィンドウ内のすべての RSI 値以下で、その値が 50 未満の場合、ストラテジーはロング ポジションをオープンします。
  • 最大検出 – 最新の RSI 値がルックバック ウィンドウ内のすべての値以上で、その値が 50 を超えている場合、ストラテジーはショート ポジションをオープンします。

ポジション管理

  • エグジットトリガー – RSI がニュートラル 50 ラインを反対側に横切ると、ポジションはクローズされます (ロングは 50 を超えてエグジット、ショートは 50 を下回ってエグジットします)。
  • 固定ターゲット – オプションのストップロスとテイクプロフィットの距離をピップで表します。有効にすると、この戦略は最新のローソク足の高値/安値をそれらの目標価格と比較し、いずれかのレベルに達した場合にポジションをクローズします。
  • 数量調整 – すべての注文数量は、送信前に証券のステップ、最小値、および最大値の設定に合わせて調整されます。

Martingale の回復

  • トリガー – マイナスの利益でポジションがクローズされた後、戦略は負けた取引の方向と量を記憶します。
  • 再エントリー – 次の適格なローソク足で、ポジションがオープンしていない場合に限り、反対方向の取引をすぐに開始できます。ボリュームは、Enable Martingale スイッチに応じて、損失ボリュームに Martingale Multiplier を乗算するか、ベースの Initial Volume を乗算したものになります。
  • リセット – マーチンゲール注文が送信されると、反復試行を避けるために保存された損失情報がクリアされます。

日々の資本管理

  • ベースライン – この戦略は、各取引日の開始時に口座資産を取得し、一時停止フラグをリセットします。
  • 監視ウィンドウ – 1 日の制限は Daily Control StartDaily Control End 時間の間でのみ評価されます。
  • 一時停止 – 株式が Daily Profit % を超えて増加するか、Daily Loss % を下回る場合、戦略はオープンポジションをすべて閉じ、翌日まで新しい取引をスキップします。

セッションフィルター

  • 取引ウィンドウ – 新しいポジションは、現在の時間が Trading StartTrading End (両端を含む) の間にある場合にのみ許可されます。
  • 時間帯回避 – 24 個のブール値パラメータはソース EA の「ニュース回避」設定を反映し、選択した時間帯の取引をブロックします。

パラメーター

  • 初期数量 – 標準エントリの基本注文数量。
  • RSI 期間 – RSI インジケーターで使用される期間の数。
  • 極端なバー – 最新の RSI の最小値または最大値を検索するときにスキャンされる完成したキャンドルの数。
  • テイクプロフィット (pips) – 固定テイクプロフィットまでの距離。無効にするには、0 に設定します。
  • ストップロス (pips) – 固定ストップロスまでの距離。無効にするには、0 に設定します。
  • Martingale を有効にする – 損失取引後のマーチンゲール回復モジュールを有効にします。
  • Martingale 乗数 – マーチンゲールがアクティブな場合に、以前の損失ボリュームに適用される乗数。
  • 日次目標 – 日次の損益停止ロジックを切り替えます。
  • 日次利益 % – その日の取引を停止する利益の割合。
  • 日次損失% – その日の取引を停止した損失の割合。
  • 日次制御開始/日次制御終了 – 日次制限を評価するための時間境界。
  • 取引開始/取引終了 – 新しいポジションを許可する時間境界。
  • 00 時間を避けます…23 時間を避けます – 対応する時間帯の取引を無効にします。
  • ローソク足タイプ – RSI インジケーターとすべての計算に使用されるローソク足のサブスクリプション。

追加の注意事項

  • この戦略は終了したローソク足のみに作用し、バー内ティックは評価しません。
  • 毎日の利益計算では、実現した戦略損益と最新の終値に基づく変動損益を組み合わせます。
  • パッケージにはこの戦略の Python 実装はありません。 C# バージョンのみが提供されます。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RSI extremes strategy with martingale recovery.
/// Buys when RSI is at a local minimum below 50, sells when RSI is at a local maximum above 50.
/// Closes on RSI crossing 50. Doubles volume after a losing trade.
/// </summary>
public class RSIMartingaleStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _barsForCondition;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<decimal> _recentRsi = new();
	private decimal _entryPrice;
	private int _direction; // 1=long, -1=short, 0=flat

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

	public int BarsForCondition
	{
		get => _barsForCondition.Value;
		set => _barsForCondition.Value = value;
	}

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

	public RSIMartingaleStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI indicator period", "Indicator");

		_barsForCondition = Param(nameof(BarsForCondition), 10)
			.SetDisplay("Bars For Extremes", "Number of RSI values to check for extremes", "Indicator");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "Data");
	}

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

		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;

		_recentRsi.Add(rsiValue);
		if (_recentRsi.Count > BarsForCondition)
			_recentRsi.RemoveAt(0);

		if (_recentRsi.Count < BarsForCondition)
			return;

		// Check exit: close on RSI crossing 50
		if (_direction > 0 && rsiValue > 50)
		{
			SellMarket();
			_direction = 0;
			return;
		}
		else if (_direction < 0 && rsiValue < 50)
		{
			BuyMarket();
			_direction = 0;
			return;
		}

		if (Position != 0)
			return;

		// Check if current RSI is local minimum (oversold entry)
		if (IsLocalMinimum() && rsiValue < 50 && Position <= 0)
		{
			BuyMarket();
			_entryPrice = candle.ClosePrice;
			_direction = 1;
		}
		// Check if current RSI is local maximum (overbought entry)
		else if (IsLocalMaximum() && rsiValue > 50 && Position >= 0)
		{
			SellMarket();
			_entryPrice = candle.ClosePrice;
			_direction = -1;
		}
	}

	private bool IsLocalMinimum()
	{
		if (_recentRsi.Count < 2)
			return false;

		var current = _recentRsi[_recentRsi.Count - 1];
		for (var i = 0; i < _recentRsi.Count - 1; i++)
		{
			if (current > _recentRsi[i])
				return false;
		}
		return true;
	}

	private bool IsLocalMaximum()
	{
		if (_recentRsi.Count < 2)
			return false;

		var current = _recentRsi[_recentRsi.Count - 1];
		for (var i = 0; i < _recentRsi.Count - 1; i++)
		{
			if (current < _recentRsi[i])
				return false;
		}
		return true;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_recentRsi.Clear();
		_entryPrice = 0;
		_direction = 0;

		base.OnReseted();
	}
}