Esta estratégia é um port em C# do consultor especialista MetaTrader "MACD 1 MIN SCALPER". Combina médias móveis ponderadas com confirmações de MACD em múltiplos períodos e um filtro de momentum antes de abrir operações. O objetivo é negociar na direção da tendência quando os indicadores de períodos inferior e superior estão alinhados e o momentum do preço é suficientemente forte.
Lógica de Negociação
Período base – configurável (padrão M1). Duas médias móveis ponderadas (WMA) com períodos 50 e 200, calculadas sobre o preço típico (Máxima + Mínima + Fechamento) / 3, definem a tendência de curto prazo.
Filtro de tendência de período superior – WMAs com os mesmos períodos são calculadas no período H1. Configurações longas requerem que ambas as WMAs rápidas estejam acima de suas contrapartes lentas, as vendidas requerem o oposto. Se o período de trabalho já é H1, as WMAs base são reutilizadas.
Confirmações MACD – o MACD (12, 26, 9) deve ter sua linha principal acima da linha de sinal no período base, no período H1 e em um período mensal (aprox. 43200 minutos). Entradas vendidas requerem que todos os três MACDs estejam abaixo de seus sinais.
Filtro de momentum – um indicador de momentum com período 14 opera em um período superior derivado do período base do MetaTrader (M1→M15, M5→M30, …). O desvio absoluto de 100 deve exceder um limiar configurável em pelo menos uma das últimas três barras completadas.
Regras de entrada – uma posição longa é aberta quando todas as condições altistas são atendidas e a estratégia atualmente não tem exposição longa. Uma posição curta requer as condições baixistas refletidas. Se uma posição oposta estiver aberta, o tamanho da ordem inclui automaticamente a quantidade necessária para fechá-la.
Gestão de risco – distâncias opcionais de stop-loss e take-profit são especificadas em pips e convertidas para pontos do instrumento na inicialização. Funções de trailing, breakeven e gestão monetária do script original são intencionalmente omitidas neste port de alto nível.
Parâmetros
Parâmetro
Descrição
CandleType
Período de trabalho para os indicadores base.
OrderVolume
Volume enviado com cada entrada de mercado. Também usado para fechar/inverter posições.
FastMaPeriod / SlowMaPeriod
Comprimentos das médias móveis ponderadas rápida e lenta.
Comprimento do indicador de momentum no período de confirmação.
MomentumThreshold
Desvio absoluto mínimo de 100 necessário para aceitar o momentum.
TakeProfitPips / StopLossPips
Níveis protetores opcionais especificados em pips.
Notas de Implementação
A estratégia depende das assinaturas de velas de alto nível do StockSharp (SubscribeCandles) e da vinculação de indicadores (Bind / BindEx). Nenhum cálculo manual de indicadores ou buffers históricos é usado.
O período de momentum é derivado do mapeamento do MetaTrader: [1,5,15,30,60,240,1440,10080,43200]. Se um valor estiver fora desta lista, um multiplicador 4× do período base é usado como fallback.
StartProtection é iniciado apenas quando pelo menos um dos parâmetros de risco é maior que zero. Não há implementação de trailing stop neste port.
A renderização do gráfico está habilitada para as velas base, ambas as WMAs e o MACD para facilitar a inspeção visual durante a depuração ou negociação ao vivo.
Dicas de Uso
Defina o parâmetro OrderVolume de acordo com o tamanho mínimo de lote do instrumento. O auxiliar ajusta automaticamente o volume enviado para corresponder ao passo e às restrições de min/max do símbolo.
Certifique-se de que os dados de períodos superiores (H1 e mensal) estejam disponíveis no feed de dados. Sem essas velas, a estratégia não abrirá posições porque os sinais de confirmação permanecem incompletos.
A filtragem de momentum é sensível ao limiar escolhido. Valores mais altos exigem impulsos de momentum mais fortes, enquanto valores mais baixos resultam em operações mais frequentes.
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 Macd1MinScalperStrategy : 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 Macd1MinScalperStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).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 macd_1_min_scalper_strategy(Strategy):
def __init__(self):
super(macd_1_min_scalper_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_1_min_scalper_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(macd_1_min_scalper_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._fast_ind.IsFormed or not self._slow_ind.IsFormed:
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast
self._prev_slow = slow
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.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow 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 < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return macd_1_min_scalper_strategy()