Esta estrategia es una versión StockSharp del asesor experto MetaTrader 4 RUBBERBANDS_3. Mantiene dos precios extremos, abre posiciones adicionales cada vez que el precio se expande en una distancia configurable y liquida toda la secuencia una vez que se produce un contramovimiento de un tamaño determinado. Después de un retroceso, la estrategia opcionalmente gira en la dirección opuesta mientras monitorea un objetivo de pérdidas y ganancias a nivel de sesión.
Nota: StockSharp opera en posiciones neteadas. El script MT4 original puede mantener órdenes largas y cortas simultáneamente, pero el puerto cierra la secuencia activa antes de cambiar de dirección. Se preserva el comportamiento general de escalar hacia las tendencias y revertir los retrocesos.
Lógica de trading
Registre el precio de cierre actual como máximo y mínimo (o reutilice los valores guardados al reiniciar).
Cuando el precio suba PipStep puntos por encima del máximo actual, envíe una orden de compra de mercado de tamaño OrderVolume y actualice el máximo al nuevo precio.
Cuando el precio caiga PipStep puntos por debajo del mínimo actual, envíe una orden de venta de mercado de tamaño OrderVolume y actualice el mínimo.
Si el mercado retrocede BackStep puntos en contra de la dirección activa, cierre todas las posiciones en esa dirección y establezca una reversión. El lado opuesto se abre una vez liquidada por completo la secuencia anterior.
Supervise el resultado acumulado de la sesión. Si el beneficio realizado más abierto alcanza SessionTakeProfit × OrderVolume, cierre la sesión. Cuando la reducción durante la reversión exceda SessionStopLoss × OrderVolume, cierre todo también.
La palanca QuiesceNow evita nuevas operaciones cuando la estrategia es plana. El indicador StopNow detiene toda la lógica y CloseNow solicita un aplanamiento inmediato de la cartera.
Los pedidos se generan a partir de velas terminadas del CandleType configurado. El período de tiempo predeterminado es un minuto, que coincide con el tiempo del EA original que activó las comprobaciones al comienzo de cada minuto.
Parámetros
Parámetro
Descripción
Predeterminado
OrderVolume
Tamaño base de cada orden de mercado.
0.02
MaxOrders
Número máximo de posiciones concurrentes en una sola dirección. Las entradas adicionales se bloquean cuando se alcanza el límite.
10
PipStep
Distancia de expansión en puntos que suma un nuevo comercio.
100
BackStep
Contramovimiento en puntos que fuerza una salida y prepara una reversión.
20
QuiesceNow
Cuando true, la estrategia permanece inactiva mientras no haya posiciones abiertas.
false
DoNow
Abre la primera secuencia larga inmediatamente después de que comienza la estrategia.
false
StopNow
Bandera de parada dura que impide cualquier procesamiento posterior. Las posiciones existentes permanecen intactas.
false
CloseNow
Solicita una posición plana inmediata, provocando cierres secuenciales.
false
UseSessionTakeProfit
Habilita la toma de ganancias acumulada de la sesión.
true
SessionTakeProfit
Beneficio objetivo en la moneda de la cuenta por lote utilizado para cerrar la sesión.
2000
UseSessionStopLoss
Habilita el stop-loss acumulado de la sesión.
true
SessionStopLoss
Pérdida máxima tolerada por lote al revertir antes del cierre de la sesión.
4000
UseInitialValues
Al reiniciar, reutilice los InitialMax y InitialMin proporcionados manualmente en lugar del último precio de cierre.
false
InitialMax
El extremo superior almacenado se reutiliza cuando UseInitialValues está habilitado.
0
InitialMin
El extremo inferior almacenado se reutiliza cuando UseInitialValues está habilitado.
0
CandleType
Serie de velas procesadas por la estrategia. El valor predeterminado es velas de un minuto.
TimeFrame(1m)
Gestión de sesiones
Agregación de ganancias: las ganancias realizadas se acumulan después de cada cierre completo, mientras que las ganancias no realizadas se recalculan a partir de los precios de entrada promedio ponderados de todas las posiciones abiertas.
Obtención de beneficios de la sesión: una vez que se alcanza SessionTakeProfit, la estrategia cierra todas las operaciones y restablece los extremos almacenados.
Stop-loss de sesión: durante una secuencia de reversión (BackStep activada), la estrategia rastrea la pérdida flotante. Si la reducción excede SessionStopLoss, todas las posiciones se liquidan y la sesión se reinicia con las estadísticas borradas.
Notas de uso
El paso de precio utilizado para convertir puntos en precios se toma de Security.PriceStep. Configure los metadatos del instrumento en consecuencia; de lo contrario, se aplica una reserva de 0.0001.
Debido a que las órdenes se compensan, la estrategia ejecuta operaciones de cierre antes de abrir en la dirección opuesta. Al migrar datos heredados, tenga en cuenta que el historial de pedidos puede diferir del de las plataformas cubiertas.
La bandera DoNow solo abre la primera posición larga. Las entradas adicionales siguen las condiciones de ruptura habituales.
Utilice QuiesceNow cuando desee dejar la estrategia cargada pero inactiva después de que aplana el libro.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Rubberbands 3: Grid expansion strategy using SMA+ATR bands.
/// Enters at band extremes, adds on continuation, exits at mean.
/// </summary>
public class Rubberbands3Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _entryPrice;
private int _gridCount;
public Rubberbands3Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_smaLength = Param(nameof(SmaLength), 20)
.SetDisplay("SMA Length", "SMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_gridCount = 0;
var sma = new SimpleMovingAverage { Length = SmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (atrVal <= 0)
return;
var close = candle.ClosePrice;
var upper = smaVal + atrVal * 1.5m;
var lower = smaVal - atrVal * 1.5m;
if (Position > 0)
{
if (close >= smaVal)
{
SellMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (close <= _entryPrice - atrVal * 5m)
{
SellMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (_gridCount < 4 && close <= _entryPrice - atrVal * 0.8m)
{
_entryPrice = (_entryPrice + close) / 2m;
_gridCount++;
BuyMarket();
}
}
else if (Position < 0)
{
if (close <= smaVal)
{
BuyMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (close >= _entryPrice + atrVal * 5m)
{
BuyMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (_gridCount < 4 && close >= _entryPrice + atrVal * 0.8m)
{
_entryPrice = (_entryPrice + close) / 2m;
_gridCount++;
SellMarket();
}
}
if (Position == 0)
{
if (close <= lower)
{
_entryPrice = close;
_gridCount = 0;
BuyMarket();
}
else if (close >= upper)
{
_entryPrice = close;
_gridCount = 0;
SellMarket();
}
}
}
}
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.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class rubberbands_3_strategy(Strategy):
def __init__(self):
super(rubberbands_3_strategy, self).__init__()
self._sma_length = self.Param("SmaLength", 20).SetDisplay("SMA Length", "SMA period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Timeframe", "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(rubberbands_3_strategy, self).OnReseted()
self._entry_price = 0
self._grid_count = 0
def OnStarted2(self, time):
super(rubberbands_3_strategy, self).OnStarted2(time)
self._entry_price = 0
self._grid_count = 0
sma = SimpleMovingAverage()
sma.Length = self._sma_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sma, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sma_val, atr_val):
if candle.State != CandleStates.Finished:
return
if atr_val <= 0:
return
close = float(candle.ClosePrice)
upper = sma_val + atr_val * 1.5
lower = sma_val - atr_val * 1.5
if self.Position > 0:
if close >= sma_val:
self.SellMarket()
self._entry_price = 0
self._grid_count = 0
elif close <= self._entry_price - atr_val * 5.0:
self.SellMarket()
self._entry_price = 0
self._grid_count = 0
elif self._grid_count < 4 and close <= self._entry_price - atr_val * 0.8:
self._entry_price = (self._entry_price + close) / 2.0
self._grid_count += 1
self.BuyMarket()
elif self.Position < 0:
if close <= sma_val:
self.BuyMarket()
self._entry_price = 0
self._grid_count = 0
elif close >= self._entry_price + atr_val * 5.0:
self.BuyMarket()
self._entry_price = 0
self._grid_count = 0
elif self._grid_count < 4 and close >= self._entry_price + atr_val * 0.8:
self._entry_price = (self._entry_price + close) / 2.0
self._grid_count += 1
self.SellMarket()
if self.Position == 0:
if close <= lower:
self._entry_price = close
self._grid_count = 0
self.BuyMarket()
elif close >= upper:
self._entry_price = close
self._grid_count = 0
self.SellMarket()
def CreateClone(self):
return rubberbands_3_strategy()