Ver en GitHub

Estrategia Fibo Stop

Descripción general

La estrategia Fibo Stop mueve el stop de protección a lo largo de los niveles de retroceso de Fibonacci definidos por dos precios: inicio y fin. La estrategia abre una posición en la dirección del nivel de inicio al nivel de fin y mueve el stop a cada nuevo nivel de Fibonacci una vez que el precio lo cruza.

Algoritmo

  1. Determinar la dirección desde el precio de inicio al precio de fin. Si el fin es mayor que el inicio, se abre una posición larga; de lo contrario, una posición corta.
  2. Calcular los niveles de Fibonacci: 0%, 23.6%, 38.6%, 50%, 61.8%, 78.6%, 100%, 127% basados en el rango.
  3. El stop inicial se coloca detrás del nivel de inicio usando el desplazamiento especificado en pasos de precio.
  4. A medida que el precio de mercado se mueve y cruza el siguiente nivel de Fibonacci, el stop se mueve a ese nivel menos/más el desplazamiento.
  5. La posición se cierra cuando el precio alcanza el stop móvil.

Parámetros

  • FiboStart – precio base donde comienza el cálculo de Fibonacci.
  • FiboEnd – precio final que define el rango de Fibonacci.
  • OffsetPoints – número de pasos de precio añadidos detrás de cada nivel de Fibonacci para colocar el stop.
  • CandleType – serie de velas utilizada para monitorear el precio.

Notas

La estrategia utiliza solo velas completadas y no depende del historial de valores del indicador. Está diseñada como ejemplo de gestión de un trailing stop con la API de alto nivel de StockSharp.

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 that uses Fibonacci retracement levels for entry and trailing stop.
/// Enters on pullback to Fibonacci level and trails stop along levels.
/// </summary>
public class FiboStopStrategy : Strategy
{
	private readonly StrategyParam<int> _lookbackPeriod;
	private readonly StrategyParam<decimal> _entryFiboLevel;
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<int> _cooldownBars;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _highestHigh;
	private decimal _lowestLow;
	private int _barCount;
	private int _barsSinceTrade;
	private bool _rangeSet;
	private decimal _entryPrice;

	public int LookbackPeriod { get => _lookbackPeriod.Value; set => _lookbackPeriod.Value = value; }
	public decimal EntryFiboLevel { get => _entryFiboLevel.Value; set => _entryFiboLevel.Value = value; }
	public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
	public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public FiboStopStrategy()
	{
		_lookbackPeriod = Param(nameof(LookbackPeriod), 500)
			.SetGreaterThanZero()
			.SetDisplay("Lookback", "Bars to calculate high/low range", "General");

		_entryFiboLevel = Param(nameof(EntryFiboLevel), 0.382m)
			.SetDisplay("Entry Fibo", "Fibonacci level for entry (0.236, 0.382, 0.5, 0.618)", "Fibonacci");

		_stopLossPct = Param(nameof(StopLossPct), 2m)
			.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");

		_cooldownBars = Param(nameof(CooldownBars), 50)
			.SetGreaterThanZero()
			.SetDisplay("Cooldown Bars", "Bars between new entries", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
		_highestHigh = decimal.MinValue;
		_lowestLow = decimal.MaxValue;
		_barCount = 0;
		_barsSinceTrade = CooldownBars;
		_rangeSet = false;
		_entryPrice = 0;
	}

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

		_highestHigh = decimal.MinValue;
		_lowestLow = decimal.MaxValue;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

		StartProtection(
			stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
			takeProfit: new Unit(2, UnitTypes.Percent)
		);

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

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

		_barCount++;
		_barsSinceTrade++;

		if (candle.HighPrice > _highestHigh)
			_highestHigh = candle.HighPrice;
		if (candle.LowPrice < _lowestLow)
			_lowestLow = candle.LowPrice;

		if (_barCount < LookbackPeriod)
			return;

		if (!_rangeSet)
		{
			_rangeSet = true;
			return;
		}

		var range = _highestHigh - _lowestLow;
		if (range <= 0)
			return;

		// Calculate Fibonacci retracement levels from high
		var fiboLevel = _highestHigh - range * EntryFiboLevel;
		var fibo618 = _highestHigh - range * 0.618m;

		if (Position == 0)
		{
			if (_barsSinceTrade < CooldownBars)
				return;

			if (candle.ClosePrice <= fiboLevel && candle.ClosePrice > fibo618)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_barsSinceTrade = 0;
			}
			else if (candle.ClosePrice >= _lowestLow + range * (1m - EntryFiboLevel) && candle.ClosePrice < _lowestLow + range * 0.382m)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_barsSinceTrade = 0;
			}
		}
		// Exits handled by StartProtection

		// Update rolling high/low
		if (_barCount > LookbackPeriod * 2)
		{
			_highestHigh = candle.HighPrice;
			_lowestLow = candle.LowPrice;
			_barCount = LookbackPeriod;
		}
	}
}