Ver en GitHub

Re Open Positions

This strategy is a StockSharp port of the MQL5 example Exp_ReOpenPositions. It demonstrates how to reopen positions when the current trade becomes profitable.

Logic

  1. The strategy opens an initial long position on start.
  2. When price advances by ProfitThreshold points from the last entry price, it opens another long position.
  3. Each new entry updates stop loss and take profit levels relative to its own price.
  4. If price reaches the stop loss or take profit, all positions are closed and the cycle resets.

The same rules work for short trades if the first position is short.

Parameters

  • ProfitThreshold – price movement in points required to add a new position.
  • MaxPositions – maximum number of opened positions.
  • StopLossPoints – distance from entry to protective stop.
  • TakeProfitPoints – distance from entry to target profit.
  • CandleType – candle data type for processing.

Notes

The example is simplified for educational purposes and does not manage trade volume or money management as in the original script.

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;
		}
	}
}