Ver en GitHub

Estrategia Stochastic Automatizada

Esta estrategia opera utilizando el Oscilador Stochastic en el marco temporal de velas seleccionado. Espera a que %K y %D entren en zonas extremas y luego actúa en los cruces para abrir posiciones. Un take profit y stop loss fijos protegen cada operación, mientras que un trailing stop asegura las ganancias.

Lógica

  1. Entrada
    • Largo:
      • Tanto %K como %D están por debajo de OverSold hace dos velas.
      • %D estaba por encima de %K hace dos velas y por debajo de %K hace una vela.
      • %D está subiendo.
    • Corto:
      • Tanto %K como %D están por encima de OverBought hace dos velas.
      • %D estaba por debajo de %K hace dos velas y por encima de %K hace una vela.
      • %D está bajando.
  2. Salida
    • La posición se cierra cuando el Stochastic sale de la zona extrema o %D gira en la dirección opuesta.
    • Un trailing stop sale si el precio retrocede en TrailingStop.
    • Se aplican TakeProfit y StopLoss globales a cada operación.

Parámetros

Nombre Descripción
CandleType Marco temporal para los cálculos del Stochastic.
KPeriod Período de retrospección para la línea %K.
DPeriod Período de suavizado para la línea %D.
Slowing Suavizado adicional para %K.
OverBought Umbral superior que indica mercado sobrecomprado.
OverSold Umbral inferior que indica mercado sobrevendido.
TakeProfit Distancia desde la entrada para el objetivo de ganancia (unidades de precio).
StopLoss Distancia desde la entrada para el stop de protección (unidades de precio).
TrailingStop Distancia de seguimiento una vez que la operación se mueve a favor (unidades de precio).

Indicadores

  • StochasticOscillator

Notas

  • Los comentarios en el código están en inglés.
  • La versión de Python se omite intencionalmente.
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>
/// Stochastic oscillator based strategy.
/// Buys on K/D crossover in oversold, sells on crossover in overbought.
/// </summary>
public class StochasticAutomatedStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _overBought;
	private readonly StrategyParam<decimal> _overSold;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal OverBought { get => _overBought.Value; set => _overBought.Value = value; }
	public decimal OverSold { get => _overSold.Value; set => _overSold.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public StochasticAutomatedStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("%K Period", "Stochastic %K period", "Stochastic");

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

		_overBought = Param(nameof(OverBought), 80m)
			.SetDisplay("Overbought", "Overbought threshold", "Stochastic");

		_overSold = Param(nameof(OverSold), 20m)
			.SetDisplay("Oversold", "Oversold threshold", "Stochastic");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevK = _prevD = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var stochastic = new StochasticOscillator();
		stochastic.K.Length = KPeriod;
		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 = (IStochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal k || stoch.D is not decimal d)
			return;

		if (_prevK is decimal pk && _prevD is decimal pd)
		{
			// Buy: K crosses above D in oversold zone
			if (pk <= pd && k > d && pd < OverSold && Position <= 0)
				BuyMarket();

			// Sell: K crosses below D in overbought zone
			if (pk >= pd && k < d && pd > OverBought && Position >= 0)
				SellMarket();
		}

		_prevK = k;
		_prevD = d;
	}
}