Ver no GitHub

Estratégia de Histograma do Oscilador MA

Visão geral

Esta estratégia é uma tradução do consultor especialista MQL5 Exp_MAOscillatorHist.mq5. Utiliza a diferença entre uma Média Móvel Simples (SMA) rápida e uma lenta para formar um oscilador. Os sinais de negociação são gerados quando o oscilador forma mínimos ou máximos locais, que são interpretados como potenciais reversões de tendência.

Lógica de negociação

  1. Duas SMAs são calculadas no período de velas selecionado:
    • SMA rápida com um período mais curto.
    • SMA lenta com um período mais longo.
  2. O valor do oscilador é a SMA rápida menos a SMA lenta.
  3. A estratégia acompanha os três últimos valores do oscilador. Um mínimo local ocorre quando o valor mais antigo é maior que o anterior e o anterior é menor que o atual. Um máximo local é o oposto.
  4. Quando um mínimo local é detetado:
    • Fechar posições vendidas (se permitido).
    • Abrir uma nova posição comprada (se permitido).
  5. Quando um máximo local é detetado:
    • Fechar posições compradas (se permitido).
    • Abrir uma nova posição vendida (se permitido).

Parâmetros

Parâmetro Descrição
Fast Period Período da SMA rápida.
Slow Period Período da SMA lenta.
Enable Buy Open Se verdadeiro, posições compradas podem ser abertas.
Enable Sell Open Se verdadeiro, posições vendidas podem ser abertas.
Enable Buy Close Se verdadeiro, posições compradas podem ser fechadas em sinais opostos.
Enable Sell Close Se verdadeiro, posições vendidas podem ser fechadas em sinais opostos.
Candle Type Período das velas utilizadas para os cálculos.

Notas

  • A estratégia utiliza a API de alto nível do StockSharp com SubscribeCandles e ligação de indicadores.
  • StartProtection está ativado com ordens de mercado para execução mais segura.
  • Nenhuma versão Python disponível.
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;
	}
}