Стратегия использует осциллятор Stochastic на выбранном таймфрейме свечей. Она ждёт, пока линии %K и %D войдут в экстремальные зоны, и открывает позицию при их пересечении. Для каждой сделки задаются фиксированные уровни тейк‑профита и стоп‑лосса, а трейлинг‑стоп защищает уже полученную прибыль.
Логика
Вход
Покупка:
Две свечи назад обе линии были ниже уровня OverSold.
Две свечи назад линия %D была выше %K, а одну свечу назад ниже %K.
%D растёт.
Продажа:
Две свечи назад обе линии были выше уровня OverBought.
Две свечи назад линия %D была ниже %K, а одну свечу назад выше %K.
%D снижается.
Выход
Позиция закрывается, когда Stochastic выходит из экстремальной зоны или %D меняет направление.
Трейлинг‑стоп закрывает позицию, если цена откатывается на величину TrailingStop.
На каждую сделку распространяются глобальные уровни TakeProfit и StopLoss.
Параметры
Имя
Описание
CandleType
Таймфрейм свечей для расчёта Stochastic.
KPeriod
Период расчёта линии %K.
DPeriod
Период сглаживания линии %D.
Slowing
Дополнительное сглаживание %K.
OverBought
Верхний уровень перекупленности.
OverSold
Нижний уровень перепроданности.
TakeProfit
Расстояние от цены входа до тейк‑профита (в ценовых единицах).
StopLoss
Расстояние от цены входа до стоп‑лосса (в ценовых единицах).
TrailingStop
Размер трейлинг‑стопа (в ценовых единицах).
Индикаторы
StochasticOscillator
Примечания
Комментарии в коде даны на английском языке.
Версия на Python отсутствует.
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 oscillator based strategy.
/// Buys on K/D crossover in oversold, sells on crossover in overbought.
/// </summary>
public class StochasticAutomatedStrategy : Strategy
{
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<decimal> _overBought;
private readonly StrategyParam<decimal> _overSold;
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 OverBought { get => _overBought.Value; set => _overBought.Value = value; }
public decimal OverSold { get => _overSold.Value; set => _overSold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public StochasticAutomatedStrategy()
{
_kPeriod = Param(nameof(KPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("%K Period", "Stochastic %K period", "Stochastic");
_dPeriod = Param(nameof(DPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("%D Period", "Stochastic %D period", "Stochastic");
_overBought = Param(nameof(OverBought), 80m)
.SetDisplay("Overbought", "Overbought threshold", "Stochastic");
_overSold = Param(nameof(OverSold), 20m)
.SetDisplay("Oversold", "Oversold threshold", "Stochastic");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevK = _prevD = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stochastic = new StochasticOscillator();
stochastic.K.Length = KPeriod;
stochastic.D.Length = DPeriod;
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;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var stoch = (IStochasticOscillatorValue)stochValue;
if (stoch.K is not decimal k || stoch.D is not decimal d)
return;
if (_prevK is decimal pk && _prevD is decimal pd)
{
// Buy: K crosses above D in oversold zone
if (pk <= pd && k > d && pd < OverSold && Position <= 0)
BuyMarket();
// Sell: K crosses below D in overbought zone
if (pk >= pd && k < d && pd > OverBought && 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_automated_strategy(Strategy):
def __init__(self):
super(stochastic_automated_strategy, self).__init__()
self._k_period = self.Param("KPeriod", 14) \
.SetDisplay("%K Period", "Stochastic %K period", "Stochastic")
self._d_period = self.Param("DPeriod", 3) \
.SetDisplay("%D Period", "Stochastic %D period", "Stochastic")
self._over_bought = self.Param("OverBought", 80.0) \
.SetDisplay("Overbought", "Overbought threshold", "Stochastic")
self._over_sold = self.Param("OverSold", 20.0) \
.SetDisplay("Oversold", "Oversold threshold", "Stochastic")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame", "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 over_bought(self):
return self._over_bought.Value
@property
def over_sold(self):
return self._over_sold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(stochastic_automated_strategy, self).OnReseted()
self._prev_k = None
self._prev_d = None
def OnStarted2(self, time):
super(stochastic_automated_strategy, self).OnStarted2(time)
stochastic = StochasticOscillator()
stochastic.K.Length = self.k_period
stochastic.D.Length = self.d_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stochastic, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, stochastic)
self.DrawOwnTrades(area)
def process_candle(self, candle, stoch_value):
if candle.State != CandleStates.Finished:
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:
ob = float(self.over_bought)
os_val = float(self.over_sold)
# Buy: K crosses above D in oversold zone
if self._prev_k <= self._prev_d and k > d and self._prev_d < os_val and self.Position <= 0:
self.BuyMarket()
# Sell: K crosses below D in overbought zone
if self._prev_k >= self._prev_d and k < d and self._prev_d > ob and self.Position >= 0:
self.SellMarket()
self._prev_k = k
self._prev_d = d
def CreateClone(self):
return stochastic_automated_strategy()