Esta estratégia é uma tradução de alto nível do StockSharp do expert advisor MQL "The Predator". O sistema original mistura filtros de direção de tendência com momentum, Bandas de Bollinger e osciladores estocásticos. Dois modelos de entrada independentes (Estratégia 1 e Estratégia 2) estão disponíveis, replicando os modos selecionáveis dentro da implementação MQL.
A conversão foca no processamento baseado em velas, usando assinaturas e vinculações de indicadores do StockSharp. Todos os cálculos são realizados em uma única série de velas configurável.
Indicadores principais
Médias Móveis Linearmente Ponderadas (LWMA) – estrutura rápida/lenta para confirmar a tendência de curto prazo.
Índice de Movimento Direcional + Índice Direcional Médio (DMI/ADX) – força direcional e confirmação de tendência.
Momentum (período 14 por padrão) – mede a distância do nível neutro 100 tanto para lógica de rompimento quanto de retração.
Bandas de Bollinger – dois envelopes (estreito e largo) para detectar contexto e localização da vela anterior, especialmente para a Estratégia 2.
Oscilador Estocástico – filtro adicional para a Estratégia 2 para exigir zonas de exaustão de momentum.
MACD – confirmação de momentum de tendência comparando a linha MACD com seu sinal.
Lógica de negociação
Filtros comuns
Processar apenas velas completadas.
Exigir que os indicadores selecionados estejam formados antes de negociar (IsFormedAndOnlineAndAllowTrading).
ADX deve ser maior que o limiar configurado.
O histórico de desvio de Momentum é mantido para os últimos três valores para corresponder às verificações MQL sem chamar GetValue nos indicadores.
Estratégia 1
Entradas compradas quando:
ADX acima do limiar e +DI supera −DI.
LWMA rápida acima da LWMA lenta.
Desvio de Momentum acima do limiar de compra em qualquer um dos últimos três valores.
Linha MACD acima de sua linha de sinal.
Entradas vendidas espelham o acima com os sinais invertidos.
Estratégia 2
Entradas compradas requerem adicionalmente:
Fechamento da vela anterior em ou acima do limite inferior de Bollinger de banda estreita anterior.
Linhas de sinal e principal estocásticas ambas acima do limiar superior.
Desvio de Momentum abaixo do limiar de compra em qualquer um dos últimos três valores (buscando retrações dentro de tendências).
Entradas vendidas requerem:
Fechamento da vela anterior em ou abaixo do limite superior de Bollinger de banda estreita anterior.
Linha de sinal estocástica acima do limiar superior enquanto a linha principal está abaixo do limiar inferior.
Desvio de Momentum abaixo do limiar de venda em qualquer um dos últimos três valores.
Tratamento de posições
A estratégia cancela quaisquer ordens ativas pendentes antes de abrir uma nova operação.
Quando ocorre um sinal de reversão, a estratégia fecha a exposição atual e abre uma nova posição na direção oposta usando uma ordem a mercado combinada.
Gestão de risco
StartProtection configura:
Distância inicial de stop-loss em pips.
Distância inicial de take-profit em pips.
Trailing stop opcional que segue um valor fixo de pips uma vez ativado.
As distâncias de risco são convertidas em unidades de preço absolutas usando o passo de preço do instrumento.
Os módulos de ponto de equilíbrio baseado em dinheiro e trailing do EA original são substituídos por essas proteções baseadas em pips (diferença documentada abaixo).
Parâmetros
Parâmetro
Descrição
Mode
Escolhe Estratégia 1 (rompimento de tendência) ou Estratégia 2 (retração com filtros estocásticos).
FastMaLength, SlowMaLength
Comprimentos LWMA usados para determinar a direção da tendência.
DmiPeriod, AdxSmoothing
Parâmetros do Índice de Movimento Direcional.
MomentumPeriod
Lookback usado pelo indicador de momentum.
MomentumBuyThreshold, MomentumSellThreshold
Desvio mínimo de 100 necessário para aceitar sinais.
AdxThreshold
Nível mínimo de ADX sinalizando uma tendência acionável.
BollingerPeriod, TightBandWidth, WideBandWidth
Configurações de Banda de Bollinger para os filtros de contexto.
Parâmetros para o oscilador estocástico usado na Estratégia 2.
TradeVolume
Volume enviado com ordens a mercado.
StopLossPips, TakeProfitPips, TrailingStopPips
Distâncias de risco (convertidas em unidades de preço com o passo do instrumento).
CandleType
Série de dados usada pela estratégia.
Diferenças em relação à versão MQL
Os valores de take-profit, stop-loss e trailing baseados em dinheiro são traduzidos em distâncias de pips tratadas por StartProtection.
Ajustes de ponto de equilíbrio e mensagens de notificação por e-mail/push não são portados (não disponíveis na API de alto nível).
O expert MQL chamava MACD e Momentum em períodos superiores. No StockSharp a lógica roda apenas na série de velas configurada; dados multitemporal podem ser adicionados através de assinaturas adicionais se necessário.
Otimização de volume de ordens e dimensionamento estilo martingale não estão implementados; a versão StockSharp usa um parâmetro TradeVolume fixo.
Uso
Criar um conector e portfólio como em outras amostras do StockSharp.
Instanciar ThePredatorStrategy, atribuir Security, Portfolio e os parâmetros desejados.
Iniciar a estratégia. A visualização é opcional, mas disponível quando uma área de gráfico é fornecida.
A tradução mantém a árvore de decisão fiel ao original enquanto adota as melhores práticas do StockSharp como vinculação de indicadores e StartProtection para risco. Ajuste os limiares ao instrumento e período escolhidos.
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()