GitHub で見る

基本トレーリングストップ戦略

基本トレーリングストップ戦略は、Commodity Channel Index (CCI)とRelative Strength Index (RSI)のフィルターをシンプルなトレーリングストップと組み合わせます。両インジケーターが売られすぎまたは買われすぎの状態を示したとき、戦略は成行注文でポジションを開き、直ちにpips単位のトレーリングストップを設定します。価格が有利に動くにつれて、ストップレベルがトレンドを追跡して利益を確定します。

テストでは平均年間リターン約32%が示されています。外国為替市場で最もよく機能します。

ストップレベルが価格を継続的に追跡するため、トレンドが伸びるとリスクは自動的に絞られます。決済はトレーリングストップが発動したときのみ発生します。システムは一度に1ポジションを保持し、両方向で取引できます。

詳細

  • エントリー条件:
    • ロング: CCIが-150から-100の間かつRSIが0から30の間。
    • ショート: CCIが100から250の間かつRSIが70から100の間。
  • ロング/ショート: 両方。
  • エグジット条件: トレーリングストップ発動。
  • ストップ: トレーリングストップのみ。
  • デフォルト値:
    • StopLossPips = 20
    • CciPeriod = 14
    • RsiPeriod = 14
    • CandleType = TimeSpan.FromMinutes(1)
  • フィルター:
    • カテゴリ: モメンタム
    • 方向: 両方
    • インジケーター: CCI, 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;

/// <summary>
/// Strategy implementing a basic trailing stop with CCI and RSI signals.
/// </summary>
public class BasicTrailingStopStrategy : Strategy
{
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _stopPrice;

	public decimal StopLossPct
	{
		get => _stopLossPct.Value;
		set => _stopLossPct.Value = value;
	}

	public int CciPeriod
	{
		get => _cciPeriod.Value;
		set => _cciPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

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

	public BasicTrailingStopStrategy()
	{
		_stopLossPct = Param(nameof(StopLossPct), 1.5m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss %", "Trailing stop distance as percentage", "Risk Management");

		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "Commodity Channel Index period", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Relative Strength Index period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_stopPrice = 0m;
	}

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

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

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(cci, rsi, (candle, cciVal, rsiVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!cciVal.IsFormed || !rsiVal.IsFormed)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				ProcessCandle(candle, cciVal.ToDecimal(), rsiVal.ToDecimal());
			})
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal cciValue, decimal rsiValue)
	{
		var stopOffset = candle.ClosePrice * StopLossPct / 100m;

		if (Position > 0)
		{
			var newStop = candle.ClosePrice - stopOffset;
			if (newStop > _stopPrice)
				_stopPrice = newStop;

			if (candle.LowPrice <= _stopPrice)
			{
				SellMarket();
				_stopPrice = 0m;
			}

			return;
		}

		if (Position < 0)
		{
			var newStop = candle.ClosePrice + stopOffset;
			if (_stopPrice == 0m || newStop < _stopPrice)
				_stopPrice = newStop;

			if (candle.HighPrice >= _stopPrice)
			{
				BuyMarket();
				_stopPrice = 0m;
			}

			return;
		}

		// No position - evaluate entry signals
		var longSignal = cciValue < -50m && rsiValue < 40m;
		var shortSignal = cciValue > 50m && rsiValue > 60m;

		if (longSignal)
		{
			BuyMarket();
			_stopPrice = candle.ClosePrice - stopOffset;
		}
		else if (shortSignal)
		{
			SellMarket();
			_stopPrice = candle.ClosePrice + stopOffset;
		}
	}
}