SpectrAnalysis Chaikin-Strategie
Diese Strategie verwendet den Chaikin-Oszillator, um Momentum-Wechsel zu erkennen. Der Oszillator wird aus der Akkumulations-/Distributions-Linie berechnet, die durch zwei linear gewichtete gleitende Durchschnitte geglättet wird. Wenn die Steigung des Oszillators nach oben dreht und der letzte Wert über den vorherigen Wert kreuzt, wird eine Long-Position eröffnet. Umgekehrt wird eine Short-Position eröffnet, wenn die Steigung nach unten dreht und der letzte Wert unter den vorherigen Wert kreuzt.
Parameter
| Name | Beschreibung |
|---|---|
FastMaPeriod |
Periode des schnellen linear gewichteten gleitenden Durchschnitts im Chaikin-Oszillator. |
SlowMaPeriod |
Periode des langsamen linear gewichteten gleitenden Durchschnitts im Chaikin-Oszillator. |
BuyPosOpen |
Eröffnen von Long-Positionen aktivieren. |
SellPosOpen |
Eröffnen von Short-Positionen aktivieren. |
BuyPosClose |
Schließen von Long-Positionen bei erfüllten Bedingungen aktivieren. |
SellPosClose |
Schließen von Short-Positionen bei erfüllten Bedingungen aktivieren. |
CandleType |
Zeitrahmen der Kerzen für die Berechnung. |
Hinweise
- Für Ein- und Ausstiege werden Marktorders verwendet.
- Die Strategie setzt keine Stop-Loss- oder Take-Profit-Orders.
- Es wird nur die C#-Version bereitgestellt; eine Python-Implementierung ist nicht enthalten.
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 the Chaikin oscillator direction.
/// </summary>
public class SpectrAnalysisChaikinStrategy : Strategy
{
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private readonly StrategyParam<DataType> _candleType;
private int _barCount;
private decimal? _fastEma;
private decimal? _slowEma;
private decimal? _prev;
private decimal? _prev2;
/// <summary>
/// Fast MA period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow MA period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// Allow opening long positions.
/// </summary>
public bool BuyPosOpen
{
get => _buyPosOpen.Value;
set => _buyPosOpen.Value = value;
}
/// <summary>
/// Allow opening short positions.
/// </summary>
public bool SellPosOpen
{
get => _sellPosOpen.Value;
set => _sellPosOpen.Value = value;
}
/// <summary>
/// Allow closing long positions.
/// </summary>
public bool BuyPosClose
{
get => _buyPosClose.Value;
set => _buyPosClose.Value = value;
}
/// <summary>
/// Allow closing short positions.
/// </summary>
public bool SellPosClose
{
get => _sellPosClose.Value;
set => _sellPosClose.Value = value;
}
/// <summary>
/// Candle type used for calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="SpectrAnalysisChaikinStrategy"/>.
/// </summary>
public SpectrAnalysisChaikinStrategy()
{
_fastMaPeriod = Param(nameof(FastMaPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast EMA period", "Indicator");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow EMA period", "Indicator");
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Buy Position Open", "Allow opening long positions", "Trading");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Sell Position Open", "Allow opening short positions", "Trading");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Buy Position Close", "Allow closing long positions", "Trading");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Sell Position Close", "Allow closing short positions", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "Data");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_barCount = 0;
_fastEma = null;
_slowEma = null;
_prev = null;
_prev2 = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_barCount = 0;
_fastEma = null;
_slowEma = null;
_prev = null;
_prev2 = null;
var ad = new AccumulationDistributionLine();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ad, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ad);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal adValue)
{
if (candle.State != CandleStates.Finished)
return;
_barCount++;
_fastEma = UpdateEma(_fastEma, adValue, FastMaPeriod);
_slowEma = UpdateEma(_slowEma, adValue, SlowMaPeriod);
if (_fastEma is not decimal fastEma || _slowEma is not decimal slowEma)
return;
var oscillator = fastEma - slowEma;
if (_barCount < SlowMaPeriod || !IsFormedAndOnlineAndAllowTrading())
{
UpdateHistory(oscillator);
return;
}
if (_prev is decimal prev && _prev2 is decimal prev2)
{
if (prev < prev2 && oscillator >= prev && oscillator > 0)
{
if (BuyPosOpen && Position <= 0)
BuyMarket(Position < 0 ? Volume + Math.Abs(Position) : Volume);
else if (SellPosClose && Position < 0)
BuyMarket(Math.Abs(Position));
}
else if (prev > prev2 && oscillator <= prev && oscillator < 0)
{
if (SellPosOpen && Position >= 0)
SellMarket(Position > 0 ? Volume + Position : Volume);
else if (BuyPosClose && Position > 0)
SellMarket(Position);
}
}
UpdateHistory(oscillator);
}
private decimal UpdateEma(decimal? current, decimal value, int length)
{
if (current is null)
return value;
var multiplier = 2m / (length + 1);
return current.Value + ((value - current.Value) * multiplier);
}
private void UpdateHistory(decimal oscillator)
{
_prev2 = _prev;
_prev = oscillator;
}
}
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 AccumulationDistributionLine
from StockSharp.Algo.Strategies import Strategy
class spectr_analysis_chaikin_strategy(Strategy):
def __init__(self):
super(spectr_analysis_chaikin_strategy, self).__init__()
self._fast_ma_period = self.Param("FastMaPeriod", 3) \
.SetDisplay("Fast MA", "Fast EMA period", "Indicator")
self._slow_ma_period = self.Param("SlowMaPeriod", 10) \
.SetDisplay("Slow MA", "Slow EMA period", "Indicator")
self._buy_pos_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Buy Position Open", "Allow opening long positions", "Trading")
self._sell_pos_open = self.Param("SellPosOpen", True) \
.SetDisplay("Sell Position Open", "Allow opening short positions", "Trading")
self._buy_pos_close = self.Param("BuyPosClose", True) \
.SetDisplay("Buy Position Close", "Allow closing long positions", "Trading")
self._sell_pos_close = self.Param("SellPosClose", True) \
.SetDisplay("Sell Position Close", "Allow closing short positions", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candles", "Data")
self._bar_count = 0
self._fast_ema = None
self._slow_ema = None
self._prev = None
self._prev2 = None
@property
def fast_ma_period(self):
return self._fast_ma_period.Value
@property
def slow_ma_period(self):
return self._slow_ma_period.Value
@property
def buy_pos_open(self):
return self._buy_pos_open.Value
@property
def sell_pos_open(self):
return self._sell_pos_open.Value
@property
def buy_pos_close(self):
return self._buy_pos_close.Value
@property
def sell_pos_close(self):
return self._sell_pos_close.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(spectr_analysis_chaikin_strategy, self).OnReseted()
self._bar_count = 0
self._fast_ema = None
self._slow_ema = None
self._prev = None
self._prev2 = None
def OnStarted2(self, time):
super(spectr_analysis_chaikin_strategy, self).OnStarted2(time)
self._bar_count = 0
self._fast_ema = None
self._slow_ema = None
self._prev = None
self._prev2 = None
ad = AccumulationDistributionLine()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ad, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ad)
self.DrawOwnTrades(area)
def _update_ema(self, current, value, length):
if current is None:
return value
multiplier = 2.0 / (length + 1)
return current + ((value - current) * multiplier)
def _update_history(self, oscillator):
self._prev2 = self._prev
self._prev = oscillator
def process_candle(self, candle, ad_value):
if candle.State != CandleStates.Finished:
return
ad_value = float(ad_value)
self._bar_count += 1
fast_period = int(self.fast_ma_period)
slow_period = int(self.slow_ma_period)
self._fast_ema = self._update_ema(self._fast_ema, ad_value, fast_period)
self._slow_ema = self._update_ema(self._slow_ema, ad_value, slow_period)
if self._fast_ema is None or self._slow_ema is None:
return
oscillator = self._fast_ema - self._slow_ema
if self._bar_count < slow_period:
self._update_history(oscillator)
return
if self._prev is not None and self._prev2 is not None:
if self._prev < self._prev2 and oscillator >= self._prev and oscillator > 0:
if self.buy_pos_open and self.Position <= 0:
self.BuyMarket()
elif self.sell_pos_close and self.Position < 0:
self.BuyMarket()
elif self._prev > self._prev2 and oscillator <= self._prev and oscillator < 0:
if self.sell_pos_open and self.Position >= 0:
self.SellMarket()
elif self.buy_pos_close and self.Position > 0:
self.SellMarket()
self._update_history(oscillator)
def CreateClone(self):
return spectr_analysis_chaikin_strategy()