Ver no GitHub

Estratégia Stoch Komposter

Esta estratégia é um port do expert MQL5 Exp_iStochKomposter. Utiliza o Oscilador Estocástico para detectar reversões de momentum e negocia quando a linha %K cruza limites predefinidos.

Como Funciona

  • Calcula o Oscilador Estocástico no período selecionado.
  • Gera um sinal de compra quando %K cruza acima do nível inferior (padrão 30).
  • Gera um sinal de venda quando %K cruza abaixo do nível superior (padrão 70).
  • Em cada sinal, a estratégia fecha qualquer posição oposta e abre uma nova posição na direção do sinal usando ordens a mercado.
  • Níveis opcionais de stop loss e take profit são aplicados via StartProtection.

Parâmetros

Nome Descrição Padrão
KPeriod Período de cálculo da linha %K 5
DPeriod Período de suavização da linha %D 3
UpLevel Limiar de sobrecompra para acionar vendas 70
DownLevel Limiar de sobrevenda para acionar compras 30
StopLoss Stop loss absoluto em unidades de preço 1000
TakeProfit Take profit absoluto em unidades de preço 2000
CandleType Período para cálculos 1 hora

Notas

  • A estratégia opera apenas em velas finalizadas.
  • Não calcula os níveis ATR do indicador original; eram usados apenas para posicionamento de setas na versão MQL.
  • O tamanho da posição é definido pela propriedade Volume da estratégia.
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>
/// Strategy using Stochastic Oscillator crossovers.
/// Opens long when %K crosses above the lower level and opens short when crossing below the upper level.
/// </summary>
public class StochKomposterStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _upLevel;
	private readonly StrategyParam<decimal> _downLevel;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal UpLevel { get => _upLevel.Value; set => _upLevel.Value = value; }
	public decimal DownLevel { get => _downLevel.Value; set => _downLevel.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public StochKomposterStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("K Period", "Stochastic %K calculation period", "Indicators");

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("D Period", "Stochastic %D smoothing period", "Indicators");

		_upLevel = Param(nameof(UpLevel), 70m)
			.SetDisplay("Upper Level", "Overbought threshold", "Indicators");

		_downLevel = Param(nameof(DownLevel), 30m)
			.SetDisplay("Lower Level", "Oversold threshold", "Indicators");

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

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

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

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

		_prevK = null;

		var stochastic = new StochasticOscillator
		{
			K = { Length = KPeriod },
			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;

		if (stochValue is not IStochasticOscillatorValue value || value.K is not decimal k)
			return;

		if (_prevK is null)
		{
			_prevK = k;
			return;
		}

		var prev = _prevK.Value;

		// %K crosses above lower level -> buy
		if (prev <= DownLevel && k > DownLevel && Position <= 0)
			BuyMarket();
		// %K crosses below upper level -> sell
		else if (prev >= UpLevel && k < UpLevel && Position >= 0)
			SellMarket();

		_prevK = k;
	}
}