Auf GitHub ansehen

Sie Kanskigor tägliche Strategie

Überblick

She Kanskigor Daily Strategy ist ein einmal pro Tag stattfindendes Breakout-System, das den ursprünglichen MetaTrader-Expertenberater SHE_kanskigor.mq4 widerspiegelt. Die Strategie wertet die Richtung der vorherigen Tageskerze aus und eröffnet innerhalb eines engen Zeitfensters zu Beginn des neuen Handelstages eine einzelne Marktposition. Es überwacht automatisch die Position und schließt sie anhand einer konfigurierbaren Take-Profit- oder Stop-Loss-Distanz, ausgedrückt in Wertpapierpreisschritten.

Handelslogik

  1. Abonnieren Sie sowohl Intraday-Kerzen (Standard: 1 Minute) als auch Tageskerzen für das ausgewählte Wertpapier.
  2. Aktualisieren Sie die gespeicherten täglichen Öffnungs- und Schlusswerte, sobald eine fertige Tageskerze eintrifft.
  3. Bei jeder fertigen Intraday-Kerze:
    • Setzen Sie die Markierung „Heute gehandelt“ zurück, wenn ein neues Kalenderdatum beginnt.
    • Verwalten Sie die aktive Position, indem Sie prüfen, ob der Schlusskurs die Stop-Loss- oder Take-Profit-Schwellenwerte erreicht.
    • Überprüfen Sie, ob die aktuelle Zeit innerhalb des konfigurierten Handelsfensters liegt (Standardstart: 00:05, Fensterlänge: 5 Minuten).
    • Wenn heute noch keine Position eröffnet wurde und eine gültige vorherige Tageskerze verfügbar ist:
      • Gehen Sie long, wenn der vorherige tägliche Eröffnungskurs höher ist als der Schlusskurs (bärische Kerze).
      • Gehen Sie short, wenn der vorherige tägliche Eröffnungskurs niedriger ist als der Schlusskurs (bullische Kerze).
    • Überspringen Sie den Handel, wenn der Vortag unverändert geschlossen wurde.
  4. Die Strategie führt Schutzausstiege mithilfe von Marktaufträgen durch, sobald der Schlusskurs die konfigurierten Schwellenwerte erreicht.

Parameter

Name Beschreibung Standard
Volumen Auftragsvolumen, das für Einträge verwendet wird. 0.1
Gewinn mitnehmen Gewinnziel ausgedrückt in Preisschritten. Ein Wert von 0 deaktiviert das Ziel. 35
Stop-Loss Verlustschwelle ausgedrückt in Preisschritten. Ein Wert von 0 deaktiviert den Stopp. 55
Startzeit Uhrzeit (Börsenzeitzone), zu der das Eingabefenster beginnt. 00:05
Fenster (min.) Dauer des Eingabefensters in Minuten. 5
Intraday-Kerze Kerzendatentyp, der für die Intraday-Verarbeitung verwendet wird (Standard: 1-Minuten-Kerzen). TimeFrameCandleMessage(1m)

Notizen

  • Die Strategie erlaubt nur einen Eintrag pro Handelstag.
  • Tägliche Kerzendaten müssen verfügbar sein; andernfalls wartet die Strategie, bis eine fertige Kerze eintrifft.
  • Schutzausgänge basieren auf dem Schlusskurs fertiger Intraday-Kerzen.
  • Der Code verwendet StockSharp auf hoher Ebene API (SubscribeCandles mit Bind) und entspricht den Kodierungsstandards des Projekts (Tabulatoren, englische Kommentare und Parametermetadaten).
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>
/// Daily breakout strategy that opens a position during a short time window.
/// Uses the previous daily candle direction to decide whether to buy or sell.
/// Applies configurable take-profit and stop-loss levels expressed in price steps.
/// </summary>
public class SheKanskigorDailyStrategy : Strategy
{
	private readonly StrategyParam<TimeSpan> _startTime;
	private readonly StrategyParam<int> _tradeWindowMinutes;
	private readonly StrategyParam<decimal> _takeProfitSteps;
	private readonly StrategyParam<decimal> _stopLossSteps;
	private readonly StrategyParam<DataType> _intradayCandleType;

	private readonly DataType _dailyCandleType;

	private DateTime _currentDate;
	private bool _tradePlaced;
	private bool _dailyReady;
	private decimal _previousOpen;
	private decimal _previousClose;
	private decimal _entryPrice;

	/// <summary>
	/// Start time of the trading window.
	/// </summary>
	public TimeSpan StartTime
	{
		get => _startTime.Value;
		set => _startTime.Value = value;
	}

	/// <summary>
	/// Width of the trading window in minutes.
	/// </summary>
	public int TradeWindowMinutes
	{
		get => _tradeWindowMinutes.Value;
		set => _tradeWindowMinutes.Value = value;
	}

