Ver en GitHub

Estrategia de Histograma del Oscilador MA

Descripción general

Esta estrategia es una traducción del experto MQL5 Exp_MAOscillatorHist.mq5. Utiliza la diferencia entre una Media Móvil Simple (SMA) rápida y una lenta para formar un oscilador. Las señales de trading se generan cuando el oscilador forma mínimos o máximos locales, que se interpretan como posibles reversiones de tendencia.

Lógica de trading

  1. Se calculan dos SMA en el marco temporal de velas seleccionado:
    • SMA rápida con un período más corto.
    • SMA lenta con un período más largo.
  2. El valor del oscilador es la SMA rápida menos la SMA lenta.
  3. La estrategia rastrea los tres últimos valores del oscilador. Un mínimo local ocurre cuando el valor más antiguo es mayor que el anterior y el anterior es menor que el actual. Un máximo local es lo opuesto.
  4. Cuando se detecta un mínimo local:
    • Cerrar posiciones cortas (si está permitido).
    • Abrir una nueva posición larga (si está permitido).
  5. Cuando se detecta un máximo local:
    • Cerrar posiciones largas (si está permitido).
    • Abrir una nueva posición corta (si está permitido).

Parámetros

Parámetro Descripción
Fast Period Período de la SMA rápida.
Slow Period Período de la SMA lenta.
Enable Buy Open Si es verdadero, se pueden abrir posiciones largas.
Enable Sell Open Si es verdadero, se pueden abrir posiciones cortas.
Enable Buy Close Si es verdadero, las posiciones largas se pueden cerrar con señales opuestas.
Enable Sell Close Si es verdadero, las posiciones cortas se pueden cerrar con señales opuestas.
Candle Type Marco temporal de las velas utilizadas para los cálculos.

Notas

  • La estrategia utiliza la API de alto nivel de StockSharp con SubscribeCandles y vinculación de indicadores.
  • StartProtection está habilitado con órdenes de mercado para una ejecución más segura.
  • No se proporciona versión en Python.
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>
/// Moving Average Oscillator Histogram strategy.
/// Generates signals when the oscillator forms local minima or maxima.
/// </summary>
public class MaOscillatorHistogramStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<bool> _enableBuyOpen;
	private readonly StrategyParam<bool> _enableSellOpen;
	private readonly StrategyParam<bool> _enableBuyClose;
	private readonly StrategyParam<bool> _enableSellClose;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevOsc1;
	private decimal _prevOsc2;
	private bool _isWarmup;

	/// <summary>
	/// Fast MA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow MA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Enable opening long positions.
	/// </summary>
	public bool EnableBuyOpen
	{
		get => _enableBuyOpen.Value;
		set => _enableBuyOpen.Value = value;
	}

	/// <summary>
	/// Enable opening short positions.
	/// </summary>
	public bool EnableSellOpen
	{
		get => _enableSellOpen.Value;
		set => _enableSellOpen.Value = value;
	}

	/// <summary>
	/// Enable closing long positions.
	/// </summary>
	public bool EnableBuyClose
	{
		get => _enableBuyClose.Value;
		set => _enableBuyClose.Value = value;
	}

	/// <summary>
	/// Enable closing short positions.
	/// </summary>
	public bool EnableSellClose
	{
		get => _enableSellClose.Value;
		set => _enableSellClose.Value = value;
	}

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

	/// <summary>
	/// Initializes a new instance of the <see cref="MaOscillatorHistogramStrategy"/>.
	/// </summary>
	public MaOscillatorHistogramStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 13)
			.SetDisplay("Fast Period", "Period of fast moving average", "Indicators")
			;

		_slowPeriod = Param(nameof(SlowPeriod), 24)
			.SetDisplay("Slow Period", "Period of slow moving average", "Indicators")
			;

		_enableBuyOpen = Param(nameof(EnableBuyOpen), true)
			.SetDisplay("Enable Buy Open", "Allow opening long positions", "Signals");

		_enableSellOpen = Param(nameof(EnableSellOpen), true)
			.SetDisplay("Enable Sell Open", "Allow opening short positions", "Signals");

		_enableBuyClose = Param(nameof(EnableBuyClose), true)
			.SetDisplay("Enable Buy Close", "Allow closing long positions", "Signals");

		_enableSellClose = Param(nameof(EnableSellClose), true)
			.SetDisplay("Enable Sell Close", "Allow closing short positions", "Signals");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevOsc1 = default;
		_prevOsc2 = default;
		_isWarmup = true;
	}

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

		// Create moving averages
		var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
		var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };

		// Subscribe to candles and bind indicators
		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastMa, slowMa, ProcessCandle)
			.Start();

		// Chart visualization
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fastMa);
			DrawIndicator(area, slowMa);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		// Process only finished candles
		if (candle.State != CandleStates.Finished)
			return;

		// Ensure indicators are formed and trading is allowed
		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var osc = fastValue - slowValue;

		if (_isWarmup)
		{
			_prevOsc1 = osc;
			_prevOsc2 = osc;
			_isWarmup = false;
			return;
		}

		var buySignal = _prevOsc2 > _prevOsc1 && _prevOsc1 < osc;
		var sellSignal = _prevOsc2 < _prevOsc1 && _prevOsc1 > osc;

		if (buySignal)
		{
			if (EnableSellClose && Position < 0)
				BuyMarket();

			if (EnableBuyOpen && Position <= 0)
				BuyMarket();
		}
		else if (sellSignal)
		{
			if (EnableBuyClose && Position > 0)
				SellMarket();

			if (EnableSellOpen && Position >= 0)
				SellMarket();
		}

		_prevOsc2 = _prevOsc1;
		_prevOsc1 = osc;
	}
}