This strategy implements a trading system based on the DiNapoli Stochastic oscillator. It reacts to the crossovers between the %K and %D lines of the stochastic indicator.
Strategy Logic
Subscribe to candles of the selected timeframe.
Calculate the DiNapoli Stochastic values using the standard Stochastic oscillator with smoothing periods.
Close short positions whenever the previous %K was above %D.
Close long positions whenever the previous %K was below %D.
Open a long position when %K crosses below %D and long trades are allowed.
Open a short position when %K crosses above %D and short trades are allowed.
Parameters
FastK – base period for %K.
SlowK – smoothing period for %K.
SlowD – smoothing period for %D.
BuyOpen – enable or disable long entries.
SellOpen – enable or disable short entries.
BuyClose – enable or disable closing long positions.
SellClose – enable or disable closing short positions.
CandleType – candle timeframe used for calculations.
Notes
The strategy uses the high-level StockSharp API and processes only finished candles. Indicator values are obtained through BindEx without using historical value requests.
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>
/// DiNapoli Stochastic cross strategy.
/// Opens a long position when the %K line crosses above %D and
/// a short position when %K crosses below %D.
/// </summary>
public class DiNapoliStochasticStrategy : Strategy
{
private readonly StrategyParam<int> _fastK;
private readonly StrategyParam<int> _slowD;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevK;
private decimal _prevD;
private bool _prevReady;
public int FastK { get => _fastK.Value; set => _fastK.Value = value; }
public int SlowD { get => _slowD.Value; set => _slowD.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public DiNapoliStochasticStrategy()
{
_fastK = Param(nameof(FastK), 8)
.SetGreaterThanZero()
.SetDisplay("Fast %K", "Base period for %K", "DiNapoli");
_slowD = Param(nameof(SlowD), 3)
.SetGreaterThanZero()
.SetDisplay("Slow %D", "%D smoothing period", "DiNapoli");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(6).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevK = 0m;
_prevD = 0m;
_prevReady = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(null, null);
var stochastic = new StochasticOscillator();
stochastic.K.Length = FastK;
stochastic.D.Length = SlowD;
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(stochastic, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, stochastic);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
var stoch = (IStochasticOscillatorValue)stochValue;
if (stoch.K is not decimal k || stoch.D is not decimal d)
return;
if (!_prevReady)
{
_prevK = k;
_prevD = d;
_prevReady = true;
return;
}
// %K crosses above %D - buy signal
if (_prevK <= _prevD && k > d && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// %K crosses below %D - sell signal
else if (_prevK >= _prevD && k < d && Position >= 0)
{
if (Position > 0)
SellMarket();
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 di_napoli_stochastic_strategy(Strategy):
def __init__(self):
super(di_napoli_stochastic_strategy, self).__init__()
self._fast_k = self.Param("FastK", 8) \
.SetDisplay("Fast %K", "Base period for %K", "DiNapoli")
self._slow_d = self.Param("SlowD", 3) \
.SetDisplay("Slow %D", "%D smoothing period", "DiNapoli")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(6))) \
.SetDisplay("Candle Type", "Type of candles for calculation", "General")
self._prev_k = 0.0
self._prev_d = 0.0
self._prev_ready = False
@property
def FastK(self):
return self._fast_k.Value
@FastK.setter
def FastK(self, value):
self._fast_k.Value = value
@property
def SlowD(self):
return self._slow_d.Value
@SlowD.setter
def SlowD(self, value):
self._slow_d.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(di_napoli_stochastic_strategy, self).OnStarted2(time)
stochastic = StochasticOscillator()
stochastic.K.Length = self.FastK
stochastic.D.Length = self.SlowD
self.SubscribeCandles(self.CandleType) \
.BindEx(stochastic, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, stoch_value):
if candle.State != CandleStates.Finished:
return
k_val = stoch_value.K
d_val = stoch_value.D
if k_val is None or d_val is None:
return
k = float(k_val)
d = float(d_val)
if not self._prev_ready:
self._prev_k = k
self._prev_d = d
self._prev_ready = True
return
if self._prev_k <= self._prev_d and k > d and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_k >= self._prev_d and k < d and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_k = k
self._prev_d = d
def OnReseted(self):
super(di_napoli_stochastic_strategy, self).OnReseted()
self._prev_k = 0.0
self._prev_d = 0.0
self._prev_ready = False
def CreateClone(self):
return di_napoli_stochastic_strategy()