GitHub で見る

RsiBoosterStrategy戦略

概要

RsiBoosterStrategy は、MetaTrader のエキスパートアドバイザー RSI booster を StockSharp に移植したものです。この戦略は、現在のローソク足で計算した高速 RSI 値と、前のローソク足を使う遅延 RSI を比較します。差がユーザー定義の比率を超えると市場ポジションを開き、その後は固定ストップ、take-profit 目標、任意の trailing stop、損失回復用の逆方向注文チェーンで取引を管理します。

この戦略は StockSharp の高レベル API 上に構築されています。単一のローソク足系列を購読し、組み込みの RelativeStrengthIndex インジケーターを使用し、すべての入力を Designer 内で最適化できるように戦略パラメーターシステムを利用します。

取引ロジック

  1. 確定した各ローソク足で 2 つの RSI インジケーターを計算します。
    • 高速 RSI は FirstRsiPeriodFirstRsiPrice を使い、直近のローソク足を読み取ります。
    • 遅延 RSI は SecondRsiPeriodSecondRsiPrice を使いますが、戦略は前回値を保持するため、1 バー遅れとして機能します。
  2. fast RSI - delayed RSIRatio より大きい場合、ロングポジションが開いていなければ買います。差が -Ratio を下回る場合、ショートポジションが開いていなければ売ります。
  3. OnlyOnePositionPerBar により、同じローソク足のタイムスタンプでは方向ごとに最大 1 回だけエントリーします。
  4. 各ローソク足の後、戦略は stop-loss、take-profit、trailing のルールを評価します。いずれかの条件が発動すると、ポジションは直ちに決済されます。
  5. ポジションがマイナスの実現 PnL で決済された場合、任意の回復ロジックにより、同じ数量で逆方向のポジションに入ることができます。連鎖する回復取引の数は ReturnOrdersMax で制限されます。

リスク管理

  • Stop-loss - StopLossPips により、商品のポイント単位で表されます。価格がストップ水準を交差するとポジションを決済します。
  • Take-profit - TakeProfitPips により、商品のポイント単位で表されます。
  • Trailing stop - TrailingStopPips で有効にすると、利益が設定距離を超えた時点でストップが追随を開始します。TrailingStepPips は trailing 水準を動かす前に必要な最小改善幅を定義します。
  • リターン注文 - ReturnOrderEnabledtrue のときに有効になります。損失取引の後、戦略は反対方向の成行注文を即座に開き、発行した回復注文数を数え続けます。

パラメーター

パラメーター 説明
Volume 各成行注文に使用する取引数量 (ロットまたは契約)。
Ratio ポジションを開くために必要な最小 RSI 差。
StopLossPips 商品ポイント単位の stop-loss 距離。
TakeProfitPips 商品ポイント単位の take-profit 距離。
TrailingStopPips 商品ポイント単位の trailing stop 距離。
TrailingStepPips trailing stop を動かす前に必要な最小改善幅。
OnlyOnePositionPerBar 同じローソク足内で複数回エントリーすることを防ぎます。
ReturnOrderEnabled 逆方向注文による回復ロジックを有効にします。
ReturnOrdersMax 連続する回復注文の最大数。
FirstRsiPeriod 高速 RSI の期間。
FirstRsiPrice 高速 RSI の価格ソース (MetaTrader の適用価格モードに対応)。
SecondRsiPeriod 遅延 RSI の期間。
SecondRsiPrice 遅延 RSI の価格ソース (MetaTrader の適用価格モードに対応)。
CandleType 分析に使用するローソク足系列。

注意事項

  • 価格ステップの変換では、利用可能な場合に商品の PriceStep を尊重します。商品が価格ステップを提供しない場合は、代替値として 0.0001 を使用します。
  • 回復チェーンのカウンターは、利益の出た取引が発生したとき、または設定された回復注文の最大数に達したときにリセットされます。
  • 戦略は、実行済み取引と並べてすばやく視覚確認できるように、両方の RSI インジケーターをチャート領域に描画します。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class RsiBoosterStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public RsiBoosterStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}