Auf GitHub ansehen

Strategie TenKijun Cross Alert Strategy (ID 3562)

Überblick

Diese Strategie ist eine StockSharp-High-Level-API-Portierung des MetaTrader-Expertenberaters TenKijun.mq4. Der ursprüngliche EA beobachtet nur den Ichimoku-Indikator und sendet Push-Benachrichtigungen, wenn der Tenkan-sen (Umrechnungslinie) den Kijun-sen (Basislinie) überschreitet. Die C#-Version behält den reinen Alarmcharakter bei, erweitert die Implementierung jedoch um StockSharp-Infrastruktur, Diagrammbindungen, Parametrisierung und sichere Sitzungsverarbeitung.

Die Logik funktioniert bei abgeschlossenen Kerzen eines konfigurierbaren Zeitrahmens. Wenn eine neue Kerze innerhalb der aktiven Handelszeiten schließt, wertet die Strategie den mit den klassischen 9/26/52-Perioden berechneten Ichimoku-Indikator aus und zeichnet die neuesten Tenkan/Kijun-Werte auf. Wenn der Tenkan den Kijun überschreitet, wird eine Informationsmeldung protokolliert, die auf ein bullisches Kreuz hinweist; Wenn Tenkan Kijun unterschreitet, wird eine bärische Warnung protokolliert. Es werden keine Trades ausgeführt – die Strategie ist zur Signalgenerierung oder zur Kombination mit externer Automatisierung gedacht.

Indikator und Datenfluss

  • Indikator – StockSharp Ichimoku-Indikator mit separat parametrisierten Tenkan-, Kijun- und Senkou-Span-B-Längen. Für die Entscheidungsfindung werden nur die Tenkan- und Kijun-Linien verwendet, die das ursprüngliche EA widerspiegeln.
  • Datenabonnement – Verwendet SubscribeCandles mit einem konfigurierbaren CandleType. Standardmäßig werden 30-Minuten-Zeitrahmenkerzen angefordert.
  • BindungBindEx wird verwendet, damit das typisierte IchimokuValue ohne manuelle Aufrufe von GetValue an den Handler übermittelt wird.
  • Charting – Kerzen und der Indikator Ichimoku werden automatisch an das Strategiediagramm angehängt, um eine schnelle visuelle Validierung von Warnungen zu ermöglichen.

Handelssitzungsfilter

Das MetaTrader-Skript beschränkte Warnungen auf ein benutzerdefiniertes Sitzungsfenster. Der Port stellt dieselbe Funktion über zwei Parameter bereit:

  • StartHour – inklusive Beginn des aktiven Fensters (Standard 0). Akzeptiert 0-23.
  • LastHour – inklusive Ende des aktiven Fensters (Standard 20). Akzeptiert 0-23.

Wenn StartHour kleiner oder gleich LastHour ist, werden zwischen diesen beiden Stunden des Tages Warnungen erzeugt. Wenn der Anfang länger als das Ende liegt, wird das Fenster als Nachtfenster behandelt (z. B. 20 → 6 deckt die Sitzung vom späten Abend bis zum frühen Morgen ab).

Parameter

Parameter Beschreibung Standard Notizen
StartHour Stunde, in der Warnungen beginnen können. 0 Inklusive, Bereich 0–23.
LastHour Stunde, in der die Warnungen enden. 20 Inklusive, Bereich 0–23.
TenkanPeriod Rückblick auf die Conversion-Linie. 9 Optimierbar.
KijunPeriod Rückblick auf die Grundlinie. 26 Optimierbar.
SenkouSpanBPeriod Führender Span-B-Lookback. 52 Der Vollständigkeit halber bereitgestellt, auch wenn Warnungen nicht von der Cloud abhängen.
CandleType Für den Indikator verwendete Kerzenserie. 30-minütiger Zeitrahmen Wählen Sie einen beliebigen TimeSpan-basierten Zeitrahmen.

Alarmlogik

  1. Warten Sie auf die erste fertige Kerze, um die Tenkan- und Kijun-Geschichte zu initialisieren.
  2. Bei jeder weiteren fertigen Kerze innerhalb des Handelsfensters:
    • Extrahieren Sie Tenkan- und Kijun-Werte aus dem Indikator Ichimoku.
    • Erkennen Sie einen bullischen Cross, wenn der vorherige Tenkan kleiner oder gleich dem vorherigen Kijun war und der aktuelle Tenkan größer als der aktuelle Kijun ist.
    • Erkennen Sie einen rückläufigen Cross, wenn der vorherige Tenkan größer oder gleich dem vorherigen Kijun war und der aktuelle Tenkan kleiner als der aktuelle Kijun ist.
    • Geben Sie einen informativen Protokolleintrag aus, der die Richtung, den Preis und den Zeitstempel des Kreuzes beschreibt.

