Estratégia de Pairs Trading

Visão Geral

PairsTradingStrategy é uma estratégia de pairs trading baseada em arbitragem estatística entre dois instrumentos relacionados. Acompanha o spread entre os preços de dois ativos e abre posições quando o spread se desvia significativamente da média, esperando uma reversão para a média.

Componentes Principais

A estratégia herda de Strategy e utiliza parâmetros para configuração:

public class PairsTradingStrategy : Strategy
{
	private readonly StrategyParam<int> _spreadLength;
	private readonly StrategyParam<decimal> _entryThreshold;
	private readonly StrategyParam<decimal> _exitThreshold;
	private readonly StrategyParam<DataType> _candleType;

	// Últimos preços para cada instrumento
	private decimal? _lastPrice1;
	private decimal? _lastPrice2;
}

Parâmetros da Estratégia

A estratégia permite personalizar os seguintes parâmetros:

  • SpreadLength - período para calcular a média e o desvio padrão do spread (predefinição 20)
  • EntryThreshold - limiar de Z-Score para entrar numa posição (predefinição 2.0)
  • ExitThreshold - limiar de Z-Score para sair de uma posição (predefinição 0.5)
  • CandleType - tipo de vela com que trabalhar (predefinição 5 minutos)

Todos os parâmetros estão disponíveis para otimização com intervalos de valores especificados.

Inicialização da Estratégia

No método OnStarted2, são criados indicadores e configuradas subscrições de velas para dois instrumentos:

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

	// Obter dois instrumentos para pairs trading
	var securities = GetWorkingSecurities().ToArray();
	if (securities.Length < 2)
		throw new InvalidOperationException("Dois instrumentos devem ser especificados.");

	var sec1 = securities[0].sec;
	var sec2 = securities[1].sec;

	// Indicadores para calcular a média e o desvio padrão do spread
	var sma = new SimpleMovingAverage { Length = SpreadLength };
	var stdDev = new StandardDeviation { Length = SpreadLength };

	_lastPrice1 = null;
	_lastPrice2 = null;

	// Subscrever velas do primeiro instrumento
	SubscribeCandles(CandleType, security: sec1)
		.Bind(c =>
		{
			if (c.State != CandleStates.Finished)
				return;

			_lastPrice1 = c.ClosePrice;
		})
		.Start();

	// Subscrever velas do segundo instrumento com processamento do spread
	SubscribeCandles(CandleType, security: sec2)
		.Bind(c =>
		{
			if (c.State != CandleStates.Finished)
				return;

			_lastPrice2 = c.ClosePrice;

			if (_lastPrice1 == null)
				return;

			ProcessSpread(_lastPrice1.Value, _lastPrice2.Value, sma, stdDev);
		})
		.Start();
}

Processamento do Spread

O método ProcessSpread calcula o Z-Score do spread e gera sinais de negociação:

private void ProcessSpread(decimal price1, decimal price2,
	SimpleMovingAverage sma, StandardDeviation stdDev)
{
	// Calcular o spread como diferença de preços
	var spread = price1 - price2;

	// Processar indicadores
	var smaValue = sma.Process(new DecimalIndicatorValue(sma, spread));
	var devValue = stdDev.Process(new DecimalIndicatorValue(stdDev, spread));

	if (!sma.IsFormed || !stdDev.IsFormed)
		return;

	if (!IsFormedAndOnlineAndAllowTrading())
		return;

	var mean = smaValue.ToDecimal();
	var dev = devValue.ToDecimal();

	if (dev == 0)
		return;

	// Calcular Z-Score: desvio do spread face à média em unidades de desvio padrão
	var zScore = (spread - mean) / dev;

	// Spread demasiado alto: vender o primeiro instrumento, comprar o segundo
	if (zScore > EntryThreshold && Position >= 0)
	{
		SellMarket(Volume + Math.Abs(Position));
	}
	// Spread demasiado baixo: comprar o primeiro instrumento, vender o segundo
	else if (zScore < -EntryThreshold && Position <= 0)
	{
		BuyMarket(Volume + Math.Abs(Position));
	}
	// Reversão para a média: fechar posição
	else if (Math.Abs(zScore) < ExitThreshold && Position != 0)
	{
		ClosePosition();
	}
}

Lógica de Negociação

  • Sinal de venda: o Z-Score do spread excede o limiar de entrada (predefinição 2.0) quando não existe posição curta
  • Sinal de compra: o Z-Score do spread fica abaixo do limiar de entrada negativo (predefinição -2.0) quando não existe posição longa
  • Fechar posição: o valor absoluto do Z-Score desce abaixo do limiar de saída (predefinição 0.5), sinalizando que o spread está a reverter para a média

Funcionalidades

  • A estratégia trabalha com dois instrumentos obtidos através do método GetWorkingSecurities()
  • O spread é calculado como a diferença dos preços de fecho das velas de dois instrumentos
  • O Z-Score é usado para normalizar o desvio do spread face à média
  • A estratégia implementa o conceito clássico de reversão à média
  • A estratégia trabalha apenas com velas concluídas
  • A otimização de parâmetros é suportada para encontrar definições ideais da estratégia