A Estratégia de Exp BlauHlm é um port StockSharp do consultor especialista MetaTrader 5 Exp_BlauHLM.mq5. O sistema baseia-se no oscilador Blau High-Low Momentum (HLM) que compara máximas e mínimas recentes, suaviza a diferença com um pipeline XMA configurável e reage a três modos de operação distintos:
Breakdown – negocia uma quebra da linha zero do componente do histograma.
Twist – busca torções de momentum dentro do histograma para capturar transições de inclinação.
CloudTwist – trabalha com os envelopes superior e inferior produzidos pelo indicador e reage a cruzamentos de "nuvem".
A implementação StockSharp mantém os mesmos parâmetros, valores padrão e regras de trading enquanto traduz os detalhes de gerenciamento de dinheiro para a propriedade genérica Volume da estratégia base.
Lógica de trading
Para cada vela concluída do período configurado, a estratégia calcula o oscilador Blau HLM:
Calcular a diferença entre a máxima mais recente e a máxima XLength - 1 barras atrás e uma diferença espelhada para mínimas.
Limitar contribuições negativas a zero e subtraí-las para obter o valor HLM bruto (expresso em pontos quando o instrumento especifica um tamanho de tick).
Suavizar a sequência através de quatro médias móveis em cascata com métodos idênticos mas comprimentos independentes.
Dependendo do Mode selecionado:
Breakdown abre uma posição comprada quando o valor do histograma anterior é positivo e o novo não é positivo (recuperação da linha zero) e fecha vendidos na mesma situação. Uma regra simétrica trata entradas vendidas/saídas compradas quando o histograma muda de negativo para não negativo.
Twist compara a inclinação do histograma em três pontos históricos. Uma aceleração local (valor médio subindo após uma queda) aciona a lógica comprada, enquanto uma desaceleração (valor médio caindo após uma subida) ativa a lógica vendida.
CloudTwist monitora os dois envelopes suavizados. Quando a banda superior anterior está acima da inferior e os novos valores se cruzam abaixo/acima um do outro, sinais comprados ou vendidos são produzidos respectivamente.
O gerenciamento de posições segue as permissões BuyOpen, SellOpen, BuyClose, SellClose e usa o Volume da estratégia para entradas de mercado. Sinais opostos fecham posições existentes antes de abrir uma nova.
Parâmetros
Nome
Tipo
Padrão
Descrição
CandleType
DataType
Velas H4
Período processado pelo oscilador.
SmoothingMethod
SmoothMethod
Exponential
Método de média móvel para cada estágio de suavização (modos legacy não suportados recorrem a EMA).
XLength
int
2
Período em barras para medir o momentum bruto de máxima/mínima.
FirstLength
int
20
Período do primeiro estágio de suavização.
SecondLength
int
5
Período do segundo estágio de suavização.
ThirdLength
int
3
Período do terceiro estágio de suavização.
FourthLength
int
3
Período do suavizador de sinal final.
Phase
int
15
Parâmetro de fase Jurik (limitado a ±100, ignorado por suavizadores não Jurik).
SignalBar
int
1
Deslocamento histórico ao comparar valores do indicador.
EntryMode
Mode
Twist
Lógica de trading copiada do especialista MQL (Breakdown, Twist, CloudTwist).
BuyOpen / SellOpen
bool
true
Permitir abertura de posições compradas/vendidas.
BuyClose / SellClose
bool
true
Permitir fechamento de posições compradas/vendidas com sinal oposto.
Notas de conversão
A biblioteca MQL SmoothAlgorithms.mqh inclui filtros proprietários (JJMA, JurX, ParMA, T3, VIDYA, AMA). O StockSharp fornece alternativas integradas para as variantes mais comuns, portanto modos não suportados são aproximados com a média móvel exponencial para manter o fluxo de trabalho intacto.
Parâmetros de gerenciamento de dinheiro (MM, MarginMode, StopLoss, TakeProfit, Deviation) controlam o tamanho da ordem e execução no MetaTrader. Neste port, a propriedade genérica Volume define o tamanho da posição e ordens são sempre enviadas a mercado.
O timing do sinal espelha o deslocamento SignalBar usado pelo especialista original: a estratégia mantém um buffer circular interno de valores do indicador e realiza comparações em snapshots históricos para que os resultados de otimização permaneçam consistentes.
A proteção de risco é delegada ao StartProtection(); configure regras globais de stop-loss/take-profit na estratégia pai ou conector de trading se necessário.
Dicas de uso
Definir a propriedade Volume antes de iniciar a estratégia para definir o número de lotes/contratos por operação.
Para símbolos sem um PriceStep significativo, o oscilador trabalha em unidades de preço brutas. Considere reescalar os parâmetros se o ativo usar tamanhos de tick grandes.
Ao experimentar com suavizadores não exponenciais, lembre que comprimentos muito curtos combinados com extremos de fase Jurik podem levar a sinais instáveis; amplie os períodos para maior estabilidade.
Combine a estratégia com controles de risco em nível de portfólio ou as regras de proteção integradas para emular o comportamento original de stop-loss/take-profit.
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 ExpBlauHlmStrategy : 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 ExpBlauHlmStrategy()
{
_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 exp_blau_hlm_strategy(Strategy):
def __init__(self):
super(exp_blau_hlm_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(exp_blau_hlm_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(exp_blau_hlm_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 exp_blau_hlm_strategy()