Estrategia de Retroceso de Precio
Esta estrategia opera brechas de precio diarias. Al comienzo de un día de la semana seleccionado, compara el último precio de cierre con el precio de apertura 24 horas antes. Si la brecha es mayor que el parámetro Corridor, abre una posición en la dirección del retroceso:
- Brecha al alza → vender.
- Brecha a la baja → comprar.
Las operaciones utilizan stop loss y take profit fijos en unidades de precio. Se aplica un trailing stop con paso después de que la posición avanza en ganancias. Todas las posiciones se cierran al final del día (22:45).
Parámetros
Corridor– umbral de la brecha.StopLoss– distancia de stop loss fija.TakeProfit– objetivo de take profit fijo.TrailingStop– distancia del trailing stop.TrailingStep– movimiento necesario para actualizar el trailing.TradingDay– día de la semana para abrir operaciones (0=domingo).CandleType– marco temporal para los cálculos.
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>
/// Price rollback strategy that detects price gaps (large moves) and trades the pullback.
/// When price gaps up beyond a corridor, it sells expecting rollback.
/// When price gaps down beyond a corridor, it buys expecting rollback.
/// Uses trailing stop and take profit for exits.
/// </summary>
public class PriceRollbackStrategy : Strategy
{
private readonly StrategyParam<decimal> _corridor;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<DataType> _type;
private decimal _prevClose;
private bool _hasPrev;
public decimal Corridor { get => _corridor.Value; set => _corridor.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal TrailingStop { get => _trailingStop.Value; set => _trailingStop.Value = value; }
public DataType CandleType { get => _type.Value; set => _type.Value = value; }
public PriceRollbackStrategy()
{
_corridor = Param(nameof(Corridor), 5000m)
.SetDisplay("Corridor", "Minimum gap size for entry", "General");
_stopLoss = Param(nameof(StopLoss), 500m)
.SetDisplay("Stop Loss", "Stop loss distance", "Risk");
_takeProfit = Param(nameof(TakeProfit), 400m)
.SetDisplay("Take Profit", "Take profit distance", "Risk");
_trailingStop = Param(nameof(TrailingStop), 300m)
.SetDisplay("Trailing Stop", "Trailing stop distance", "Risk");
_type = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0m;
_hasPrev = false;
}
public override IEnumerable<(Security, DataType)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var atr = new AverageTrueRange { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, atr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (_hasPrev && Position == 0)
{
// Detect strong candle move (body > corridor) - trade rollback
var body = close - candle.OpenPrice;
var bodySize = Math.Abs(body);
if (bodySize > atrValue * 1.5m)
{
// Strong move up - sell expecting rollback
if (body > 0)
{
SellMarket();
}
// Strong move down - buy expecting rollback
else if (body < 0)
{
BuyMarket();
}
}
}
_prevClose = close;
_hasPrev = true;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class price_rollback_strategy(Strategy):
def __init__(self):
super(price_rollback_strategy, self).__init__()
self._corridor = self.Param("Corridor", 5000.0)
self._stop_loss = self.Param("StopLoss", 500.0)
self._take_profit = self.Param("TakeProfit", 400.0)
self._trailing_stop = self.Param("TrailingStop", 300.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_close = 0.0
self._entry_price = 0.0
self._trail_price = 0.0
self._has_prev = False
@property
def Corridor(self):
return self._corridor.Value
@Corridor.setter
def Corridor(self, value):
self._corridor.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def TrailingStop(self):
return self._trailing_stop.Value
@TrailingStop.setter
def TrailingStop(self, value):
self._trailing_stop.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(price_rollback_strategy, self).OnStarted2(time)
self._has_prev = False
self._entry_price = 0.0
self._trail_price = 0.0
self._prev_close = 0.0
atr = AverageTrueRange()
atr.Length = 14
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(atr, self.ProcessCandle).Start()
self.StartProtection(
Unit(2.0, UnitTypes.Percent),
Unit(1.0, UnitTypes.Percent))
def ProcessCandle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
atr_val = float(atr_value)
if self._has_prev and self.Position == 0:
body = close - open_price
body_size = abs(body)
if body_size > atr_val * 1.5:
if body > 0.0:
self.SellMarket()
elif body < 0.0:
self.BuyMarket()
self._prev_close = close
self._has_prev = True
def OnReseted(self):
super(price_rollback_strategy, self).OnReseted()
self._prev_close = 0.0
self._entry_price = 0.0
self._trail_price = 0.0
self._has_prev = False
def CreateClone(self):
return price_rollback_strategy()