HaramiStrategy converte o consultor especialista "Harami" do MetaTrader na API de alto nível do StockSharp. A estratégia combina um padrão Harami altista/baixista detectado em um período de tempo superior com expansão de momentum e um filtro MACD de longo prazo. Apenas velas concluídas são processadas e toda a gestão de operações é realizada através do motor de proteção integrado do StockSharp.
Dados e indicadores
Período base: configurável (velas de 15 minutos por padrão) para detecção de tendência por médias móveis.
Período superior: configurável (padrão de uma hora) para reconhecimento de padrões e confirmação de momentum.
Período MACD: configurável (padrão de velas de 30 dias) para emular o filtro MACD mensal original.
Indicadores:
Média Móvel Ponderada Linear (FastMaLength) no período base.
Média Móvel Exponencial (SlowMaLength) no período base.
Momentum (MomentumPeriod) no período superior. A estratégia usa a distância absoluta do valor neutro (100) para as últimas três barras do período superior.
Convergência/Divergência de Médias Móveis (12/26/9) no período MACD.
Configuração comprada
A EMA lenta está acima da LWMA rápida no período base, sinalizando uma tendência de alta.
O período superior forma uma sequência Harami altista: duas velas atrás foi baixista, a vela anterior foi altista e seu corpo é menor que o corpo baixista anterior.
Qualquer um dos três últimos desvios de momentum do período superior excede MomentumBuyThreshold.
A linha principal MACD está acima da linha de sinal no período MACD.
Nenhuma posição comprada está aberta (Position <= 0).
A estratégia envia uma ordem de compra a mercado dimensionada para reverter qualquer exposição vendida e adicionar Volume lotes.
Configuração vendida
A EMA lenta está abaixo da LWMA rápida no período base.
O período superior forma um Harami baixista: duas velas atrás foi altista, a vela anterior foi baixista e o último corpo é menor.
Qualquer um dos três últimos desvios de momentum do período superior excede MomentumSellThreshold.
A linha principal MACD está abaixo da linha de sinal.
Nenhuma exposição vendida está aberta (Position >= 0).
A estratégia envia uma ordem de venda a mercado suficientemente grande para fechar posições compradas e abrir uma nova posição vendida de tamanho Volume.
Gestão de risco
StartProtection instala níveis de stop-loss e take-profit (expressos em pontos). Recursos adicionais de trailing, break-even e gestão monetária do EA original são intencionalmente omitidos para manter a versão StockSharp concisa. As mudanças de direção de operação achatam automaticamente a exposição oposta.
Parâmetros
Nome
Descrição
Padrão
CandleType
Período primário para médias móveis e execução de sinais.
Velas de 15 minutos
HigherCandleType
Período usado para confirmação de Harami e momentum.
Velas de 1 hora
MacdCandleType
Período para o filtro de tendência MACD.
Velas de 30 dias
FastMaLength
Comprimento da MA ponderada linear rápida.
6
SlowMaLength
Comprimento da MA exponencial lenta.
85
MomentumPeriod
Período de retrocesso do Momentum no período superior.
14
MomentumBuyThreshold
Desvio mínimo de momentum para confirmação comprada.
0.3
MomentumSellThreshold
Desvio mínimo de momentum para confirmação vendida.
0.3
StopLossPoints
Distância de stop-loss em pontos.
40
TakeProfitPoints
Distância de take-profit em pontos.
100
Dicas de uso
Alinhar CandleType, HigherCandleType e MacdCandleType com dados históricos disponíveis; garantir que o período superior seja mais longo que o período base.
Ajustar os limiares de momentum para corresponder à volatilidade do instrumento negociado.
Usar o otimizador do StockSharp através dos intervalos de parâmetros fornecidos para ajustar comprimentos de MA e limiares de momentum.
Sempre realizar backtesting com configurações realistas de comissão/latência antes de implantar ao vivo.
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 HaramiStrategy : 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 HaramiStrategy()
{
_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 harami_strategy(Strategy):
def __init__(self):
super(harami_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(harami_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(harami_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 harami_strategy()