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
- La estrategia abre una posición larga inicial al inicio.
- Cuando el precio avanza
ProfitThresholdpuntos desde el último precio de entrada, se abre otra posición larga. - Cada nueva entrada actualiza los niveles de stop loss y take profit relativos a su propio precio.
- 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;
}
}
}
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()