Esta estrategia es una traducción de alto nivel de StockSharp del experto asesor MQL "The Predator". El sistema original mezcla filtros de dirección de tendencia con momentum, Bandas de Bollinger y osciladores estocásticos. Dos plantillas de entrada independientes (Estrategia 1 y Estrategia 2) están disponibles, replicando los modos seleccionables dentro de la implementación MQL.
La conversión se centra en el procesamiento basado en velas, usando suscripciones e indicadores de StockSharp. Todos los cálculos se realizan en una única serie de velas configurable.
Indicadores principales
Medias móviles linealmente ponderadas (LWMA) – estructura rápida/lenta para confirmar la tendencia a corto plazo.
Índice de Movimiento Direccional + Índice de Dirección Promedio (DMI/ADX) – fuerza direccional y confirmación de tendencia.
Momentum (período 14 por defecto) – mide la distancia desde el nivel neutral 100 tanto para lógica de ruptura como de retroceso.
Bandas de Bollinger – dos envolventes (estrecha y ancha) para detectar contexto y la ubicación de la vela anterior, especialmente para la Estrategia 2.
Oscilador Estocástico – filtro adicional para la Estrategia 2 que requiere zonas de agotamiento de momentum.
MACD – confirmación de momentum de tendencia comparando la línea MACD con su señal.
Lógica de trading
Filtros comunes
Procesar solo velas completadas.
Requerir que los indicadores seleccionados estén formados antes de operar (IsFormedAndOnlineAndAllowTrading).
El ADX debe ser mayor que el umbral configurado.
El historial de desviación de Momentum se mantiene para los últimos tres valores para coincidir con las comprobaciones MQL sin llamar a GetValue en los indicadores.
Estrategia 1
Entradas largas cuando:
ADX por encima del umbral y +DI supera a −DI.
LWMA rápida por encima de la LWMA lenta.
Desviación de Momentum por encima del umbral de compra en cualquiera de los últimos tres valores.
Línea MACD por encima de su línea de señal.
Entradas cortas reflejan lo anterior con los signos invertidos.
Estrategia 2
Entradas largas requieren adicionalmente:
El cierre de la vela anterior en o por encima del límite inferior de Bollinger de banda estrecha anterior.
Las líneas de señal y principal del estocástico ambas por encima del umbral superior.
Desviación de Momentum por debajo del umbral de compra en cualquiera de los últimos tres valores (buscando retrocesos dentro de tendencias).
Entradas cortas requieren:
El cierre de la vela anterior en o por debajo del límite superior de Bollinger de banda estrecha anterior.
La línea de señal del estocástico por encima del umbral superior mientras la línea principal está por debajo del umbral inferior.
Desviación de Momentum por debajo del umbral de venta en cualquiera de los últimos tres valores.
Manejo de posiciones
La estrategia cancela cualquier orden activa pendiente antes de abrir una nueva operación.
Cuando ocurre una señal de reversión, la estrategia cierra la exposición actual y abre una nueva posición en la dirección opuesta usando una orden de mercado combinada.
Gestión de riesgo
StartProtection configura:
Distancia inicial de stop-loss en pips.
Distancia inicial de take-profit en pips.
Trailing stop opcional que sigue un monto fijo de pips una vez activado.
Las distancias de riesgo se convierten en unidades de precio absolutas usando el paso de precio del instrumento.
Los módulos de punto de equilibrio basado en dinero y trailing del EA original se reemplazan con estas protecciones basadas en pips (diferencia documentada a continuación).
Parámetros
Parámetro
Descripción
Mode
Elige Estrategia 1 (ruptura de tendencia) o Estrategia 2 (retroceso con filtros estocásticos).
FastMaLength, SlowMaLength
Longitudes LWMA usadas para determinar la dirección de la tendencia.
DmiPeriod, AdxSmoothing
Parámetros del Índice de Movimiento Direccional.
MomentumPeriod
Período de retroceso usado por el indicador de momentum.
MomentumBuyThreshold, MomentumSellThreshold
Desviación mínima desde 100 requerida para aceptar señales.
AdxThreshold
Nivel mínimo de ADX que señala una tendencia accionable.
BollingerPeriod, TightBandWidth, WideBandWidth
Configuración de Bandas de Bollinger para los filtros de contexto.
Parámetros para el oscilador estocástico usado en la Estrategia 2.
TradeVolume
Volumen enviado con órdenes de mercado.
StopLossPips, TakeProfitPips, TrailingStopPips
Distancias de riesgo (convertidas a unidades de precio con el paso del instrumento).
CandleType
Serie de datos usada por la estrategia.
Diferencias respecto a la versión MQL
Los valores de take-profit, stop-loss y trailing basados en dinero se traducen en distancias de pips manejadas por StartProtection.
Los ajustes de punto de equilibrio y los mensajes de notificación por email/push no están portados (no disponibles en la API de alto nivel).
El experto MQL llamaba a MACD y Momentum en marcos temporales superiores. En StockSharp la lógica se ejecuta solo en la serie de velas configurada; los datos multitemporal pueden añadirse a través de suscripciones adicionales si es necesario.
La optimización de volumen de órdenes y el dimensionamiento estilo martingala no están implementados; la versión StockSharp usa un parámetro TradeVolume fijo.
Uso
Crear un conector y portafolio como en otras muestras de StockSharp.
Instanciar ThePredatorStrategy, asignar Security, Portfolio y los parámetros deseados.
Iniciar la estrategia. La visualización es opcional pero disponible cuando se proporciona un área de gráfico.
La traducción mantiene el árbol de decisiones fiel al original mientras adopta las mejores prácticas de StockSharp como el enlace de indicadores y StartProtection para el riesgo. Ajuste los umbrales al instrumento y marco temporal elegidos.
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;
public class ThePredatorStrategy : 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;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public ThePredatorStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).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");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
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;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_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 the_predator_strategy(Strategy):
def __init__(self):
super(the_predator_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA 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(the_predator_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(the_predator_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 = 100
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 = 100
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 = 100
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 = 100
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 = 100
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 = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return the_predator_strategy()