Nutzungstipps

  • Kombinieren Sie diese Strategie mit StockSharp-Benachrichtigungsadaptern (E-Mail, Telegram, Sound), indem Sie das Strategieprotokoll abonnieren oder die ProcessCandle-Methode mit benutzerdefiniertem Benachrichtigungscode erweitern.
  • Um den automatisierten Handel voranzutreiben, erben Sie von TenKijunCrossStrategy und überschreiben Sie ProcessCandle, um Aufträge zu erteilen, anstatt oder zusätzlich zur Protokollierung von Nachrichten.
  • Passen Sie den Zeitrahmen der Kerze so an, dass er mit dem ursprünglichen MetaTrader-Diagramm übereinstimmt, das von EA verwendet wurde, um die Benachrichtigungen aufeinander abzustimmen.

Unterschiede zum Original EA

  • Verwendet StockSharp-Protokollierung anstelle von MetaTrader SendNotification. Das Verhalten dient weiterhin nur der Warnung, hängt jedoch von der Nachrichtenpipeline der Plattform ab.
  • Fügt vollständige Parametermetadaten (SetDisplay, Bereiche, Optimierungsflags) hinzu und macht die Strategie für Designer-/Optimierungstools bereit.
  • Zeichnet automatisch Kerzen und den Indikator Ichimoku im Diagrammfenster StockSharp, sofern verfügbar.

Dateien

  • CS/TenKijunCrossStrategy.cs – Haupt-C#-Implementierung der Alarmlogik.
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>
/// Tenkan/Kijun cross strategy based on Ichimoku indicator.
/// Buys when Tenkan crosses above Kijun, sells when Tenkan crosses below Kijun.
/// Uses SMA proxies for Tenkan (short) and Kijun (long) since Ichimoku complex type
/// requires BindEx and special value handling.
/// </summary>
public class TenKijunCrossStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _tenkanPeriod;
	private readonly StrategyParam<int> _kijunPeriod;

	private readonly Queue<decimal> _highsTenkan = new();
	private readonly Queue<decimal> _lowsTenkan = new();
	private readonly Queue<decimal> _highsKijun = new();
	private readonly Queue<decimal> _lowsKijun = new();
	private decimal? _prevTenkan;
	private decimal? _prevKijun;

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

	public int TenkanPeriod
	{
		get => _tenkanPeriod.Value;
		set => _tenkanPeriod.Value = value;
	}

	public int KijunPeriod
	{
		get => _kijunPeriod.Value;
		set => _kijunPeriod.Value = value;
	}

	public TenKijunCrossStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for Ichimoku calculations", "General");

		_tenkanPeriod = Param(nameof(TenkanPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Tenkan Period", "Tenkan-sen conversion line period", "Indicators");

		_kijunPeriod = Param(nameof(KijunPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Kijun Period", "Kijun-sen base line period", "Indicators");
	}

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

		_prevTenkan = null;
		_prevKijun = null;
		_highsTenkan.Clear();
		_lowsTenkan.Clear();
		_highsKijun.Clear();
		_lowsKijun.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;

		// Compute Tenkan-sen = (highest high + lowest low) / 2 over TenkanPeriod
		_highsTenkan.Enqueue(candle.HighPrice);
		_lowsTenkan.Enqueue(candle.LowPrice);
		if (_highsTenkan.Count > TenkanPeriod)
		{
			_highsTenkan.Dequeue();
			_lowsTenkan.Dequeue();
		}

		// Compute Kijun-sen = (highest high + lowest low) / 2 over KijunPeriod
		_highsKijun.Enqueue(candle.HighPrice);
		_lowsKijun.Enqueue(candle.LowPrice);
		if (_highsKijun.Count > KijunPeriod)
		{
			_highsKijun.Dequeue();
			_lowsKijun.Dequeue();
		}

		if (_highsTenkan.Count < TenkanPeriod || _highsKijun.Count < KijunPeriod)
			return;

		var highsTenkan = _highsTenkan.ToArray();
		var lowsTenkan = _lowsTenkan.ToArray();
		var highsKijun = _highsKijun.ToArray();
		var lowsKijun = _lowsKijun.ToArray();
		var tenkan = (Max(highsTenkan) + Min(lowsTenkan)) / 2;
		var kijun = (Max(highsKijun) + Min(lowsKijun)) / 2;

		if (_prevTenkan is null || _prevKijun is null)
		{
			_prevTenkan = tenkan;
			_prevKijun = kijun;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var crossUp = _prevTenkan.Value <= _prevKijun.Value && tenkan > kijun;
		var crossDown = _prevTenkan.Value >= _prevKijun.Value && tenkan < kijun;

		if (crossUp)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossDown)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevTenkan = tenkan;
		_prevKijun = kijun;
	}

	private static decimal Max(IEnumerable<decimal> values)
	{
		decimal max = decimal.MinValue;

		foreach (var v in values)
			if (v > max) max = v;

		return max;
	}

	private static decimal Min(IEnumerable<decimal> values)
	{
		decimal min = decimal.MaxValue;

		foreach (var v in values)
			if (v < min) min = v;

		return min;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_prevTenkan = null;
		_prevKijun = null;
		_highsTenkan.Clear();
		_lowsTenkan.Clear();
		_highsKijun.Clear();
		_lowsKijun.Clear();

		base.OnReseted();
	}
}