A estratégia de breakout ASC++ Williams transfere o especialista legado MQL4 "ASC++.mq4" para o StockSharp de alto nível do API. A lógica procura faixas de negociação estreitas confirmadas pelo oscilador Williams %R e, em seguida, coloca ordens de stop um pouco além dos extremos da vela. Uma vez acionado, o gerenciamento de risco integrado mantém a posição protegida com take-profit automático, stop loss e comportamento de trailing opcional.
Como funciona a estratégia
Preparação de indicadores
Osciladores %R rápidos e lentos Williams (padrão 9 e 54 períodos) medem o impulso de curto prazo.
Um intervalo verdadeiro médio de 10 períodos suaviza o cálculo do intervalo ponderado "ASC".
Os limites dinâmicos x1 = 67 + RiskLevel e x2 = 33 - RiskLevel imitam as bandas adaptativas originais de sobrecompra/sobrevenda.
Pontuação de sinal
Cada vela finalizada calcula value2 = 100 - |%R_fast|. Valores abaixo de x2 indicam um ambiente de sobrevenda com pressão para romper para cima; valores acima de x1 sinalizam uma condição de sobrecompra que pode quebrar.
Velas consecutivas que ficam dentro dos mesmos contadores de confirmação de incremento extremo. Uma negociação é permitida somente após SignalConfirmation barras consecutivas (padrão 5) para aproximar os SigVal temporizadores originais.
Colocação de pedido
Quando o filtro de intervalo (ATR < EntryRange) confirma a consolidação e o momentum concorda (%R_fast acima/abaixo de %R_slow), a estratégia coloca uma ordem de stop:
Stop de compra em High + ATR * 0.5 + EntryStopLevel * PriceStep para quebras de alta.
Stop de venda em Low - ATR * 0.5 - EntryStopLevel * PriceStep para quebras de baixa.
As ordens pendentes do lado oposto são canceladas para evitar exposição conflitante.
Gerenciamento de posição
As ordens de proteção são configuradas via StartProtection (takeprofit e stop loss expressos em pontos, rastreamento opcional ativado quando TrailingStopPoints > 0).
Se um novo sinal entrar em conflito com uma posição existente (por exemplo, um rompimento de alta enquanto vendido), o mecanismo imediatamente nivela a exposição oposta antes de enfileirar a ordem de rompimento, assim como a fonte EA.
Parâmetros
Parâmetro
Padrão
Descrição
CandleType
Período de 15 minutos
Fonte de vela base usada para os cálculos.
FastLength
9
Williams %R comprimento usado para o detector de momento rápido.
SlowLength
54
Williams %R comprimento usado para o oscilador de confirmação.
RangeLength
10
Janela de suavização ATR substituindo o loop de intervalo ponderado manual.
EntryStopLevel
10 pontos
Compensação extra (em etapas de preço) adicionada às ordens stop de rompimento.
EntryRange
27 pontos
Faixa média máxima permitida antes de aceitar uma configuração.
RiskLevel
3
Ajusta os limites de x1/x2, tornando as faixas de confirmação mais estreitas ou mais largas.
SignalConfirmation
5 barras
Número de velas consecutivas que devem permanecer no mesmo extremo antes que uma ordem seja armada.
TakeProfitPoints
100 pontos
Distância da ordem de take-profit automática.
StopLossPoints
40 pontos
Distância da ordem de stop loss automática.
TrailingStopPoints
20 pontos
Ativa o comportamento de rastreamento quando maior que zero.
Notas de conversão
O EA original construiu um ATR ponderado manualmente; a porta StockSharp usa o indicador nativo AverageTrueRange com o mesmo lookback de 10 períodos. Isso corresponde à intenção de suavização, evitando buffers personalizados.
Os temporizadores SigValBuy e SigValSell no código MQL dependiam de contadores baseados em minutos. A versão C# os emula com SignalConfirmation verificações de velas consecutivas para manter a cadência de entrada consistente sem acessar carimbos de data e hora de minuto.
Pedidos de entrada pendentes são implementados com ajudantes BuyStop/SellStop. Antes de fazer um novo pedido, o lado oposto é cancelado, espelhando a lógica herdada OrderDelete.
O gerenciamento de stop depende de StartProtection, que lida automaticamente com take-profit, stop loss e trailing. Isso cobre a escada final MQL (TSLevel1, TSLevel2) de uma forma simplificada, mas robusta.
Todo o acesso aos indicadores ocorre por meio de assinaturas e vinculações de alto nível, conforme exigido pelas diretrizes do projeto – sem chamadas manuais GetValue ou caches de indicadores personalizados.
Dicas de uso
A estratégia espera instrumentos com um PriceStep definido; caso contrário, o padrão é 1. Ajuste EntryStopLevel, EntryRange e parâmetros de risco para corresponder ao tamanho do tick do instrumento.
Reduza SignalConfirmation para negociações mais agressivas em prazos mais curtos ou aumente-o para negociar apenas consolidações pronunciadas.
Considere ativar o desenho do gráfico em um aplicativo host para visualizar as ordens de stop e confirmar se os níveis de rompimento estão alinhados com os máximos/mínimos recentes.
Sempre teste os dados históricos porque a estratégia é muito sensível a spreads, derrapagens e definições de etapas de preços específicas do corretor.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class AscPlusPlusStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldownRemaining;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AscPlusPlusStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevFast = fast;
_prevSlow = slow;
}
}