Esta estrategia es un puerto StockSharp de alto nivel del asesor experto MetaTrader "iCHO Trend CCIDualOnMA Filter". Combina un filtro de régimen de línea cero del oscilador Chaikin con una confirmación dual del índice de canal de productos básicos (CCI) que se calcula sobre una serie de precios suavizada. El resultado es un enfoque de seguimiento de tendencias que reacciona a los cambios de impulso pero aún requiere una confirmación de impulso por parte del par CCI antes de iniciar una operación.
Lógica comercial
Núcleo del oscilador Chaikin: la línea de acumulación/distribución se suaviza mediante dos medias móviles configurables. Su diferencia replica el oscilador Chaikin. Los cruces por encima/por debajo de cero indican un cambio en el flujo de capital dominante.
Filtro dual CCI: ambas instancias CCI utilizan la misma entrada de precio suavizada de promedio móvil pero diferentes períodos retrospectivos. Una configuración larga requiere que el CCI rápido se recupere del territorio negativo y cruce por encima del CCI lento mientras el oscilador Chaikin se mantiene por encima de cero. Una configuración breve refleja estas condiciones.
Inversión opcional: el EA original proporciona un indicador "inverso" que intercambia señales largas y cortas. El puerto mantiene este comportamiento para que se puedan utilizar las mismas reglas para las pruebas de contratendencia.
Gestión de posiciones: las banderas opcionales cierran la exposición opuesta antes de abrir una nueva posición y limitan la estrategia a una única posición abierta. Se aplica una regla de una operación por barra para imitar la implementación de MetaTrader.
Filtro de sesión: las operaciones se pueden restringir a una ventana intradiaria definida por el usuario, incluidas las sesiones envolventes que pasan de la medianoche.
Parámetros
Parámetro
Descripción
FastChaikinLength
Período de media móvil rápida utilizado dentro del oscilador Chaikin.
SlowChaikinLength
Período de media móvil lenta utilizado dentro del oscilador Chaikin.
ChaikinMethod
Método de media móvil (simple, exponencial, suavizado, ponderado lineal) aplicado a la línea de acumulación/distribución.
FastCciLength
Vista retrospectiva del rápido índice del canal de productos básicos.
SlowCciLength
Vista retrospectiva del lento índice del canal de materias primas.
MaLength
Longitud de la media móvil de preprocesamiento que alimenta los CCI.
MaMethod
Método de media móvil utilizado para preprocesar el precio antes de que llegue a los CCI.
MaPrice
Tipo de precio (cierre, apertura, máximo, mínimo, mediana, típico, ponderado) que se suaviza antes de los CCI.
UseClosedBar
Procese solo velas completamente terminadas (el valor predeterminado es verdadero, idéntico a SignalsBarCurrent=bar_1 en EA).
ReverseSignals
Intercambia lógica larga y corta.
CloseOpposite
Cierre una posición abierta en la dirección opuesta antes de ingresar a una nueva.
OnlyOnePosition
Permita solo una posición abierta en cualquier momento.
TradeMode
Restrinja la ejecución a posiciones largas, cortas o ambas (BuyOnly, SellOnly, BuyAndSell).
UseTimeFilter
Habilite el filtro de sesión de negociación.
StartHour, StartMinute, EndHour, EndMinute
Límites de la sesión (incluido el inicio, excluyendo el final) expresados en tiempo de intercambio. Se admiten sesiones integrales.
CandleType
Plazo de suscripción de velas que alimenta los indicadores.
Notas
La estrategia utiliza sólo enlaces SubscribeCandles de alto nivel e indicadores integrados; no se requieren buffers personalizados ni solicitudes históricas.
Todos los cálculos basados en precios adoptan el mismo preprocesamiento de promedio móvil que el indicador MetaTrader CCIDualOnMA alimentando el CCI con una serie de precios suavizada.
Los parámetros predeterminados reproducen los valores predeterminados originales de EA: Chaikin 3/10 EMA, CCI períodos 14 y 50, preprocesamiento de SMA de 12 períodos y una ventana de negociación de 10:01 a 15:02.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Combines a Chaikin oscillator zero-line filter with CCI confirmation.
/// Buys when Chaikin crosses above zero and CCI is rising, sells on opposite.
/// </summary>
public class iCHO_Trend_CCIDualOnMA_FilterStrategy : Strategy
{
private readonly StrategyParam<int> _cciLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _cciLevel;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal? _prevCci;
private decimal? _prevPrevCci;
private int _candlesSinceTrade;
public int CciLength
{
get => _cciLength.Value;
set => _cciLength.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal CciLevel
{
get => _cciLevel.Value;
set => _cciLevel.Value = value;
}
public int SignalCooldownCandles
{
get => _signalCooldownCandles.Value;
set => _signalCooldownCandles.Value = value;
}
public iCHO_Trend_CCIDualOnMA_FilterStrategy()
{
_cciLength = Param(nameof(CciLength), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Length", "CCI period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Primary candle series", "Data");
_cciLevel = Param(nameof(CciLevel), 100m)
.SetDisplay("CCI Level", "CCI threshold for entry", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between entries", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
_prevPrevCci = null;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
_prevPrevCci = null;
_candlesSinceTrade = SignalCooldownCandles;
var cci = new CommodityChannelIndex { Length = CciLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, cci);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (_prevCci.HasValue && _prevPrevCci.HasValue)
{
if (_prevPrevCci.Value < -CciLevel && _prevCci.Value < -CciLevel && cciValue > -CciLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (_prevPrevCci.Value > CciLevel && _prevCci.Value > CciLevel && cciValue < CciLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevPrevCci = _prevCci;
_prevCci = cciValue;
}
}
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 i_cho__trend_cci_dual_on_ma__filter_strategy(Strategy):
def __init__(self):
super(i_cho__trend_cci_dual_on_ma__filter_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._cci_length = self.Param("CciLength", 14)
self._cci_level = self.Param("CciLevel", 100.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 4)
self._prev_cci = 0.0
self._prev_prev_cci = 0.0
self._candles_since_trade = 4
self._has_two = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def CciLength(self):
return self._cci_length.Value
@CciLength.setter
def CciLength(self, value):
self._cci_length.Value = value
@property
def CciLevel(self):
return self._cci_level.Value
@CciLevel.setter
def CciLevel(self, value):
self._cci_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(i_cho__trend_cci_dual_on_ma__filter_strategy, self).OnReseted()
self._prev_cci = 0.0
self._prev_prev_cci = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_two = False
def OnStarted2(self, time):
super(i_cho__trend_cci_dual_on_ma__filter_strategy, self).OnStarted2(time)
self._prev_cci = 0.0
self._prev_prev_cci = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_two = False
cci = CommodityChannelIndex()
cci.Length = self.CciLength
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)
level = float(self.CciLevel)
if self._has_two:
# Both prev_prev and prev were below -level, now crossing above -level
if self._prev_prev_cci < -level and self._prev_cci < -level and cci_val > -level and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
# Both prev_prev and prev were above +level, now crossing below +level
elif self._prev_prev_cci > level and self._prev_cci > level and cci_val < level and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_prev_cci = self._prev_cci
self._prev_cci = cci_val
if not self._has_two:
if self._prev_prev_cci != 0.0 or self._prev_cci != 0.0:
self._has_two = True
def CreateClone(self):
return i_cho__trend_cci_dual_on_ma__filter_strategy()