La estrategia reacciona a los niveles extremos del Oscilador Stochastic. Cuando la línea %K se sumerge en territorio de sobreventa, el sistema espera un rebote; mientras que lecturas de sobrecompra pueden presagiar una caída. El método opera en velas intradía cortas para que las señales lleguen rápidamente.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 73%. Funciona mejor en el mercado cripto.
Después de suscribirse al marco temporal seleccionado, monitorea las líneas %K y %D. Una configuración alcista se forma cuando %K cae por debajo de 20 y luego comienza a recuperarse. Por el contrario, una configuración bajista aparece si %K sube por encima de 80 y empieza a girar hacia abajo. Un stop de porcentaje fijo controla el riesgo para ambos lados.
Las posiciones se cierran cuando la línea %K cruza de nuevo el nivel 50, señalando que el impulso ha cambiado hacia la dirección opuesta. Dado que los stops escalan con el ATR más reciente, el tamaño de la operación se adapta a la volatilidad.
Detalles
Criterios de entrada:
Largo: %K < 20 con giro alcista.
Corto: %K > 80 con giro bajista.
Largo/Corto: Ambos.
Criterios de salida: %K cruzando el nivel 50 o stop-loss.
Stops: Sí, a una distancia de 2%.
Valores predeterminados:
StochPeriod = 14
KPeriod = 3
DPeriod = 3
CandleType = 5 minute
Filtros:
Categoría: Oscilador
Dirección: Ambos
Indicadores: Stochastic
Stops: Sí
Complejidad: Básico
Marco temporal: Intradía
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
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>
/// Stochastic Overbought/Oversold strategy.
/// Buys when K is oversold, sells when K is overbought.
/// </summary>
public class StochasticOverboughtOversoldStrategy : Strategy
{
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// K period.
/// </summary>
public int KPeriod
{
get => _kPeriod.Value;
set => _kPeriod.Value = value;
}
/// <summary>
/// D period.
/// </summary>
public int DPeriod
{
get => _dPeriod.Value;
set => _dPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public StochasticOverboughtOversoldStrategy()
{
_kPeriod = Param(nameof(KPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("K Period", "Smoothing period for %K", "Indicators");
_dPeriod = Param(nameof(DPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("D Period", "Smoothing period for %D", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
var stochastic = new StochasticOscillator
{
K = { Length = KPeriod },
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 (!stochValue.IsFormed)
return;
var stochTyped = (StochasticOscillatorValue)stochValue;
if (stochTyped.K is not decimal kValue)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
if (Position == 0 && kValue < 20)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && kValue > 80)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && kValue > 80)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && kValue < 20)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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_overbought_oversold_strategy(Strategy):
"""
Stochastic Overbought/Oversold strategy.
Buys when K is oversold (<20), sells when K is overbought (>80).
"""
def __init__(self):
super(stochastic_overbought_oversold_strategy, self).__init__()
self._k_period = self.Param("KPeriod", 3).SetDisplay("K Period", "Smoothing period for %K", "Indicators")
self._d_period = self.Param("DPeriod", 3).SetDisplay("D Period", "Smoothing period for %D", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(stochastic_overbought_oversold_strategy, self).OnReseted()
self._cooldown = 0
def OnStarted2(self, time):
super(stochastic_overbought_oversold_strategy, self).OnStarted2(time)
self._cooldown = 0
stochastic = StochasticOscillator()
stochastic.K.Length = self._k_period.Value
stochastic.D.Length = self._d_period.Value
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
if not stoch_value.IsFormed:
return
k_val = stoch_value.K
if k_val is None:
return
kv = float(k_val)
if self._cooldown > 0:
self._cooldown -= 1
return
cd = self._cooldown_bars.Value
if self.Position == 0 and kv < 20:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and kv > 80:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and kv > 80:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and kv < 20:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return stochastic_overbought_oversold_strategy()