Открыть на GitHub

Повторное открытие позиций

Стратегия представляет собой порт MQL5 примера Exp_ReOpenPositions на StockSharp и показывает, как добавлять позиции при появлении прибыли.

Логика

  1. После запуска стратегия открывает первоначальную длинную позицию.
  2. Как только цена проходит ProfitThreshold пунктов от последней цены входа, добавляется ещё одна позиция в том же направлении.
  3. Для каждого нового входа заново рассчитываются уровни стоп‑лосса и тейк‑профита.
  4. При срабатывании стопа или тейка все позиции закрываются и цикл начинается заново.

Такие же правила действуют и для коротких позиций.

Параметры

  • ProfitThreshold – требуемое движение цены в пунктах для добавления позиции.
  • MaxPositions – максимальное количество открытых позиций.
  • StopLossPoints – расстояние от цены входа до стоп‑лосса.
  • TakeProfitPoints – расстояние от цены входа до тейк‑профита.
  • CandleType – тип обрабатываемых свечей.

Примечание

Пример упрощён для демонстрации и не содержит механизмов управления капиталом оригинального скрипта.

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