Esta estratégia é uma porta StockSharp de alto nível do consultor especialista MetaTrader "iCHO Trend CCIDualOnMA Filter". Ele combina um filtro de regime de linha zero do oscilador Chaikin com uma confirmação dupla do índice de canal de commodities (CCI) que é calculada sobre uma série de preços suavizados. O resultado é uma abordagem de acompanhamento de tendências que reage às mudanças de impulso, mas ainda requer uma confirmação de impulso do par CCI antes de entrar em uma negociação.
Lógica de negociação
Núcleo do oscilador Chaikin – a linha de acumulação/distribuição é suavizada por duas médias móveis configuráveis. A diferença deles replica o oscilador Chaikin. Cruzamentos acima/abaixo de zero sinalizam uma mudança no fluxo de capital dominante.
Filtro CCI duplo – ambas as instâncias CCI usam a mesma entrada de preço suavizado por média móvel, mas diferentes períodos de lookback. Uma configuração longa requer que o CCI rápido se recupere do território negativo e cruze acima do CCI lento enquanto o oscilador Chaikin permanece acima de zero. Uma breve configuração reflete essas condições.
Reversão opcional – o EA original fornece um sinalizador “reverso” que troca sinais longos e curtos. A porta mantém esse comportamento para que as mesmas regras possam ser usadas para testes de contratendência.
Gerenciamento de posição – sinalizadores opcionais fecham a exposição oposta antes de abrir uma nova posição e limitam a estratégia a uma única posição aberta. Uma regra de uma negociação por barra é aplicada para imitar a implementação MetaTrader.
Filtro de sessão – a negociação pode ser restrita a uma janela intradiária definida pelo usuário, incluindo sessões wrap-around que passam da meia-noite.
Parâmetros
Parâmetro
Descrição
FastChaikinLength
Período de média móvel rápida usado dentro do oscilador Chaikin.
SlowChaikinLength
Período de média móvel lenta usado dentro do oscilador Chaikin.
ChaikinMethod
Método de média móvel (Simples, Exponencial, Suavizado, LinearWeighted) aplicado à linha de acumulação/distribuição.
FastCciLength
Retrospectiva do índice rápido de canais de commodities.
SlowCciLength
Retrospectiva do lento Commodity Channel Index.
MaLength
Comprimento da média móvel de pré-processamento que alimenta os CCIs.
MaMethod
Método de média móvel usado para pré-processar o preço antes de atingir os CCIs.
MaPrice
Tipo de preço (fechamento, abertura, máximo, mínimo, mediano, típico, ponderado) que é suavizado antes dos CCIs.
UseClosedBar
Processe apenas velas totalmente concluídas (padrão verdadeiro, idêntico a SignalsBarCurrent=bar_1 em EA).
ReverseSignals
Troque lógica longa e curta.
CloseOpposite
Feche uma posição aberta na direção oposta antes de entrar em uma nova.
OnlyOnePosition
Permitir apenas uma única posição aberta por vez.
TradeMode
Restrinja a execução a posições compradas, vendidas ou ambas (BuyOnly, SellOnly, BuyAndSell).
UseTimeFilter
Habilite o filtro da sessão de negociação.
StartHour, StartMinute, EndHour, EndMinute
Limites da sessão (inclusive o início, excluindo o final) expressos em tempo de troca. Sessões envolventes são suportadas.
CandleType
Prazo de assinatura da vela alimentando os indicadores.
Notas
A estratégia usa apenas ligações SubscribeCandles de alto nível e indicadores integrados; nenhum buffer personalizado ou solicitação histórica é necessária.
Todos os cálculos baseados em preços adotam o mesmo pré-processamento de média móvel que o indicador MetaTrader CCIDualOnMA, alimentando o CCI com uma série de preços suavizados.
Os parâmetros padrão reproduzem os padrões originais do EA: Chaikin 3/10 EMA, CCI períodos 14 e 50, pré-processamento de 12 períodos SMA e uma janela de negociação das 10h01 às 15h02.
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()