Ver en GitHub

Estrategia Bezier de Desviación Estándar

Esta estrategia negocia puntos de giro en la volatilidad usando un indicador de desviación estándar. Interpreta los mínimos y máximos locales del indicador como posibles reversiones en la acción del precio. Cuando la desviación estándar forma un valle, el sistema espera que la volatilidad se expanda al alza y entra en una posición larga. Cuando aparece un pico, vende en corto anticipando una contracción de la volatilidad.

El enfoque está diseñado para operaciones tanto largas como cortas en un marco temporal de cuatro horas por defecto. No aplica órdenes de stop-loss, centrándose en cambio en salidas basadas en señales.

Detalles

  • Criterios de entrada:
    • Largo: El valor de la desviación estándar en la barra anterior es menor que sus vecinos (mínimo local).
    • Corto: El valor de la desviación estándar en la barra anterior es mayor que sus vecinos (máximo local).
  • Largo/Corto: Ambos.
  • Criterios de salida:
    • Una señal opuesta desencadena una reversión.
  • Stops: No.
  • Valores predeterminados:
    • StdDev Period = 9.
    • Candle Type = velas de 4 horas.
  • Filtros:
    • Categoría: Reversión a la media
    • Dirección: Ambos
    • Indicadores: Desviación estándar
    • Stops: No
    • Complejidad: Simple
    • Marco temporal: Medio plazo
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on standard deviation turning points.
/// Opens long at local minima and short at local maxima of the indicator.
/// </summary>
public class BezierStDevStrategy : Strategy
{
	private readonly StrategyParam<int> _stdDevPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevValue1;
	private decimal _prevValue2;

	/// <summary>
	/// Standard deviation calculation period.
	/// </summary>
	public int StdDevPeriod
	{
		get => _stdDevPeriod.Value;
		set => _stdDevPeriod.Value = value;
	}

	/// <summary>
	/// Type of candles used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public BezierStDevStrategy()
	{
		_stdDevPeriod = Param(nameof(StdDevPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("StdDev Period", "Period for standard deviation calculation", "General")
			
			.SetOptimize(5, 20, 1);

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevValue1 = 0m;
		_prevValue2 = 0m;
	}

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

		var stdDev = new StandardDeviation { Length = StdDevPeriod };

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

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

	private void ProcessCandle(ICandleMessage candle, decimal stdDevValue)
	{
		// We only work with finished candles.
		if (candle.State != CandleStates.Finished)
			return;

		// Ensure the strategy is ready for trading.
		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		// Check for local minima and maxima at the previous value.
		if (_prevValue2 != 0m)
		{
			var isLocalMin = _prevValue1 < _prevValue2 && _prevValue1 < stdDevValue;
			var isLocalMax = _prevValue1 > _prevValue2 && _prevValue1 > stdDevValue;

			if (isLocalMin)
			{
				if (Position <= 0)
					BuyMarket();
			}
			else if (isLocalMax)
			{
				if (Position >= 0)
					SellMarket();
			}
		}

		// Shift stored values for next calculation.
		_prevValue2 = _prevValue1;
		_prevValue1 = stdDevValue;
	}
}