A Estratégia Cryptocurrency Divergence procura divergências clássicas de momentum entre a ação do preço e o Relative Strength Index (RSI), confirmando a direção da tendência com médias móveis e MACD. O expert advisor MetaTrader original dependia de checagens de momentum multi-timeframe, gestão monetária e extensa lógica de trailing. Este port StockSharp mantém o espírito do sistema ao:
Detectar divergências altistas quando o preço imprime uma mínima mais baixa, mas o RSI forma uma mínima mais alta.
Detectar divergências baixistas quando o preço cria uma máxima mais alta, mas o RSI imprime uma máxima mais baixa.
Validar configurações com médias móveis rápida/lenta e linha MACD versus linha de sinal.
Gerenciar posições por stop loss, take profit, break-even e trailing stop configuráveis, expressos em passos de preço.
A estratégia foi projetada para criptomoedas spot, mas pode ser aplicada a qualquer instrumento que entregue volatilidade suficiente e pontos de swing claros.
Indicadores
Média móvel simples (SMA): uma SMA rápida e uma lenta fornecem o filtro primário de tendência.
Relative Strength Index (RSI): fornece os valores de pivô de momentum usados para medir a força da divergência.
Moving Average Convergence Divergence (MACD): confirma que o momentum concorda com a direção da divergência detectada.
Todos os indicadores são vinculados pela API de alto nível, então nenhum buffer manual é necessário.
Lógica de negociação
Assinar o tipo de candle configurado e calcular valores de SMA, RSI e MACD em cada barra concluída.
Acompanhar os swing highs e lows mais recentes junto com seus valores RSI. Apenas extensões monotônicas (novas máximas mais altas ou mínimas mais baixas) atualizam os dados de swing.
Uma divergência altista aparece quando uma nova mínima mais baixa no preço é combinada com uma mínima mais alta no RSI. A operação também exige que a SMA rápida esteja acima da lenta, que a linha MACD exceda a linha de sinal e que o RSI permaneça abaixo do nível neutro (padrão 45) para garantir condições de sobrevenda.
Uma divergência baixista exige uma nova máxima mais alta no preço com uma máxima mais baixa no RSI, SMA rápida abaixo da lenta, linha MACD abaixo do sinal e RSI acima do nível baixista neutro (padrão 55).
A estratégia abre apenas uma posição líquida por vez. Reversões fecham a posição existente e entram imediatamente na direção oposta quando os sinais se alinham.
Gestão de risco
Volume: tamanho de operação definido pelo usuário e aplicado a todas as ordens a mercado.
Stop Loss / Take Profit: expressos em passos de preço e anexados após cada execução usando o preço real de execução.
Movimento de break-even: opcionalmente substitui o stop loss por um offset acima/abaixo da entrada quando o preço percorre uma distância configurável.
Trailing Stop: opcionalmente acompanha atrás do preço de fechamento a uma distância fixa medida em passos. O trailing stop tem prioridade sobre o stop loss original após a ativação.
Stops e metas são avaliados em cada candle concluído, garantindo comportamento determinístico que corresponde entre backtests e execução em tempo real.
Parâmetros
Nome
Descrição
CandleType
Série de candles usada para análise (timeframe de 15 minutos por padrão).
TradeVolume
Volume de ordem aplicado a todas as entradas.
FastMaLength / SlowMaLength
Períodos das SMAs rápida e lenta.
RsiLength
Comprimento de cálculo do RSI.
RsiBullishLevel / RsiBearishLevel
Limiares RSI que definem zonas de sobrevenda e sobrecompra para confirmação de divergência.
Cada parâmetro é exposto por StrategyParam<T> para poder ser otimizado dentro do designer StockSharp.
Notas de uso
Anexe a estratégia a um símbolo de criptomoeda e garanta que o instrumento tenha PriceStep e Board definidos. Sem passo de preço, a estratégia não consegue calcular stops.
Alinhe o tipo de candle ao mercado negociado (por exemplo, 15m, 1h). A detecção de divergência é sensível ao timeframe.
Ajuste as distâncias de stop e alvo à volatilidade do instrumento. Pares cripto com cinco casas decimais costumam exigir contagens de passos maiores.
Habilite break-even ou trailing apenas após observar colchão de lucro suficiente em testes históricos; trailing agressivo pode encerrar operações prematuramente.
Monitore a estratégia no designer StockSharp ou no painel de dados de mercado para visualizar alinhamento de indicadores e operações executadas.
Diferenças em relação à versão MQL
Trailing baseado em dinheiro e proteções de stop de patrimônio são simplificados em gestão de stop baseada em passos de preço.
Checagens de momentum multi-timeframe são substituídas por confirmação MACD em um único timeframe para clareza.
Efeitos colaterais de e-mail/notificação são omitidos porque são tratados externamente nos ecossistemas StockSharp.
Apesar desses ajustes, a detecção central de divergência e a lógica protetora permanecem fiéis à intenção do expert advisor original.
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 CryptocurrencyDivergenceStrategy : 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 CryptocurrencyDivergenceStrategy()
{
_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 cryptocurrency_divergence_strategy(Strategy):
def __init__(self):
super(cryptocurrency_divergence_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(cryptocurrency_divergence_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(cryptocurrency_divergence_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 cryptocurrency_divergence_strategy()