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
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.
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.
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).
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
Wählen Sie das gewünschte Symbol und den gewünschten Zeitrahmen in StockSharp aus.
Konfigurieren Sie die Parameter, insbesondere CandleType, LotSize und Indikatorzeiträume.
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();
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class band_os_ma_strategy(Strategy):
def __init__(self):
super(band_os_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._macd_fast_period = self.Param("MacdFastPeriod", 20)
self._macd_slow_period = self.Param("MacdSlowPeriod", 50)
self._macd_signal_period = self.Param("MacdSignalPeriod", 12)
self._bollinger_period = self.Param("BollingerPeriod", 14)
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0)
self._macd_history = []
self._osma_history = []
self._prev_osma = None
self._prev_upper = None
self._prev_lower = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MacdFastPeriod(self):
return self._macd_fast_period.Value
@MacdFastPeriod.setter
def MacdFastPeriod(self, value):
self._macd_fast_period.Value = value
@property
def MacdSlowPeriod(self):
return self._macd_slow_period.Value
@MacdSlowPeriod.setter
def MacdSlowPeriod(self, value):
self._macd_slow_period.Value = value
@property
def MacdSignalPeriod(self):
return self._macd_signal_period.Value
@MacdSignalPeriod.setter
def MacdSignalPeriod(self, value):
self._macd_signal_period.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerDeviation(self):
return self._bollinger_deviation.Value
@BollingerDeviation.setter
def BollingerDeviation(self, value):
self._bollinger_deviation.Value = value
def OnReseted(self):
super(band_os_ma_strategy, self).OnReseted()
self._macd_history = []
self._osma_history = []
self._prev_osma = None
self._prev_upper = None
self._prev_lower = None
def OnStarted2(self, time):
super(band_os_ma_strategy, self).OnStarted2(time)
self._macd_history = []
self._osma_history = []
self._prev_osma = None
self._prev_upper = None
self._prev_lower = None
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.MacdFastPeriod
macd.LongMa.Length = self.MacdSlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
macd_val = float(macd_value)
signal_period = self.MacdSignalPeriod
bb_period = self.BollingerPeriod
bb_dev = float(self.BollingerDeviation)
# Compute signal line manually
self._macd_history.append(macd_val)
while len(self._macd_history) > signal_period:
self._macd_history.pop(0)
if len(self._macd_history) < signal_period:
return
signal = sum(self._macd_history) / signal_period
osma = macd_val - signal
# Compute Bollinger Bands on OsMA
self._osma_history.append(osma)
while len(self._osma_history) > bb_period:
self._osma_history.pop(0)
if len(self._osma_history) < bb_period:
return
mean = sum(self._osma_history) / len(self._osma_history)
variance = sum((x - mean) ** 2 for x in self._osma_history) / len(self._osma_history)
std_dev = math.sqrt(variance)
upper = mean + bb_dev * std_dev
lower = mean - bb_dev * std_dev
if self._prev_osma is not None and self._prev_upper is not None and self._prev_lower is not None:
# Buy: OsMA crosses below lower band
if self._prev_osma > self._prev_lower and osma <= lower and self.Position <= 0:
self.BuyMarket()
# Sell: OsMA crosses above upper band
elif self._prev_osma < self._prev_upper and osma >= upper and self.Position >= 0:
self.SellMarket()
self._prev_osma = osma
self._prev_upper = upper
self._prev_lower = lower
def CreateClone(self):
return band_os_ma_strategy()