Ver en GitHub

Estrategia de Cierre por Porcentaje de Capital

Esta estrategia de gestión de riesgo monitorea el capital de la cartera y cierra cualquier posición abierta cuando el capital supera el balance actual multiplicado por un multiplicador definido por el usuario. Está diseñada para asegurar ganancias una vez que el valor de la cuenta alcanza un porcentaje deseado sobre el valor base.

La estrategia realiza verificaciones periódicas utilizando velas y no genera entradas de operaciones por sí misma; solo gestiona una posición existente. Tras el cierre, el balance de referencia se actualiza, permitiendo que el proceso se repita para operaciones posteriores.

Detalles

  • Criterios de entrada: Ninguno (gestiona la posición existente).
  • Largo/Corto: Ambos direcciones.
  • Criterios de salida: Capital mayor que balance * EquityPercentFromBalance.
  • Stops: No.
  • Valores predeterminados:
    • EquityPercentFromBalance = 1.2m
    • CandleType = TimeSpan.FromMinutes(1)
  • Filtros:
    • Categoría: Gestión de riesgos
    • Dirección: Ambos
    • Indicadores: Ninguno
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: Intradía (1m)
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Bajo
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>
/// Closes position when equity exceeds balance by a given multiplier.
/// </summary>
public class CloseByEquityPercentStrategy : Strategy
{
	private readonly StrategyParam<decimal> _equityPercent;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _currentBalance;

	/// <summary>
	/// Equity to balance multiplier.
	/// </summary>
	public decimal EquityPercentFromBalance
	{
		get => _equityPercent.Value;
		set => _equityPercent.Value = value;
	}

	/// <summary>
	/// Candle type for periodic checks.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="CloseByEquityPercentStrategy"/>.
	/// </summary>
	public CloseByEquityPercentStrategy()
	{
		_equityPercent = Param(nameof(EquityPercentFromBalance), 1.2m)
			.SetDisplay("Equity/Bal Multiplier", "Threshold multiplier for equity relative to balance", "Risk Management")
			
			.SetOptimize(1.1m, 2m, 0.1m);

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_currentBalance = 0m;
	}

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

		_currentBalance = Portfolio?.CurrentValue ?? 0m;

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

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

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

		var equity = Portfolio?.CurrentValue ?? 0m;

		if (equity > _currentBalance * EquityPercentFromBalance)
		{
			if (Position > 0)
				SellMarket(Position);
			else if (Position < 0)
				BuyMarket(-Position);

			_currentBalance = equity;
			return;
		}

		// Simple entry when flat
		if (Position == 0)
		{
			_currentBalance = equity;
			if (candle.ClosePrice > candle.OpenPrice)
				BuyMarket();
			else if (candle.ClosePrice < candle.OpenPrice)
				SellMarket();
		}
	}
}