Esta pasta contém o port do StockSharp do consultor especialista de MetaTrader "Fractals Martingale". A estratégia combina fractais de Bill Williams, um filtro de tendência baseado em Ichimoku e uma confirmação mensal de MACD. O dimensionamento de posição segue uma sequência martingale clássica que multiplica o volume de operação após cada ciclo perdedor, enquanto um resfriamento opcional evita exposição descontrolada.
Lógica de trading
Detecção de fractais no período de trabalho – velas finalizadas são armazenadas em buffer para detectar máximas e mínimas locais separadas por FractalDepth vizinhos. Uma configuração de alta é registrada quando a próxima vela abre acima da máxima fractal, enquanto uma configuração de baixa requer a próxima abertura abaixo da mínima fractal. Os níveis detectados permanecem válidos por FractalLookback velas processadas.
Filtro de tendência Ichimoku – o fractal deve se alinhar com a tendência do Ichimoku calculada no período superior definido por IchimokuCandleType. Operações compradas exigem Tenkan-sen acima de Kijun-sen; operações vendidas requerem Tenkan-sen abaixo de Kijun-sen.
Confirmação mensal de MACD – o EA original usava um MACD mensal para decidir se compradores ou vendedores dominam. O port assina a série MacdCandleType (velas de 30 dias por padrão) e aceita apenas sinais comprados quando a linha MACD está acima da linha de sinal; sinais vendidos precisam da condição oposta.
Filtro de sessão – as ordens são colocadas apenas entre StartHour (inclusive) e EndHour (exclusive). Uma janela de envolvimento é suportada para sessões de trading noturnas.
Escala de volume martingale – o tamanho base da ordem vem de TradeVolume. Após cada rodada perdedora, o próximo volume de ordem é multiplicado por Multiplier e alinhado ao passo de volume do instrumento. Operações vencedoras reiniciam a sequência. Quando MaxConsecutiveLosses é excedido, o algoritmo pausa por PauseMinutes antes de retomar com o volume base.
Troca de direção – sempre que uma nova operação é enviada, a estratégia compensa automaticamente qualquer posição oposta antes de abrir exposição na direção solicitada.
Gestão de risco
StopLossPips e TakeProfitPips são convertidos para distâncias de preço absolutas usando o tamanho de pip detectado e aplicados via StartProtection. Isso espelha o EA original onde ambos os stops eram definidos em pips.
A implementação original expunha trailing stops opcionais baseados em dinheiro. O port do StockSharp depende do bloco de proteção integrado porque o tratamento real da moeda do portfólio é específico do broker.
Parâmetros
Parâmetro
Descrição
TradeVolume
Tamanho base da ordem usado para a primeira entrada de uma sequência.
Multiplier
Fator aplicado ao próximo volume de operação após uma perda.
StopLossPips, TakeProfitPips
Distâncias de stop de proteção e alvo medidas em pips.
FractalDepth
Número de velas em cada lado necessárias para confirmar um máximo/mínimo fractal.
FractalLookback
Número máximo de velas processadas para as quais um fractal detectado permanece válido.
StartHour, EndHour
Janela de trading expressa em horas da bolsa. Quando ambos os valores coincidem, o filtro é desabilitado.
MaxConsecutiveLosses
Número de operações perdedoras antes de a estratégia pausar.
PauseMinutes
Duração do período de resfriamento ativado após exceder o limite de perda.
TenkanPeriod, KijunPeriod, SenkouPeriod
Comprimentos do Ichimoku Kinko Hyo usados no período superior.
MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod
Comprimentos de EMA para a confirmação MACD do período superior.
CandleType
Série de velas primária onde fractais e execuções são avaliados.
IchimokuCandleType
Período superior usado para calcular as linhas Tenkan e Kijun.
MacdCandleType
Período usado para calcular o filtro MACD (mensal por padrão).
Notas de uso
Cálculo do tamanho do pip – o valor do pip é derivado de Security.PriceStep. Cotações forex de cinco dígitos são automaticamente escaladas para corresponder à definição do MetaTrader usada no EA fonte.
Assinaturas de indicadores – a estratégia consome até três séries de velas. Certifique-se de que o feed de dados pode fornecer todos os períodos solicitados para manter os filtros sincronizados.
Precauções de martingale – dobrar o volume aumenta rapidamente a exposição. Use os parâmetros de resfriamento ou reduza o multiplicador se a conta não puder suportar sequências prolongadas de perdas.
Diferenças vs. o EA MT4 – alertas de e-mail/notificação, trailing stops baseados em saldo e verificações de margem explícitas foram removidos porque o StockSharp já lida com conectividade, segurança do portfólio e execução de ordens. A lógica de entrada/saída central corresponde à implementação MQL.
Arquivos
CS/FractalsMartingaleStrategy.cs – implementação em C# usando a API de estratégia de alto nível.
README.md – documentação em inglês (este arquivo).
README_zh.md – tradução para chinês simplificado.
README_ru.md – tradução para russo.
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 FractalsMartingaleStrategy : 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 FractalsMartingaleStrategy()
{
_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 fractals_martingale_strategy(Strategy):
def __init__(self):
super(fractals_martingale_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(fractals_martingale_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(fractals_martingale_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 fractals_martingale_strategy()