Diese Strategie ist ein StockSharp-Port des originalen MQL-Experten Exp_Stochastic_Histogram.
Sie verwendet den Stochastic-Oszillator, um in zwei Modi konträre Handelssignale zu erzeugen:
Levels – Ein Signal erscheint, wenn %K die durch HighLevel und LowLevel definierten überkauften oder überverkauften Bereiche verlässt.
Cross – Ein Signal erscheint, wenn %K die %D-Linie kreuzt. Der Trade wird in der entgegengesetzten Richtung der Kreuzung eröffnet.
Wann immer ein neues Signal empfangen wird, schließt die Strategie eine bestehende Position und eröffnet eine neue in der erforderlichen Richtung.
Parameter
KPeriod – Haupt-%K-Zeitraum.
DPeriod – %D-Glättungszeitraum.
Slowing – Zusätzliche Glättung von %K.
HighLevel – Obere Schwelle für den Levels-Modus.
LowLevel – Untere Schwelle für den Levels-Modus.
Mode – Levels oder Cross.
CandleType – Kerzen-Zeitrahmen für Berechnungen.
Funktionsweise
Für jede abgeschlossene Kerze wird der Stochastic-Oszillator aktualisiert und bewertet. Im Levels-Modus wird ein Long-Trade eröffnet, wenn %K unter das hohe Niveau zurückkehrt, und ein Short-Trade, wenn %K über das niedrige Niveau steigt. Im Cross-Modus wird ein Long-Trade bei abwärts gerichteten Kreuzungen von %K unter %D eröffnet, während aufwärts gerichtete Kreuzungen Short-Trades auslösen. Die Strategie hat jederzeit höchstens eine offene Position.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Stochastic-based strategy with crossover mode.
/// Generates contrarian signals when K crosses D.
/// </summary>
public class StochasticHistogramStrategy : Strategy
{
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevK;
private decimal? _prevD;
public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
public decimal HighLevel { get => _highLevel.Value; set => _highLevel.Value = value; }
public decimal LowLevel { get => _lowLevel.Value; set => _lowLevel.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public StochasticHistogramStrategy()
{
_kPeriod = Param(nameof(KPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("K Period", "Stochastic %K period", "Stochastic");
_dPeriod = Param(nameof(DPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("D Period", "Stochastic %D period", "Stochastic");
_highLevel = Param(nameof(HighLevel), 80m)
.SetDisplay("High Level", "Upper threshold", "Stochastic");
_lowLevel = Param(nameof(LowLevel), 20m)
.SetDisplay("Low Level", "Lower threshold", "Stochastic");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for calculation", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevK = null;
_prevD = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stoch = new StochasticOscillator();
stoch.K.Length = KPeriod;
stoch.D.Length = DPeriod;
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(stoch, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, stoch);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
var sv = stochValue as IStochasticOscillatorValue;
if (sv?.K is not decimal k || sv?.D is not decimal d)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevK = k;
_prevD = d;
return;
}
if (_prevK is decimal pk && _prevD is decimal pd)
{
// K crosses above D in oversold zone - buy
if (pk <= pd && k > d && k < LowLevel && Position <= 0)
BuyMarket();
// K crosses below D in overbought zone - sell
else if (pk >= pd && k < d && k > HighLevel && Position >= 0)
SellMarket();
}
_prevK = k;
_prevD = d;
}
}
import clr
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 StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class stochastic_histogram_strategy(Strategy):
def __init__(self):
super(stochastic_histogram_strategy, self).__init__()
self._k_period = self.Param("KPeriod", 5) \
.SetDisplay("K Period", "Stochastic %K period", "Stochastic")
self._d_period = self.Param("DPeriod", 3) \
.SetDisplay("D Period", "Stochastic %D period", "Stochastic")
self._high_level = self.Param("HighLevel", 80.0) \
.SetDisplay("High Level", "Upper threshold", "Stochastic")
self._low_level = self.Param("LowLevel", 20.0) \
.SetDisplay("Low Level", "Lower threshold", "Stochastic")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for calculation", "General")
self._prev_k = None
self._prev_d = None
@property
def k_period(self):
return self._k_period.Value
@property
def d_period(self):
return self._d_period.Value
@property
def high_level(self):
return self._high_level.Value
@property
def low_level(self):
return self._low_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(stochastic_histogram_strategy, self).OnReseted()
self._prev_k = None
self._prev_d = None
def OnStarted2(self, time):
super(stochastic_histogram_strategy, self).OnStarted2(time)
stoch = StochasticOscillator()
stoch.K.Length = self.k_period
stoch.D.Length = self.d_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stoch, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, stoch)
self.DrawOwnTrades(area)
def process_candle(self, candle, stoch_value):
if candle.State != CandleStates.Finished:
return
if not stoch_value.IsFormed:
return
k = stoch_value.K
d = stoch_value.D
if k is None or d is None:
return
k = float(k)
d = float(d)
if self._prev_k is not None and self._prev_d is not None:
pk = self._prev_k
pd = self._prev_d
if pk <= pd and k > d and k < float(self.low_level) and self.Position <= 0:
self.BuyMarket()
elif pk >= pd and k < d and k > float(self.high_level) and self.Position >= 0:
self.SellMarket()
self._prev_k = k
self._prev_d = d
def CreateClone(self):
return stochastic_histogram_strategy()