GitHub で見る

GG-RSI-CCI戦略

この戦略はStockSharpの高レベルAPIを使用してMetaTraderのエキスパートアドバイザーGG-RSI-CCIを再現します。相対力指数(RSI)とコモディティチャンネルインデックス(CCI)を組み合わせ、それぞれを2つの移動平均で平滑化します。両方のインジケーターが同じ方向を示したときにポジションをオープンします。

ロジック

  1. インジケーター
    • 同じ期間でRSIとCCIを計算する。
    • 各インジケーターを速い移動平均と遅い移動平均で平滑化する。
  2. シグナル
    • 速いRSIが遅いRSIより上かつ速いCCIが遅いCCIより上の場合に買い
    • 速いRSIが遅いRSIより下かつ速いCCIが遅いCCIより下の場合に売り
    • モードがFlatに設定されている場合、中立状態は現在のポジションをクローズします。
  3. リスク管理
    • 戦略は開始時に一度StartProtectionを呼び出します。ストップロスとテイクプロフィットのレベルはプラットフォームのリスクマネージャーを通じて設定できます。

パラメーター

名前 説明
CandleType 計算に使用する時間軸。
Length RSIとCCIの期間。
FastPeriod 速い平滑化の期間。
SlowPeriod 遅い平滑化の期間。
Volume 注文数量。
AllowBuyOpen ロングポジションのオープンを有効化。
AllowSellOpen ショートポジションのオープンを有効化。
AllowBuyClose ショートポジションのクローズを有効化。
AllowSellClose ロングポジションのクローズを有効化。
Mode Trendは逆シグナルでのみクローズ、Flatは中立シグナルでもクローズ。

注意事項

この戦略は完成したローソク足のみを処理し、高レベルの注文ヘルパー(BuyMarket / SellMarket)を使用します。インジケーターバッファへの直接アクセスを避け、状態を内部に保存します。

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;
using StockSharp.Algo;

namespace StockSharp.Samples.Strategies;



/// <summary>
/// Strategy based on the GG-RSI-CCI indicator.
/// </summary>
public class GgRsiCciStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _length;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<bool> _allowBuyOpen;
	private readonly StrategyParam<bool> _allowSellOpen;
	private readonly StrategyParam<bool> _allowBuyClose;
	private readonly StrategyParam<bool> _allowSellClose;
	private readonly StrategyParam<SignalModes> _mode;

	private SimpleMovingAverage _rsiFast = null!;
	private SimpleMovingAverage _rsiSlow = null!;
	private SimpleMovingAverage _cciFast = null!;
	private SimpleMovingAverage _cciSlow = null!;
	private int _prevSignal;

	/// <summary>
	/// Defines how positions are closed.
	/// </summary>
	public enum SignalModes
	{
		/// <summary>Position is closed only on opposite signal.</summary>
		Trend,
		/// <summary>Position is closed on any neutral signal.</summary>
		Flat,
	}

	public GgRsiCciStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Time frame for indicator calculation.", "General");

		_length = Param(nameof(Length), 8)
			.SetGreaterThanZero()
			.SetDisplay("Length", "RSI and CCI period.", "Indicators");

		_fastPeriod = Param(nameof(FastPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast smoothing period.", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow smoothing period.", "Indicators");


		_allowBuyOpen = Param(nameof(AllowBuyOpen), true)
			.SetDisplay("Allow Buy", "Permit opening long positions.", "Permissions");

		_allowSellOpen = Param(nameof(AllowSellOpen), true)
			.SetDisplay("Allow Sell", "Permit opening short positions.", "Permissions");

		_allowBuyClose = Param(nameof(AllowBuyClose), true)
			.SetDisplay("Close Short", "Permit closing short positions.", "Permissions");

		_allowSellClose = Param(nameof(AllowSellClose), true)
			.SetDisplay("Close Long", "Permit closing long positions.", "Permissions");

		_mode = Param(nameof(Mode), SignalModes.Trend)
			.SetDisplay("Mode", "Closing style.", "Trading");
	}

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

	public int Length
	{
		get => _length.Value;
		set => _length.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}


	public bool AllowBuyOpen
	{
		get => _allowBuyOpen.Value;
		set => _allowBuyOpen.Value = value;
	}

	public bool AllowSellOpen
	{
		get => _allowSellOpen.Value;
		set => _allowSellOpen.Value = value;
	}

	public bool AllowBuyClose
	{
		get => _allowBuyClose.Value;
		set => _allowBuyClose.Value = value;
	}

	public bool AllowSellClose
	{
		get => _allowSellClose.Value;
		set => _allowSellClose.Value = value;
	}

	public SignalModes Mode
	{
		get => _mode.Value;
		set => _mode.Value = value;
	}

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

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

		_rsiFast?.Reset();
		_rsiSlow?.Reset();
		_cciFast?.Reset();
		_cciSlow?.Reset();
		_prevSignal = -1;
	}

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

		var rsi = new RelativeStrengthIndex { Length = Length };
		var cci = new CommodityChannelIndex { Length = Length };

		_rsiFast = new SimpleMovingAverage { Length = FastPeriod };
		_rsiSlow = new SimpleMovingAverage { Length = SlowPeriod };
		_cciFast = new SimpleMovingAverage { Length = FastPeriod };
		_cciSlow = new SimpleMovingAverage { Length = SlowPeriod };

		_prevSignal = -1;

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var rsiFast = _rsiFast.Process(new DecimalIndicatorValue(_rsiFast, rsiValue, candle.OpenTime)).ToDecimal();
		var rsiSlow = _rsiSlow.Process(new DecimalIndicatorValue(_rsiSlow, rsiValue, candle.OpenTime)).ToDecimal();
		var cciFast = _cciFast.Process(new DecimalIndicatorValue(_cciFast, cciValue, candle.OpenTime)).ToDecimal();
		var cciSlow = _cciSlow.Process(new DecimalIndicatorValue(_cciSlow, cciValue, candle.OpenTime)).ToDecimal();

		int signal;
		if (rsiFast > rsiSlow && cciFast > cciSlow && cciValue > 0m)
			signal = 2;
		else if (rsiFast < rsiSlow && cciFast < cciSlow && cciValue < 0m)
			signal = 0;
		else
			signal = 1;

		if (signal == 2)
		{
			if (AllowSellClose && Position < 0)
				BuyMarket(Math.Abs(Position));

			if (AllowBuyOpen && Position <= 0 && _prevSignal != 2)
				BuyMarket(Volume + Math.Abs(Position));
		}
		else if (signal == 0)
		{
			if (AllowBuyClose && Position > 0)
				SellMarket(Position);

			if (AllowSellOpen && Position >= 0 && _prevSignal != 0)
				SellMarket(Volume + Math.Abs(Position));
		}
		else if (Mode == SignalModes.Flat)
		{
			if (AllowBuyClose && Position > 0)
				SellMarket(Position);
			if (AllowSellClose && Position < 0)
				BuyMarket(Math.Abs(Position));
		}

		_prevSignal = signal;
	}
}