Renko Fractals Grid é um port direto do consultor especialista MetaTrader 4 "RENKO FRACTALS GRID". A estratégia opera rompimentos de fractais recentes de Bill Williams confirmados por um filtro de volatilidade estilo Renko, uma tendência de média móvel ponderada e a força do momentum derivada do indicador de taxa de variação. A versão StockSharp mantém o gerenciamento de posições em grade do robô original, incluindo dimensionamento de posições com martingale, gerenciamento de ponto de equilíbrio, trailing stops, proteção de equity e trailing opcional de lucro flutuante em unidades de moeda.
Lógica de trading
Rompimento de fractal: Uma configuração comprada requer que o fractal de alta mais recente seja rompido pela última vela fechada enquanto pelo menos um dos três fechamentos anteriores permaneceu abaixo desse nível. As operações vendidas espelham esse comportamento com fractais de baixa.
Filtro Renko: A estratégia inspeciona o intervalo de máxima/mínima das últimas CandlesToRetrace barras. Um rompimento é válido somente quando o fechamento atual está pelo menos um "bloco" Renko (seja uma distância fixa em pips ou o último valor ATR) afastado desses extremos.
Filtro de tendência: As médias móveis ponderadas rápida e lenta devem estar alinhadas (rápida acima da lenta para posições compradas e abaixo para vendidas).
Verificação de momentum: O desvio absoluto dos últimos três valores de taxa de variação de 100 deve exceder os limiares configurados. Isso imita o filtro de momentum MQL baseado em iMomentum.
Confirmação MACD: As operações são permitidas somente quando a linha principal do MACD está no lado correto de sua linha de sinal. A mesma verificação é usada para o timing de saída.
Gestão de riscos
Grade martingale: Cada posição adicional multiplica o volume base por LotExponent enquanto o número de operações simultâneas é limitado por MaxTrades.
Stop-loss e take-profit: Offsets de preço estáticos em pips são aplicados a partir do preço médio de entrada.
Ponto de equilíbrio: Quando o preço avança por BreakEvenTriggerPips, o stop se move para a entrada mais BreakEvenOffsetPips.
Trailing stop: Um trailing stop baseado em velas mantém a melhor excursão observada desde a entrada.
Trailing monetário: O gerenciamento opcional de lucro flutuante fecha todas as operações após um recuo de MoneyStopLoss uma vez que o lucro aberto excede MoneyTakeProfit.
Stop de equity: A estratégia rastreia o pico de equity em execução (baseado no valor do portfólio e PnL aberto). Se o drawdown exceder EquityRiskPercent, toda a posição é liquidada.
Parâmetros
Nome
Descrição
CandleType
Tipo de vela principal usado para todos os indicadores.
FastMaLength / SlowMaLength
Períodos das médias móveis ponderadas que definem a direção da tendência.
MomentumLength
Lookback de taxa de variação para o filtro de momentum.
MomentumBuyThreshold / MomentumSellThreshold
Desvio absoluto mínimo de 100 requerido para entradas.
UseAtrFilter
Usar ATR em vez de uma distância fixa em pips para a confirmação Renko.
BoxSizePips
Tamanho do bloco Renko sintético quando a filtragem ATR está desabilitada.
CandlesToRetrace
Número de velas inspecionadas ao medir máximas e mínimas recentes.
BaseVolume
Volume de operação inicial antes de aplicar o multiplicador martingale.
LotExponent
Multiplicador aplicado a cada nova posição na grade.
MaxTrades
Número máximo de posições simultâneas por direção.
StopLossPips / TakeProfitPips
Distâncias de stop protetor estático e objetivo.
TrailingStopPips
Distância do trailing stop em pips (definir como zero para desabilitar).
UseBreakEven
Habilitar mover o stop para o ponto de equilíbrio.
BreakEvenTriggerPips / BreakEvenOffsetPips
Distância necessária antes da ativação do ponto de equilíbrio e o offset aplicado depois.
UseMoneyTarget
Habilitar trailing de lucro flutuante em unidades de moeda.
MoneyTakeProfit / MoneyStopLoss
Limiar de lucro que ativa o trailing monetário e o recuo máximo permitido.
UseEquityStop
Habilitar stop-out global baseado em equity.
EquityRiskPercent
Drawdown máximo permitido a partir do pico de equity antes de fechar todas as operações.
Notas de implementação
O EA original avalia o MACD no período mensal. O port do StockSharp usa a mesma configuração de indicadores no período de trabalho porque dados multi-período não estão disponíveis por padrão.
Todos os offsets de preço que se originaram de "pips" no MQL são convertidos através do passo de preço do instrumento para trabalhar com cotações de pip fracionadas.
O rastreamento de lucro realizado é aproximado via eventos de ordens preenchidas, o que é suficiente para a lógica de drawdown de equity na ausência de estatísticas de conta fornecidas pelo broker.
A estratégia utiliza assinaturas de velas de alto nível com vinculação de indicadores conforme exigido pelas diretrizes do projeto e mantém todos os comentários em linha em inglês conforme solicitado.
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>
/// Renko Fractals Grid strategy. Uses fast/slow WMA crossover with momentum confirmation.
/// </summary>
public class RenkoFractalsGridStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public RenkoFractalsGridStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 6)
.SetGreaterThanZero()
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevAbove && !currAbove && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 renko_fractals_grid_strategy(Strategy):
def __init__(self):
super(renko_fractals_grid_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 8) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(renko_fractals_grid_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(renko_fractals_grid_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return renko_fractals_grid_strategy()