A estratégia reproduz a lógica do expert advisor MetaTrader 4 Signal-COunt-with array.mq4.
Ela monitora os extremos do canal Donchian para um conjunto configurável de offsets de preço e conta com que frequência
a saída do indicador muda, fica vazia ou retorna a um valor de sinal. A implementação mantém
o foco diagnóstico do script original: nenhuma operação é executada. Em vez disso, a estratégia imprime
estatísticas detalhadas sempre que um novo máximo/mínimo é registrado ou quando o log por candle está habilitado.
Conceito
Substituir a pesquisa iCustom original de super_signals_v2_alert por um canal Donchian que
fornece a máxima mais alta e a mínima mais baixa durante ChannelPeriod candles.
Avaliar uma grade de offsets (GapStart, GapStep, GapCount) que emulam as múltiplas configurações de indicadores
testadas pelo script MQL.
Para cada offset rastrear seis contadores que espelham os arrays originais, incluindo transições para e
fora do valor sentinela (2147483647 para leituras superiores vazias e -2147483646 para leituras inferiores vazias).
Gerar uma tabela de texto com os contadores acumulados para que o usuário possa inspecionar com que frequência cada buffer
produz um novo sinal, retorna ao vazio ou sai do estado zero padrão.
Parâmetros
Parâmetro
Padrão
Descrição
CandleType
Período de 5 minutos
Série de candles usada para os cálculos de Donchian.
ChannelPeriod
24
Número de candles usados para determinar as máximas e mínimas de Donchian.
GapStart
0
Primeiro offset (em múltiplos do passo de preço) aplicado aos valores de sinal virtuais.
GapStep
1
Tamanho do passo (em passos de preço) entre offsets consecutivos.
GapCount
8
Número de offsets a avaliar (corresponde ao loop 0..7 original).
LogOnEachCandle
false
Quando habilitado, força o log após cada candle terminado.
Contadores
Cada offset mantém duas linhas: o índice 0 representa o buffer superior do Donchian (sinal altista) e
o índice 1 representa o buffer inferior (sinal baixista). As seguintes estatísticas são coletadas:
Changed – incrementa sempre que o valor bruto do indicador difere da observação anterior.
Empty – conta quantas vezes o buffer retornou o sentinela positivo (2147483647).
NegEmpty – conta ocorrências do sentinela negativo (-2147483646), principalmente para o buffer inferior.
Zero – rastreia transições do estado zero padrão para qualquer valor diferente de zero.
NewFromEmpty – incrementa quando um sinal baseado em preço real substitui o valor sentinela.
BackToEmpty – incrementa quando o buffer retorna ao seu sentinela após manter um valor não sentinela.
Esses contadores correspondem um a um com os arrays mantidos no Expert Advisor original
(GetInd_iCustom_changed, GetInd_iCustom_maxInt, GetInd_iCustom_minInt, etc.).
Registro
A estratégia imprime diagnósticos através de AddInfoLog em duas situações:
Sempre que a banda superior do Donchian sobe ou a banda inferior desce, indicando um novo extremo.
Cada candle terminado quando LogOnEachCandle está definido como true.
Cada entrada de log começa com o tempo do candle e depois lista os contadores para cada offset, facilitando
a comparação do comportamento entre diferentes configurações de indicadores virtuais.
Notas de uso
Anexar a estratégia a qualquer instrumento; ela depende apenas de candles históricos e não envia ordens.
Ajustar ChannelPeriod para corresponder à volatilidade do instrumento que está sendo estudado. Um período mais longo
imita uma detecção de swing mais ampla similar ao indicador MT4.
Aumentar GapCount se precisar observar mais offsets. Os arrays são redimensionados automaticamente no início.
Combinar os diagnósticos com desenhos de gráfico (candles mais canal Donchian) para alinhar visualmente as
estatísticas impressas com a estrutura do mercado.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class SignalCountWithArrayStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevCci;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public SignalCountWithArrayStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 14).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal cciVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevCci = cciVal; return; }
if (_prevCci == null) { _prevCci = cciVal; return; }
if (_prevCci.Value < 0m && cciVal >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevCci.Value > 0m && cciVal <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevCci = cciVal;
}
}
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
from datatype_extensions import *
from indicator_extensions import *
class signal_count_with_array_strategy(Strategy):
def __init__(self):
super(signal_count_with_array_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 14).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(signal_count_with_array_strategy, self).OnReseted()
self._prev_cci = None
def OnStarted2(self, time):
super(signal_count_with_array_strategy, self).OnStarted2(time)
self._prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(cci, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle, cci_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = cci_val
return
if self._prev_cci is None:
self._prev_cci = cci_val
return
if self._prev_cci < 0 and cci_val >= 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_cci > 0 and cci_val <= 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_cci = cci_val
def CreateClone(self):
return signal_count_with_array_strategy()