Ver no GitHub

Estratégia suavizada de CHO EA

Visão geral

Esta estratégia replica a lógica do Expert Advisor "CHO Smoothed EA" original. Ele observa os cruzamentos do oscilador Chaikin em velas concluídas e suaviza o oscilador com uma média móvel configurável. Filtros opcionais limitam a negociação a uma sessão específica, restringem a direção da negociação e validam sinais com confirmação de linha zero. Quando um sinal é aceito, a estratégia envia uma ordem de mercado e gerencia a posição usando distâncias fixas em pontos para stop-loss, take-profit e proteção de trailing.

Lógica de negociação

  • Os valores do oscilador Chaikin são calculados em cada vela finalizada com períodos rápidos e lentos configuráveis.
  • Uma média móvel do oscilador cria a linha de sinal. O período e o tipo de média móvel podem ser ajustados.
  • Entradas longas ocorrem quando o oscilador cruza acima da linha suavizada. Entradas curtas ocorrem no cruzamento oposto. Os sinais podem ser revertidos para negociar contra a direção original.
  • Se o filtro de nível zero estiver habilitado, ambos os valores do oscilador deverão estar abaixo de zero para negociações longas e acima de zero para negociações curtas.
  • A estratégia pode fechar automaticamente posições opostas antes de entrar em uma nova negociação ou ignorar sinais até que a posição atual fique estável. Também pode impor um modo de posição única.
  • A negociação pode ser restrita a uma janela de tempo diária. Windows que cruzam a meia-noite são suportados.
  • Após uma entrada, a estratégia armazena o preço de entrada, converte as distâncias dos pontos configurados em compensações de preço e monitora as velas para eventos de stop-loss, take-profit e trailing-stop.

Gestão de risco

  • Os níveis de stop-loss e take-profit são calculados a partir do preço de entrada usando distâncias de pontos multiplicadas pela etapa de preço do instrumento.
  • O trailing stop é ativado após o preço avançar pelo passo final configurado e depois segue na distância final.
  • Quando um nível de proteção é atingido, a posição é fechada imediatamente com uma ordem de mercado e todos os níveis de risco são redefinidos.

Parâmetros

  • Tipo de vela – período usado para construir as velas para cálculos de indicadores.
  • Período Rápido / Período Lento – Períodos rápidos e lentos do Oscilador Chaikin.
  • Período MA do sinal / Tipo MA do sinal – suavização das configurações de média móvel aplicadas ao oscilador.
  • Use Nível Zero – exige que ambos os valores do oscilador estejam no lado correto de zero antes de negociar.
  • Modo de negociação – permite apenas posições compradas, apenas vendidas ou ambas as direções.
  • Sinais Reversos – troque entradas longas e curtas.
  • Fechar Oposto – feche posições opostas existentes antes de abrir uma nova negociação.
  • Apenas uma posição – evita entradas quando uma posição já está aberta.
  • Use Controle de Tempo / Hora de Início / Hora de Término – habilite e configure a janela de negociação diária.
  • Stop Loss (pts) – distância em pontos para o stop de proteção.
  • Take Profit (pts) – distância em pontos para metas de lucro.
  • Trailing Stop (pts) – distância do trailing stop em pontos.
  • Trailing Step (pts) – movimento mínimo favorável (em pontos) antes de mover o trailing stop.

Notas adicionais

  • Defina a propriedade Volume da estratégia antes de iniciá-la para controlar o tamanho da negociação.
  • Como a estratégia emite ordens de mercado, garanta liquidez suficiente e considere derrapagens em ambientes reais.
  • Quando os horários de início e término da janela de negociação são iguais, a estratégia permanece inativa, correspondendo ao comportamento original do Expert Advisor.
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>
/// Trades CCI oscillator zero-line crossovers with signal MA smoothing.
/// Originally based on Chaikin Oscillator concept, adapted to use CCI.
/// </summary>
public class ChoSmoothedEaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<int> _maPeriod;

	private CommodityChannelIndex _cci;
	private readonly Queue<decimal> _cciHistory = new();
	private decimal? _prevCci;
	private decimal? _prevSignal;

	/// <summary>
	/// Initializes a new instance of the <see cref="ChoSmoothedEaStrategy"/> class.
	/// </summary>
	public ChoSmoothedEaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for signal calculations", "General");

		_cciPeriod = Param(nameof(CciPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "Period for CCI oscillator", "Indicator");

		_maPeriod = Param(nameof(MaPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("Signal MA Period", "Period of smoothing moving average on CCI", "Indicator");
	}

	/// <summary>
	/// Candle type used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// CCI oscillator period.
	/// </summary>
	public int CciPeriod
	{
		get => _cciPeriod.Value;
		set => _cciPeriod.Value = value;
	}

	/// <summary>
	/// Period of the smoothing moving average.
	/// </summary>
	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevCci = null;
		_prevSignal = null;
		_cciHistory.Clear();

		_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 cciValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		_cciHistory.Enqueue(cciValue);
		while (_cciHistory.Count > MaPeriod)
			_cciHistory.Dequeue();

		if (!_cci.IsFormed)
			return;

		if (_cciHistory.Count < MaPeriod)
		{
			_prevCci = cciValue;
			return;
		}

		// Calculate signal line (SMA of CCI)
		var sum = 0m;
		var history = _cciHistory.ToArray();
		foreach (var v in history)
			sum += v;
		var signalValue = sum / history.Length;

		if (_prevCci is null || _prevSignal is null)
		{
			_prevCci = cciValue;
			_prevSignal = signalValue;
			return;
		}

		var crossUp = _prevCci <= _prevSignal && cciValue > signalValue;
		var crossDown = _prevCci >= _prevSignal && cciValue < signalValue;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var minSpread = 25m;

		if (crossUp && Math.Abs(cciValue - signalValue) >= minSpread)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossDown && Math.Abs(cciValue - signalValue) >= minSpread)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevCci = cciValue;
		_prevSignal = signalValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_prevCci = null;
		_prevSignal = null;
		_cci = null;
		_cciHistory.Clear();

		base.OnReseted();
	}
}