Ver en GitHub

Estrategia de Reapertura de Posiciones

Esta estrategia es un puerto StockSharp del ejemplo MQL5 Exp_ReOpenPositions. Demuestra cómo reabrir posiciones cuando la operación actual se vuelve rentable.

Lógica

  1. La estrategia abre una posición larga inicial al inicio.
  2. Cuando el precio avanza ProfitThreshold puntos desde el último precio de entrada, se abre otra posición larga.
  3. Cada nueva entrada actualiza los niveles de stop loss y take profit relativos a su propio precio.
  4. Si el precio alcanza el stop loss o el take profit, se cierran todas las posiciones y el ciclo se reinicia.

Las mismas reglas funcionan para operaciones cortas si la primera posición es corta.

Parámetros

  • ProfitThreshold – movimiento del precio en puntos necesario para añadir una nueva posición.
  • MaxPositions – número máximo de posiciones abiertas.
  • StopLossPoints – distancia desde la entrada hasta el stop de protección.
  • TakeProfitPoints – distancia desde la entrada hasta el beneficio objetivo.
  • CandleType – tipo de datos de velas para el procesamiento.

Notas

El ejemplo está simplificado con fines educativos y no gestiona el volumen de operaciones ni la gestión monetaria como en el script original.

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 that reopens positions once profit reaches a target in points.
/// </summary>
public class ReOpenPositionsStrategy : Strategy
{
	private readonly StrategyParam<decimal> _profitThreshold;
	private readonly StrategyParam<int> _maxPositions;
	private readonly StrategyParam<decimal> _stopLossPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<DataType> _candleType;

	private int _openedCount;
	private decimal _lastEntryPrice;
	private decimal _currentStop;
	private decimal _currentTake;

	public decimal ProfitThreshold
	{
		get => _profitThreshold.Value;
		set => _profitThreshold.Value = value;
	}

	public int MaxPositions
	{
		get => _maxPositions.Value;
		set => _maxPositions.Value = value;
	}

	public decimal StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	public decimal TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

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

	public ReOpenPositionsStrategy()
	{
		_profitThreshold = Param(nameof(ProfitThreshold), 300m)
			.SetDisplay("Profit Threshold", "Points to reopen a position", "Parameters");

		_maxPositions = Param(nameof(MaxPositions), 1)
			.SetDisplay("Max Positions", "Maximum number of positions", "Parameters");

		_stopLossPoints = Param(nameof(StopLossPoints), 1000m)
			.SetDisplay("Stop Loss (pts)", "Stop loss distance in points", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000m)
			.SetDisplay("Take Profit (pts)", "Take profit distance in points", "Risk");

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

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

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

		_openedCount = 0;
		_lastEntryPrice = default;
		_currentStop = default;
		_currentTake = default;
	}

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

		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 close = candle.ClosePrice;

		if (Position > 0)
		{
			// Check for stop loss or take profit.
			if (close <= _currentStop || close >= _currentTake)
			{
				SellMarket();
				_openedCount = 0;
			}
			else if (_openedCount < MaxPositions && close - _lastEntryPrice >= ProfitThreshold)
			{
				BuyMarket();
				_lastEntryPrice = close;
				_openedCount++;
				_currentStop = _lastEntryPrice - StopLossPoints;
				_currentTake = _lastEntryPrice + TakeProfitPoints;
			}
		}
		else if (Position < 0)
		{
			// Check for stop loss or take profit for short position.
			if (close >= _currentStop || close <= _currentTake)
			{
				BuyMarket();
				_openedCount = 0;
			}
			else if (_openedCount < MaxPositions && _lastEntryPrice - close >= ProfitThreshold)
			{
				SellMarket();
				_lastEntryPrice = close;
				_openedCount++;
				_currentStop = _lastEntryPrice + StopLossPoints;
				_currentTake = _lastEntryPrice - TakeProfitPoints;
			}
		}
		else
		{
			// Open the first position.
			BuyMarket();
			_lastEntryPrice = close;
			_openedCount = 1;
			_currentStop = _lastEntryPrice - StopLossPoints;
			_currentTake = _lastEntryPrice + TakeProfitPoints;
		}
	}
}