Esta estratégia é uma versão StockSharp de alto nível API do consultor especialista MetaTrader TenKijun.mq4. O EA original apenas observa o indicador Ichimoku e envia notificações push quando o Tenkan-sen (linha de conversão) cruza o Kijun-sen (linha de base). A versão C# mantém a natureza apenas de alerta, mas atualiza a implementação com infraestrutura StockSharp, ligações de gráficos, parametrização e manipulação segura de sessões.
A lógica funciona em velas concluídas de um período configurável. Quando uma nova vela fecha dentro do horário de negociação ativo, a estratégia avalia o indicador Ichimoku calculado com os períodos clássicos de 26/09/52 e registra os últimos valores Tenkan/Kijun. Se o Tenkan cruzar acima do Kijun, uma mensagem informativa será registrada indicando uma linha de alta; se Tenkan cruzar abaixo de Kijun, um alerta de baixa será registrado. Nenhuma negociação é executada – a estratégia destina-se à geração de sinais ou a ser combinada com automação externa.
Indicador e Fluxo de Dados
Indicador – indicador StockSharp Ichimoku com comprimentos Tenkan, Kijun e Senkou Span B parametrizados separadamente. Apenas as linhas Tenkan e Kijun são usadas para tomada de decisão, espelhando o EA original.
Assinatura de dados – Usa SubscribeCandles com um CandleType configurável. Por padrão, são solicitadas velas de período de 30 minutos.
Binding – BindEx é empregado para que o IchimokuValue digitado seja entregue ao manipulador sem chamadas manuais para GetValue.
Gráficos – Velas e o indicador Ichimoku são anexados automaticamente ao gráfico de estratégia para rápida validação visual de alertas.
Filtro de Sessão de Negociação
O script MetaTrader restringiu alertas a uma janela de sessão definida pelo usuário. A porta expõe o mesmo recurso por meio de dois parâmetros:
StartHour – início inclusivo da janela ativa (padrão 0). Aceita 0-23.
LastHour – fim inclusivo da janela ativa (padrão 20). Aceita 0-23.
Se StartHour for menor ou igual a LastHour, os alertas serão produzidos entre essas duas horas do dia. Se o início for maior que o fim, a janela é tratada como noturna (por exemplo, 20 → 6 abrange a sessão do final da noite até o início da manhã).
Parâmetros
Parâmetro
Descrição
Padrão
Notas
StartHour
Hora em que os alertas podem começar.
0
Inclusive, faixa de 0 a 23.
LastHour
Hora em que os alertas param.
20
Inclusive, faixa de 0 a 23.
TenkanPeriod
Lookback da linha de conversão.
9
Otimizável.
KijunPeriod
Lookback da linha base.
26
Otimizável.
SenkouSpanBPeriod
Lookback do período B inicial.
52
Fornecido para ser completo, mesmo que os alertas não dependam da nuvem.
CandleType
Série de velas usada para o indicador.
Prazo de 30 minutos
Escolha qualquer período baseado em TimeSpan.
Lógica de Alerta
Aguarde a primeira vela finalizada para inicializar o histórico de Tenkan e Kijun.
Em cada vela finalizada subsequente dentro da janela de negociação:
Extraia os valores Tenkan e Kijun do indicador Ichimoku.
Detecte uma linha de alta quando o Tenkan anterior for menor ou igual ao Kijun anterior e o Tenkan atual for maior que o Kijun atual.
Detecte uma linha de baixa quando o Tenkan anterior for maior ou igual ao Kijun anterior e o Tenkan atual for menor que o Kijun atual.
Emita uma entrada de registro informativa descrevendo a direção, o preço e o carimbo de data/hora da cruz.
Dicas de uso
Combine esta estratégia com adaptadores de notificação StockSharp (e-mail, telegrama, som) inscrevendo-se no registro de estratégia ou estendendo o método ProcessCandle com código de notificação personalizado.
Para impulsionar a negociação automatizada, herde de TenKijunCrossStrategy e substitua ProcessCandle para fazer pedidos em vez de - ou além de - registrar mensagens.
Ajuste o período da vela para corresponder ao gráfico MetaTrader original usado pelo EA para manter os alertas alinhados.
Diferenças do original EA
Usa registro StockSharp em vez de MetaTrader SendNotification. O comportamento permanece apenas de alerta, mas depende do pipeline de mensagens da plataforma.
Adiciona metadados de parâmetros completos (SetDisplay, intervalos, sinalizadores de otimização), tornando a estratégia pronta para ferramentas Designer/Optimizer.
Desenha automaticamente velas e o indicador Ichimoku na janela do gráfico StockSharp quando disponível.
Arquivos
CS/TenKijunCrossStrategy.cs – implementação principal em C# da lógica de alerta.
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;
/// <summary>
/// Tenkan/Kijun cross strategy based on Ichimoku indicator.
/// Buys when Tenkan crosses above Kijun, sells when Tenkan crosses below Kijun.
/// Uses SMA proxies for Tenkan (short) and Kijun (long) since Ichimoku complex type
/// requires BindEx and special value handling.
/// </summary>
public class TenKijunCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private readonly Queue<decimal> _highsTenkan = new();
private readonly Queue<decimal> _lowsTenkan = new();
private readonly Queue<decimal> _highsKijun = new();
private readonly Queue<decimal> _lowsKijun = new();
private decimal? _prevTenkan;
private decimal? _prevKijun;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int TenkanPeriod
{
get => _tenkanPeriod.Value;
set => _tenkanPeriod.Value = value;
}
public int KijunPeriod
{
get => _kijunPeriod.Value;
set => _kijunPeriod.Value = value;
}
public TenKijunCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for Ichimoku calculations", "General");
_tenkanPeriod = Param(nameof(TenkanPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Tenkan Period", "Tenkan-sen conversion line period", "Indicators");
_kijunPeriod = Param(nameof(KijunPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Kijun Period", "Kijun-sen base line period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevTenkan = null;
_prevKijun = null;
_highsTenkan.Clear();
_lowsTenkan.Clear();
_highsKijun.Clear();
_lowsKijun.Clear();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Compute Tenkan-sen = (highest high + lowest low) / 2 over TenkanPeriod
_highsTenkan.Enqueue(candle.HighPrice);
_lowsTenkan.Enqueue(candle.LowPrice);
if (_highsTenkan.Count > TenkanPeriod)
{
_highsTenkan.Dequeue();
_lowsTenkan.Dequeue();
}
// Compute Kijun-sen = (highest high + lowest low) / 2 over KijunPeriod
_highsKijun.Enqueue(candle.HighPrice);
_lowsKijun.Enqueue(candle.LowPrice);
if (_highsKijun.Count > KijunPeriod)
{
_highsKijun.Dequeue();
_lowsKijun.Dequeue();
}
if (_highsTenkan.Count < TenkanPeriod || _highsKijun.Count < KijunPeriod)
return;
var highsTenkan = _highsTenkan.ToArray();
var lowsTenkan = _lowsTenkan.ToArray();
var highsKijun = _highsKijun.ToArray();
var lowsKijun = _lowsKijun.ToArray();
var tenkan = (Max(highsTenkan) + Min(lowsTenkan)) / 2;
var kijun = (Max(highsKijun) + Min(lowsKijun)) / 2;
if (_prevTenkan is null || _prevKijun is null)
{
_prevTenkan = tenkan;
_prevKijun = kijun;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
var crossUp = _prevTenkan.Value <= _prevKijun.Value && tenkan > kijun;
var crossDown = _prevTenkan.Value >= _prevKijun.Value && tenkan < kijun;
if (crossUp)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevTenkan = tenkan;
_prevKijun = kijun;
}
private static decimal Max(IEnumerable<decimal> values)
{
decimal max = decimal.MinValue;
foreach (var v in values)
if (v > max) max = v;
return max;
}
private static decimal Min(IEnumerable<decimal> values)
{
decimal min = decimal.MaxValue;
foreach (var v in values)
if (v < min) min = v;
return min;
}
/// <inheritdoc />
protected override void OnReseted()
{
_prevTenkan = null;
_prevKijun = null;
_highsTenkan.Clear();
_lowsTenkan.Clear();
_highsKijun.Clear();
_lowsKijun.Clear();
base.OnReseted();
}
}