Esta estratégia é um port para StockSharp do expert advisor "Crypto Analysis" do MetaTrader 4. Ela procura rompimentos que ocorrem depois que o preço toca a banda externa de Bollinger no timeframe principal de negociação, enquanto a estrutura de mercado permanece baixista (LWMA rápida abaixo da LWMA lenta). O sistema só permite operações quando um surto de momentum em timeframe superior e um filtro MACD mensal concordam com a direção desejada. Depois de entrar no mercado, a posição é gerenciada por um bloco de proteção em camadas que espelha o EA original: stops baseados em pips, trailing baseado em dinheiro, realocação para break-even e controles de drawdown da carteira.
Lógica de negociação
Timeframe de sinal: configurável (M15 por padrão). Todas as regras de entrada/saída são avaliadas nesses candles.
Gatilho de volatilidade: a mínima do candle anterior deve tocar ou perfurar a banda inferior de Bollinger (20, 2) para preparar uma configuração comprada; um toque na banda superior prepara uma configuração vendida.
Filtro de tendência: ambos os cenários exigem que a média móvel linearmente ponderada rápida (LWMA, padrão 6) permaneça abaixo da LWMA lenta (padrão 85), replicando a checagem de viés baixista do EA.
Confirmação RSI: RSI(14) precisa estar acima de 50 para compras e abaixo de 50 para vendas.
Surto de momentum: o desvio absoluto máximo dos três últimos valores Momentum(14) do timeframe superior em relação à linha-base 100 deve exceder os limiares de compra/venda. Isso captura os picos de momentum usados pelo código MQL.
Filtro MACD mensal: um MACD mensal separado (candles de 30 dias por padrão) (12, 26, 9) confirma a direção; compras exigem MACD principal acima do sinal, vendas exigem o oposto.
Execução de entrada: quando todos os filtros se alinham, a estratégia abre uma ordem a mercado. Posições opostas são zeradas antes da reversão para manter uma única posição líquida, espelhando o comportamento do EA de fechar operações contrárias.
Gestão de posição
Stop e alvo iniciais: distâncias configuráveis em pips são convertidas a partir do tamanho de tick do instrumento usando o mesmo tratamento de 5 dígitos/3 dígitos do EA (passos 0.00001 e 0.001 são multiplicados por 10).
Trailing stop: após a formação de uma nova máxima (compra) ou mínima (venda), o stop é puxado atrás do preço por TrailingStopPips, sempre respeitando o melhor nível alcançado.
Break-even: quando o lucro atinge BreakEvenTriggerPips, o stop é movido para o preço de entrada mais BreakEvenOffsetPips (compra) ou menos o offset (venda).
Metas monetárias: limites opcionais de lucro absoluto ou percentual fecham a posição assim que o PnL flutuante atinge o nível solicitado.
Trailing monetário: quando o lucro não realizado excede MoneyTrailTarget, a estratégia acompanha o pico e fecha a posição se a devolução for igual ou superior a MoneyTrailStop.
Stop de patrimônio: o patrimônio flutuante (valor atual da carteira mais PnL não realizado) é monitorado; se o drawdown a partir do pico ultrapassar EquityRiskPercent, a posição é zerada.
Dados multi-timeframe
Três assinaturas são registradas automaticamente:
Série principal de candles para as regras de Bollinger/LWMA/RSI.
Candles de timeframe superior para o filtro de momentum (H1 por padrão).
Candles mensais para a confirmação MACD (barras de 30 dias por padrão).
Parâmetros
Parâmetro
Descrição
OrderVolume
Tamanho base da ordem. Posições opostas são fechadas antes de abrir uma nova.
UseMoneyTakeProfit
Habilita a meta absoluta de take-profit monetário.
MoneyTakeProfit
Lucro na moeda da carteira que dispara uma saída quando UseMoneyTakeProfit é verdadeiro.
UsePercentTakeProfit
Habilita a meta de take-profit percentual calculada a partir do patrimônio inicial.
PercentTakeProfit
Percentual de lucro necessário para fechar a posição quando a meta percentual está ativa.
EnableMoneyTrailing
Ativa o bloco de trailing baseado em dinheiro.
MoneyTrailTarget
Nível de lucro que inicia o trailing monetário.
MoneyTrailStop
Devolução máxima permitida do lucro depois que MoneyTrailTarget foi alcançado.
StopLossPips
Distância inicial do stop-loss em pips.
TakeProfitPips
Distância inicial do take-profit em pips.
TrailingStopPips
Distância do trailing stop em pips.
UseBreakEven
Habilita a realocação do stop para break-even.
BreakEvenTriggerPips
Lucro em pips necessário antes de ativar a proteção break-even.
BreakEvenOffsetPips
Pips adicionais somados ao preço de entrada ao posicionar o stop de break-even.
FastMaPeriod
Comprimento da LWMA rápida calculada sobre preço típico.
SlowMaPeriod
Comprimento da LWMA lenta calculada sobre preço típico.
MomentumPeriod
Período do indicador Momentum no timeframe superior.
MomentumBuyThreshold
Desvio mínimo de momentum para entradas compradas.
MomentumSellThreshold
Desvio mínimo de momentum para entradas vendidas.
MacdFastLength
Comprimento da EMA rápida para o filtro MACD de timeframe superior.
MacdSlowLength
Comprimento da EMA lenta para o filtro MACD de timeframe superior.
MacdSignalLength
Comprimento do sinal para o filtro MACD de timeframe superior.
UseEquityStop
Habilita a proteção contra drawdown da carteira.
EquityRiskPercent
Percentual permitido de drawdown do patrimônio antes de fechar a posição forçadamente.
CandleType
Timeframe primário usado para entradas.
MomentumCandleType
Timeframe superior usado para confirmação de momentum.
MacdCandleType
Timeframe superior usado para confirmação MACD.
Notas
O port StockSharp mantém uma única posição líquida, correspondendo ao EA que fecha ordens opostas antes de abrir uma nova operação.
Todas as regras de proteção operam em candles fechados para replicar o processamento de "nova barra" do script original.
Ao usar símbolos sintéticos ou instrumentos sem tamanho de pip padrão, ajuste StopLossPips e parâmetros relacionados ao valor de tick da bolsa.
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 CryptoAnalysisStrategy : 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 CryptoAnalysisStrategy()
{
_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 crypto_analysis_strategy(Strategy):
def __init__(self):
super(crypto_analysis_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(crypto_analysis_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(crypto_analysis_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 crypto_analysis_strategy()