Ver en GitHub

Estrategia Sophia 1_1

Sophia 1_1 es una estrategia de trading de cuadrícula basada en el principio de martingala. La estrategia abre una posición después de cuatro velas consecutivas moviéndose en la misma dirección:

  • Cuatro velas ascendentes activan una entrada corta.
  • Cuatro velas descendentes activan una entrada larga.

Una vez en el mercado, el algoritmo añade posiciones cada vez que el precio se mueve contra la posición actual en un número fijo de pasos de precio (Pip Step). El volumen de cada operación adicional se multiplica por Lot Exponent, formando una cuadrícula de martingala clásica.

La gestión del riesgo se maneja a través de Take Profit, Stop Loss y un trailing stop opcional. El mecanismo de trailing se activa cuando el beneficio alcanza Trail Start y sigue el nivel de stop en Trail Stop pasos de precio.

Parámetros

  • Volume – volumen base para la primera operación.
  • Pip Step – distancia en pasos de precio antes de añadir una nueva posición.
  • Lot Exponent – multiplicador para el volumen de cada operación adicional.
  • Max Trades – número máximo de posiciones en la cuadrícula.
  • Take Profit – objetivo de beneficio en pasos de precio desde el precio de entrada promedio.
  • Stop Loss – umbral de pérdida en pasos de precio desde el precio de entrada promedio.
  • Use Trailing – habilitar o deshabilitar el trailing stop.
  • Trail Start – beneficio requerido antes de que el trailing stop se active.
  • Trail Stop – distancia del trailing stop en pasos de precio.
  • Candle Type – marco temporal de las velas usadas para los cálculos.
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>
/// Grid mean-reversion strategy. Enters on 3-bar momentum, exits at SMA or ATR stop.
/// </summary>
public class Sophia11Strategy : Strategy
{
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prev1, _prev2, _prev3;

	public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Sophia11Strategy()
	{
		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA for exit target", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR for stops", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prev1 = _prev2 = _prev3 = 0;
	}

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

		var sma = new SimpleMovingAverage { Length = SmaPeriod };
		var atr = new StandardDeviation { Length = AtrPeriod };

		SubscribeCandles(CandleType).Bind(sma, atr, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;

		if (_prev3 > 0)
		{
			// 3-bar declining => counter-trend buy
			if (_prev1 < _prev2 && _prev2 < _prev3 && Position <= 0)
			{
				if (Position < 0) BuyMarket();
				BuyMarket();
			}
			// 3-bar rising => counter-trend sell
			else if (_prev1 > _prev2 && _prev2 > _prev3 && Position >= 0)
			{
				if (Position > 0) SellMarket();
				SellMarket();
			}
			// Exit long at SMA or ATR stop
			else if (Position > 0 && (close >= sma || (atr > 0 && close < sma - atr * 3)))
			{
				SellMarket();
			}
			// Exit short at SMA or ATR stop
			else if (Position < 0 && (close <= sma || (atr > 0 && close > sma + atr * 3)))
			{
				BuyMarket();
			}
		}

		_prev3 = _prev2;
		_prev2 = _prev1;
		_prev1 = close;
	}
}