A Estratégia de Estabilização de Pedidos é uma conversão do MetaTrader consultor especialista hjueiisyx8lp2o379e_www_forex-instruments_info.mq4. O robô original coloca um par de ordens stop em torno do preço atual e aguarda um rompimento. Depois que uma posição é aberta, o sistema monitora os corpos recentes das velas para determinar se a ação do preço estagnou ("estabilizada") e sai da negociação quando o mercado perde impulso ou quando um limite de lucro predefinido é atingido.
Esta porta C# mantém a mesma lógica usando o StockSharp API de alto nível. Ele se baseia em velas concluídas em vez de ticks brutos, tornando o comportamento determinístico durante backtesting e negociações ao vivo.
Regras de negociação
Quando não há posições abertas ou ordens ativas, a estratégia apresenta um stop de compra acima do mercado e um stop de venda abaixo do mercado. A distância é medida em MetaTrader pontos (geralmente igual a um pip).
Se uma ordem de parada for executada:
A ordem preenchida abre uma posição de OrderVolume lotes.
A ordem de stop oposta permanece pendente para detectar um rompimento na outra direção.
Enquanto uma posição está aberta, a estratégia verifica o tamanho do corpo das duas velas finalizadas mais recentes:
Se o último corpo da vela for menor que StabilizationPoints e o lucro flutuante for maior que ProfitThreshold, a posição será fechada e a ordem pendente oposta será cancelada.
Se duas velas consecutivas forem menores que StabilizationPoints, a negociação será fechada independentemente do lucro atual.
Se o lucro atingir AbsoluteFixation, a negociação será encerrada imediatamente.
Os pedidos pendentes são cancelados e recriados após ExpirationMinutes, a menos que o valor seja definido como zero (vida útil infinita).
Parâmetros
Nome
Descrição
Padrão
OrderVolume
Volume de negociação em lotes utilizados para ambas as entradas de stop.
0.1
OrderDistancePoints
Distância entre o preço de fechamento atual e cada ordem de stop, expressa em MetaTrader pontos.
20
ProfitThreshold
Lucro flutuante mínimo (moeda da conta) exigido antes que uma saída desencadeada pela estabilização seja permitida.
-2
AbsoluteFixation
Nível de lucro (moeda da conta) que força uma saída imediata.
30
StabilizationPoints
Tamanho máximo do corpo da vela (pontos) que sinaliza um mercado estável.
25
ExpirationMinutes
Vida útil das ordens stop pendentes em minutos. 0 desativa a expiração.
20
CandleType
Tipo de vela usado para avaliar a estabilização (o padrão é um período de 5 minutos).
TimeFrame(5m)
Notas de conversão
O consultor especialista original operava com base nos ticks do gráfico. Esta porta avalia apenas velas finalizadas, preservando a lógica e garantindo backtests reproduzíveis.
MetaTrader "pontos" são mapeados para StockSharp PriceStep. Se o instrumento não tiver um passo de preço, um passo de 1 será assumido.
O lucro é aproximado usando PriceStep e StepPrice para traduzir o movimento do preço na moeda da conta.
Todos os comentários do código foram reescritos em inglês e os metadados dos parâmetros incluem descrições fáceis de usar com agrupamento.
Uso
Adicione a estratégia à sua solução StockSharp e atribua a segurança e o portfólio desejados.
Configure os parâmetros, especialmente o intervalo de tempo da vela e a distância em pontos, para corresponder às características do instrumento.
Comece a estratégia. Ele enviará ordens de stop emparelhadas e gerenciará posições de acordo com a lógica de estabilização descrita acima.
Mais ideias
Experimente diferentes intervalos de velas para equilibrar a capacidade de resposta e a filtragem de ruído.
Combine a estratégia com filtros de volatilidade (ATR, Bollinger Bandas) para evitar negociações durante sessões extremamente silenciosas.
Estenda a lógica com trailing stops ou saídas parciais de posição quando a meta de lucro absoluto for atingida.
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>
/// Order stabilization strategy - trades breakouts after periods of low volatility.
/// When candle body is small (stabilization), waits for a directional breakout.
/// Goes long on bullish breakout candle after stabilization, short on bearish.
/// </summary>
public class OrderStabilizationStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _stabilizationFactor;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevBody;
private decimal _prevAtr;
private bool _hasPrev;
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal StabilizationFactor { get => _stabilizationFactor.Value; set => _stabilizationFactor.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public OrderStabilizationStrategy()
{
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetDisplay("ATR Period", "ATR period for volatility", "Indicators");
_stabilizationFactor = Param(nameof(StabilizationFactor), 0.5m)
.SetDisplay("Stabilization Factor", "Body must be less than ATR * factor for stabilization", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevBody = 0m;
_prevAtr = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
var threshold = atrValue * StabilizationFactor;
if (!_hasPrev)
{
_prevBody = body;
_prevAtr = atrValue;
_hasPrev = true;
return;
}
var prevThreshold = _prevAtr * StabilizationFactor;
var wasStabilized = _prevBody < prevThreshold;
// After stabilization, trade breakout candle
if (wasStabilized && body > threshold)
{
var bullish = candle.ClosePrice > candle.OpenPrice;
if (bullish && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (!bullish && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
_prevBody = body;
_prevAtr = atrValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class order_stabilization_strategy(Strategy):
"""Trades breakouts after periods of low volatility (stabilization).
When previous candle body is small relative to ATR, waits for directional breakout.
Goes long on bullish breakout candle, short on bearish."""
def __init__(self):
super(order_stabilization_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for volatility", "Indicators")
self._stabilization_factor = self.Param("StabilizationFactor", 0.5) \
.SetDisplay("Stabilization Factor", "Body must be less than ATR * factor for stabilization", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_body = 0.0
self._prev_atr = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@property
def StabilizationFactor(self):
return self._stabilization_factor.Value
def OnReseted(self):
super(order_stabilization_strategy, self).OnReseted()
self._prev_body = 0.0
self._prev_atr = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(order_stabilization_strategy, self).OnStarted2(time)
self._has_prev = False
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(atr, self._process_candle).Start()
def _process_candle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
atr_val = float(atr_value)
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
body = abs(close - open_price)
factor = float(self.StabilizationFactor)
threshold = atr_val * factor
if not self._has_prev:
self._prev_body = body
self._prev_atr = atr_val
self._has_prev = True
return
prev_threshold = self._prev_atr * factor
was_stabilized = self._prev_body < prev_threshold
# After stabilization, trade breakout candle
if was_stabilized and body > threshold:
bullish = close > open_price
if bullish and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif not bullish and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_body = body
self._prev_atr = atr_val
def CreateClone(self):
return order_stabilization_strategy()