Ver no GitHub

Estratégia de Linear Regression Channel (Fibo)

Visão geral

Esta estratégia é a conversão StockSharp do consultor especialista MetaTrader "linear regression channel". Opera na direção da tendência linear de período superior confirmada por um conjunto de médias móveis ponderadas, leituras de Momentum e um filtro MACD mensal. As regras de gestão de dinheiro replicam o comportamento original com metas de lucro flutuantes, trailing de ganhos acumulados, proteção de ponto de equilíbrio e um stop de capital.

Lógica de trading

  1. Período principal – tipo de candle configurável (padrão 15 minutos). Todos os cálculos de sinal são executados neste período.
  2. Filtro de tendência – uma LWMA rápida e uma lenta calculadas sobre o preço típico. Sinais longos requerem que a LWMA rápida esteja acima da lenta; sinais curtos requerem o oposto.
  3. Confirmação de Momentum – o indicador de Momentum é avaliado em um período superior que espelha o mapeamento original do MetaTrader (M1→M15, M5→M30, M15→H1, M30→H4, H1→D1, H4→W1, D1→MN1). Os últimos três valores de Momentum são convertidos para a distância absoluta do nível 100. Uma configuração longa precisa que qualquer uma das três distâncias exceda o limiar altista, enquanto uma configuração curta precisa que qualquer uma das três exceda o limiar baixista.
  4. Viés MACD mensal – candles mensais alimentam um filtro MACD(12,26,9). Trades longos só são permitidos quando a linha principal do MACD está acima de sua linha de sinal; trades curtos requerem a relação oposta.
  5. Condição de entrada – quando todos os filtros se alinham e o trading é permitido, a estratégia abre uma ordem de mercado na direção correspondente. A posição atual é fechada e revertida quando um sinal oposto é produzido.

Gestão de risco e trades

  • Stop-loss / take-profit fixo – distâncias são definidas em pontos do instrumento e aplicadas a cada entrada. Se o máximo/mínimo do candle perfurar esses níveis, a posição é fechada.
  • Trailing stop – opcional; ativa quando a posição ganha uma quantidade configurável de pontos e segue o melhor preço com o offset especificado.
  • Ponto de equilíbrio – opcional; após o preço avançar pela distância de acionamento, o nível de stop é movido para o preço de entrada mais/menos um offset para garantir lucros.
  • Take-profit de lucro flutuante – meta monetária opcional. Quando o lucro flutuante líquido (expresso em moeda da conta) excede o limiar, todas as posições são fechadas.
  • Take-profit baseado em percentual – meta opcional baseada no capital inicial no momento em que a estratégia inicia.
  • Trailing monetário – uma vez que o lucro flutuante atinge o acionador, a estratégia registra o lucro máximo. Se o lucro recuar pelo valor de stop especificado, a posição é fechada.
  • Stop de capital – proteção contra drawdown opcional. Enquanto a posição está perdendo, se a perda flutuante exceder uma porcentagem do pico de capital observado, a estratégia liquida a posição.

Parâmetros

Nome Descrição
Candle Type Período principal para geração de sinais.
Fast LWMA / Slow LWMA Períodos para as médias móveis ponderadas linealmente rápida e lenta.
Momentum Length Comprimento de retrospectiva do Momentum no período superior.
Momentum Buy Threshold / Momentum Sell Threshold Distância absoluta mínima de 100 necessária para confirmação de Momentum altista/baixista.
Take Profit (points) / Stop Loss (points) Distâncias de proteção expressas em pontos do instrumento.
Use Trailing, Trailing Activation, Trailing Offset Configuração do trailing stop.
Use Break-even, Break-even Trigger, Break-even Offset Parâmetros de lógica de ponto de equilíbrio.
Max Trades Número máximo de entradas sequenciais permitidas durante a execução.
Order Volume Volume base para ordens de mercado.
Use Money TP, Money Take Profit Take-profit monetário flutuante.
Use Percent TP, Percent Take Profit Take-profit calculado como percentual do capital inicial.
Enable Money Trailing, Money Trailing Trigger, Money Trailing Stop Trailing do lucro flutuante.
Use Equity Stop, Equity Risk % Proteção de stop-loss baseada em capital.

Notas

  • A estratégia mantém apenas uma posição líquida (longa ou curta) e reverte quando um sinal oposto chega.
  • As assinaturas de Momentum e MACD adicionam automaticamente os períodos superiores necessários ao feed de dados através de GetWorkingSecurities().
  • Todos os comentários dentro do código estão em inglês conforme 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;

public class LinearRegressionChannelFibStrategy : 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 LinearRegressionChannelFibStrategy()
	{
		_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;
	}
}