Auf GitHub ansehen

LazyBot V1-Strategie

Überblick

LazyBot V1 ist eine tägliche Breakout-Strategie, die vom ursprünglichen MetaTrader 5 Expert Advisor übernommen wurde. An jedem Handelstag platziert es ein Paar ausstehender Stop-Orders um die Preisspanne des Vortages herum und verwendet einen Trailing-Stop, um offene Positionen zu schützen. Die Konvertierung nutzt das High-Level-StockSharp API mit Kerzenabonnements und automatischer Auftragsverwaltung.

Handelslogik

  1. Warten Sie auf eine abgeschlossene Kerze des konfigurierten Zeitrahmens (standardmäßig täglich).
  2. Stellen Sie an einem neuen Tag optional sicher, dass die aktuelle Serverzeit innerhalb des zulässigen Handelsfensters liegt, und überspringen Sie Wochenenden.
  3. Stornieren Sie alle bestehenden Breakout-Pending-Orders, die durch die Strategie erstellt wurden.
  4. Platzieren Sie einen Kaufstopp über dem Hoch des Vortages und einen Verkaufsstopp unter dem Tief des Vortages. Der Parameter Breakout Offset (pips) fügt beiden Ausbruchsebenen zusätzliche Distanz hinzu.
  5. Wenn eine Order ausgelöst wird, halten Sie den schützenden Stop-Loss auf einem festen Abstand und verfolgen ihn immer dann, wenn der Preis zu Gunsten des Handels um mehr als den konfigurierten Pip-Abstand steigt.
  6. Berechnen Sie das Volumen für die nächsten Aufträge neu, indem Sie entweder eine feste Losgröße oder das risikobasierte Größenmodul verwenden.

Parameter

Name Beschreibung
Kerzentyp Zeitrahmen, der zum Sammeln der Referenzkerzen verwendet wird (standardmäßig täglich).
Bot-Name Der Wert wird zur einfacheren Nachverfolgung in die Bestellkommentare geschrieben.
Stop-Loss (Pips) Distanz, die sowohl für den ersten als auch für den hinteren Stopp verwendet wird.
Breakout-Offset (Pips) Bei der Platzierung ausstehender Aufträge wird ein zusätzlicher Abstand zum vorherigen Hoch/Tief angewendet.
Maximaler Spread (Pips) Maximal zulässiger Spread vor der Erstellung neuer Breakout-Orders. Auf 0 setzen, um die Prüfung zu deaktivieren.
Nutzen Sie die Handelszeiten Aktiviert den Startstundenfilter ähnlich dem ursprünglichen EA.
Startstunde Erste Stunde (einschließlich), in der neue Bestellungen aufgegeben werden können.
Endstunde Stunde, zu der die Planung neuer Bestellungen endet. Bei Gleichheit mit der Startstunde fungiert der Filter als einfache Untergrenze.
Nutzungsrisiko % Ermöglicht eine risikobasierte Volumenberechnung.
Risiko % Prozentsatz des Portfolio-Eigenkapitals, der zur Größenbestimmung von Positionen verwendet wird, wenn Use Risk % aktiviert ist.
Feste Lautstärke Festes Auftragsvolumen, das verwendet wird, wenn die Risikogrößenbestimmung deaktiviert ist. Bei Null greift die Strategie auf die globale Eigenschaft Volume zurück (Standardwert ist 0,01).

Risikomanagement

  • Der Trailing-Stop spiegelt die MetaTrader-Trailing-Logik wider, indem er den Stop-Loss Stop Loss (pips) vom besten Geld-/Briefkurs fernhält und ihn nur dann verengt, wenn ein besserer Preis erreicht wird.
  • Der Spread-Filter schützt die Strategie davor, neue Breakout-Orders einzureichen, wenn der Markt zu breit ist.
  • Die risikobasierte Größenbestimmung dividiert das zulässige monetäre Risiko (equity * Risk %) durch die in Preiseinheiten ausgedrückte Stop-Distanz und unterschreitet niemals die feste Losgröße.

Zusätzliche Hinweise

  • Bestellkommentare haben das Format BotName;SymbolId;YYYYMMDD, wodurch ausstehende Orders, die an verschiedenen Tagen erstellt wurden, leicht unterschieden werden können.
  • Die Strategie abonniert Level1-Daten, um den aktuellen Spread für den Filter auszuwerten und Trail-Stops mit den neuesten Geld-/Briefwerten zu ermitteln.
  • Trailing Stops werden bei jeder Kerzenaktualisierung und unmittelbar nach Füllungen erneut angewendet, um dem ursprünglichen EA-Verhalten zu entsprechen.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "LazyBot V1" MetaTrader expert.
/// Daily breakout strategy using previous N-bar high/low range.
/// Buys when price breaks above previous high, sells when below previous low.
/// </summary>
public class LazyBotV1Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _lookback;

	private readonly Queue<decimal> _highs = new();
	private readonly Queue<decimal> _lows = new();

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

	public int Lookback
	{
		get => _lookback.Value;
		set => _lookback.Value = value;
	}

	public LazyBotV1Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for breakout detection", "General");

		_lookback = Param(nameof(Lookback), 30)
			.SetGreaterThanZero()
			.SetDisplay("Lookback", "Number of bars for high/low range", "Indicators");
	}

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

		_highs.Clear();
		_lows.Clear();

		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;

		// Build range from previous bars (not including current)
		if (_highs.Count >= Lookback)
		{
			var highs = _highs.ToArray();
			var lows = _lows.ToArray();
			decimal highest = decimal.MinValue;
			decimal lowest = decimal.MaxValue;
			foreach (var h in highs)
				if (h > highest) highest = h;
			foreach (var l in lows)
				if (l < lowest) lowest = l;

			var close = candle.ClosePrice;
			var volume = Volume;
			if (volume <= 0)
				volume = 1;
			var padding = (highest - lowest) * 0.05m;

			if (close > highest + padding)
			{
				if (Position <= 0)
					BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
			}
			else if (close < lowest - padding)
			{
				if (Position >= 0)
					SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
			}
		}

		_highs.Enqueue(candle.HighPrice);
		_lows.Enqueue(candle.LowPrice);

		if (_highs.Count > Lookback)
		{
			_highs.Dequeue();
			_lows.Dequeue();
		}
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_highs.Clear();
		_lows.Clear();

		base.OnReseted();
	}
}