GitHub で見る

サイダス v1 戦略

概要

Sidus v1 は、2 セットの指数移動平均 (EMA) と相対強度指数 (RSI) フィルターを組み合わせたトレンド追跡戦略です。元の MetaTrader 4 エキスパート アドバイザーは、速い EMA が遅い EMA から分岐し、RSI が売られすぎまたは買われすぎの状態を確認したときにポジションをオープンします。この StockSharp ポートはコア ロジックを維持し、取引を出来高の少ないローソク足に制限し、ロング ポジションとショート ポジションに非対称の保護注文を付けます。

使用されるインジケーター

  • 高速 EMA (買いレッグ) – ロングエントリーの短期的な勢いを測定します。
  • スロー EMA (買いレッグ) – ロングエントリーの長期トレンドフィルターを表します。
  • 速い EMA (売りレッグ) – ショートエントリーの短期的な勢いを測定します。
  • スロー EMA (売りレッグ) – 短期エントリーの長期トレンド フィルターを表します。
  • RSI (買いレッグ) – ロング取引の売られ過ぎ条件を検証します。
  • RSI (売りレッグ) – ショートトレードの買われ過ぎの状態を検証します。

取引ロジック

  1. 設定されたローソク足シリーズ (デフォルトの 15 分の時間枠) を購読します。
  2. 完成した各ローソク足のすべての EMA および RSI インジケーターを計算します。
  3. ろうそくの量が設定された制限 (デフォルトは 10) を超えた場合、信号の評価をスキップします。
  4. 購入条件:
    • 高速 EMA から低速 EMA を引いた値は購入基準を下回っています。
    • RSI の値は購入基準 RSI を下回っています。
    • 既存の長時間エクスポージャーはありません (ネットポジションは非プラスである必要があります)。
  5. 販売条件:
    • 高速 EMA (売りレッグ) から低速 EMA (売りレッグ) を引いた値が売り閾値を上回っています。
    • RSI (売りレッグ) は売り閾値 RSI を上回っています。
    • 既存のショートエクスポージャーはありません (ネットポジションはマイナスでない必要があります)。
  6. シグナルがトリガーされると、未決の保護注文をキャンセルし、ネットポジションを希望する側に反転するサイズの成行注文を実行し、ポジションの方向に合わせたテイクプロフィット注文とストップロス注文を即座に発注します。

リスク管理

  • ロング取引では、テイクプロフィットは entry + BuyTakeProfitPips * priceStep、ストップロスは entry - BuyStopLossPips * priceStep に設定されます。
  • ショートトレードでは、テイクプロフィットは entry - SellTakeProfitPips * priceStep、ストップロスは entry + SellStopLossPips * priceStep に設定されます。
  • 保護注文では、現在の証券価格ステップが再利用されます。異なるティックサイズのインストゥルメントに適応するために pip パラメータを変更します。

パラメーター

パラメータ 説明 デフォルト
FastEmaLength 買いシグナルの高速 EMA の長さ。 23
SlowEmaLength 買いシグナルの遅い EMA の長さ。 62
FastEma2Length 売りシグナルの高速 EMA の長さ。 18
SlowEma2Length 売りシグナルの低速 EMA の長さ。 54
RsiPeriod 購入確認の期間は RSI です。 67
RsiPeriod2 販売確認の期間は RSI です。 97
BuyDifferenceThreshold 購入できる最大の高速と低速の差は EMA です。 63
BuyRsiThreshold 購入できる最大 RSI レベル。 59
SellDifferenceThreshold 売りを許可する最小のファストとスローの差は EMA です。 -57
SellRsiThreshold 販売を許可する最小の RSI レベル。 60
BuyTakeProfitPips ロングトレードの利食い距離 (pips)。 95
BuyStopLossPips ロングトレードのストップロス距離 (pips)。 100
SellTakeProfitPips 短期取引の利食い距離 (pips)。 17
SellStopLossPips 短期取引のストップロス距離 (pips)。 69
OrderVolume 新しくオープンしたポジションのボリューム。 0.5
MaxCandleVolume 取引できるキャンドルの最大量。 10
CandleType 計算に使用される時間枠。 15分キャンドル

使用上の注意

  • 適切なリスク管理のために、接続された証券が同時成行注文、逆指値注文、指値注文をサポートしていることを確認します。
  • 元のエキスパートが想定した MT4 ポイント値と異なる場合は、商品のティック サイズを反映するようにピップ設定を調整します。
  • この戦略はネットポジションに基づいて機能します。反対方向の新しい取引を確立する前に、反対方向のエクスポージャーを平坦化します。
using System;
using System.Linq;
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;

/// <summary>
/// Strategy based on the Sidus v1 expert advisor using EMA and RSI filters.
/// Buys when the fast EMA is sufficiently below the slow EMA and RSI is oversold.
/// Sells when the fast EMA is sufficiently above the slow EMA and RSI is overbought.
/// </summary>
public class SidusV1Strategy : Strategy
{
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _fastEma2Length;
	private readonly StrategyParam<int> _slowEma2Length;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _rsiPeriod2;
	private readonly StrategyParam<decimal> _buyDifferenceThreshold;
	private readonly StrategyParam<decimal> _buyRsiThreshold;
	private readonly StrategyParam<decimal> _sellDifferenceThreshold;
	private readonly StrategyParam<decimal> _sellRsiThreshold;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<DataType> _candleType;

	/// <summary>
	/// Length of the fast EMA for buy signal calculation.
	/// </summary>
	public int FastEmaLength
	{
		get => _fastEmaLength.Value;
		set => _fastEmaLength.Value = value;
	}

