Auf GitHub ansehen

BandOsMa-Strategie

Überblick

Die BandOsMa-Strategie wandelt den MetaTrader 5 „BandOsMA“-Expertenberater in eine StockSharp-Strategie um. Es wertet das MACD-Histogramm (OsMA) mithilfe von Bollinger-Bändern aus, die direkt auf den Histogrammwerten basieren. Ausbrüche über oder unter den Bändern erzeugen Einstiegssignale, während ein zusätzlicher gleitender Durchschnitt des Histogramms Signalausgänge verwaltet.

Die Strategie basiert auf einem einzelnen Symbol und einem vom Benutzer ausgewählten Zeitrahmen. Die Indikatorwerte werden für fertige Kerzen mithilfe der High-Level-Kerzenabonnements von StockSharp berechnet.

Handelslogik

  1. Indikatoren
    • MovingAverageConvergenceDivergenceSignal stellt das MACD-Histogramm (OsMA) bereit.
    • BollingerBands wird auf die OsMA-Sequenz angewendet, um extreme Abweichungen zu erkennen.
    • Ein konfigurierbarer gleitender Durchschnitt glättet das Histogramm und fungiert als Ausgangsfilter.
  2. Eintrag
    • Ein Long-Signal erscheint, wenn der aktuelle OsMA unterhalb des unteren Bandes schließt, während der vorherige Balken darüber blieb.
    • Ein Short-Signal erscheint, wenn der aktuelle OsMA über dem oberen Band schließt, während der vorherige Balken darunter blieb.
  3. Ausstieg
    • Signale werden gelöscht, wenn das Histogramm den gleitenden Durchschnitt in die entgegengesetzte Richtung kreuzt.
    • Wenn eine offene Position nicht mehr mit dem aktiven Signal übereinstimmt, wird die Position sofort geschlossen.
    • Jeder Position ist ein Pip-basierter Stop-Loss zugeordnet. Der Stopp fungiert auch als Trailing-Stop mit derselben Distanz und einem Trailing-Schritt gleich StopLossPoints / 50 (Spiegelung der Hilfsklasse MetaTrader).

Positionsmanagement

  • Stop Loss & Trailing: Die Stop-Distanz wird in MetaTrader Punkten ausgedrückt und mithilfe des PriceStep des Instruments in Preiseinheiten umgerechnet. Der gleiche Abstand wird für den Trailing Stop verwendet, der sich nach vorne bewegt, sobald sich der Schlusskurs um mindestens den Trailing Step verbessert.
  • Eine Position nach der anderen: Es wird nur eine Nettoposition beibehalten. Entgegengesetzte Signale schließen die aktuelle Position, bevor ein neuer Eintrag in Betracht gezogen wird.

Parameter

Gruppe Name Beschreibung Standard
Allgemein CandleType Zeitrahmen für das Kerzenabonnement und die Indikatorberechnung. H1
Risiko LotSize Handelsvolumen in Lots. 0.01
Risiko StopLossPoints Stop-Loss-Distanz, ausgedrückt in MetaTrader Punkten (wird auch für Trailing verwendet). 1000
Indikatoren MacdFastPeriod Schnelle Länge von EMA in MACD. 12
Indikatoren MacdSlowPeriod Langsame EMA-Länge in MACD. 26
Indikatoren MacdSignalPeriod Signallänge von EMA in MACD. 9
Indikatoren PriceType Angewandter Preis für MACD-Eingabe (Close, Open, High, Low, Median, Typical, Weighted). Typical
Indikatoren BollingerPeriod Periode von Bollinger Bändern über der OsMA-Sequenz. 26
Indikatoren BollingerShift Verschiebung wird auf Bollinger Puffer angewendet (nicht negativ). 0
Indikatoren BollingerDeviation Standardabweichungsmultiplikator für Bollinger-Bänder. 2
Indikatoren MovingAveragePeriod Länge des auf OsMA angewendeten gleitenden Durchschnitts. 10
Indikatoren MovingAverageShift Auf den gleitenden Durchschnittspuffer angewendete Verschiebung (nicht negativ). 0
Indikatoren MovingAverageMethod Typ des gleitenden Durchschnitts (Simple, Exponential, Smoothed, LinearWeighted). Simple

