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
- The strategy opens an initial long position on start.
- When price advances by
ProfitThresholdpoints from the last entry price, it opens another long position. - Each new entry updates stop loss and take profit levels relative to its own price.
- 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;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class re_open_positions_strategy(Strategy):
def __init__(self):
super(re_open_positions_strategy, self).__init__()
self._profit_threshold = self.Param("ProfitThreshold", 300.0).SetDisplay("Profit Threshold", "Points to reopen", "Parameters")
self._max_positions = self.Param("MaxPositions", 1).SetDisplay("Max Positions", "Maximum positions", "Parameters")
self._sl_points = self.Param("StopLossPoints", 1000.0).SetDisplay("Stop Loss (pts)", "SL distance", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 2000.0).SetDisplay("Take Profit (pts)", "TP distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle type", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(re_open_positions_strategy, self).OnReseted()
self._opened_count = 0
self._last_entry = 0
self._current_stop = 0
self._current_take = 0
def OnStarted2(self, time):
super(re_open_positions_strategy, self).OnStarted2(time)
self._opened_count = 0
self._last_entry = 0
self._current_stop = 0
self._current_take = 0
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if self.Position > 0:
if close <= self._current_stop or close >= self._current_take:
self.SellMarket()
self._opened_count = 0
elif self._opened_count < self._max_positions.Value and close - self._last_entry >= self._profit_threshold.Value:
self.BuyMarket()
self._last_entry = close
self._opened_count += 1
self._current_stop = self._last_entry - self._sl_points.Value
self._current_take = self._last_entry + self._tp_points.Value
elif self.Position < 0:
if close >= self._current_stop or close <= self._current_take:
self.BuyMarket()
self._opened_count = 0
elif self._opened_count < self._max_positions.Value and self._last_entry - close >= self._profit_threshold.Value:
self.SellMarket()
self._last_entry = close
self._opened_count += 1
self._current_stop = self._last_entry + self._sl_points.Value
self._current_take = self._last_entry - self._tp_points.Value
else:
self.BuyMarket()
self._last_entry = close
self._opened_count = 1
self._current_stop = self._last_entry - self._sl_points.Value
self._current_take = self._last_entry + self._tp_points.Value
def CreateClone(self):
return re_open_positions_strategy()