Ver no GitHub

Estratégia Exp de Trailing ATR

Este exemplo demonstra como gerenciar posições existentes com um trailing stop baseado no indicador Average True Range (ATR). A estratégia não gera sinais de entrada; ela apenas ajusta o nível de saída de uma posição aberta de acordo com a volatilidade do mercado.

Como funciona

  1. A estratégia se inscreve em dados de velas de um período escolhido.
  2. Um indicador AverageTrueRange é calculado em cada vela.
  3. Para posições compradas, o nível de stop é movido para cima para Close - ATR * BuyFactor.
  4. Para posições vendidas, o nível de stop é movido para baixo para Close + ATR * SellFactor.
  5. Quando o preço cruza o nível de trailing, a posição é fechada a mercado.

O trailing stop apenas se move na direção do trade e nunca recua, fornecendo uma saída ajustada à volatilidade.

Parâmetros

Nome Descrição
AtrPeriod Período de cálculo do ATR.
BuyFactor Multiplicador aplicado ao ATR ao fazer trailing de uma posição comprada.
SellFactor Multiplicador aplicado ao ATR ao fazer trailing de uma posição vendida.
CandleType Período das velas usadas para análise.

Notas de uso

  • Anexar a estratégia a um instrumento e abrir uma posição manualmente ou a partir de outra estratégia.
  • Adequada para gestão de risco onde as saídas são controladas separadamente das entradas.
  • A área do gráfico exibe velas, valores de ATR e negociações executadas para análise visual.

Referências

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>
/// ATR trailing stop strategy. Enters on EMA crossover, exits when ATR trailing stop is hit.
/// </summary>
public class ExpAtrTrailingStrategy : Strategy
{
	private readonly StrategyParam<int> _stdPeriod;
	private readonly StrategyParam<decimal> _stdFactor;
	private readonly StrategyParam<int> _fastEma;
	private readonly StrategyParam<int> _slowEma;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _longTrail;
	private decimal _shortTrail;
	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int StdPeriod { get => _stdPeriod.Value; set => _stdPeriod.Value = value; }
	public decimal StdFactor { get => _stdFactor.Value; set => _stdFactor.Value = value; }
	public int FastEma { get => _fastEma.Value; set => _fastEma.Value = value; }
	public int SlowEma { get => _slowEma.Value; set => _slowEma.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ExpAtrTrailingStrategy()
	{
		_stdPeriod = Param(nameof(StdPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("StdDev Period", "StdDev period", "Indicators");

		_stdFactor = Param(nameof(StdFactor), 2m)
			.SetDisplay("StdDev Factor", "StdDev multiplier for trailing stop", "Indicators");

		_fastEma = Param(nameof(FastEma), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA for entry", "Indicators");

		_slowEma = Param(nameof(SlowEma), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA for entry", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_longTrail = 0;
		_shortTrail = 0;
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastEma };
		var slow = new ExponentialMovingAverage { Length = SlowEma };
		var stdDev = new StandardDeviation { Length = StdPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, stdDev, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal stdVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		// Trail management
		if (Position > 0)
		{
			var stop = candle.ClosePrice - stdVal * StdFactor;
			if (stop > _longTrail)
				_longTrail = stop;

			if (candle.LowPrice <= _longTrail)
			{
				SellMarket();
				_longTrail = 0;
			}
		}
		else if (Position < 0)
		{
			var stop = candle.ClosePrice + stdVal * StdFactor;
			if (stop < _shortTrail || _shortTrail == 0)
				_shortTrail = stop;

			if (candle.HighPrice >= _shortTrail)
			{
				BuyMarket();
				_shortTrail = 0;
			}
		}

		// Entry signals
		if (_hasPrev && stdVal > 0)
		{
			var crossUp = _prevFast <= _prevSlow && fast > slow;
			var crossDown = _prevFast >= _prevSlow && fast < slow;

			if (crossUp && Position <= 0)
			{
				BuyMarket();
				_longTrail = candle.ClosePrice - stdVal * StdFactor;
				_shortTrail = 0;
			}
			else if (crossDown && Position >= 0)
			{
				SellMarket();
				_shortTrail = candle.ClosePrice + stdVal * StdFactor;
				_longTrail = 0;
			}
		}

		_prevFast = fast;
		_prevSlow = slow;
		_hasPrev = true;
	}
}