A FitFul 13 Time Gated Strategy é uma versão StockSharp do MetaTrader 4 consultor especialista "FitFul_13". A estratégia constrói uma escada dinâmica semanal (PP, R0.5, R1, R1.5, R2, R2.5, R3 e os níveis de suporte correspondentes) usando a máxima, a mínima e o fechamento da semana anterior. As decisões comerciais são tomadas no prazo principal (padrão 1 hora) e são opcionalmente confirmadas por um prazo mais rápido (padrão 15 minutos). Novas posições são permitidas apenas em minutos intradiários específicos para imitar o comportamento original EA.
Lógica de sinal
Cálculo de pivô semanal
No final de cada vela semanal, a escada pivô é recalculada.
Os preços stop-loss e take-profit são compensados dos níveis base por uma distância configurável expressa em pontos de preço.
Primárias condições de prazo
A última vela primária concluída deve ser de alta para procurar entradas longas ou de baixa para procurar entradas curtas.
A vela primária anterior deve abranger um dos níveis de pivô (abrir abaixo e fechar acima para posições compradas, abrir acima e fechar abaixo para posições vendidas).
Condições de prazo de confirmação
Se a vela de confirmação atual for de alta, os mínimos das duas velas de confirmação anteriores deverão perfurar e fechar acima do mesmo nível de pivô para confirmar um sinal longo.
Se a vela de confirmação atual for de baixa, as máximas das duas velas de confirmação anteriores deverão perfurar e fechar abaixo de um nível de pivô para confirmar um sinal curto.
Tempo de entrada
Uma negociação é realizada somente quando o minuto de abertura da vela primária finalizada for igual a um dos quatro minutos configurados (0, 15, 30 ou 45 por padrão).
A exposição líquida é limitada por MaxNetPositions × Volume para emular a restrição de "máximo de três pedidos abertos" da versão MetaTrader.
Gestão de risco
Stops e metas – Cada posição recebe um stop-loss e um take-profit derivados do pivô imediatamente após a entrada.
Trailing Stop – Uma vez que o preço avança pelo número configurado de pontos, o stop é seguido na direção da negociação.
Tempo máximo de retenção – As negociações lucrativas são fechadas quando o tempo de retenção excede a duração configurada (48 horas por padrão).
Regra fixa de sexta-feira – Às sextas-feiras, qualquer posição aberta é fechada entre os minutos configurados da hora especificada (padrão 21h50–21h59).
Parâmetros
Nome
Descrição
PrimaryCandleType
Prazo usado para as principais verificações cruzadas do pivô.
ConfirmationCandleType
Prazo mais rápido que valida reações pivot.
Volume
Volume líquido de ordens de mercado.
MaxNetPositions
Exposição máxima medida em múltiplos de Volume.
OffsetPoints
Distância do ponto de preço aplicada a stops e alvos em torno de cada pivô.
TrailingStopPoints
Distância do trailing stop em faixas de preço.
CloseAfter
Tempo máximo de manutenção para posições lucrativas.
CloseHour, CloseMinuteFrom, CloseMinuteTo
Janela horária de sexta-feira para saídas forçadas.
EntryMinute0..3
Minutos permitidos (a cada hora) para abertura de novas posições.
Notas
A conversão mantém a dependência do EA original na escada dinâmica da semana anterior e nas janelas de execução de um quarto de hora.
O gerenciamento de dinheiro foi simplificado: o parâmetro StockSharp Volume controla o tamanho do pedido diretamente em vez de reimplementar o cálculo dinâmico do lote de MetaTrader.
Todos os comentários dentro do código são escritos em inglês, conforme exigido pelas diretrizes do projeto.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// FitFul 13 Time Gated strategy - channel midpoint crossover.
/// Buys when close crosses above the midpoint of Highest/Lowest channel.
/// Sells when close crosses below the midpoint.
/// </summary>
public class FitFul13TimeGatedStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FitFul13TimeGatedStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 13)
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 13)
.SetDisplay("EMA Period", "EMA trend filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevMid = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest, decimal ema)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev)
{
_prevClose = close;
_prevMid = mid;
_hasPrev = true;
return;
}
// Cross above midpoint with EMA confirmation
if (_prevClose <= _prevMid && close > mid && close > ema && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Cross below midpoint with EMA confirmation
else if (_prevClose >= _prevMid && close < mid && close < ema && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevMid = mid;
}
}
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 Highest, Lowest, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fit_ful13_time_gated_strategy(Strategy):
def __init__(self):
super(fit_ful13_time_gated_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 13) \
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._ema_period = self.Param("EmaPeriod", 13) \
.SetDisplay("EMA Period", "EMA trend filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
@property
def channel_period(self):
return self._channel_period.Value
@property
def ema_period(self):
return self._ema_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(fit_ful13_time_gated_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(fit_ful13_time_gated_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, ema, self.process_candle).Start()
def process_candle(self, candle, highest, lowest, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
high_val = float(highest)
low_val = float(lowest)
ema_val = float(ema)
mid = (high_val + low_val) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._prev_close <= self._prev_mid and close > mid and close > ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_mid and close < mid and close < ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return fit_ful13_time_gated_strategy()