Implementierungshinweise

  • Die Kerzenverarbeitung verwendet WhenCandlesFinished, um sicherzustellen, dass nur die letzten Balken die Logik steuern.
  • Indikatorwerte werden in Verlaufspuffern gespeichert, um Pufferverschiebungen im MetaTrader-Stil zu emulieren. Negative Verschiebungen werden nicht unterstützt; Verwenden Sie Nullwerte oder positive Werte wie in den ursprünglichen Expertenstandards.
  • Trailing-Stops basieren auf Kerzenschließungen und nicht auf Tick-für-Tick-Aktualisierungen. Passen Sie den Pip-Abstand an, wenn ein präzises Nachlaufen auf Tick-Ebene erforderlich ist.

Nutzung

  1. Wählen Sie das gewünschte Symbol und den gewünschten Zeitrahmen in StockSharp aus.
  2. Konfigurieren Sie die Parameter, insbesondere CandleType, LotSize und Indikatorzeiträume.
  3. Starten Sie die Strategie; Es abonniert Kerzen, berechnet die Indikatoren und führt Geschäfte gemäß der beschriebenen Logik aus.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy combining the MACD histogram (OsMA) with Bollinger Bands to trade reversals.
/// When OsMA crosses below lower Bollinger band, buy signal is generated.
/// When OsMA crosses above upper Bollinger band, sell signal is generated.
/// </summary>
public class BandOsMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _macdSignalPeriod;
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;

	private decimal _prevOsma;
	private decimal _prevUpper;
	private decimal _prevLower;
	private bool _hasPrev;

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

	public int MacdFastPeriod
	{
		get => _macdFastPeriod.Value;
		set => _macdFastPeriod.Value = value;
	}

	public int MacdSlowPeriod
	{
		get => _macdSlowPeriod.Value;
		set => _macdSlowPeriod.Value = value;
	}

	public int MacdSignalPeriod
	{
		get => _macdSignalPeriod.Value;
		set => _macdSignalPeriod.Value = value;
	}

	public int BollingerPeriod
	{
		get => _bollingerPeriod.Value;
		set => _bollingerPeriod.Value = value;
	}

	public decimal BollingerDeviation
	{
		get => _bollingerDeviation.Value;
		set => _bollingerDeviation.Value = value;
	}

	public BandOsMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Primary timeframe", "General");

		_macdFastPeriod = Param(nameof(MacdFastPeriod), 20)
			.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 50)
			.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");

		_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 12)
			.SetDisplay("MACD Signal", "Signal EMA length", "Indicators");

		_bollingerPeriod = Param(nameof(BollingerPeriod), 14)
			.SetDisplay("Bollinger Period", "OsMA Bollinger Bands period", "Indicators");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetDisplay("Bollinger Deviation", "Bollinger Bands deviation", "Indicators");
	}

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

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = MacdFastPeriod },
				LongMa = { Length = MacdSlowPeriod }
			},
			SignalMa = { Length = MacdSignalPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, macd);
			DrawOwnTrades(area);
		}
	}

	private BollingerBands _bollinger;

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var val = (IMovingAverageConvergenceDivergenceSignalValue)macdValue;
		if (val.Macd is not decimal macdLine || val.Signal is not decimal signalLine)
			return;

		var osma = macdLine - signalLine;

		_bollinger ??= new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};

		var bbResult = (BollingerBandsValue)_bollinger.Process(new DecimalIndicatorValue(_bollinger, osma, candle.CloseTime));
		if (bbResult.UpBand is not decimal upper || bbResult.LowBand is not decimal lower)
		{
			return;
		}

		if (_hasPrev)
		{
			// Buy: OsMA crosses below lower band (reversal up expected)
			if (_prevOsma > _prevLower && osma <= lower && Position <= 0)
			{
				BuyMarket(Position < 0 ? Math.Abs(Position) + 1 : 1);
			}
			// Sell: OsMA crosses above upper band (reversal down expected)
			else if (_prevOsma < _prevUpper && osma >= upper && Position >= 0)
			{
				SellMarket(Position > 0 ? Math.Abs(Position) + 1 : 1);
			}
		}

		_prevOsma = osma;
		_prevUpper = upper;
		_prevLower = lower;
		_hasPrev = true;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_prevOsma = 0;
		_prevUpper = 0;
		_prevLower = 0;
		_hasPrev = false;
		_bollinger = null;

		base.OnReseted();
	}
}