Auf GitHub ansehen

Eugene Inside-Ausbruch-Strategie

Die Eugene Inside-Ausbruch-Strategie ist eine direkte Portierung des ursprünglichen MetaTrader-Expertenberaters von barabashkakvn. Sie konzentriert sich auf reine Price-Action: eine Inside-Kerzen-Sequenz gefolgt von einem Bereichsausbruch. Bestätigungsniveaus aus dem Körper der vorherigen Kerze stellen sicher, dass der Ausbruch Momentum entwickelt, bevor die Strategie eine Position eingeht.

Übersicht

Die Strategie überwacht auf ein frisches Hoch oder Tief relativ zur vorherigen Kerze. Long-Setups erfordern, dass die vorherige Kerze ein Tief unterhalb des Hochs der Kerze davor hat, was die Kompression vor dem Ausbruch betont. Short-Setups lehnen den Handel ab, wenn die vorherige Kerze eine Inside-Bar ist, und spiegeln die Sicherheitsvorkehrungen in der Quell-MQL-Logik wider. Orders werden immer zum Markt mit einem festen Volumen ausgeführt.

Marktlogik

  • Betont Ausbrüche des jüngsten Hochs/Tiefs, um Richtungsbewegungen früh zu erfassen.
  • Verwendet den Körper der vorherigen Kerze zur Berechnung von zwei Ein-Drittel-Retracement-Niveaus (zigLevelBuy und zigLevelSell). Der Preis muss diese Niveaus berühren, oder die Sitzung muss über die konfigurierte Aktivierungsstunde hinaus sein, bevor ein Einstieg erlaubt wird.
  • Verhindert neue Positionen, wenn ein Ausbruch mit einer Inside-Kerze gegen die Trade-Richtung zusammenfällt.
  • Schließt offene Positionen, sobald das entgegengesetzte Ausbruchssignal bestätigt wird, und stellt sicher, dass die Strategie immer flach oder am letzten Signal ausgerichtet ist.

Einstiegsregeln

Long

  1. Das aktuelle Kerzenhoch ist höher als das vorherige Kerzenhoch.
  2. Bestätigung wird erhalten, wenn das aktuelle Tief das Ein-Drittel-Retracement des vorherigen Kerzenkörpers durchbricht, oder die aktuelle Stunde über dem Aktivierungsstunden-Parameter liegt.
  3. Das aktuelle Tief muss über dem vorherigen Tief bleiben, während das vorherige Tief unter dem Hoch von zwei Kerzen zuvor liegt.
  4. Keine bestehende Position ist offen.

Short

  1. Das aktuelle Kerzentief liegt unter dem vorherigen Kerzentief.
  2. Bestätigung wird erhalten, wenn das aktuelle Hoch das obere Ein-Drittel-Retracement des vorherigen Kerzenkörpers testet, oder die aktuelle Stunde über dem Aktivierungsstunden-Parameter liegt.
  3. Die vorherige Kerze darf keine Inside-Bar sein.
  4. Das aktuelle Hoch muss unter dem vorherigen Hoch liegen.
  5. Keine bestehende Position ist offen.

Ausstiegsregeln

  • Long-Positionen schließen, wenn ein validierter Short-Ausbruch entsteht (Bedingungen 1–3 der Short-Einstiegslogik).
  • Short-Positionen schließen, wenn ein validierter Long-Ausbruch entsteht (Bedingungen 1–3 der Long-Einstiegslogik).

Parameter

Name Beschreibung Standard
CandleType Zeitrahmen der von der Strategie verarbeiteten Kerzen. 1-Stunden-Kerzen
Volume Ordergröße, die mit jeder Marktorder gesendet wird. 0.1
ActivationHour Tagesstunde, nach der Bestätigungen automatisch akzeptiert werden, und der TimeCurrent()-Filter aus dem MQL-Code repliziert wird. 8

Hinweise

  • Die Bestätigungsprüfungen, die im Originalskript als "white bird" und "black bird" bezeichnet werden, werten aufgrund der Quellbedingungen immer als falsch aus; sie werden für Parität erhalten, beeinflussen aber keine Handelsentscheidungen.
  • Keine zusätzlichen Indikatoren oder Trailing-Stops werden verwendet—der Ansatz ist rein preisbasiert und kehrt Positionen bei jedem entgegengesetzten Ausbruch um.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Breakout strategy derived from the Eugene expert advisor.
