GitHub で見る

JBrainUltraRSI戦略

このサンプル戦略は、相対力指数(RSI)とストキャスティクスオシレーターを組み合わせて取引シグナルを生成します。 このアイデアは、JBrainTrendSig1UltraRSIインジケーターを使用したオリジナルのMetaTraderエキスパートアドバイザーから派生しています。このアダプテーションでは、ストキャスティクスオシレーターがトレンドフィルターとして機能し、RSIがエントリーシグナルを提供します。

動作原理

  1. インジケーター
    • RSI:最近の利益と損失を比較してモメンタムを測定します。50レベルを上抜けすると強気のモメンタムを示し、50を下抜けすると弱気のモメンタムを示します。
    • ストキャスティクスオシレーター:最近のレンジに対する終値の位置を評価します。%Kと%Dラインのクロスがトレンド方向を確認します。
  2. モード
    • JBrainSig1Filter – RSIがシグナルを生成し、ストキャスティクスオシレーターが方向を確認します。
    • UltraRsiFilter – ストキャスティクスオシレーターがシグナルを提供し、RSIでフィルタリングします。
    • Composition – 両方のインジケーターが方向に同意した場合のみシグナルを取ります。
  3. 取引ルール
    • 買いシグナルが出現し、ショートポジションが存在しないか決済されている場合にロングポジションを建てます。
    • 売りシグナルが出現し、ロングポジションが存在しないか決済されている場合にショートポジションを建てます。
    • 許可されている場合、逆シグナルで既存ポジションを決済します。

パラメーター

パラメーター 説明
RsiPeriod RSI計算期間。
StochLength ストキャスティクスオシレーターの%K期間。
SignalLength ストキャスティクスオシレーターの%D期間。
Mode インジケーターの組み合わせモード。
AllowLongEntry / AllowShortEntry ロングまたはショートポジションを建てる許可。
AllowLongExit / AllowShortExit ロングまたはショートポジションを決済する許可。
CandleType 戦略が使用するローソク足の時間軸。

注意事項

  • この戦略はStockSharpの高水準APIを使用し、インジケーター処理にBind / BindExを使用します。
  • ストップとターゲットは組み込みの保護メカニズムStartProtection()で設定できます。
  • チャートエリアが利用可能な場合、サンプルの可視化ではローソク足、インジケーター、自身のトレードが描画されます。

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>
/// Strategy combining RSI and Stochastic oscillator signals.
/// </summary>
public class JBrainUltraRsiStrategy : Strategy
{
        /// <summary>
        /// Combination modes for indicators.
        /// </summary>
        public enum AlgorithmModes
        {
                JBrainSig1Filter,
                UltraRsiFilter,
                Composition
        }

	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _stochLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<AlgorithmModes> _mode;
	private readonly StrategyParam<bool> _allowLongEntry;
	private readonly StrategyParam<bool> _allowShortEntry;
	private readonly StrategyParam<bool> _allowLongExit;
	private readonly StrategyParam<bool> _allowShortExit;
	private readonly StrategyParam<DataType> _candleType;
	
	private RelativeStrengthIndex _rsi;
	private StochasticOscillator _stochastic;
	private decimal? _prevRsi;
	private decimal? _prevK;
	private decimal? _prevD;
	
	/// <summary>
	/// RSI calculation period.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}
	
	/// <summary>
	/// Stochastic %K period.
	/// </summary>
	public int StochLength
	{
		get => _stochLength.Value;
		set => _stochLength.Value = value;
	}
	
	/// <summary>
	/// Stochastic %D period.
	/// </summary>
	public int SignalLength
	{
		get => _signalLength.Value;
		set => _signalLength.Value = value;
	}
	
	/// <summary>
	/// Mode combining indicators.
	/// </summary>
	public AlgorithmModes Mode
	{
		get => _mode.Value;
		set => _mode.Value = value;
	}
	
	/// <summary>
	/// Permission to open long positions.
	/// </summary>
	public bool AllowLongEntry
	{
		get => _allowLongEntry.Value;
		set => _allowLongEntry.Value = value;
	}
	
