La confirmación de Harami CCI es un puerto StockSharp de alto nivel del MetaTrader 5 asesor experto Expert_ABH_BH_CCI. El EA original intercambia los patrones de reversión Bullish Harami y Bearish Harami de dos velas. Antes de ingresar a una operación, exige la confirmación de un oscilador del índice de canal de productos básicos (CCI) y mide el tamaño del cuerpo de la vela frente a un promedio móvil para garantizar que la vela más grande realmente domine el rango. La conversión StockSharp mantiene la misma lógica de confirmación, procesa solo velas completadas y utiliza el módulo de protección integrado de la plataforma para la seguridad de los pedidos.
Lógica estratégica
Detección de patrones
Cálculo del cuerpo promedio: mantiene un promedio móvil de los cuerpos absolutos de las velas durante las últimas N barras (predeterminado 5). Esto refleja la clase auxiliar MetaTrader que suaviza el tamaño de la vela y la referencia de tendencia.
Harami alcista: requiere que la vela anterior sea alcista, la vela anterior sea bajista con un cuerpo más largo que el promedio y que el cuerpo alcista permanezca dentro del rango bajista. El punto medio de la vela anterior también debe ubicarse por debajo del promedio móvil de cierres, lo que confirma una tendencia bajista.
Harami bajista – condiciones reflejadas: la vela anterior debe ser bajista, la vela anterior alcista y larga, el cuerpo bajista debe estar contenido dentro del rango alcista y el punto medio debe estar por encima del promedio móvil de cierre para confirmar una tendencia alcista.
CCI confirmación
Filtro de entrada: la estrategia verifica el valor CCI de la vela completada más recientemente (cambio 1). Las operaciones largas requieren que CCI esté por debajo de -EntryThreshold (predeterminado 50), mientras que las operaciones cortas exigen un valor superior a +EntryThreshold.
Banda de salida: el historial de CCI se monitorea para detectar cruces de ±ExitBand (80 predeterminado). Cuando el indicador sube hasta -ExitBand, cualquier posición corta abierta se cierra. Cuando cae por debajo de +ExitBand, la exposición larga existente se cierra. Esto reproduce los "votos" utilizados por el experto MetaTrader para aplanar posiciones.
Gestión comercial
Reversiones: si se confirma la configuración opuesta de Harami mientras la estrategia ya mantiene una posición, negociará suficiente volumen para cerrar la exposición existente y abrir la nueva dirección.
Protección: StartProtection() está activado para que los usuarios puedan adjuntar configuraciones de límite de pérdidas o toma de ganancias a través de la interfaz de usuario de StockSharp si lo desean. No se aplican paradas fijas de forma predeterminada para permanecer alineado con la fuente EA, que dependía de la configuración manual de administración del dinero.
Parámetros
Volumen de pedidos: volumen base enviado con cada entrada al mercado. Se agrega volumen adicional automáticamente para cerrar la posición opuesta cuando ocurre una reversión.
CCI Período – duración del oscilador del índice del canal de productos básicos.
Promedio corporal: número de velas históricas utilizadas para promediar los tamaños corporales y los precios de cierre.
CCI Entrada: valor mínimo absoluto CCI necesario para aceptar una señal Harami.
CCI Banda de salida: magnitud de la banda que define las reglas de salida de cruce CCI.
Tipo de vela: período de tiempo utilizado para las velas (predeterminado: período de 1 hora).
Notas adicionales
Todos los cálculos se ejecutan en velas completas proporcionadas por SubscribeCandles. Las señales intrabar se ignoran intencionalmente para que coincidan con el modelo de ejecución MetaTrader.
La estrategia mantiene un breve historial deslizante de velas y valores CCI para evaluar las reglas de Harami sin recrear los buffers de indicador completos.
En esta carpeta sólo se proporciona la implementación de C#; No existe una versión de Python para esta conversión.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Harami CCI Confirmation strategy: Harami pattern with CCI confirmation.
/// </summary>
public class HaramiCciConfirmationStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _entryLevel;
private readonly StrategyParam<int> _signalCooldownCandles;
private readonly List<ICandleMessage> _candles = new();
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public decimal EntryLevel { get => _entryLevel.Value; set => _entryLevel.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public HaramiCciConfirmationStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
_entryLevel = Param(nameof(EntryLevel), 0m)
.SetDisplay("Entry Level", "CCI threshold", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
_candles.Add(candle);
if (_candles.Count > 5) _candles.RemoveAt(0);
if (_candles.Count >= 2)
{
var curr = _candles[^1];
var prev = _candles[^2];
var bullishHarami = prev.OpenPrice > prev.ClosePrice
&& curr.ClosePrice > curr.OpenPrice
&& curr.OpenPrice > prev.ClosePrice
&& curr.ClosePrice < prev.OpenPrice;
var bearishHarami = prev.ClosePrice > prev.OpenPrice
&& curr.OpenPrice > curr.ClosePrice
&& curr.ClosePrice > prev.OpenPrice
&& curr.OpenPrice < prev.ClosePrice;
if (bullishHarami && cciValue < -EntryLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (bearishHarami && cciValue > EntryLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
}
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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class harami_cci_confirmation_strategy(Strategy):
def __init__(self):
super(harami_cci_confirmation_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._cci_period = self.Param("CciPeriod", 14)
self._entry_level = self.Param("EntryLevel", 0.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles = []
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def CciPeriod(self):
return self._cci_period.Value
@CciPeriod.setter
def CciPeriod(self, value):
self._cci_period.Value = value
@property
def EntryLevel(self):
return self._entry_level.Value
@EntryLevel.setter
def EntryLevel(self, value):
self._entry_level.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(harami_cci_confirmation_strategy, self).OnReseted()
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(harami_cci_confirmation_strategy, self).OnStarted2(time)
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(cci, self._process_candle).Start()
def _process_candle(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
cci_val = float(cci_value)
self._candles.append(candle)
if len(self._candles) > 5:
self._candles.pop(0)
if len(self._candles) >= 2:
curr = self._candles[-1]
prev = self._candles[-2]
bullish_harami = (float(prev.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) > float(curr.OpenPrice)
and float(curr.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) < float(prev.OpenPrice))
bearish_harami = (float(prev.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) > float(curr.ClosePrice)
and float(curr.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) < float(prev.ClosePrice))
if bullish_harami and cci_val < -self.EntryLevel and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif bearish_harami and cci_val > self.EntryLevel and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return harami_cci_confirmation_strategy()