Ver no GitHub

Estratégia de Cruzamento Auto KD

Visão geral

A estratégia de Cruzamento Auto KD replica o exemplo MQL5 original autoKD_EA.
Usa o indicador StochasticOscillator para gerar sinais de compra e venda com base em cruzamentos das linhas %K e %D.

O cálculo base usa a fórmula RSV: RSV = (Close - LowestLow) / (HighestHigh - LowestLow) * 100 onde a máxima mais alta e a mínima mais baixa são calculadas sobre barras KDPeriod.
A linha %K é uma média móvel do RSV com comprimento KPeriod; %D é uma média móvel de %K com comprimento DPeriod.

Parâmetros

Nome Descrição Padrão
KDPeriod Número de barras para o período base do RSV. 30
KPeriod Período de suavização para a linha %K. 3
DPeriod Período de suavização para a linha %D. 6
CandleType Tipo e período de velas usadas para cálculos. Período de 5 minutos
Volume Volume de ordem herdado de Strategy. Strategy.Volume

Todos os parâmetros estão disponíveis para otimização.

Lógica de Trading

  1. Inscrever-se na série de velas selecionada e calcular o oscilador Estocástico.
  2. Quando o valor anterior de %K estava abaixo de %D e o %K atual cruza acima de %D, uma posição comprada é aberta.
  3. Quando o valor anterior de %K estava acima de %D e o %K atual cruza abaixo de %D, uma posição vendida é aberta.
  4. A estratégia mantém apenas uma posição por vez. Cruzamentos na direção oposta fecham a posição e abrem o lado oposto.
  5. StartProtection() habilita os mecanismos de proteção de perda/lucro padrão fornecidos pelo StockSharp.

Visualização

A estratégia exibe automaticamente velas, o indicador Estocástico e trades executados no gráfico.

Notas

  • Funciona com qualquer instrumento e período.
  • Os parâmetros devem ser adaptados à volatilidade do mercado selecionado.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on %K and %D crossover from the Stochastic oscillator.
/// </summary>
public class AutoKdStrategy : Strategy
{
	private readonly StrategyParam<int> _kdPeriod;
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;

	/// <summary>
	/// Lookback period for RSV calculation.
	/// </summary>
	public int KdPeriod
	{
		get => _kdPeriod.Value;
		set => _kdPeriod.Value = value;
	}

	/// <summary>
	/// Smoothing period for %K.
	/// </summary>
	public int KPeriod
	{
		get => _kPeriod.Value;
		set => _kPeriod.Value = value;
	}

	/// <summary>
	/// Smoothing period for %D.
	/// </summary>
	public int DPeriod
	{
		get => _dPeriod.Value;
		set => _dPeriod.Value = value;
	}

	/// <summary>
	/// Type of candles used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="AutoKdStrategy"/>.
	/// </summary>
	public AutoKdStrategy()
	{
		_kdPeriod = Param(nameof(KdPeriod), 30)
		.SetGreaterThanZero()
		.SetDisplay("KD Period", "Base period for RSV", "Parameters")
		
		.SetOptimize(10, 60, 5);

		_kPeriod = Param(nameof(KPeriod), 3)
		.SetGreaterThanZero()
		.SetDisplay("K Period", "%K smoothing", "Parameters")
		
		.SetOptimize(1, 10, 1);

		_dPeriod = Param(nameof(DPeriod), 6)
		.SetGreaterThanZero()
		.SetDisplay("D Period", "%D smoothing", "Parameters")
		
		.SetOptimize(1, 10, 1);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Timeframe for analysis", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevK = null;
		_prevD = null;
	}

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

		var stochastic = new StochasticOscillator();
		stochastic.K.Length = KdPeriod;
		stochastic.D.Length = DPeriod;

		var subscription = SubscribeCandles(CandleType);
		subscription
		.BindEx(stochastic, ProcessCandle)
		.Start();

		var area = CreateChartArea();
		if (area != null)
		{
		DrawCandles(area, subscription);
		DrawIndicator(area, stochastic);
		DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
	{
		if (candle.State != CandleStates.Finished)
		return;

		if (!IsFormedAndOnlineAndAllowTrading())
		return;

		var stoch = (StochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal k || stoch.D is not decimal d)
			return;

		if (_prevK is decimal prevK && _prevD is decimal prevD)
		{
			if (prevK < prevD && k > d && Math.Min(prevK, k) < 30m && Position <= 0)
				BuyMarket(Volume + Math.Abs(Position));
			else if (prevK > prevD && k < d && Math.Max(prevK, k) > 70m && Position >= 0)
				SellMarket(Volume + Math.Abs(Position));
		}

		_prevK = k;
		_prevD = d;
	}
}