	/// <summary>
	/// Permission to open short positions.
	/// </summary>
	public bool AllowShortEntry
	{
		get => _allowShortEntry.Value;
		set => _allowShortEntry.Value = value;
	}
	
	/// <summary>
	/// Permission to close long positions.
	/// </summary>
	public bool AllowLongExit
	{
		get => _allowLongExit.Value;
		set => _allowLongExit.Value = value;
	}
	
	/// <summary>
	/// Permission to close short positions.
	/// </summary>
	public bool AllowShortExit
	{
		get => _allowShortExit.Value;
		set => _allowShortExit.Value = value;
	}
	
	/// <summary>
	/// Candle type to process.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	
	/// <summary>
	/// Initializes a new instance of <see cref="JBrainUltraRsiStrategy"/>.
	/// </summary>
	public JBrainUltraRsiStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 13)
		.SetGreaterThanZero()
		.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
		;
		
		_stochLength = Param(nameof(StochLength), 9)
		.SetGreaterThanZero()
		.SetDisplay("Stochastic %K", "Period for %K line", "Indicators")
		;
		
		_signalLength = Param(nameof(SignalLength), 3)
		.SetGreaterThanZero()
		.SetDisplay("Stochastic %D", "Period for %D line", "Indicators")
		;
		
		_mode = Param(nameof(Mode), AlgorithmModes.Composition)
		.SetDisplay("Mode", "Algorithm to enter the market", "General");
		
		_allowLongEntry = Param(nameof(AllowLongEntry), true)
		.SetDisplay("Allow Long Entry", "Permission to open long positions", "Trading");
		
		_allowShortEntry = Param(nameof(AllowShortEntry), true)
		.SetDisplay("Allow Short Entry", "Permission to open short positions", "Trading");
		
		_allowLongExit = Param(nameof(AllowLongExit), true)
		.SetDisplay("Allow Long Exit", "Permission to close long positions", "Trading");
		
		_allowShortExit = Param(nameof(AllowShortExit), true)
		.SetDisplay("Allow Short Exit", "Permission to close short positions", "Trading");
		
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Type of candles", "General");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		
		_rsi = default;
		_stochastic = default;
		_prevRsi = default;
		_prevK = default;
		_prevD = default;
	}
	
	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		StartProtection(null, null);
		
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		_stochastic = new StochasticOscillator
		{
			K = { Length = StochLength },
			D = { Length = SignalLength },
		};
		
		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(_stochastic, ProcessCandle)
			.Start();

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

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

		// process RSI manually
		var rsiResult = _rsi.Process(candle.ClosePrice, candle.OpenTime, true);
		if (!rsiResult.IsFormed)
			return;

		var rsi = rsiResult.ToDecimal();

		var stoch = (StochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal k || stoch.D is not decimal d)
		{
			_prevRsi = rsi;
			return;
		}

		var rsiUp = _prevRsi is decimal pr && pr <= 50m && rsi > 50m;
		var rsiDown = _prevRsi is decimal pr2 && pr2 >= 50m && rsi < 50m;
		var stochUp = _prevK is decimal pk && _prevD is decimal pd && pk <= pd && k > d;
		var stochDown = _prevK is decimal pk2 && _prevD is decimal pd2 && pk2 >= pd2 && k < d;

		var buySignal = false;
		var sellSignal = false;

		switch (Mode)
		{
			case AlgorithmModes.JBrainSig1Filter:
				buySignal = rsiUp && k > d;
				sellSignal = rsiDown && k < d;
				break;
			case AlgorithmModes.UltraRsiFilter:
				buySignal = stochUp && rsi > 50m;
				sellSignal = stochDown && rsi < 50m;
				break;
			case AlgorithmModes.Composition:
				buySignal = rsiUp && stochUp;
				sellSignal = rsiDown && stochDown;
				break;
		}

		if (buySignal)
		{
			if (Position < 0 && AllowShortExit)
				BuyMarket();
			if (AllowLongEntry && Position <= 0)
				BuyMarket();
		}
		else if (sellSignal)
		{
			if (Position > 0 && AllowLongExit)
				SellMarket();
			if (AllowShortEntry && Position >= 0)
				SellMarket();
		}

		_prevRsi = rsi;
		_prevK = k;
		_prevD = d;
	}
}