Estratégia de Spearman Rank Correlation Histogram Time Window
Visão geral
Esta estratégia reproduz o especialista do MetaTrader Exp_SpearmanRankCorrelation_Histogram_TimeWeekPeriod na API de alto nível do StockSharp. Ela subscreve um único fluxo de velas (padrão: barras de 4 horas) e avalia o histograma de correlação de posto de Spearman publicado no indicador MQL original. A cor do histograma determina se a tendência de curto prazo é altista (valores acima de zero) ou baixista (valores abaixo de zero). Uma janela de negociação dedicada mantém a atividade entre um intervalo configurável de dia da semana/hora, espelhando os controles TimeTrade do código fonte.
Lógica de negociação
Cálculo do indicador
Em cada vela concluída a estratégia armazena o preço de fechamento e calcula a correlação de posto de Spearman sobre RangeLength fechamentos.
A cor do histograma é atribuída exatamente como no indicador: 4 quando a correlação está acima de HighLevel, 3 quando está entre 0 e HighLevel, 1 quando está entre LowLevel e 0, 0 quando está abaixo de LowLevel, e 2 quando é exatamente zero.
Os sinais são avaliados na barra fechada número SignalBar (padrão: a barra que acabou de fechar). A barra fechada anterior é usada para detectar transições de cor.
Modos de operação – o parâmetro TradeMode controla como as cores são interpretadas:
Mode1 – abrir comprados quando a cor salta acima de 2 depois de estar abaixo de 3; abrir vendidos quando a cor cai abaixo de 2 depois de estar acima de 1. Cada cor altista também solicita fechamento vendido, cada cor baixista fechamento comprado.
Mode2 – abrir comprados na cor 4 (transição de qualquer coisa abaixo de 4), abrir vendidos na cor 0 (transição de qualquer coisa acima de 0). Cores maiores que 2 fecham vendidos; cores menores que 2 fecham comprados.
Mode3 – abrir comprados na cor 4 e fechar vendidos ao mesmo tempo; abrir vendidos na cor 0 e fechar comprados simultaneamente.
Após uma entrada bem-sucedida a estratégia impõe um tempo de espera igual ao comprimento da vela (a próxima ordem na mesma direção é adiada até que a próxima barra tenha fechado no MetaTrader).
Gestão de dinheiro e tamanho de ordem
MoneyManagement combinado com MarginMode converte frações de patrimônio ou risco em um volume de ordem. Valores positivos seguem as regras de gestão de dinheiro originais, zero volta ao Volume da estratégia, e números negativos são interpretados como um tamanho de lote fixo.
Modos baseados em risco (LossFreeMargin, LossBalance) requerem um StopLossPoints positivo. Se o stop for zero a estratégia volta para Volume assim como o EA recusaria a operação.
Gestão de risco
StopLossPoints e TakeProfitPoints são traduzidos em níveis de preço usando Security.PriceStep. As saídas são verificadas em cada vela concluída usando a máxima/mínima da vela e todas as posições abertas são revertidas ao plano quando um nível é tocado.
DeviationPoints é preservado para completude da interface; ordens de mercado do StockSharp ignoram o valor.
Janela de negociação semanal
Quando TimeTrade é true o horário atual deve estar entre (StartDay, StartHour, StartMinute, StartSecond) e (EndDay, EndHour, EndMinute, EndSecond). Fora dessa janela todas as posições no instrumento da estratégia são fechadas imediatamente, correspondendo à saída de emergência original.
A implementação assume que StartDay não é posterior a EndDay. Para sessões sobrepostas (por exemplo Sexta → Segunda) ajustar os parâmetros adequadamente.
Comportamento diverso
Pelo menos RangeLength + SignalBar + 1 velas concluídas devem estar disponíveis antes que os sinais possam ser gerados.
Direction é um interruptor reservado do indicador MQL; é mantido para paridade de parâmetros mas não tem efeito neste port.
Parâmetros
Nome
Descrição
Valor padrão
MoneyManagement
Fração de capital ou tamanho de lote fixo para dimensionamento de posição.
0.1
MarginMode
Interpretação de MoneyManagement (FreeMargin, Balance, LossFreeMargin, LossBalance, Lot).
Lot
StopLossPoints
Distância de stop-loss em pontos de preço.
1000
TakeProfitPoints
Distância de take-profit em pontos de preço.
2000
DeviationPoints
Tolerância de slippage informativa em pontos.
10
BuyOpen / SellOpen
Habilitar abertura de posições compradas ou vendidas.
true
BuyClose / SellClose
Permitir fechamento de posições compradas ou vendidas em sinais.
true
TradeMode
Modo de interpretação do histograma (Mode1, Mode2, Mode3).
Mode1
TimeTrade
Ativar a janela de negociação semanal.
true
StartDay, StartHour, StartMinute, StartSecond
Início da janela (dia da semana e hora).
Terça-feira, 8, 0, 0
EndDay, EndHour, EndMinute, EndSecond
Fim da janela (dia da semana e hora).
Sexta-feira, 20, 59, 40
CandleType
Período das velas processadas.
H4
RangeLength
Número de fechamentos usados pela correlação de Spearman.
14
MaxRange
RangeLength máximo permitido (guarda de segurança).
30
Direction
Sinalizador de indicador reservado, sem efeito no port.
true
HighLevel, LowLevel
Limiares superiores e inferiores do histograma.
0.5, -0.5
SignalBar
Número de barras fechadas para trás ao ler o buffer de cor.
1
Toda a outra configuração da estratégia (seleção de portfólio, atribuição de segurança, Volume base, regras de risco) segue o fluxo de trabalho padrão do 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()