/// </summary>
public class EugeneInsideBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _activationHour;

	private decimal _prevOpen1;
	private decimal _prevClose1;
	private decimal _prevHigh1;
	private decimal _prevLow1;

	private decimal _prevOpen2;
	private decimal _prevClose2;
	private decimal _prevHigh2;
	private decimal _prevLow2;

	private bool _hasPrev1;
	private bool _hasPrev2;

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


	/// <summary>
	/// Hour of day after which confirmations are automatically valid.
	/// </summary>
	public int ActivationHour
	{
		get => _activationHour.Value;
		set => _activationHour.Value = value;
	}

	/// <summary>
	/// Initializes <see cref="EugeneInsideBreakoutStrategy"/>.
	/// </summary>
	public EugeneInsideBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to process", "General");


		_activationHour = Param(nameof(ActivationHour), 8)
			.SetRange(0, 23)
			.SetDisplay("Activation Hour", "Hour when confirmations become unconditional", "Filters");

		ResetHistory();
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		ResetHistory();
	}

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

		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;

		if (!_hasPrev2)
		{
			UpdateHistory(candle);
			return;
		}

		var open1 = _prevOpen1;
		var close1 = _prevClose1;
		var open2 = _prevOpen2;
		var close2 = _prevClose2;
		var high0 = candle.HighPrice;
		var high1 = _prevHigh1;
		var high2 = _prevHigh2;
		var low0 = candle.LowPrice;
		var low1 = _prevLow1;
		var low2 = _prevLow2;

		// Replicate the original expert advisor checks for inside bars.
		var blackInsider = high1 <= high2 && low1 >= low2 && close1 <= open1;
		var whiteInsider = high1 <= high2 && low1 >= low2 && close1 > open1;
		var whiteBird = whiteInsider && close2 > open2;
		var blackBird = blackInsider && close2 < open2;

		// ZigZag style confirmation levels based on the previous candle body.
		var zigLevelBuy = close1 < open1
			? open1 - (close1 - open1) / 3m
			: open1 - (open1 - low1) / 3m;

		var zigLevelSell = close1 > open1
			? open1 + (close1 - open1) / 3m
			: open1 + (high1 - open1) / 3m;

		var confirmBuy = (low0 <= zigLevelBuy || candle.CloseTime.Hour >= ActivationHour) && !blackBird && !whiteInsider;
		var confirmSell = (high0 >= zigLevelSell || candle.CloseTime.Hour >= ActivationHour) && !whiteBird && !blackInsider;

		var buySignal = high0 > high1;
		var sellSignal = low0 < low1;

		if (Position == 0)
		{
			if (buySignal && confirmBuy && low0 > low1 && low1 < high2)
			{
				BuyMarket();
			}
			else if (sellSignal && confirmSell && high0 < high1)
			{
				SellMarket();
			}
		}
		else if (Position > 0)
		{
			if (sellSignal && confirmSell && high0 < high1)
				SellMarket();
		}
		else if (Position < 0)
		{
			if (buySignal && confirmBuy && low0 > low1 && low1 < high2)
				BuyMarket();
		}

		UpdateHistory(candle);
	}

	private void UpdateHistory(ICandleMessage candle)
	{
		// Keep the two most recent completed candles for decision making.
		_prevOpen2 = _prevOpen1;
		_prevClose2 = _prevClose1;
		_prevHigh2 = _prevHigh1;
		_prevLow2 = _prevLow1;
		_hasPrev2 = _hasPrev1;

		_prevOpen1 = candle.OpenPrice;
		_prevClose1 = candle.ClosePrice;
		_prevHigh1 = candle.HighPrice;
		_prevLow1 = candle.LowPrice;
		_hasPrev1 = true;
	}

	private void ResetHistory()
	{
		_prevOpen1 = default;
		_prevClose1 = default;
		_prevHigh1 = default;
		_prevLow1 = default;
		_prevOpen2 = default;
		_prevClose2 = default;
		_prevHigh2 = default;
		_prevLow2 = default;
		_hasPrev1 = false;
		_hasPrev2 = false;
	}
}