Ver en GitHub

Estrategia de Reversión del Cuerpo de Vela Go

Estrategia basada en el indicador Go que promedia el tamaño del cuerpo de la vela. Abre una posición larga cuando el cuerpo suavizado de la vela cruza por debajo de cero después de ser positivo y abre una posición corta en el cruce opuesto. Las posiciones existentes se cierran con señales opuestas.

Detalles

  • Criterios de entrada: cambio de signo del SMA del cuerpo (positivo a negativo para largo, negativo a positivo para corto)
  • Largo/Corto: Ambos
  • Criterios de salida: cambio de signo opuesto del SMA del cuerpo
  • Stops: No
  • Valores predeterminados:
    • Period = 174
    • CandleType = 1 hora
  • Filtros:
    • Categoría: Reversión
    • Dirección: Largo y Corto
    • Indicadores: SMA
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: Intradía
    • 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 smoothed candle body direction.
/// Smooths (close-open) with SMA, trades on sign changes.
/// </summary>
public class GoCandleBodyReversalStrategy : Strategy
{
	private readonly StrategyParam<int> _period;
	private readonly StrategyParam<DataType> _candleType;

	private ExponentialMovingAverage _bodySma;
	private int _prevSign;

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

	public GoCandleBodyReversalStrategy()
	{
		_period = Param(nameof(Period), 30)
			.SetGreaterThanZero()
			.SetDisplay("Period", "SMA period for candle body", "Parameters");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_bodySma = null;
		_prevSign = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_bodySma = new ExponentialMovingAverage { Length = Period };
		Indicators.Add(_bodySma);

		// Use a warmup EMA bound to close price
		var warmup = new ExponentialMovingAverage { Length = Period };

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

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

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

		var body = candle.ClosePrice - candle.OpenPrice;
		var maResult = _bodySma.Process(new DecimalIndicatorValue(_bodySma, body, candle.OpenTime) { IsFinal = true });

		if (!maResult.IsFormed)
			return;

		var value = maResult.GetValue<decimal>();
		var sign = value > 0 ? 1 : value < 0 ? -1 : 0;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevSign = sign;
			return;
		}

		if (_prevSign == 0)
		{
			_prevSign = sign;
			return;
		}

		// Body direction turns negative (bearish reversal) -> sell
		if (sign < 0 && _prevSign > 0 && Position >= 0)
			SellMarket();
		// Body direction turns positive (bullish reversal) -> buy
		else if (sign > 0 && _prevSign < 0 && Position <= 0)
			BuyMarket();

		_prevSign = sign;
	}
}