Ver en GitHub

Stop Trailing Básico

La estrategia Basic Trailing Stop combina filtros del Commodity Channel Index (CCI) y del Relative Strength Index (RSI) con un stop trailing simple. Cuando ambos indicadores señalan condiciones de sobreventa o sobrecompra, la estrategia abre una posición de mercado y coloca inmediatamente un stop trailing medido en pips. A medida que el precio se mueve favorablemente, el nivel del stop sigue la tendencia para asegurar ganancias.

Las pruebas indican un rendimiento anual medio de aproximadamente el 32%. Funciona mejor en el mercado de divisas.

Dado que el nivel del stop sigue continuamente al precio, el riesgo se ajusta automáticamente cuando se extiende la tendencia. Las salidas ocurren solo si se alcanza el stop trailing. El sistema mantiene una posición a la vez y puede operar en ambas direcciones.

Detalles

  • Criterios de entrada:
    • Largo: CCI entre -150 y -100 y RSI entre 0 y 30.
    • Corto: CCI entre 100 y 250 y RSI entre 70 y 100.
  • Largo/Corto: Ambos.
  • Criterios de salida: Stop trailing alcanzado.
  • Stops: Solo stop trailing.
  • Valores predeterminados:
    • StopLossPips = 20
    • CciPeriod = 14
    • RsiPeriod = 14
    • CandleType = TimeSpan.FromMinutes(1)
  • Filtros:
    • Categoría: Momentum
    • Dirección: Ambos
    • Indicadores: CCI, RSI
    • Stops: Sí
    • Complejidad: Principiante
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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;
		}
	}
}