Ver no GitHub

Estratégia de Trend Is Your Friend

Visão geral

A estratégia Trend Is Your Friend é um sistema de seguimento de tendência multi-período inspirado no consultor especialista MetaTrader original. Alinha o momentum intradiário com um filtro MACD de período superior, enquanto o risco é gerenciado através de saídas de Bandas de Bollinger, alvos clássicos de stop-loss e take-profit, um bloqueio de break-even opcional e gerenciamento de trailing stop.

A estratégia trabalha em um período base configurável (padrão: 1 hora) e analisa a estrutura de velas para um padrão de momentum de curto prazo: uma vela baixista seguida de uma vela altista mais forte para negociações longas, ou o inverso para negociações curtas. Esses padrões devem concordar com um filtro de tendência de média móvel e um sinal MACD mensal antes de um posição ser aberta.

Lógica de entrada

  1. Calcular uma EMA rápida e uma LWMA lenta no período de entrada.
  2. Rastrear as últimas duas velas concluídas para formar um padrão de momentum:
    • Setup longo: a vela de duas barras atrás é baixista, a vela anterior é altista e de maior magnitude.
    • Setup curto: a vela de duas barras atrás é altista, a vela anterior é baixista e de menor magnitude.
  3. Confirmar o setup com o filtro de tendência de média móvel (MA rápida acima da MA lenta para negociações longas, abaixo para curtas).
  4. Confirmar a tendência de longo prazo com um sinal MACD calculado no período superior (padrão: mensal). A linha MACD deve estar acima da linha de sinal para negociações longas e abaixo para curtas.
  5. Quando todos os filtros se alinham, abrir uma posição a mercado com o volume configurado.

Lógica de saída

  • Saída por Bandas de Bollinger: posições longas são fechadas quando o preço fecha acima da banda superior; posições curtas quando o preço fecha abaixo da banda inferior.
  • Take-profit / stop-loss: distâncias fixas opcionais medidas em pips. A implementação converte pips para distância de preço via o passo de preço do ativo.
  • Break-even: opcional, move o stop de proteção para (ou além do) preço de entrada após um limiar de lucro configurável ter sido atingido.
  • Trailing stop: opcional, é ativado após um limiar de lucro e segue o preço por uma distância fixa de pip. O trailing stop compartilha o mesmo armazenamento com o nível de break-even.

Parâmetros

Nome Descrição Padrão
Entry Candle Tipo de vela para lógica de entrada 1 hora
MACD Candle Período superior usado para filtro MACD 30 dias
Fast MA Comprimento da EMA rápida 8
Slow MA Comprimento da LWMA lenta 20
Bollinger Length Período das Bandas de Bollinger 20
Bollinger Width Multiplicador de desvio padrão das Bandas de Bollinger 2.0
Stop Loss (pips) Distância de stop de proteção 20
Take Profit (pips) Distância do alvo de lucro 50
Use Break-Even Habilitar ajuste de break-even true
Break-Even Trigger Lucro (pips) necessário para mover o stop 10
Break-Even Offset Offset aplicado ao stop de break-even 5
Use Trailing Habilitar trailing stop true
Trailing Activation Lucro (pips) necessário para ativar o trailing 40
Trailing Distance Distância (pips) mantida pelo trailing stop 40

Notas

  • A estratégia armazena apenas as duas últimas velas concluídas para evitar buffers históricos pesados.
  • Os dados MACD são subscritos do período superior configurado com agregação habilitada, permitindo que sinais mensais sejam construídos a partir de dados diários quando necessário.
  • A conversão de pip para preço usa o passo de preço do ativo. Instrumentos com definições de pip não-padrão podem requerer ajuste de parâmetros.
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 TrendIsYourFriendStrategy : 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 TrendIsYourFriendStrategy()
	{
		_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;
	}
}