Ver en GitHub

Estrategia de Escape

Esta estrategia opera basándose en medias móviles simples de los precios de apertura de las velas. Compara el cierre más reciente de 5 minutos con dos medias móviles calculadas sobre el precio de apertura:

  • SMA rápida (4 períodos) – utilizada como umbral para entradas cortas.
  • SMA lenta (5 períodos) – utilizada como umbral para entradas largas.

Cómo funciona

  1. En cada vela de 5 minutos completada, la estrategia actualiza dos SMA del precio de apertura de las velas.
  2. Si no hay posición activa:
    • Entrar en largo cuando el último cierre está por debajo de la SMA lenta.
    • Entrar en corto cuando el último cierre está por encima de la SMA rápida.
  3. Tras entrar en una posición, la estrategia establece niveles fijos de stop-loss y take-profit medidos en unidades de precio.
  4. La posición se cierra cuando se alcanza el take-profit o el stop-loss.

La lógica usa la API de alto nivel de StockSharp y está destinada a propósitos educativos.

Parámetros

Nombre Descripción Predeterminado
FastLength Período de la SMA rápida. 4
SlowLength Período de la SMA lenta. 5
TakeProfitLong Distancia de take-profit para operaciones largas en unidades de precio. 25
TakeProfitShort Distancia de take-profit para operaciones cortas en unidades de precio. 26
StopLossLong Distancia de stop-loss para operaciones largas en unidades de precio. 25
StopLossShort Distancia de stop-loss para operaciones cortas en unidades de precio. 3
CandleType Tipo de vela utilizado para el análisis. TimeFrame(5m)

Todos los parámetros pueden optimizarse mediante el optimizador de StockSharp.

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>
/// Simple strategy based on SMA of open prices and previous close comparison.
/// Buys when the previous close is below the slow SMA.
/// Sells short when the previous close is above the fast SMA.
/// Uses fixed take profit and stop loss levels for both directions.
/// </summary>
public class EscapeStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<decimal> _takeProfitLong;
	private readonly StrategyParam<decimal> _takeProfitShort;
	private readonly StrategyParam<decimal> _stopLossLong;
	private readonly StrategyParam<decimal> _stopLossShort;
	private readonly StrategyParam<DataType> _candleType;

	private SimpleMovingAverage _fastMa;
	private SimpleMovingAverage _slowMa;
	private bool _initialized;
	private decimal _previousClose;
	private decimal _previousFast;
	private decimal _previousSlow;

	/// <summary>
	/// Length of fast SMA.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	/// <summary>
	/// Length of slow SMA.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	/// <summary>
	/// Take profit distance for long positions in price units.
	/// </summary>
	public decimal TakeProfitLong
	{
		get => _takeProfitLong.Value;
		set => _takeProfitLong.Value = value;
	}

	/// <summary>
	/// Take profit distance for short positions in price units.
	/// </summary>
	public decimal TakeProfitShort
	{
		get => _takeProfitShort.Value;
		set => _takeProfitShort.Value = value;
	}

	/// <summary>
	/// Stop loss distance for long positions in price units.
	/// </summary>
	public decimal StopLossLong
	{
		get => _stopLossLong.Value;
		set => _stopLossLong.Value = value;
	}

	/// <summary>
	/// Stop loss distance for short positions in price units.
	/// </summary>
	public decimal StopLossShort
	{
		get => _stopLossShort.Value;
		set => _stopLossShort.Value = value;
	}

	/// <summary>
	/// Candle type to analyze.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public EscapeStrategy()
	{
		_fastLength = Param(nameof(FastLength), 4)
			.SetDisplay("Fast SMA Length", "Length of fast SMA", "Parameters")
			.SetGreaterThanZero()
			;

		_slowLength = Param(nameof(SlowLength), 5)
			.SetDisplay("Slow SMA Length", "Length of slow SMA", "Parameters")
			.SetGreaterThanZero()
			;

		_takeProfitLong = Param(nameof(TakeProfitLong), 25m)
			.SetDisplay("Take Profit Long", "Take profit for long trades", "Trading")
			.SetGreaterThanZero();

		_takeProfitShort = Param(nameof(TakeProfitShort), 26m)
			.SetDisplay("Take Profit Short", "Take profit for short trades", "Trading")
			.SetGreaterThanZero();

		_stopLossLong = Param(nameof(StopLossLong), 25m)
			.SetDisplay("Stop Loss Long", "Stop loss for long trades", "Trading")
			.SetGreaterThanZero();

		_stopLossShort = Param(nameof(StopLossShort), 3m)
			.SetDisplay("Stop Loss Short", "Stop loss for short trades", "Trading")
			.SetGreaterThanZero();

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for candles", "General");
	}

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

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

		_fastMa = null;
		_slowMa = null;
		_initialized = false;
		_previousClose = 0m;
		_previousFast = 0m;
		_previousSlow = 0m;
	}

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

		_fastMa = new SMA { Length = FastLength };
		_slowMa = new SMA { Length = SlowLength };

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

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

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

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

		var fast = _fastMa!.Process(new DecimalIndicatorValue(_fastMa, candle.OpenPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
		var slow = _slowMa!.Process(new DecimalIndicatorValue(_slowMa, candle.OpenPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();

		if (!_initialized)
		{
			_initialized = true;
			_previousClose = candle.ClosePrice;
			_previousFast = fast;
			_previousSlow = slow;
			return;
		}

		var close = candle.ClosePrice;
		var buySignal = _previousClose >= _previousSlow && close < slow;
		var sellSignal = _previousClose <= _previousFast && close > fast;

		if (Position == 0)
		{
			if (buySignal)
				BuyMarket();
			else if (sellSignal)
				SellMarket();
		}

		_previousClose = close;
		_previousFast = fast;
		_previousSlow = slow;
	}
}