Auf GitHub ansehen

Follow Your Heart-Strategie

Übersicht

Diese Strategie ist eine StockSharp-Portierung des MetaTrader-Expert-Advisors „Follow Your Heart". Sie analysiert die letzten mehreren Kerzen und summiert die relativen Änderungen ihrer Eröffnungs-, Schluss-, Hoch- und Tiefspreise. Eine Long-Position wird eröffnet, wenn alle Änderungen über einem Schwellenwert liegen und der Gesamtwert positiv ist. Eine Short-Position wird bei den entgegengesetzten Bedingungen eröffnet. Es kann immer nur eine Position gleichzeitig existieren.

Positionen werden durch Gewinn- und Verlustlimits in Kontowährung sowie durch Take-Profit/Stop-Loss in Punkten geschützt. Optionale Handelssitzungen erlauben Signale nur innerhalb festgelegter Stunden.

Parameter

  • Bars – Anzahl der Kerzen zur Akkumulation von Preisänderungen. Standard: 6.
  • Level – Schwellenwert für Eröffnungs- und Schlussänderungen. Standard: 2.3.
  • ProfitBuy – Geld-Gewinnziel zum Schließen der Long-Position. Standard: 75.
  • ProfitSell – Geld-Gewinnziel zum Schließen der Short-Position. Standard: 56.
  • LossBuy – Geld-Verlustschwelle zum Schließen der Long-Position. Standard: -54.
  • LossSell – Geld-Verlustschwelle zum Schließen der Short-Position. Standard: -51.
  • TakeProfit – Take-Profit in Punkten. Standard: 550.
  • StopLoss – Stop-Loss in Punkten. Standard: 550.
  • TradingHoursOn – Sitzungsfilterung aktivieren. Standard: true.
  • OpenHourBuy / CloseHourBuy – erlaubte Stunden für Kaufsignale. Standard: 6 / 12.
  • OpenHourSell / CloseHourSell – erlaubte Stunden für Verkaufssignale. Standard: 4 / 10.
  • CandleType – Kerzen-Zeitrahmen. Standard: 1 Minute.

Strategielogik

  1. Für jede abgeschlossene Kerze werden die relativen Änderungen von Eröffnung, Schluss, Hoch und Tief im Vergleich zur vorherigen Kerze berechnet und die gleitenden Summen aktualisiert.
  2. Wenn keine Position besteht:
    • Kauf, wenn die Gesamtsumme positiv ist, sowohl Eröffnungs- als auch Schlussänderungen über Level liegen und die Schlussänderung größer als die Eröffnungsänderung während der Kaufsitzung ist.
    • Verkauf, wenn die Gesamtsumme negativ ist, sowohl Eröffnungs- als auch Schlussänderungen unter -Level liegen und die Schlussänderung kleiner als die Eröffnungsänderung während der Verkaufssitzung ist.
  3. Wenn eine Position besteht, wird sie geschlossen, wenn Gewinn oder Verlust die konfigurierten Geldlimits überschreitet oder wenn der Preis sich um TakeProfit/StopLoss Punkte bewegt.

Hinweise

  • Es werden nur Marktorders verwendet.
  • Das Geldmanagement aus dem Originalcode ist vereinfacht; das Positionsvolumen wird aus der Volume-Eigenschaft der Strategie entnommen.
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>
/// Momentum strategy based on EMA crossover (converted from OHLC sum).
/// </summary>
public class FollowYourHeartStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public FollowYourHeartStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType).Bind(fast, slow, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
	{
		if (candle.State != CandleStates.Finished) return;

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
		var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}