Auf GitHub ansehen

Strategie Tweezer Top

Der Tweezer Top spiegelt die Bodenversion, erscheint aber nach einem Aufschwung. Zwei Kerzen teilen nahezu dasselbe Hoch und zeigen, dass Käufer nicht über ein bestimmtes Niveau hinaus drücken konnten.

Tests zeigen eine durchschnittliche jährliche Rendite von etwa 187%. Die Strategie funktioniert am besten am Aktienmarkt.

Die Strategie eröffnet eine Short-Position, sobald die zweite Kerze die Decke bestätigt, und erwartet einen Rückzug, wenn der bullische Schwung ins Stocken gerät.

Ein enger Stop oberhalb der Doppelhochs hält das Risiko in Schach, und der Trade wird beendet, wenn der Preis wieder über diesen Widerstand klettert.

Details

  • Einstiegskriterien: Mustererkennung
  • Long/Short: Beide
  • Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
  • Stops: Ja, prozentbasiert
  • Standardwerte:
    • CandleType = 15 Minuten
    • TolerancePercent = 0.1
    • StopLossPercent = 2 Die Strategie verkauft nur. Der Stop liegt StopLossPercent über dem höchsten Hoch des Musters, und die Position schließt, wenn eine Kerze darüber schließt.
  • Filter:
    • Kategorie: Muster
    • Richtung: Beide
    • Indikatoren: Candlestick
    • Stops: Ja
    • Komplexität: Mittel
    • Zeitrahmen: Intraday
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
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);
	}
}