	/// <summary>
	/// Length of the slow EMA for buy signal calculation.
	/// </summary>
	public int SlowEmaLength
	{
		get => _slowEmaLength.Value;
		set => _slowEmaLength.Value = value;
	}

	/// <summary>
	/// Length of the fast EMA for sell signal calculation.
	/// </summary>
	public int FastEma2Length
	{
		get => _fastEma2Length.Value;
		set => _fastEma2Length.Value = value;
	}

	/// <summary>
	/// Length of the slow EMA for sell signal calculation.
	/// </summary>
	public int SlowEma2Length
	{
		get => _slowEma2Length.Value;
		set => _slowEma2Length.Value = value;
	}

	/// <summary>
	/// RSI period used for buy signals.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	/// <summary>
	/// RSI period used for sell signals.
	/// </summary>
	public int RsiPeriod2
	{
		get => _rsiPeriod2.Value;
		set => _rsiPeriod2.Value = value;
	}

	/// <summary>
	/// Threshold for EMA difference to allow buy orders (negative means fast below slow).
	/// </summary>
	public decimal BuyDifferenceThreshold
	{
		get => _buyDifferenceThreshold.Value;
		set => _buyDifferenceThreshold.Value = value;
	}

	/// <summary>
	/// RSI threshold to confirm oversold conditions.
	/// </summary>
	public decimal BuyRsiThreshold
	{
		get => _buyRsiThreshold.Value;
		set => _buyRsiThreshold.Value = value;
	}

	/// <summary>
	/// Threshold for EMA difference to allow sell orders (positive means fast above slow).
	/// </summary>
	public decimal SellDifferenceThreshold
	{
		get => _sellDifferenceThreshold.Value;
		set => _sellDifferenceThreshold.Value = value;
	}

	/// <summary>
	/// RSI threshold to confirm overbought conditions.
	/// </summary>
	public decimal SellRsiThreshold
	{
		get => _sellRsiThreshold.Value;
		set => _sellRsiThreshold.Value = value;
	}

	/// <summary>
	/// Stop loss distance in absolute price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit distance in absolute price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Candle type used for indicator calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="SidusV1Strategy"/> class.
	/// </summary>
	public SidusV1Strategy()
	{
		_fastEmaLength = Param(nameof(FastEmaLength), 23)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA Length", "Length of the fast EMA for buy signals", "Indicators");

		_slowEmaLength = Param(nameof(SlowEmaLength), 62)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA Length", "Length of the slow EMA for buy signals", "Indicators");

		_fastEma2Length = Param(nameof(FastEma2Length), 18)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA Length (Sell)", "Length of the fast EMA for sell signals", "Indicators");

		_slowEma2Length = Param(nameof(SlowEma2Length), 54)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA Length (Sell)", "Length of the slow EMA for sell signals", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 67)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period used for buy signals", "Indicators");

		_rsiPeriod2 = Param(nameof(RsiPeriod2), 97)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period (Sell)", "RSI period used for sell signals", "Indicators");

		_buyDifferenceThreshold = Param(nameof(BuyDifferenceThreshold), -100m)
			.SetDisplay("Buy EMA Threshold", "Maximum fast-slow EMA difference to allow buy", "Trading Rules");

		_buyRsiThreshold = Param(nameof(BuyRsiThreshold), 45m)
			.SetDisplay("Buy RSI Threshold", "Maximum RSI level to allow buy", "Trading Rules");

		_sellDifferenceThreshold = Param(nameof(SellDifferenceThreshold), 100m)
			.SetDisplay("Sell EMA Threshold", "Minimum fast-slow EMA difference to allow sell", "Trading Rules");

		_sellRsiThreshold = Param(nameof(SellRsiThreshold), 55m)
			.SetDisplay("Sell RSI Threshold", "Minimum RSI level to allow sell", "Trading Rules");

		_stopLoss = Param(nameof(StopLoss), 500m)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop loss distance in absolute price units", "Risk Management");

		_takeProfit = Param(nameof(TakeProfit), 500m)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take profit distance in absolute price units", "Risk Management");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles used for calculations", "General");
	}

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		var fastEma = new EMA { Length = FastEmaLength };
		var slowEma = new EMA { Length = SlowEmaLength };
		var fastEma2 = new EMA { Length = FastEma2Length };
		var slowEma2 = new EMA { Length = SlowEma2Length };
		var rsi = new RSI { Length = RsiPeriod };
		var rsi2 = new RSI { Length = RsiPeriod2 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, fastEma2, slowEma2, rsi, rsi2, ProcessCandle)
			.Start();

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

		// Use StartProtection for SL/TP
		var tp = TakeProfit > 0 ? new Unit(TakeProfit, UnitTypes.Absolute) : null;
		var sl = StopLoss > 0 ? new Unit(StopLoss, UnitTypes.Absolute) : null;
		StartProtection(tp, sl);

		base.OnStarted2(time);
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var diffBuy = fastEmaValue - slowEmaValue;
		var diffSell = fastEma2Value - slowEma2Value;

		// Buy when fast EMA is sufficiently below slow EMA and RSI is oversold
		if (diffBuy < BuyDifferenceThreshold && rsiValue < BuyRsiThreshold && Position <= 0)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));
			BuyMarket(Volume);
		}
		// Sell when fast EMA is sufficiently above slow EMA and RSI is overbought
		else if (diffSell > SellDifferenceThreshold && rsi2Value > SellRsiThreshold && Position >= 0)
		{
			if (Position > 0)
				SellMarket(Position);
			SellMarket(Volume);
		}
	}
}