	/// <summary>
	/// Take-profit distance expressed in security price steps.
	/// </summary>
	public decimal TakeProfitSteps
	{
		get => _takeProfitSteps.Value;
		set => _takeProfitSteps.Value = value;
	}

	/// <summary>
	/// Stop-loss distance expressed in security price steps.
	/// </summary>
	public decimal StopLossSteps
	{
		get => _stopLossSteps.Value;
		set => _stopLossSteps.Value = value;
	}

	/// <summary>
	/// Intraday candle type used to evaluate the trading window.
	/// </summary>
	public DataType IntradayCandleType
	{
		get => _intradayCandleType.Value;
		set => _intradayCandleType.Value = value;
	}

	/// <summary>
	/// Initializes <see cref="SheKanskigorDailyStrategy"/>.
	/// </summary>
	public SheKanskigorDailyStrategy()
	{
		_takeProfitSteps = Param(nameof(TakeProfitSteps), 35m)
			.SetDisplay("Take Profit", "Profit target in steps", "Risk")
			;

		_stopLossSteps = Param(nameof(StopLossSteps), 55m)
			.SetDisplay("Stop Loss", "Loss limit in steps", "Risk")
			;

		_startTime = Param(nameof(StartTime), new TimeSpan(0, 5, 0))
			.SetDisplay("Start Time", "Time of day to evaluate entries", "Schedule");

		_tradeWindowMinutes = Param(nameof(TradeWindowMinutes), 5)
			.SetDisplay("Window (min)", "Trading window duration in minutes", "Schedule")
			;

		_intradayCandleType = Param(nameof(IntradayCandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Intraday Candle", "Candle type for intraday checks", "Data");

		_dailyCandleType = TimeSpan.FromMinutes(5).TimeFrame();
	}

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

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

		_currentDate = default;
		_tradePlaced = false;
		_dailyReady = false;
		_previousOpen = 0m;
		_previousClose = 0m;
		_entryPrice = 0m;
	}

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

		var intraday = SubscribeCandles(IntradayCandleType);
		intraday.Bind(ProcessIntraday).Start();

		var daily = SubscribeCandles(_dailyCandleType);
		daily.Bind(ProcessDaily).Start();

		StartProtection(null, null);
	}

	private void ProcessDaily(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		// Store the direction of the last completed daily candle.
		_previousOpen = candle.OpenPrice;
		_previousClose = candle.ClosePrice;
		_dailyReady = true;
	}

	private void ProcessIntraday(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var openTime = candle.OpenTime;

		if (openTime.Date != _currentDate)
		{
			_currentDate = openTime.Date;
			_tradePlaced = false;
		}

		ManagePosition(candle.ClosePrice);

		var start = StartTime;
		var end = start.Add(TimeSpan.FromMinutes(TradeWindowMinutes));
		var currentTod = openTime.TimeOfDay;

		if (currentTod < start || currentTod > end)
			return;

		if (_tradePlaced)
			return;

		if (!_dailyReady)
			return;

		if (Position != 0)
		{
			_tradePlaced = true;
			return;
		}

		if (_previousOpen > _previousClose)
		{
			BuyMarket(Volume);
			_tradePlaced = true;
		}
		else if (_previousOpen < _previousClose)
		{
			SellMarket(Volume);
			_tradePlaced = true;
		}
		else
		{
			// Skip trading when the previous day closed unchanged.
			_tradePlaced = true;
		}
	}

	private void ManagePosition(decimal closePrice)
	{
		if (Position == 0)
			return;

		var step = Security?.PriceStep ?? 0m;
		if (step <= 0m || _entryPrice == 0m)
			return;

		if (Position > 0)
		{
			var target = _entryPrice + TakeProfitSteps * step;
			var stop = _entryPrice - StopLossSteps * step;

			if (TakeProfitSteps > 0m && closePrice >= target)
			{
				SellMarket(Position);
				return;
			}

			if (StopLossSteps > 0m && closePrice <= stop)
			{
				SellMarket(Position);
			}
		}
		else
		{
			var target = _entryPrice - TakeProfitSteps * step;
			var stop = _entryPrice + StopLossSteps * step;

			if (TakeProfitSteps > 0m && closePrice <= target)
			{
				BuyMarket(-Position);
				return;
			}

			if (StopLossSteps > 0m && closePrice >= stop)
			{
				BuyMarket(-Position);
			}
		}
	}

	/// <inheritdoc />
	protected override void OnOwnTradeReceived(MyTrade trade)
	{
		base.OnOwnTradeReceived(trade);

		if (trade.Order.Security != Security)
			return;

		// Track the latest fill price to evaluate protective exits.
		_entryPrice = trade.Trade.Price;
	}
}