GitHub で見る

トップス ボトムス トレンド RSI 戦略

概要

この戦略は、MetaTrader エキスパート アドバイザー「Tops Bottoms Trend and RSI EA」の StockSharp 移植です。選択した時間枠の終了したローソク足を監視し、設定可能なルックバック ウィンドウ内で新たなトレンドの天井または底を検索し、相対強度指数 (RSI) フィルターで各機会を確認します。基準が満たされると、この戦略は単一の成行注文を開き、ピップベースの距離から導出された保護的なストップロスとテイクプロフィットレベルを即座に割り当てます。

取引ロジック

  • データ ソース – アルゴリズムは構成されたローソク タイプをサブスクライブし、不完全なデータの使用を避けるために完成したローソクのみを評価します。
  • 底値検出 (ロングセットアップ) – 最新のローソク足の終値は、BuyTrendCandles バー前のローソク足の高値より少なくとも BuyTrendPips ピップス下である必要があります。すべての中間安値は現在の終値を上回っている必要があり、品質フィルター (BuyTrendQuality) では、最近の高値が基準高値から大きく乖離していないことが必要です。この構造が形成され、前のローソク足の RSI の値が BuyRsiThreshold を下回っている場合、この戦略はボリューム BuyVolume のロング ポジションをオープンします。
  • 上値検出 (ショートセットアップ) – 最新のローソク足の終値は、SellTrendCandles バー前のローソク足の安値より少なくとも SellTrendPips ピップス上である必要があります。品質フィルター (SellTrendQuality) が最近の安値を基準値付近に維持する一方で、中間高値は現在の終値を下回らないようにする必要があります。前のローソク足の RSI の値が SellRsiThreshold を超える場合、この戦略は出来高 SellVolume のショート ポジションをオープンします。
  • リスク管理 – 各エントリーの後、ストラテジーは約定価格を保存し、ピップベースの保護レベルを計算します。ストップロス オフセットには、BuyStopLossPips または SellStopLossPips を使用します。テイクプロフィット距離は主に、BuyTakeProfitPercentOfStop または SellTakeProfitPercentOfStop 経由のストップから導出されます。ロングテイクプロフィットパーセンテージが無効になっている場合 (0)、代わりに固定の BuyTakeProfitPips 距離が使用されます。後続のローソク足が対応するストップまたはテイクプロフィットレベルに達すると、ポジションは成行注文でクローズされます。
  • 位置制御 – システムは最大 1 つの開いた位置を維持します。ポジションまたはアクティブな注文が存在する間は、新しいシグナルは無視されます。 RSI の確認は常に前のローソク足 (1 バー シフト) に依存し、元の EA を反映します。

パラメーター

名前 説明 デフォルト
BuyVolume ロングポジションに使用される注文量。 0.01
BuyStopLossPips ロングトレードのストップロス距離 (pips)。 20
BuyTakeProfitPips パーセンテージモードが無効な場合のロングのテイクプロフィット距離をピップ単位で修正しました。 5
BuyTakeProfitPercentOfStop 長いストップロス距離に対するテイクプロフィットの割合。 100
SellVolume ショートポジションに使用される注文量。 0.01
SellStopLossPips ショートトレードのストップロス距離 (pips)。 20
SellTakeProfitPercentOfStop 短いストップロス距離に対するテイクプロフィットの割合。 100
SellTrendCandles 新しいトップを検索するときに検査されるローソクの数。 10
SellTrendPips 短いセットアップに必要な基準低値を上回る最小前進量 (pips)。 20
SellTrendQuality 短いセットアップ用のトレンド品質フィルター (1 ~ 9 の範囲に固定)。 5
BuyTrendCandles 新しい底値を検索するときに検査されるキャンドルの数。 10
BuyTrendPips 長いセットアップに必要な基準高値を下回る最小の下落 (pips)。 20
BuyTrendQuality 長いセットアップ用のトレンド品質フィルター (1 ~ 9 の範囲に固定)。 5
BuyRsiPeriod RSI 期間は長い確認に使用されます。 14
BuyRsiThreshold ロングエントリーを有効にするには、RSI の売られ過ぎのしきい値を上から超える必要があります。 40
SellRsiPeriod RSI の期間は短い確認に使用されます。 14
SellRsiThreshold RSI の買われすぎのしきい値。ショートエントリーを有効にするには、これを下回る必要があります。 60
CandleType 戦略によって処理されるローソク足のタイムフレーム。 30-minute time frame

注意事項

  • ピップ距離は、証券の PriceStep を使用して価格に変換されます。 5 桁および小数ピップの外国為替相場は、元の EA からの変換ルールを複製して、従来のピップ サイズに正規化されます。
  • RSI 確認では前のローソク足 (シフト = 1) が使用されるため、ストラテジーでは取引する前に完全に形成された RSI 値が少なくとも 1 つ必要です。したがって、起動後の最初の数本のキャンドルは無視されます。
  • このロジックはポジションが完全にクローズされるたびにすべての保護レベルをキャンセルし、次のエントリーが新しいリスクパラメーターで開始されることを保証します。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Tops Bottoms Trend RSI strategy: RSI trend direction with EMA filter.
/// Buys when RSI above 50 and close above EMA, sells when RSI below 50 and close below EMA.
/// </summary>
public class TopsBottomsTrendRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;

	private decimal _prevRsi;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }

	public TopsBottomsTrendRsiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0;
		_hasPrev = false;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevRsi <= 45 && rsiValue > 45 && candle.ClosePrice > emaValue && Position <= 0)
				BuyMarket();
			else if (_prevRsi >= 55 && rsiValue < 55 && candle.ClosePrice < emaValue && Position >= 0)
				SellMarket();
		}

		_prevRsi = rsiValue;
		_hasPrev = true;
	}
}