Ichimoku-Oszillator-Strategie
Die Ichimoku Oscillator-Strategie verwendet einen benutzerdefinierten Oszillator, der vom Ichimoku-Indikator abgeleitet wird. Der Oszillator ist definiert als die Differenz zwischen der Lagging Line und Senkou Span B minus der Differenz zwischen Tenkan-sen und Kijun-sen. Der resultierende Wert wird mit einem Jurik Moving Average geglättet.
Die Strategie eröffnet Positionen, wenn dieser geglättete Oszillator die Richtung wechselt und seinen vorherigen Wert kreuzt, um aufkommende Trends zu erfassen.
Funktionsweise
- Long-Einstieg: Der Oszillator steigt und der aktuelle Wert kreuzt über den vorherigen Wert. Jede Short-Position wird vor dem Long-Einstieg geschlossen.
- Short-Einstieg: Der Oszillator fällt und der aktuelle Wert kreuzt unter den vorherigen Wert. Jede Long-Position wird vor dem Short-Einstieg geschlossen.
- Optionaler Stop-Loss und Take-Profit in Prozent werden für das Risikomanagement angewendet.
Parameter
- Tenkan Period – Tenkan-sen-Periode des Ichimoku-Indikators.
- Kijun Period – Kijun-sen-Periode des Ichimoku-Indikators.
- Senkou Span B Period – Senkou-Span-B-Periode des Ichimoku-Indikators.
- Smoothing Period – Periode für die Jurik-Moving-Average-Glättung des Oszillators.
- Candle Type – Zeitrahmen für die Berechnungen.
- Stop Loss % – Stop-Loss in Prozent ausgedrückt.
- Enable Stop Loss – Aktiviert oder deaktiviert den Stop-Loss-Schutz.
- Take Profit % – Take-Profit in Prozent ausgedrückt.
Indikatoren
- Ichimoku
- Jurik Moving Average
Hinweise
Diese Strategie ist für Bildungszwecke gedacht und sollte vor dem echten Handel an historischen Daten getestet 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;
/// <summary>
/// Strategy based on Ichimoku oscillator smoothed by EMA.
/// Opens long when oscillator turns up, short when it turns down.
/// </summary>
public class IchimokuOscillatorStrategy : Strategy
{
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private readonly StrategyParam<int> _senkouSpanBPeriod;
private readonly StrategyParam<int> _smoothingPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private ExponentialMovingAverage _ema;
private decimal? _prevValue;
private decimal? _prevPrevValue;
public int TenkanPeriod { get => _tenkanPeriod.Value; set => _tenkanPeriod.Value = value; }
public int KijunPeriod { get => _kijunPeriod.Value; set => _kijunPeriod.Value = value; }
public int SenkouSpanBPeriod { get => _senkouSpanBPeriod.Value; set => _senkouSpanBPeriod.Value = value; }
public int SmoothingPeriod { get => _smoothingPeriod.Value; set => _smoothingPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
public IchimokuOscillatorStrategy()
{
_tenkanPeriod = Param(nameof(TenkanPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Tenkan Period", "Period for Tenkan-sen line", "Ichimoku");
_kijunPeriod = Param(nameof(KijunPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Kijun Period", "Period for Kijun-sen line", "Ichimoku");
_senkouSpanBPeriod = Param(nameof(SenkouSpanBPeriod), 52)
.SetGreaterThanZero()
.SetDisplay("Senkou Span B Period", "Period for Senkou Span B", "Ichimoku");
_smoothingPeriod = Param(nameof(SmoothingPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("Smoothing Period", "Period for smoothing EMA", "Oscillator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculation", "Main");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetDisplay("Stop Loss %", "Stop loss in percent", "Risk");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 4m)
.SetDisplay("Take Profit %", "Take profit in percent", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema = default;
_prevValue = null;
_prevPrevValue = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ichimoku = new Ichimoku();
ichimoku.Tenkan.Length = TenkanPeriod;
ichimoku.Kijun.Length = KijunPeriod;
ichimoku.SenkouB.Length = SenkouSpanBPeriod;
_ema = new ExponentialMovingAverage { Length = SmoothingPeriod };
Indicators.Add(_ema);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ichimoku, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPercent, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue ichimokuValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!ichimokuValue.IsFormed)
return;
var ich = (IchimokuValue)ichimokuValue;
if (ich.Chinkou is not decimal chikou ||
ich.SenkouB is not decimal spanB ||
ich.Tenkan is not decimal tenkan ||
ich.Kijun is not decimal kijun)
return;
var osc = (chikou - spanB) - (tenkan - kijun);
var emaVal = _ema.Process(osc, candle.OpenTime, true);
if (!emaVal.IsFormed)
return;
var current = emaVal.ToDecimal();
if (_prevValue is decimal prev && _prevPrevValue is decimal prevPrev)
{
var rising = prev > prevPrev;
var falling = prev < prevPrev;
if (rising && current >= prev && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (falling && current <= prev && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
}
_prevPrevValue = _prevValue;
_prevValue = current;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Ichimoku
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class ichimoku_oscillator_strategy(Strategy):
def __init__(self):
super(ichimoku_oscillator_strategy, self).__init__()
self._tenkan_period = self.Param("TenkanPeriod", 9) \
.SetDisplay("Tenkan Period", "Period for Tenkan-sen line", "Ichimoku")
self._kijun_period = self.Param("KijunPeriod", 26) \
.SetDisplay("Kijun Period", "Period for Kijun-sen line", "Ichimoku")
self._senkou_span_b_period = self.Param("SenkouSpanBPeriod", 52) \
.SetDisplay("Senkou Span B Period", "Period for Senkou Span B", "Ichimoku")
self._smoothing_period = self.Param("SmoothingPeriod", 7) \
.SetDisplay("Smoothing Period", "Period for smoothing EMA", "Oscillator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for calculation", "Main")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss in percent", "Risk")
self._take_profit_percent = self.Param("TakeProfitPercent", 4.0) \
.SetDisplay("Take Profit %", "Take profit in percent", "Risk")
self._ema = None
self._prev_value = None
self._prev_prev_value = None
@property
def TenkanPeriod(self):
return self._tenkan_period.Value
@TenkanPeriod.setter
def TenkanPeriod(self, value):
self._tenkan_period.Value = value
@property
def KijunPeriod(self):
return self._kijun_period.Value
@KijunPeriod.setter
def KijunPeriod(self, value):
self._kijun_period.Value = value
@property
def SenkouSpanBPeriod(self):
return self._senkou_span_b_period.Value
@SenkouSpanBPeriod.setter
def SenkouSpanBPeriod(self, value):
self._senkou_span_b_period.Value = value
@property
def SmoothingPeriod(self):
return self._smoothing_period.Value
@SmoothingPeriod.setter
def SmoothingPeriod(self, value):
self._smoothing_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def StopLossPercent(self):
return self._stop_loss_percent.Value
@StopLossPercent.setter
def StopLossPercent(self, value):
self._stop_loss_percent.Value = value
@property
def TakeProfitPercent(self):
return self._take_profit_percent.Value
@TakeProfitPercent.setter
def TakeProfitPercent(self, value):
self._take_profit_percent.Value = value
def OnStarted2(self, time):
super(ichimoku_oscillator_strategy, self).OnStarted2(time)
ichimoku = Ichimoku()
ichimoku.Tenkan.Length = self.TenkanPeriod
ichimoku.Kijun.Length = self.KijunPeriod
ichimoku.SenkouB.Length = self.SenkouSpanBPeriod
self._ema = ExponentialMovingAverage()
self._ema.Length = self.SmoothingPeriod
self.Indicators.Add(self._ema)
self._prev_value = None
self._prev_prev_value = None
self.SubscribeCandles(self.CandleType) \
.BindEx(ichimoku, self.ProcessCandle) \
.Start()
self.StartProtection(
takeProfit=Unit(float(self.TakeProfitPercent), UnitTypes.Percent),
stopLoss=Unit(float(self.StopLossPercent), UnitTypes.Percent),
useMarketOrders=True
)
def ProcessCandle(self, candle, ichimoku_value):
if candle.State != CandleStates.Finished:
return
if not ichimoku_value.IsFormed:
return
chikou = ichimoku_value.Chinkou
span_b = ichimoku_value.SenkouB
tenkan = ichimoku_value.Tenkan
kijun = ichimoku_value.Kijun
if chikou is None or span_b is None or tenkan is None or kijun is None:
return
osc = (chikou - span_b) - (tenkan - kijun)
t = candle.OpenTime
ema_result = process_float(self._ema, osc, t, True)
if not ema_result.IsFormed:
return
current = float(ema_result)
if self._prev_value is not None and self._prev_prev_value is not None:
prev = self._prev_value
prev_prev = self._prev_prev_value
rising = prev > prev_prev
falling = prev < prev_prev
if rising and current >= prev and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif falling and current <= prev and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_value = self._prev_value
self._prev_value = current
def OnReseted(self):
super(ichimoku_oscillator_strategy, self).OnReseted()
self._ema = None
self._prev_value = None
self._prev_prev_value = None
def CreateClone(self):
return ichimoku_oscillator_strategy()