La Estrategia GlamTrader es una conversión de la API de alto nivel de StockSharp del asesor experto de MetaTrader GlamTrader.mq5. El robot original combina una media móvil desplazada con el oscilador Laguerre RSI y el Awesome Oscillator para filtrar el momentum antes de abrir una única posición de mercado. El puerto preserva el árbol de decisiones exacto y las reglas de gestión del dinero mientras adapta la ejecución de órdenes, la representación gráfica y los controles de riesgo a las convenciones de StockSharp.
Cómo funciona la estrategia
Suscribirse a la serie de velas definida por CandleType (M15 por defecto). El marco temporal seleccionado alimenta cada indicador.
Construir una media móvil configurable en la fuente AppliedPrice seleccionada y desplazarla MaShift barras para reproducir el búfer desplazado usado en MetaTrader.
Recrear el filtro Laguerre RSI internamente usando el filtro recursivo de cuatro etapas (LaguerreGamma controla el factor de suavizado). El valor permanece en el rango [0;1] como el indicador personalizado original.
Calcular el Awesome Oscillator con promedios simples estándar de 5/34 del precio mediano y almacenar las lecturas actuales y anteriores para la detección de pendiente.
Solo cuando no hay ninguna posición abierta:
Entrada larga – media móvil por encima del cierre actual, Laguerre RSI por encima de 0.15, y Awesome Oscillator subiendo respecto a la barra anterior.
Entrada corta – media móvil por debajo del cierre actual, Laguerre RSI por debajo de 0.75, y Awesome Oscillator bajando respecto a la barra anterior.
Al entrar, la estrategia convierte las distancias de stop-loss/take-profit de pips a desplazamientos de precio usando el tamaño de tick del instrumento. Las distancias se ajustan para cotizaciones de 3 o 5 dígitos exactamente como Point * 10 en MQL.
Mientras una posición está activa, el algoritmo refleja la rutina de trailing original: una vez que el precio avanza más de TrailingStopPips + TrailingStepPips, el stop se traillea a TrailingStopPips detrás (o por encima) del mercado. Las salidas se ejecutan cuando el rango de la vela toca el precio del trailing stop o del take-profit.
Lógica de entrada y salida
Mantener como máximo una posición en todo momento. Las señales opuestas se ignoran hasta que la operación actual se cierra.
Las operaciones largas requieren una media móvil desplazada bajista (precio cruzando por encima de la línea), Laguerre RSI saliendo de la zona de sobreventa (> 0.15), y momentum del Awesome Oscillator creciente.
Las operaciones cortas requieren una media móvil desplazada alcista (precio cruzando por debajo de la línea), Laguerre RSI cayendo de la zona de sobrecompra (< 0.75), y momentum del Awesome Oscillator decreciente.
Los stops y objetivos se aplican con comparaciones de precio contra máximos/mínimos de vela para que los toques intrabarra sean respetados aunque la lógica se ejecute en velas terminadas.
El trailing sigue la regla de MetaTrader: el stop solo se mueve después de que el precio avance la distancia del stop más el paso de trailing, y nunca retrocede.
Parámetros
Parámetro
Tipo
Predeterminado
Descripción
CandleType
DataType
TimeSpan.FromMinutes(15).TimeFrame()
Marco temporal usado para los cálculos de indicadores y la toma de decisiones.
TradeVolume
decimal
1
Volumen usado para órdenes de mercado.
StopLossBuyPips
decimal
50
Distancia de stop-loss en pips para entradas largas.
TakeProfitBuyPips
decimal
50
Distancia de take-profit en pips para entradas largas.
StopLossSellPips
decimal
50
Distancia de stop-loss en pips para entradas cortas.
TakeProfitSellPips
decimal
50
Distancia de take-profit en pips para entradas cortas.
TrailingStopPips
decimal
5
Distancia del trailing stop en pips. Establezca en cero para deshabilitar el trailing.
TrailingStepPips
decimal
15
Beneficio adicional (en pips) requerido antes de que el trailing stop pueda moverse.
MaPeriod
int
14
Longitud de lookback de la media móvil.
MaShift
int
1
Desplazamiento positivo aplicado a la media móvil.
MaMethod
MaMethod
LinearWeighted
Tipo de media móvil (simple, exponencial, suavizada o ponderada linealmente).
AppliedPrice
AppliedPrice
Weighted
Fuente de precio usada para la media móvil y el filtro Laguerre.
LaguerreGamma
decimal
0.7
Coeficiente de suavizado Laguerre (rango 0–1).
Consejos de uso
Adjunte la estrategia al valor deseado, asegúrese de que el modelo de broker suministre información de tamaño/paso de tick, y establezca CandleType para que coincida con el marco temporal que desea operar.
Ajuste los parámetros de riesgo basados en pips a la volatilidad del instrumento. La conversión normaliza automáticamente las distancias usando PriceStep; los símbolos FX de cinco dígitos obtienen el multiplicador 10× esperado.
Los ayudantes de gráfico opcionales dibujan la media móvil en el área de precio y trazan el Awesome Oscillator en un panel separado junto con sus propias operaciones.
Inicie la estrategia. Gestionará los stops y el trailing internamente, reflejando las rutinas OpenBuy, OpenSell y de trailing del código MQL original.
Notas
La implementación del Laguerre RSI refleja el indicador laguerre.mq5, incluida la normalización CU/(CU+CD).
Los valores del Awesome Oscillator provienen del indicador incorporado de StockSharp, por lo que no se requiere copiar búferes manualmente.
Dado que la lógica se evalúa en velas completadas, los backtests y el trading en vivo permanecen deterministas y libres de repintado a nivel de tick.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// GlamTrader strategy using EMA crossover with momentum confirmation.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class GlamTraderStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="GlamTraderStrategy"/> class.
/// </summary>
public GlamTraderStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fast.IsFormed || !_slow.IsFormed)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// EMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 80;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 80;
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class glam_trader_strategy(Strategy):
def __init__(self):
super(glam_trader_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 25) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 100) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(glam_trader_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(glam_trader_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 80
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 80
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 80
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 80
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 80
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 80
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return glam_trader_strategy()