Ver no GitHub

Estratégia de Pivô Simples

Esta estratégia reproduz o consultor especialista "SimplePivot" do MetaTrader 5. Avalia continuamente a relação entre a abertura da barra atual e o nível de pivô da barra anterior, mantendo sempre uma única posição direcional. Quando o viés muda, a estratégia fecha a posição existente e abre imediatamente uma na direção oposta.

Visão geral

  • Regime de mercado: Swing trading sempre no mercado.
  • Instrumentos: Qualquer instrumento que forneça dados de velas para o período de tempo selecionado.
  • Períodos de tempo: Configurável pelo parâmetro Candle Type (padrão velas de 1 hora).
  • Ordens: Ordens de mercado dimensionadas pelo parâmetro Volume.

Como funciona

Cálculo do pivô

  1. Aguardar pelo menos uma vela concluída para inicializar o cálculo.
  2. Calcular o pivô da vela anterior como a média aritmética de seus preços de máxima e mínima.
  3. Reter a máxima e mínima anteriores para que o pivô para a próxima barra possa ser produzido imediatamente quando uma nova vela terminar.

Decisão direcional

  1. O viés padrão é comprado (compra).
  2. Se a vela atual abre abaixo da máxima anterior enquanto permanece acima do pivô, o viés muda para vendido (venda).
  3. Se a direção desejada não mudou em relação à última negociação executada, a posição existente é preservada e nenhuma nova ordem é enviada.

Gestão de posição

  1. Se a direção desejada difere da negociação atual, a posição em execução é encerrada por uma ordem de mercado oposta.
  2. Após encerrar, uma ordem de mercado dimensionada por Volume estabelece a nova exposição direcional.
  3. O processo se repete a cada vela concluída, garantindo que a estratégia esteja sempre comprada ou vendida.

Parâmetros

  • Volume: Tamanho da negociação usado para cada entrada. Também determina o tamanho da ordem de fechamento quando a estratégia muda de direção.
  • Candle Type: Tipo de dados das velas usadas para cálculos de pivô e entrada. O padrão é um período de 1 hora, mas qualquer período disponível pode ser selecionado.

Notas adicionais

  • A lógica reage em velas completamente concluídas (CandleStates.Finished) para evitar sinais repetidos enquanto uma vela ainda está se formando.
  • Nenhum stop ou alvo de lucro é definido; as saídas ocorrem apenas quando a regra de pivô solicita uma mudança de direção.
  • Como a estratégia está sempre no mercado, controles de risco como monitoramento de drawdown máximo ou filtros de sessão devem ser gerenciados externamente, se necessário.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simple pivot strategy that flips position based on the previous bar pivot.
/// </summary>
public class SimplePivotStrategy : Strategy
{
	private enum TradeDirections
	{
		None,
		Long,
		Short,
	}

	private readonly StrategyParam<DataType> _candleType;

	private TradeDirections _lastDirection = TradeDirections.None;
	private decimal _previousHigh;
	private decimal _previousLow;
	private bool _hasPreviousCandle;

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

	public SimplePivotStrategy()
	{

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, CandleType);
	}

	protected override void OnReseted()
	{
		base.OnReseted();

		_lastDirection = TradeDirections.None;
		_previousHigh = 0m;
		_previousLow = 0m;
		_hasPreviousCandle = false;
	}

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

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_hasPreviousCandle)
		{
			// Collect the very first completed candle as the seed for the pivot calculation.
			_previousHigh = candle.HighPrice;
			_previousLow = candle.LowPrice;
			_hasPreviousCandle = true;
			return;
		}

		var pivot = (_previousHigh + _previousLow) / 2m;
		var desiredDirection = TradeDirections.Long;

		// When the new open sits between the previous high and pivot we switch to a short bias.
		if (candle.OpenPrice < _previousHigh && candle.OpenPrice > pivot)
			desiredDirection = TradeDirections.Short;

		if (desiredDirection == _lastDirection && _lastDirection != TradeDirections.None)
		{
			// Keep the existing position when direction has not changed.
			_previousHigh = candle.HighPrice;
			_previousLow = candle.LowPrice;
			return;
		}

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_previousHigh = candle.HighPrice;
			_previousLow = candle.LowPrice;
			return;
		}

		CloseExistingPosition();

		if (desiredDirection == TradeDirections.Long)
		{
			// Enter a long position when the open is below the pivot.
			BuyMarket(Volume);
		}
		else
		{
			// Enter a short position when the open is above the pivot zone.
			SellMarket(Volume);
		}

		_lastDirection = desiredDirection;
		_previousHigh = candle.HighPrice;
		_previousLow = candle.LowPrice;
	}

	private void CloseExistingPosition()
	{
		if (Position > 0)
		{
			// Flip from long to flat before opening the opposite direction.
			SellMarket(Math.Abs(Position));
			_lastDirection = TradeDirections.None;
		}
		else if (Position < 0)
		{
			// Flip from short to flat before opening the opposite direction.
			BuyMarket(Math.Abs(Position));
			_lastDirection = TradeDirections.None;
		}
	}
}