Ver en GitHub

Estrategia Tweezer Top

El Tweezer Top es el espejo de la versión inferior, pero aparece después de un avance. Dos velas comparten casi el mismo máximo, mostrando que los compradores no pudieron superar cierto nivel.

Las pruebas indican un rendimiento anual promedio de aproximadamente 187%. Funciona mejor en el mercado de acciones.

La estrategia abre un corto una vez que la segunda vela confirma el techo, esperando un retroceso a medida que el impulso alcista se detiene.

Un stop ajustado por encima de los máximos gemelos mantiene el riesgo bajo control, y la operación se cierra si el precio sube de vuelta por encima de esa resistencia.

Detalles

  • Criterios de entrada: coincidencia de patrón
  • Largo/Corto: Ambos
  • Criterios de salida: stop-loss o señal opuesta
  • Stops: Sí, basado en porcentaje
  • Valores predeterminados:
    • CandleType = 15 minutos
    • TolerancePercent = 0.1
    • StopLossPercent = 2 La estrategia solo vende. El stop se coloca StopLossPercent por encima del máximo más alto del patrón y la posición se cierra cuando una vela cierra por encima.
  • Filtros:
    • Categoría: Patrón
    • Dirección: Ambos
    • Indicadores: Candlestick
    • Stops: Sí
    • Complejidad: Intermedio
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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>
/// Tweezer Top strategy.
/// While flat it sells after a bullish candle followed by a bearish one whose high is within TolerancePercent of the first high.
/// The stop lies StopLossPercent above the pattern's highest high, and a close beyond it closes the position.
/// </summary>
public class TweezerTopStrategy : Strategy
{
	private readonly StrategyParam<decimal> _tolerancePercent;
	private readonly StrategyParam<decimal> _stopLossPercent;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<ICandleMessage> _candles = [];
	private decimal _stopPrice;

	/// <summary>
	/// How close the two extremes must be, in percent of the first.
	/// </summary>
	public decimal TolerancePercent
	{
		get => _tolerancePercent.Value;
		set => _tolerancePercent.Value = value;
	}

	/// <summary>
	/// Distance of the stop beyond the pattern, in percent.
	/// </summary>
	public decimal StopLossPercent
	{
		get => _stopLossPercent.Value;
		set => _stopLossPercent.Value = value;
	}

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public TweezerTopStrategy()
	{
		_tolerancePercent = Param(nameof(TolerancePercent), 0.1m)
			.SetNotNegative()
			.SetDisplay("Tolerance %", "How close the two extremes must be, in percent of the first", "Pattern");

		_stopLossPercent = Param(nameof(StopLossPercent), 2m)
			.SetNotNegative()
			.SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candles.Clear();
		_stopPrice = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_candles.Clear();
		_stopPrice = default;

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

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

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

		_candles.Add(candle);

		if (_candles.Count > 2)
			_candles.RemoveAt(0);

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (Position < 0)
		{
			if (candle.ClosePrice >= _stopPrice)
				BuyMarket(-Position);

			return;
		}

		if (Position != 0 || _candles.Count < 2)
			return;

		var c0 = _candles[0];
		var c1 = _candles[1];

		if (!(c0.ClosePrice > c0.OpenPrice && c1.ClosePrice < c1.OpenPrice && Math.Abs(c0.HighPrice - c1.HighPrice) <= c0.HighPrice * TolerancePercent / 100m))
			return;

		SellMarket(Volume);
		_stopPrice = Math.Max(c0.HighPrice, c1.HighPrice) * (1 + StopLossPercent / 100m);
	}
}