Estrategia de Spearman Rank Correlation Histogram Time Window
Descripción general
Esta estrategia reproduce el experto de MetaTrader Exp_SpearmanRankCorrelation_Histogram_TimeWeekPeriod en la API de alto nivel de StockSharp. Se suscribe a un único flujo de velas (por defecto: barras de 4 horas) y evalúa el histograma de correlación de rango Spearman publicado en el indicador MQL original. El color del histograma determina si la tendencia a corto plazo es alcista (valores por encima de cero) o bajista (valores por debajo de cero). Una ventana de negociación dedicada mantiene la actividad entre un rango configurable de día de la semana/hora, reflejando los controles TimeTrade del código fuente.
Lógica de negociación
Cálculo del indicador
En cada vela terminada la estrategia almacena el precio de cierre y calcula la correlación de rango Spearman sobre RangeLength cierres.
El color del histograma se asigna exactamente como en el indicador: 4 cuando la correlación está por encima de HighLevel, 3 cuando está entre 0 y HighLevel, 1 cuando está entre LowLevel y 0, 0 cuando está por debajo de LowLevel, y 2 cuando es exactamente cero.
Las señales se evalúan en la barra cerrada número SignalBar (por defecto: la barra que acaba de cerrar). La barra cerrada anterior se usa para detectar transiciones de color.
Modos de operación – el parámetro TradeMode controla cómo se interpretan los colores:
Mode1 – abrir largos cuando el color salta por encima de 2 después de estar por debajo de 3; abrir cortos cuando el color cae por debajo de 2 después de estar por encima de 1. Cada color alcista también solicita un cierre corto, cada color bajista un cierre largo.
Mode2 – abrir largos en color 4 (transición desde cualquier cosa por debajo de 4), abrir cortos en color 0 (transición desde cualquier cosa por encima de 0). Colores mayores que 2 cierran cortos; colores menores que 2 cierran largos.
Mode3 – abrir largos en color 4 y cerrar cortos al mismo tiempo; abrir cortos en color 0 y cerrar largos simultáneamente.
Después de una entrada exitosa la estrategia impone un tiempo de espera igual a la longitud de la vela (la siguiente orden en la misma dirección se difiere hasta que la siguiente barra habría cerrado en MetaTrader).
Gestión monetaria y tamaño de orden
MoneyManagement combinado con MarginMode convierte fracciones de capital o riesgo en un volumen de orden. Los valores positivos siguen las reglas de gestión monetaria originales, cero recurre al Volume de la estrategia, y los números negativos se interpretan como un tamaño de lote fijo.
Los modos basados en riesgo (LossFreeMargin, LossBalance) requieren un StopLossPoints positivo. Si el stop es cero la estrategia recurre a Volume igual que el EA rechazaría la operación.
Gestión de riesgo
StopLossPoints y TakeProfitPoints se traducen en niveles de precio usando Security.PriceStep. Las salidas se comprueban en cada vela terminada usando el máximo/mínimo de la vela y todas las posiciones abiertas se revierten a plano cuando se toca un nivel.
DeviationPoints se preserva por completitud de la interfaz; las órdenes de mercado de StockSharp ignoran el valor.
Ventana de negociación semanal
Cuando TimeTrade es true la hora actual debe estar entre (StartDay, StartHour, StartMinute, StartSecond) y (EndDay, EndHour, EndMinute, EndSecond). Fuera de esa ventana todas las posiciones en el instrumento de la estrategia se cierran inmediatamente, coincidiendo con la salida de emergencia original.
La implementación asume que StartDay no es posterior a EndDay. Para sesiones superpuestas (por ejemplo viernes → lunes) ajustar los parámetros en consecuencia.
Comportamiento misceláneo
Al menos RangeLength + SignalBar + 1 velas completadas deben estar disponibles antes de que se puedan generar señales.
Direction es un interruptor reservado del indicador MQL; se mantiene por paridad de parámetros pero no tiene efecto en este port.
Parámetros
Nombre
Descripción
Valor predeterminado
MoneyManagement
Fracción de capital o tamaño de lote fijo para dimensionamiento de posición.
0.1
MarginMode
Interpretación de MoneyManagement (FreeMargin, Balance, LossFreeMargin, LossBalance, Lot).
Lot
StopLossPoints
Distancia de stop-loss en puntos de precio.
1000
TakeProfitPoints
Distancia de take-profit en puntos de precio.
2000
DeviationPoints
Tolerancia de deslizamiento informativa en puntos.
10
BuyOpen / SellOpen
Habilitar abrir posiciones largas o cortas.
true
BuyClose / SellClose
Permitir cerrar posiciones largas o cortas en señales.
true
TradeMode
Modo de interpretación del histograma (Mode1, Mode2, Mode3).
Mode1
TimeTrade
Activar la ventana de negociación semanal.
true
StartDay, StartHour, StartMinute, StartSecond
Inicio de la ventana (día de la semana y hora).
Martes, 8, 0, 0
EndDay, EndHour, EndMinute, EndSecond
Fin de la ventana (día de la semana y hora).
Viernes, 20, 59, 40
CandleType
Marco temporal de las velas procesadas.
H4
RangeLength
Número de cierres usados por la correlación Spearman.
14
MaxRange
RangeLength máximo permitido (guardia de seguridad).
30
Direction
Indicador de indicador reservado, sin efecto en el port.
true
HighLevel, LowLevel
Umbrales superiores e inferiores del histograma.
0.5, -0.5
SignalBar
Número de barras cerradas hacia atrás al leer el buffer de color.
1
Toda la demás configuración de la estrategia (selección de portafolio, asignación de seguridad, Volume base, reglas de riesgo) sigue el flujo de trabajo estándar de 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;
public class SpearmanRankCorrelationHistogramTimeWeekPeriodStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public SpearmanRankCorrelationHistogramTimeWeekPeriodStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class spearman_rank_correlation_histogram_time_week_period_strategy(Strategy):
def __init__(self):
super(spearman_rank_correlation_histogram_time_week_period_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(spearman_rank_correlation_histogram_time_week_period_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(spearman_rank_correlation_histogram_time_week_period_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return spearman_rank_correlation_histogram_time_week_period_strategy()