Ver no GitHub

Estratégia de BADX ADX Bollinger

Visão Geral

Esta estratégia reproduz o consultor especializado BADX do MetaTrader usando a API de alto nível do StockSharp. Combina o Average Directional Index (ADX) com Bollinger Bands para negociar condições de range: quando o ADX cai abaixo de um limiar configurável e o preço toca a banda exterior, a estratégia desfaz o movimento esperando uma reversão à média. Todas as ordens de proteção, incluindo stop-loss, take-profit e trailing stop opcional, são gerenciadas automaticamente pelo StartProtection.

Como Funciona

  1. Assina a série de candles configurada e alimenta um indicador AverageDirectionalIndex e BollingerBands através de bindings de alto nível.
  2. Para cada candle finalizado o callback recebe o valor ADX bem como os envelopes superior e inferior de Bollinger.
  3. Se o ADX estiver abaixo de AdxLevel, o mercado é considerado sem tendência:
    • Quando o preço de fechamento está abaixo da banda inferior e não há posição aberta, a estratégia compra a mercado.
    • Quando o preço de fechamento está acima da banda superior e não há posição aberta, a estratégia vende a mercado.
  4. O gerenciamento de risco converte distâncias em pips em offsets de preço absoluto. Stop-loss, take-profit e parâmetros de trailing (se habilitados) são aplicados imediatamente após as entradas pelo gerenciador de proteção.
  5. Apenas uma posição pode estar ativa de cada vez. As saídas ocorrem através de ordens de proteção ou ajustes de trailing stop.

Parâmetros

  • CandleType (DataType): Período usado para os cálculos do indicador. Padrão: candles de 15 minutos.
  • AdxPeriod (int): Período de médias para o indicador ADX. Padrão: 30.
  • AdxLevel (decimal): Valor ADX máximo que ainda qualifica como mercado em range. Padrão: 20.
  • BollingerPeriod (int): Período para a média móvel das Bollinger Bands. Padrão: 10.
  • BollingerDeviation (decimal): Multiplicador de desvio padrão para as Bollinger Bands. Padrão: 1.5.
  • StopLossPips (decimal): Distância de stop-loss medida em pips. Padrão: 50.
  • TakeProfitPips (decimal): Distância de take-profit medida em pips. Padrão: 50.
  • TrailingStopPips (decimal): Distância do trailing stop em pips. Padrão: 5.
  • TrailingStepPips (decimal): Melhoria mínima de preço em pips antes de o trailing stop ser ajustado. Padrão: 5.

Uso

  1. Anexar a estratégia a um instrumento e configurar os parâmetros desejados.
  2. Iniciar a estratégia. Ela assinará automaticamente o stream de candles necessário, construirá os indicadores e configurará as ordens de proteção.
  3. Monitorar os trades na área do gráfico: candles, as Bollinger Bands e as ordens executadas são visualizadas quando a plataforma suporta gráficos.
  4. Ajustar os parâmetros de risco (stop-loss, take-profit, distâncias de trailing) para se adequar à volatilidade do instrumento ou preferências pessoais.

Notas

  • Apenas candles terminados são processados para evitar entradas prematuras.
  • O tamanho do pip é derivado do PriceStep do instrumento; quando o instrumento usa 3 ou 5 dígitos decimais, o pip é ajustado por um fator de dez, imitando o consultor especializado original.
  • A estratégia mantém Volume em 1 por padrão. Modificar a propriedade Volume da classe base para corresponder ao tamanho de trade preferido.
  • Todos os comentários inline no código-fonte são escritos em inglês de acordo com as diretrizes do repositório.
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>
/// BADX ADX Bollinger strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class BadxAdxBollingerStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public BadxAdxBollingerStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}