Estrategia de cuadrícula Turbo Scaler
Descripción general
La estrategia Turbo Scaler Grid es una implementación StockSharp de alto nivel del asesor experto MQL5 "Turbo Scaler Grid Pending". La estrategia se centra en gestionar las rejillas de parada pendientes en torno a niveles de precios predefinidos, proteger dinámicamente las posiciones abiertas con lógica de equilibrio y seguimiento, y supervisar el capital de la cuenta para cerrar posiciones cuando se alcanzan los umbrales de ganancias o pérdidas.
La lógica funciona en múltiples períodos de tiempo simultáneamente:
- Un período de tiempo de activación configurable observa las señales de proximidad de precios que activan la cuadrícula pendiente.
- Las velas adicionales de 30 minutos, 2 horas y diarias brindan confirmación para activadores condicionales opcionales.
- Los datos de Level1 proporcionan los últimos valores de oferta/demanda utilizados para posicionar órdenes pendientes y gestionar los trailingstops.
Reglas de trading
- Cuadrícula pendiente
- Las órdenes de compra y venta se colocan a partir de precios ancla configurables (
BuyStopEntry y SellStopEntry).
- Los pedidos están espaciados por
PendingStepPoints y limitados por PendingQuantity.
- El precio de activación verifica las velas recientes en el período de activación para confirmar que el precio se acercó al nivel de anclaje con suficiente impulso.
- El activador de condición valida filtros adicionales de múltiples períodos de tiempo (rangos de bloques diarios, dirección de velas H2 y M30 y nivel de rango medio) antes de colocar órdenes pendientes.
- Protección de posición
- El stop loss inicial se calcula a partir de
StopLossPoints (o anulaciones de precio fijo).
- Cuando el precio avanza
BreakevenTriggerPoints, el stop se mueve al precio de entrada más BreakevenOffsetPoints (para posiciones largas) o menos la compensación (para posiciones cortas).
- Un trailing stop se activa solo después de alcanzar el punto de equilibrio y se actualiza una vez que el precio supera el stop anterior en
TrailMultiplier * TrailPoints.
- Supervisión de patrimonio
- La estrategia monitorea el PnL flotante y fuerza la liquidación de posiciones si la reducción excede
MaxFloatLoss (escalado al volumen de orden seleccionado).
- Un activador de ganancias flotantes bloquea las ganancias al colocar una línea de capital interna en
EquityBreakeven y seguirla en EquityTrail una vez que las ganancias superan EquityTrigger.
Parámetros
| Nombre |
Descripción |
StopLossPoints |
Distancia inicial de stop-loss en puntos. |
BreakevenTriggerPoints |
Puntos necesarios para activar el movimiento de equilibrio. |
BreakevenOffsetPoints |
Compensación agregada al precio de entrada cuando el stop se mueve al punto de equilibrio. |
TrailPoints |
Distancia utilizada para seguir después del punto de equilibrio. |
TrailMultiplier |
Multiplicador aplicado antes de que se establezca un nuevo trailing stop. |
BuyStopLossPrice / SellStopLossPrice |
Precios de parada fijos opcionales para posiciones largas/cortas. |
BuyStopEntry / SellStopEntry |
Precios base para las parrillas de parada pendientes. |
OrderVolume |
Volumen por orden pendiente. |
PendingQuantity |
Número máximo de órdenes pendientes activas. |
PendingStepPoints |
Distancia entre órdenes pendientes consecutivas. |
TriggerCandleType |
Serie de velas utilizada para la lógica de activación del precio. |
PendingPriceTrigger |
Habilita el disparador de proximidad de precio. |
PendingConditionTrigger |
Habilita el activador de confirmación de múltiples períodos de tiempo. |
OrderBuyBlockStart / OrderBuyBlockEnd |
Bloque bajo diario utilizado para validar configuraciones largas. |
OrderSellBlockStart / OrderSellBlockEnd |
Bloque alto diario utilizado para validar configuraciones cortas. |
MaxFloatLoss |
Pérdida flotante máxima permitida (escalada por volumen). |
EquityBreakeven |
Nivel de capital mantenido después de que se activa el activador de ganancias. |
EquityTrigger |
Se requiere beneficio flotante para crear el bloqueo de capital. |
EquityTrail |
Distancia de seguimiento aplicada al bloqueo de equidad. |
Notas
- El volumen del pedido se escala para que coincida con el comportamiento original de EA (los lotes
0.01 se tratan como el paso base).
- Todos los comentarios dentro del código están escritos en inglés, mientras que este documento proporciona una descripción detallada para una rápida incorporación.
- La estrategia utiliza solo API StockSharp de alto nivel (
SubscribeCandles, Bind, BuyStop, SellStop, SellMarket, BuyMarket) de acuerdo con los requisitos del proyecto.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Turbo Scaler Grid" MetaTrader expert.
/// Uses EMA crossover with RSI confirmation for scalping entries.
/// </summary>
public class TurboScalerGridStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiUpper;
private readonly StrategyParam<decimal> _rsiLower;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private RelativeStrengthIndex _rsi;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiUpper
{
get => _rsiUpper.Value;
set => _rsiUpper.Value = value;
}
public decimal RsiLower
{
get => _rsiLower.Value;
set => _rsiLower.Value = value;
}
public TurboScalerGridStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for scalping", "General");
_fastPeriod = Param(nameof(FastPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period (computed manually)", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
_rsiUpper = Param(nameof(RsiUpper), 60m)
.SetDisplay("RSI Upper", "RSI level for buy confirmation", "Signals");
_rsiLower = Param(nameof(RsiLower), 40m)
.SetDisplay("RSI Lower", "RSI level for sell confirmation", "Signals");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
_fastEma = new ExponentialMovingAverage { Length = FastPeriod };
_slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastEma, _slowEma, _rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEma);
DrawIndicator(area, _slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fastEma.IsFormed || !_slowEma.IsFormed || !_rsi.IsFormed)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
var crossUp = _prevFast.Value <= _prevSlow.Value && fastValue > slowValue;
var crossDown = _prevFast.Value >= _prevSlow.Value && fastValue < slowValue;
if (crossUp && rsiValue > RsiUpper)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossDown && rsiValue < RsiLower)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_fastEma = null;
_slowEma = null;
_rsi = null;
_prevFast = null;
_prevSlow = null;
base.OnReseted();
}
}
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 ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class turbo_scaler_grid_strategy(Strategy):
def __init__(self):
super(turbo_scaler_grid_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_period = self.Param("FastPeriod", 14)
self._slow_period = self.Param("SlowPeriod", 34)
self._rsi_period = self.Param("RsiPeriod", 14)
self._rsi_upper = self.Param("RsiUpper", 60.0)
self._rsi_lower = self.Param("RsiLower", 40.0)
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def RsiUpper(self):
return self._rsi_upper.Value
@RsiUpper.setter
def RsiUpper(self, value):
self._rsi_upper.Value = value
@property
def RsiLower(self):
return self._rsi_lower.Value
@RsiLower.setter
def RsiLower(self, value):
self._rsi_lower.Value = value
def OnReseted(self):
super(turbo_scaler_grid_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(turbo_scaler_grid_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, rsi, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value, rsi_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
rsi_val = float(rsi_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and rsi_val > float(self.RsiUpper):
if self.Position <= 0:
self.BuyMarket()
elif cross_down and rsi_val < float(self.RsiLower):
if self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return turbo_scaler_grid_strategy()