Ver en GitHub

Estrategia TCPivot Stop

Esta estrategia opera rupturas a través de la línea de pivote diaria. Calcula los niveles de pivote clásicos de los operadores de piso a partir del máximo, mínimo y cierre del día anterior. Se abre una posición larga cuando el precio de cierre cruza por encima del pivote. Se abre una posición corta cuando el precio de cierre cruza por debajo del pivote.

Tras la entrada, el sistema utiliza uno de los niveles de soporte o resistencia tanto como objetivo de beneficio como de stop loss. El nivel se selecciona mediante el parámetro Target Level:

  • 1 – utiliza Support1/Resistance1.
  • 2 – utiliza Support2/Resistance2.
  • 3 – utiliza Support3/Resistance3.

Si Intraday Only está activado, todas las posiciones abiertas se cierran a las 23:00 hora de la plataforma.

Detalles

  • Criterios de entrada
    • Largo: cierre anterior ≤ pivote y cierre actual > pivote.
    • Corto: cierre anterior ≥ pivote y cierre actual < pivote.
  • Criterios de salida
    • Largo: cierre ≥ nivel de resistencia seleccionado o cierre ≤ nivel de soporte seleccionado.
    • Corto: cierre ≤ nivel de soporte seleccionado o cierre ≥ nivel de resistencia seleccionado.
    • Si Intraday Only es verdadero, todas las posiciones se cierran a las 23:00.
  • Indicadores: solo cálculo clásico de pivote.
  • Marco temporal: configurable; velas de 5 minutos por defecto.
  • Stops: stop-loss y take-profit basados en el nivel de pivote elegido.
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>
/// Pivot-based breakout strategy.
/// Buys when close crosses above calculated pivot, sells when it crosses below.
/// Uses support/resistance levels for exits.
/// </summary>
public class TcpPivotStopStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

	private decimal _pivot;
	private decimal _res1, _sup1;
	private decimal _prevClose;
	private decimal _prevHigh;
	private decimal _prevLow;
	private int _barCount;

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

	public TcpPivotStopStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Time frame", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_pivot = _res1 = _sup1 = 0;
		_prevClose = _prevHigh = _prevLow = 0;
		_barCount = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
	}

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

		_barCount++;

		// Recalculate pivot every 12 bars (~2 days for 4h candles)
		if (_barCount % 12 == 0 && _prevHigh > 0)
		{
			_pivot = (_prevHigh + _prevLow + _prevClose) / 3m;
			_res1 = 2m * _pivot - _prevLow;
			_sup1 = 2m * _pivot - _prevHigh;
		}

		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;

		var close = candle.ClosePrice;

		if (_pivot > 0 && _prevClose > 0)
		{
			// Cross above pivot => long
			if (_prevClose <= _pivot && close > _pivot && Position <= 0)
			{
				if (Position < 0) BuyMarket();
				BuyMarket();
			}
			// Cross below pivot => short
			else if (_prevClose >= _pivot && close < _pivot && Position >= 0)
			{
				if (Position > 0) SellMarket();
				SellMarket();
			}
			// Exit long at resistance or support
			else if (Position > 0 && (close >= _res1 || close <= _sup1))
			{
				SellMarket();
			}
			// Exit short at support or resistance
			else if (Position < 0 && (close <= _sup1 || close >= _res1))
			{
				BuyMarket();
			}
		}

		_prevClose = close;
	}
}