Ver no GitHub

Estratégia da Linha da Bússola

Esta estratégia replica o especialista CompassLine mesclando dois filtros complementares:

  • Follow Line — uma trilha de ruptura de bandas Bollinger opcionalmente deslocada em ATR. Quando o preço fecha fora das bandas, a trilha se estende na direção do rompimento e nunca recua enquanto a tendência persistir.
  • Bússola — uma transformação logística do preço médio em relação à máxima mais alta e à mínima mais baixa na janela de média móvel. O sinal bruto é duplamente suavizado (média triangular) para produzir um estado estável de alta/baixa.

Uma posição é aberta somente quando ambos os filtros concordam com a tendência. Filtragem de tempo opcional e paradas de proteção espelham a lógica MQL.

Detalhes

  • Critérios de entrada:
    • A linha de acompanhamento deve apontar para cima (fechamento recente acima da banda superior) para posições compradas ou para baixo (fechamento recente abaixo da faixa inferior) para vendas. O deslocamento ATR pode ser alternado com UseAtrFilter.
    • O estado da bússola (com base em CompassPeriod) deve ser positivo para posições compradas ou negativo para posições vendidas após a fase de suavização dupla.
    • A negociação é executada somente quando o filtro de sessão opcional (UseTimeFilter com Session em HHmm-HHmm) permite.
  • Longo/Curto: Ambas as direções são suportadas.
  • Critérios de saída:
    • CloseMode = None mantém a posição até que ocorra uma entrada oposta ou parada protetora.
    • CloseMode = BothIndicators fecha quando Seguir Linha e Bússola invertem a direção simultaneamente.
    • CloseMode = FollowLineOnly sai quando Follow Line vira contra a posição.
    • CloseMode = CompassOnly sai quando a bússola muda de polaridade.
  • Paradas: distâncias TakeProfit e StopLoss (em etapas de segurança) são aplicadas após cada entrada quando maiores que zero.
  • Valores padrão:
    • FollowBbPeriod = 21
    • FollowBbDeviation = 1
    • FollowAtrPeriod = 5
    • UseAtrFilter = falso
    • CompassPeriod = 30 (comprimento de suavização = round(CompassPeriod / 3))
    • CloseMode = Nenhum
    • UseTimeFilter = falso
    • Session = "0000-2400"
    • TakeProfit = 0
    • StopLoss = 0
    • CandleType = TimeSpan.FromMinutes(15)
  • Filtros:
    • Categoria: Tendência
    • Direção: Ambos
    • Indicadores: Bollinger Bandas, ATR, Média móvel triangular
    • Paradas: Opcional
    • Complexidade: Intermediário
    • Prazo: intradiário
    • Sazonalidade: Não
    • Redes Neurais: Não
    • Divergência: Não
    • Nível de risco: Médio

Notas adicionais

  • A suavização do Compass usa uma janela triangular igual a round(CompassPeriod / 3), correspondendo de perto à implementação original do indicador.
  • Sequências de sessão como 0930-1600 restringem a negociação à janela especificada enquanto ainda atualizam os estados do indicador fora da sessão.
  • As ordens de proteção reutilizam os auxiliares de alto nível de StockSharp para que a lógica seja compatível com os módulos de gerenciamento de risco do portfólio.
using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Compass Line strategy: BB + RSI trend filter.
/// Buys when close < lower BB and RSI < 45.
/// Sells when close > upper BB and RSI > 55.
/// </summary>
public class CompassLineStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _bbPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int BbPeriod
	{
		get => _bbPeriod.Value;
		set => _bbPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public CompassLineStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

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

		var bb = new BollingerBands { Length = BbPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		decimal? prevClose = null;
		decimal? prevLower = null;
		decimal? prevUpper = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, rsi, (candle, bbVal, rsiVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var bbv = (BollingerBandsValue)bbVal;
				if (bbv.UpBand is not decimal upper || bbv.LowBand is not decimal lower)
					return;

				if (rsiVal.IsEmpty)
					return;

				var rsiDec = rsiVal.GetValue<decimal>();
				var close = candle.ClosePrice;

				if (prevClose.HasValue && prevLower.HasValue && prevUpper.HasValue)
				{
					var crossBelowLower = prevClose.Value > prevLower.Value && close <= lower;
					var crossAboveUpper = prevClose.Value < prevUpper.Value && close >= upper;

					if (crossBelowLower && rsiDec < 45m && Position <= 0)
						BuyMarket();
					else if (crossAboveUpper && rsiDec > 55m && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevLower = lower;
				prevUpper = upper;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, bb);
			DrawOwnTrades(area);
		}
	}
}