Auf GitHub ansehen

S7 Up Bot-Strategie

Ausbruchsystem, das nach nahezu gleichen Hochs oder Tiefs sucht, gefolgt von einer scharfen Preisbewegung. Wenn zwei aufeinanderfolgende Tiefs fast gleich sind und der Preis um Span Price steigt, geht der Bot long. Es geht short, wenn sich zwei Hochs angleichen und der Preis um Span Price fällt. Positionen werden mit optionalen Take-Profit-, Stop-Loss-, Trailing-Stop- und Frühaustiegsfunktionen geschützt.

Details

  • Einstiegskriterien:
    • Kauf: Differenz zwischen aktuellem und vorherigem Tief liegt unter HL Divergence und der Preis liegt Span Price über dem Tief.
    • Verkauf: Differenz zwischen aktuellem und vorherigem Hoch liegt unter HL Divergence und der Preis liegt Span Price unter dem Hoch.
  • Long/Short: Beide.
  • Ausstiegskriterien:
    • Take-Profit oder Stop-Loss.
    • Trailing-Stop oder Null-Trailing-Anpassung.
    • Frühaustieg, wenn der Preis das vorherige Hoch/Tief kreuzt (Exit At Extremum) oder sich dem Umkehrniveau nähert (Exit At Reversal).
  • Stops: Absolute Take-Profit und Stop-Loss mit optionalem Trailing.
  • Filter: Keine.

Parameter

  • Take Profit – Gewinnziel in Preiseinheiten.
  • Stop Loss – Verlustlimit in Preiseinheiten, 0 für automatischen extremwertbasierten Stop.
  • HL Divergence – maximal zulässige Differenz zwischen zwei aufeinanderfolgenden Hochs oder Tiefs.
  • Span Price – Abstand vom Extremwert zum Preis für den Einstieg.
  • Max Trades – maximale gleichzeitige Trades.
  • Use Trailing Stop – Trailing-Stop-Mechanismus aktivieren.
  • Trail Stop – Trailing-Stop-Abstand.
  • Zero Trailing – Stop in Richtung Preis bewegen, sobald Position profitabel ist.
  • Step Trailing – minimaler Schritt zur Anpassung des Null-Trailings.
  • Exit At Extremum – schließen, wenn Preis das vorherige Hoch/Tief kreuzt.
  • Exit At Reversal – schließen, wenn Preis sich dem gegenüberliegenden Extremwert nähert.
  • Span To Revers – Abstand vom Extremwert zum Auslösen des Umkehrausstiegs.
  • Candle Type – Zeitrahmen für die Analyse.
  • Order Volume – Menge pro Trade.
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>
/// S7 Up Bot breakout strategy.
/// Opens long after double bottom and short after double top.
/// </summary>
public class S7UpBotStrategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _hlDivergence;
	private readonly StrategyParam<decimal> _spanPrice;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevLow;
	private decimal _prevHigh;
	private decimal _entryPrice;
	private decimal _stopPrice;
	private decimal _takeProfitPrice;
	private bool _isLong;
	private bool _inPosition;

	public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
	public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
	public decimal HlDivergence { get => _hlDivergence.Value; set => _hlDivergence.Value = value; }
	public decimal SpanPrice { get => _spanPrice.Value; set => _spanPrice.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public S7UpBotStrategy()
	{
		_takeProfit = Param(nameof(TakeProfit), 500m)
			.SetDisplay("Take Profit", "Absolute take profit", "Risk");

		_stopLoss = Param(nameof(StopLoss), 300m)
			.SetDisplay("Stop Loss", "Absolute stop loss", "Risk");

		_hlDivergence = Param(nameof(HlDivergence), 100m)
			.SetGreaterThanZero()
			.SetDisplay("HL Divergence", "Max difference between highs or lows", "General");

		_spanPrice = Param(nameof(SpanPrice), 50m)
			.SetGreaterThanZero()
			.SetDisplay("Span Price", "Distance from extreme to price", "General");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevLow = 0m;
		_prevHigh = 0m;
		_entryPrice = 0m;
		_stopPrice = 0m;
		_takeProfitPrice = 0m;
		_isLong = false;
		_inPosition = false;
	}

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

		_prevLow = 0m;
		_prevHigh = 0m;
		_inPosition = false;

		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;

		var price = candle.ClosePrice;

		if (_inPosition)
			ManagePosition(candle, price);

		if (!_inPosition && _prevLow != 0m && _prevHigh != 0m)
			CheckEntry(candle, price);

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

	private void CheckEntry(ICandleMessage candle, decimal price)
	{
		// Double bottom: consecutive similar lows + bounce
		if (Math.Abs(candle.LowPrice - _prevLow) < HlDivergence &&
			price - candle.LowPrice > SpanPrice)
		{
			if (Position <= 0)
				BuyMarket();
			_inPosition = true;
			_isLong = true;
			_entryPrice = price;
			_stopPrice = price - StopLoss;
			_takeProfitPrice = price + TakeProfit;
		}
		// Double top: consecutive similar highs + drop
		else if (Math.Abs(candle.HighPrice - _prevHigh) < HlDivergence &&
			candle.HighPrice - price > SpanPrice)
		{
			if (Position >= 0)
				SellMarket();
			_inPosition = true;
			_isLong = false;
			_entryPrice = price;
			_stopPrice = price + StopLoss;
			_takeProfitPrice = price - TakeProfit;
		}
	}

	private void ManagePosition(ICandleMessage candle, decimal price)
	{
		if (_isLong)
		{
			if (candle.HighPrice >= _takeProfitPrice || candle.LowPrice <= _stopPrice)
			{
				SellMarket();
				_inPosition = false;
			}
		}
		else
		{
			if (candle.LowPrice <= _takeProfitPrice || candle.HighPrice >= _stopPrice)
			{
				BuyMarket();
				_inPosition = false;
			}
		}
	}
}