Auf GitHub ansehen

Trend Is Your Friend-Strategie

Übersicht

Die Trend Is Your Friend-Strategie ist ein Multi-Timeframe-Trendfolge-System, inspiriert vom ursprünglichen MetaTrader-Expertenberater. Es richtet Intraday-Momentum mit einem MACD-Filter des höheren Zeitrahmens aus, während das Risiko durch Bollinger-Bänder-Ausstiege, klassische Stop-Loss- und Take-Profit-Ziele, eine optionale Break-Even-Sperre und Trailing-Stop-Management verwaltet wird.

Die Strategie arbeitet auf einem konfigurierbaren Basis-Zeitrahmen (Standard: 1 Stunde) und analysiert die Kerzenstruktur für ein kurzfristiges Momentum-Muster: eine bärische Kerze gefolgt von einer stärkeren bullischen Kerze für Long-Trades oder das Gegenteil für Short-Trades. Diese Muster müssen mit einem gleitenden Durchschnitts-Trendfilter und einem monatlichen MACD-Signal übereinstimmen, bevor eine Position eröffnet wird.

Einstiegslogik

  1. Eine schnelle EMA und eine langsame LWMA auf dem Einstiegs-Zeitrahmen berechnen.
  2. Die letzten zwei abgeschlossenen Kerzen verfolgen, um ein Momentum-Muster zu bilden:
    • Long-Setup: die Kerze vor zwei Bars ist bärisch, die vorherige Kerze ist bullisch und größer in der Magnitude.
    • Short-Setup: die Kerze vor zwei Bars ist bullisch, die vorherige Kerze ist bärisch und kleiner in der Magnitude.
  3. Das Setup mit dem gleitenden Durchschnitts-Trendfilter bestätigen (schnelle MA über langsamer MA für Long-Trades, darunter für Short-Trades).
  4. Den langfristigen Trend mit einem MACD-Signal bestätigen, das auf dem höheren Zeitrahmen berechnet wird (Standard: monatlich). Die MACD-Linie muss für Long-Trades über der Signallinie liegen und darunter für Short-Trades.
  5. Wenn alle Filter übereinstimmen, eine Position zum Markt mit dem konfigurierten Volumen eröffnen.

Ausstiegslogik

  • Bollinger-Bänder-Ausstieg: Long-Positionen werden geschlossen, wenn der Preis über das obere Band schließt; Short-Positionen, wenn der Preis unter das untere Band schließt.
  • Take-Profit / Stop-Loss: optionale feste Abstände in Pips. Die Implementierung konvertiert Pips über den Wertpapier-Preisschritt in Preisabstand.
  • Break-Even: optional, verschiebt den Schutz-Stop auf (oder über) den Einstiegspreis, nachdem eine konfigurierbare Gewinnschwelle erreicht wurde.
  • Trailing Stop: optional, wird nach einem Gewinnschwellenwert aktiviert und verfolgt den Preis um eine feste Pip-Distanz. Der Trailing Stop teilt denselben Speicher mit dem Break-Even-Niveau.

Parameter

Name Beschreibung Standard
Entry Candle Kerzentyp für Einstiegslogik 1 Stunde
MACD Candle Höherer Zeitrahmen für MACD-Filter 30 Tage
Fast MA Schnelle EMA-Länge 8
Slow MA Langsame LWMA-Länge 20
Bollinger Length Bollinger-Bänder-Periode 20
Bollinger Width Standardabweichungs-Multiplikator der Bollinger-Bänder 2.0
Stop Loss (pips) Schutz-Stop-Distanz 20
Take Profit (pips) Gewinnziel-Distanz 50
Use Break-Even Break-Even-Anpassung aktivieren true
Break-Even Trigger Gewinn (Pips) zum Verschieben des Stops erforderlich 10
Break-Even Offset Offset am Break-Even-Stop angewendet 5
Use Trailing Trailing Stop aktivieren true
Trailing Activation Gewinn (Pips) zum Aktivieren des Trailings erforderlich 40
Trailing Distance Distanz (Pips) vom Trailing Stop gehalten 40

Hinweise

  • Die Strategie speichert nur die letzten zwei abgeschlossenen Kerzen, um schwere historische Buffer zu vermeiden.
  • MACD-Daten werden vom konfigurierten höheren Zeitrahmen mit aktivierter Aggregation abonniert, was ermöglicht, dass monatliche Signale aus Tagesdaten aufgebaut werden, wenn nötig.
  • Die Pip-zu-Preis-Konvertierung verwendet den Wertpapier-Preisschritt. Instrumente mit nicht-standardmäßigen Pip-Definitionen können eine Parameter-Anpassung erfordern.
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;

public class TrendIsYourFriendStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public TrendIsYourFriendStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}