Auf GitHub ansehen

Four Hour Swing-Strategie

Überblick

Die Four Hour Swing-Strategie portiert den MetaTrader-Expert-Advisor „4H swing" auf die hochrangige StockSharp-API. Das ursprüngliche System kombiniert Trendfolge und Oszillatorbestätigungen aus höheren Zeitrahmen. Diese C#-Version abonniert drei Zeitrahmen (Einstieg, Bestätigung und Makro-Filter) und recreiert den Indikator-Stack mit StockSharp-Komponenten.

Handelslogik

  • Der Haupt-Trendfilter verwendet drei exponentielle gleitende Durchschnitte, berechnet auf dem typischen Preis der Einstiegskerzen. Ein Long-Setup erfordert Fast EMA > Medium EMA > Slow EMA; ein Short-Setup spiegelt die Bedingung.
  • Stochastic-Oszillatorwerte werden auf dem höheren Bestätigungszeitrahmen ausgewertet. Die %K-Linie muss für Longs über %D und für Shorts darunter bleiben.
  • Momentum wird aus denselben Bestätigungskerzen abgetastet und in das MetaTrader-Verhältnis um 100 umgewandelt. Ein Trade ist nur erlaubt, wenn mindestens eine der letzten drei Momentum-Messwerte weiter als der konfigurierte Schwellenwert entfernt ist.
  • Monatliche (oder benutzerdefinierte) MACD-Werte liefern den Makro-Richtungsfilter. Ein Kauf erfordert die MACD-Linie über ihrem Signal, während ein Verkauf die entgegengesetzte Beziehung prüft.

Eine Position wird auf der nächsten Basiskerze eröffnet, sobald alle Bestätigungen übereinstimmen und das Konto flach oder in entgegengesetzter Richtung positioniert ist (in diesem Fall schließt und kehrt die Marktorder um).

Risikomanagement

  • Feste Stop-Loss- und Take-Profit-Abstände (in Pips) werden sofort nach dem Einstieg angewendet.
  • Ein optionaler Trailing-Stop folgt dem extremen Preis nach dem Einstieg.
  • Break-Even-Schutz kann den Stop auf den Einstiegspreis plus einen Offset verschieben, sobald die konfigurierte Auslösedistanz erreicht ist.
  • Ein optionaler MACD-Ausstieg schließt offene Trades, wenn der Makro-Filter kippt.

Parameter

Name Beschreibung Standardwert
TradeVolume Standard-Marktordervolumen. 0.01
CandleType Einstiegskerzentyp (z. B. 4-Stunden-Kerzen). 4H
SignalCandleType Bestätigungskerzentyp für Stochastic und Momentum. 7D (wöchentlich)
MacdCandleType Makro-Filter-Kerzentyp. 30D
FastEmaPeriod, MediumEmaPeriod, SlowEmaPeriod EMA-Längen auf dem typischen Preis. 4, 14, 50
StochasticKPeriod, StochasticDPeriod, StochasticSmoothPeriod Stochastic-Oszillator-Einstellungen. 13, 5, 5
MomentumPeriod Rückblickperiode des Momentum-Indikators. 14
MomentumThreshold Mindestabstand von 100 zur Validierung des Momentums. 0.3
StopLossPips, TakeProfitPips Schutzorders in Pips. 20, 50
TrailingStopPips Trailing-Stop-Abstand in Pips. Auf null setzen zum Deaktivieren. 40
UseBreakEven Aktiviert den Break-Even-Schutz. true
BreakEvenTriggerPips, BreakEvenOffsetPips Auslöser und Offset für die Break-Even-Verschiebung. 30, 30
UseMacdExit Positionen schließen, wenn der Makro-MACD kippt. false

Hinweise

  • Die Geldmanagement-Funktionen (Eigenkapital-Stops, Währungsziele) des ursprünglichen Experten sind absichtlich weggelassen, um die Implementierung kompakt zu halten.
  • Die Strategie verarbeitet nur abgeschlossene Kerzen, entsprechend der bar-für-bar-Auswertung von MetaTrader.
  • Standard-Zeitrahmen reproduzieren das übliche 4-Stunden-Setup (wöchentliche Bestätigung und monatlicher Filter), aber jeder DataType-Parameter kann für alternative Perioden neu konfiguriert werden.
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 FourHourSwingStrategy : 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 FourHourSwingStrategy()
	{
		_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;
	}
}