Auf GitHub ansehen

Trade-Panel-Autopilot-Strategie

Überblick

Diese Strategie reproduziert die Kernlogik des ursprünglichen MQL4-Experten "trade panel with autopilot". Sie aggregiert die Preisrichtung über mehrere Zeitrahmen und öffnet oder schließt eine einzelne Position entsprechend der vorherrschenden Marktstimmung.

Die Strategie überwacht die letzten zwei Kerzen in acht verschiedenen Zeitrahmen (M1, M5, M15, M30, H1, H4, D1, W1). Für jeden Zeitrahmen vergleicht sie mehrere Preiskomponenten zwischen den beiden aktuellsten Kerzen:

  • Open
  • High
  • Low
  • (High + Low) / 2
  • Close
  • (High + Low + Close) / 3
  • (High + Low + Close + Close) / 4

Jeder Vergleich trägt zu einem Kauf- oder Verkaufs-Score bei. Scores aus allen Zeitrahmen werden summiert und in Prozente umgerechnet. Wenn der Kauf- oder Verkaufsprozentsatz einen konfigurierten Schwellenwert überschreitet, eröffnet die Strategie eine Position. Die bestehende Position wird geschlossen, wenn der entgegengesetzte Prozentsatz unter den Schließungsschwellenwert fällt.

Parameter

  • Autopilot — aktiviert oder deaktiviert den automatischen Handel.
  • OpenThreshold — Prozentniveau zum Öffnen einer neuen Position. Standard: 85.
  • CloseThreshold — Prozentniveau zum Schließen einer bestehenden Position. Standard: 55.
  • LotFixed — festes Ordervolumen wenn UseFixedLot aktiviert ist.
  • LotPercent — Volumen als Prozentsatz des Portfoliowerts wenn UseFixedLot deaktiviert ist.
  • UseFixedLot — wechselt zwischen festem und prozentualem Volumen.
  • UseStopLoss — aktiviert den Positionsschutz wenn eingeschaltet.

Handelslogik

  1. Kerzen auf allen konfigurierten Zeitrahmen abonnieren.
  2. Kauf-/Verkaufs-Scores für jede neue abgeschlossene Kerze berechnen.
  3. Scores über alle Zeitrahmen summieren und Kauf-/Verkaufsprozentsätze berechnen.
  4. Wenn Autopilot deaktiviert ist, verfolgt die Strategie nur die Scores.
  5. Wenn keine Position offen ist und der Kaufprozentsatz OpenThreshold überschreitet, eine Long-Position eingehen. Wenn der Verkaufsprozentsatz den Schwellenwert überschreitet, eine Short-Position eingehen.
  6. Wenn eine Long-Position besteht und der Kaufprozentsatz unter CloseThreshold fällt, die Position schließen. Die gleiche Logik gilt für Short-Positionen unter Verwendung des Verkaufsprozentsatzes.

Hinweise

  • Die Strategie hält zu einem Zeitpunkt höchstens eine offene Position.
  • Optionales Stop-Loss-Management wird über StartProtection() aktiviert, wenn UseStopLoss wahr ist.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trade panel autopilot strategy v2.
/// Aggregates 7 price comparison metrics over rolling window.
/// Buys when buy percentage exceeds open threshold, sells on opposite.
/// </summary>
public class TradePanelAutopilotStrategy : Strategy
{
	private readonly StrategyParam<decimal> _openThreshold;
	private readonly StrategyParam<decimal> _closeThreshold;
	private readonly StrategyParam<int> _windowSize;
	private readonly StrategyParam<DataType> _candleType;

	private readonly Queue<(int buy, int sell)> _signalWindow = new();
	private ICandleMessage _prevCandle;

	public decimal OpenThreshold { get => _openThreshold.Value; set => _openThreshold.Value = value; }
	public decimal CloseThreshold { get => _closeThreshold.Value; set => _closeThreshold.Value = value; }
	public int WindowSize { get => _windowSize.Value; set => _windowSize.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public TradePanelAutopilotStrategy()
	{
		_openThreshold = Param(nameof(OpenThreshold), 65m)
			.SetDisplay("Open %", "Threshold for new position", "General");

		_closeThreshold = Param(nameof(CloseThreshold), 40m)
			.SetDisplay("Close %", "Threshold for closing", "General");

		_windowSize = Param(nameof(WindowSize), 8)
			.SetGreaterThanZero()
			.SetDisplay("Window Size", "Number of candles for signal aggregation", "General");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCandle = null;
		_signalWindow.Clear();
	}

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

		_prevCandle = null;
		_signalWindow.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;

		if (_prevCandle == null)
		{
			_prevCandle = candle;
			return;
		}

		int buy = 0, sell = 0;

		if (candle.OpenPrice > _prevCandle.OpenPrice) buy++; else sell++;
		if (candle.HighPrice > _prevCandle.HighPrice) buy++; else sell++;
		if (candle.LowPrice > _prevCandle.LowPrice) buy++; else sell++;
		if (candle.ClosePrice > _prevCandle.ClosePrice) buy++; else sell++;

		var hlCurr = (candle.HighPrice + candle.LowPrice) / 2m;
		var hlPrev = (_prevCandle.HighPrice + _prevCandle.LowPrice) / 2m;
		if (hlCurr > hlPrev) buy++; else sell++;

		var hlcCurr = (candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 3m;
		var hlcPrev = (_prevCandle.HighPrice + _prevCandle.LowPrice + _prevCandle.ClosePrice) / 3m;
		if (hlcCurr > hlcPrev) buy++; else sell++;

		var hlccCurr = (candle.HighPrice + candle.LowPrice + 2m * candle.ClosePrice) / 4m;
		var hlccPrev = (_prevCandle.HighPrice + _prevCandle.LowPrice + 2m * _prevCandle.ClosePrice) / 4m;
		if (hlccCurr > hlccPrev) buy++; else sell++;

		_signalWindow.Enqueue((buy, sell));

		while (_signalWindow.Count > WindowSize)
			_signalWindow.Dequeue();

		_prevCandle = candle;

		if (_signalWindow.Count < WindowSize)
			return;

		int totalBuy = 0, totalSell = 0;
		foreach (var (b, s) in _signalWindow)
		{
			totalBuy += b;
			totalSell += s;
		}

		var total = totalBuy + totalSell;
		if (total == 0) return;

		var buyPct = (decimal)totalBuy / total * 100m;
		var sellPct = (decimal)totalSell / total * 100m;

		if (Position > 0 && buyPct < CloseThreshold)
			SellMarket();
		else if (Position < 0 && sellPct < CloseThreshold)
			BuyMarket();

		if (Position == 0)
		{
			if (buyPct >= OpenThreshold)
				BuyMarket();
			else if (sellPct >= OpenThreshold)
				SellMarket();
		}
	}
}