La estrategia KPrmSt Cross es un port del experto de MetaTrader 5 exp_kprmst.mq5. Utiliza un oscilador similar al Stochastic conocido como KPrmSt para capturar reversiones cuando la línea principal del oscilador cruza la línea de señal.
La estrategia se suscribe a velas de un marco temporal configurable y calcula el indicador Stochastic (utilizado como aproximación de KPrmSt). Cuando la línea %K cruza por debajo de la línea %D, abre una posición larga; cuando %K cruza por encima de %D, abre una posición corta. Las posiciones existentes se revierten en consecuencia.
Parámetros
Candle Type – marco temporal de las velas usadas para los cálculos.
K Period – número de barras para calcular la línea principal.
D Period – período para suavizar la línea de señal.
Slowing – suavizado adicional aplicado a %K.
Stop Loss – pérdida protectora en unidades de precio. Establecer en 0 para deshabilitar.
Take Profit – beneficio objetivo en unidades de precio. Establecer en 0 para deshabilitar.
Lógica de trading
La estrategia solo escucha velas finalizadas.
Los valores del oscilador Stochastic se almacenan para detectar cruces.
Cuando %K cae por debajo de %D después de haber estado por encima, se abre una posición larga o se cierra la corta.
Cuando %K sube por encima de %D después de haber estado por debajo, se abre una posición corta o se cierra la larga.
Los niveles opcionales de stop loss y take profit cierran la posición cuando se alcanzan.
Notas
El indicador KPrmSt del experto original se aproxima mediante el indicador Stochastic de StockSharp.
Las opciones de gestión de dinero del script original no están implementadas.
La estrategia requiere un feed de datos de mercado y enrutamiento de órdenes compatible con StockSharp.
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>
/// KPrmSt cross strategy based on the stochastic oscillator.
/// Opens long when %K crosses above %D from below.
/// Opens short when %K crosses below %D from above.
/// </summary>
public class KprmStCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private StochasticOscillator _stochastic;
private decimal? _prevK;
private decimal? _prevD;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal StopLossPct
{
get => _stopLossPct.Value;
set => _stopLossPct.Value = value;
}
public decimal TakeProfitPct
{
get => _takeProfitPct.Value;
set => _takeProfitPct.Value = value;
}
public KprmStCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for indicator calculation", "General");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_stochastic = default;
_prevK = null;
_prevD = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_stochastic = new StochasticOscillator();
Indicators.Add(_stochastic);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var stochResult = _stochastic.Process(candle);
if (!stochResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var stochVal = (StochasticOscillatorValue)stochResult;
if (stochVal.K is not decimal k || stochVal.D is not decimal d)
return;
if (_prevK.HasValue && _prevD.HasValue)
{
var wasBelow = _prevK.Value < _prevD.Value;
var isAbove = k > d;
// K crosses above D -> buy
if (wasBelow && isAbove && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// K crosses below D -> sell
else if (!wasBelow && !isAbove && _prevK.Value > _prevD.Value && 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, Unit, UnitTypes
from StockSharp.Algo.Indicators import StochasticOscillator, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class kprm_st_cross_strategy(Strategy):
"""
KPrmSt cross strategy using Stochastic K/D crossover.
Buys when K crosses above D, sells when K crosses below D.
Uses StartProtection for percentage-based SL/TP.
"""
def __init__(self):
super(kprm_st_cross_strategy, self).__init__()
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame", "General")
self._stochastic = None
self._prev_k = None
self._prev_d = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(kprm_st_cross_strategy, self).OnReseted()
self._prev_k = None
self._prev_d = None
def OnStarted2(self, time):
super(kprm_st_cross_strategy, self).OnStarted2(time)
self._stochastic = StochasticOscillator()
self.Indicators.Add(self._stochastic)
self.StartProtection(
Unit(self._take_profit_pct.Value, UnitTypes.Percent),
Unit(self._stop_loss_pct.Value, UnitTypes.Percent),
useMarketOrders=True)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
cv = CandleIndicatorValue(self._stochastic, candle)
stoch_result = self._stochastic.Process(cv)
if not stoch_result.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
k = stoch_result.K
d = stoch_result.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:
was_below = self._prev_k < self._prev_d
is_above = k > d
if was_below and is_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif not was_below and not is_above and self._prev_k > self._prev_d and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_k = k
self._prev_d = d
def CreateClone(self):
return kprm_st_cross_strategy()