Esta estratégia replica o clássico consultor especializado "BreakOut" do MetaTrader de Soubra2003. Ela monitora a máxima e a
mínima da vela completada mais recente e reage sempre que o fechamento atual rompe esses níveis de referência. A abordagem é
totalmente simétrica: posições compradas são abertas em rompimentos altistas, e posições vendidas são abertas em rompimentos
baixistas. Buffers opcionais de stop-loss e take-profit expressos em unidades de preço permitem ao usuário limitar o risco ou
bloquear ganhos.
Visão Geral
Assina uma única série de velas (período de 1 hora por padrão).
Armazena a máxima e a mínima da vela anterior para agir como gatilhos de rompimento.
Opera apenas no fechamento da vela para espelhar a lógica original baseada em ticks sem depender de dados intrabar.
Suporta tanto trades comprados quanto vendidos e sempre permanece zerado quando nenhuma condição de rompimento está ativa.
Regras de Trading
Entrada por rompimento / reversão
Quando o fechamento da vela atual concluída está estritamente acima da máxima da vela anterior:
Qualquer posição vendida aberta é fechada a mercado.
Uma nova posição comprada é aberta imediatamente depois (a reversão acontece dentro do mesmo passo de processamento da vela).
Quando o fechamento está estritamente abaixo da mínima da vela anterior:
Qualquer posição comprada aberta é fechada a mercado.
Uma nova posição vendida é aberta depois.
Saídas de proteção (opcional)
Se um offset de stop-loss for configurado (> 0), a estratégia sai de uma posição comprada quando o fechamento cai offset
unidades abaixo do preço de entrada, ou sai de uma posição vendida quando o fechamento sobe offset unidades acima do
preço de entrada.
Se um offset de take-profit for configurado (> 0), a estratégia sai de uma posição comprada quando o fechamento sobe
offset unidades acima do preço de entrada, ou sai de uma posição vendida quando o fechamento cai offset unidades
abaixo do preço de entrada.
Reinicialização do estado
Após cada vela ser processada, a máxima e a mínima mais recentes se tornam os novos níveis de referência de rompimento.
Parâmetros
Candle Type – tipo de dados usado para assinatura (padrão para período horário). Defina como o tamanho de barra que
corresponde ao gráfico usado no MetaTrader para o consultor especializado original.
Stop Loss – distância em unidades de preço absoluto entre o preço de entrada e o stop de proteção. Mantenha em 0 para
desabilitar o tratamento de stop-loss.
Take Profit – distância em unidades de preço absoluto entre o preço de entrada e o alvo de lucro. Mantenha em 0 para
desabilitar o tratamento de take-profit.
Notas
Os cálculos de stop-loss e take-profit são realizados em preços de fechamento de velas. A versão MQL4 original anexava níveis
estáticos de SL/TP às ordens; no StockSharp as saídas são simuladas enviando ordens a mercado assim que os limiares são atingidos.
Use incrementos de preço específicos do instrumento ao configurar os offsets. Por exemplo, se o instrumento opera com tamanho
de tick de 0.01 e você quer um stop de 20 ticks, defina o parâmetro de stop-loss como 0.20.
Como a lógica sempre faz referência à vela imediatamente anterior, a estratégia funciona melhor em instrumentos em tendência
ou durante sessões de alta volatilidade onde os rompimentos são significativos.
Origem
Fonte: MQL/17306/BreakOut.mq4 (consultor especializado BreakOut de Soubra2003)
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Breakout strategy that trades when the close crosses the previous candle's high or low.
/// Ported from the BreakOut.mq4 expert by Soubra2003.
/// </summary>
public class PreviousCandleBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossOffset;
private readonly StrategyParam<decimal> _takeProfitOffset;
private decimal? _previousHigh;
private decimal? _previousLow;
private decimal _entryPrice;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal StopLossOffset { get => _stopLossOffset.Value; set => _stopLossOffset.Value = value; }
public decimal TakeProfitOffset { get => _takeProfitOffset.Value; set => _takeProfitOffset.Value = value; }
public PreviousCandleBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromDays(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candle subscription", "General");
_stopLossOffset = Param(nameof(StopLossOffset), 1000m)
.SetDisplay("Stop Loss", "Price distance for the stop-loss. Set 0 to disable.", "Risk")
;
_takeProfitOffset = Param(nameof(TakeProfitOffset), 1500m)
.SetDisplay("Take Profit", "Price distance for the take-profit. Set 0 to disable.", "Risk")
;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousHigh = null;
_previousLow = null;
_entryPrice = 0m;
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_previousHigh is null || _previousLow is null)
{
// Store the first finished candle to obtain reference high/low levels.
_previousHigh = candle.HighPrice;
_previousLow = candle.LowPrice;
return;
}
var previousHigh = _previousHigh.Value;
var previousLow = _previousLow.Value;
var close = candle.ClosePrice;
var breakoutAbove = close > previousHigh;
var breakoutBelow = close < previousLow;
// Manage protective exits while a position is open.
if (Position > 0)
{
if (StopLossOffset > 0m && close <= _entryPrice - StopLossOffset)
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
_entryPrice = 0m;
}
else if (TakeProfitOffset > 0m && close >= _entryPrice + TakeProfitOffset)
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
_entryPrice = 0m;
}
}
else if (Position < 0)
{
if (StopLossOffset > 0m && close >= _entryPrice + StopLossOffset)
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
_entryPrice = 0m;
}
else if (TakeProfitOffset > 0m && close <= _entryPrice - TakeProfitOffset)
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
_entryPrice = 0m;
}
}
// Breakout above the previous high opens or reverses into a long position.
if (breakoutAbove)
{
if (Position < 0)
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
_entryPrice = 0m;
}
if (Position <= 0)
{
BuyMarket();
_entryPrice = close;
}
}
else if (breakoutBelow)
{
// Breakout below the previous low opens or reverses into a short position.
if (Position > 0)
{
if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
_entryPrice = 0m;
}
if (Position >= 0)
{
SellMarket();
_entryPrice = close;
}
}
_previousHigh = candle.HighPrice;
_previousLow = candle.LowPrice;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class previous_candle_breakout_strategy(Strategy):
def __init__(self):
super(previous_candle_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromDays(1)))
self._stop_loss_offset = self.Param("StopLossOffset", 1000.0)
self._take_profit_offset = self.Param("TakeProfitOffset", 1500.0)
self._previous_high = None
self._previous_low = None
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def StopLossOffset(self):
return self._stop_loss_offset.Value
@StopLossOffset.setter
def StopLossOffset(self, value):
self._stop_loss_offset.Value = value
@property
def TakeProfitOffset(self):
return self._take_profit_offset.Value
@TakeProfitOffset.setter
def TakeProfitOffset(self, value):
self._take_profit_offset.Value = value
def OnStarted2(self, time):
super(previous_candle_breakout_strategy, self).OnStarted2(time)
self._previous_high = None
self._previous_low = None
self._entry_price = 0.0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
if self._previous_high is None or self._previous_low is None:
self._previous_high = high
self._previous_low = low
return
previous_high = self._previous_high
previous_low = self._previous_low
breakout_above = close > previous_high
breakout_below = close < previous_low
sl = float(self.StopLossOffset)
tp = float(self.TakeProfitOffset)
if self.Position > 0:
if sl > 0.0 and close <= self._entry_price - sl:
self.SellMarket()
self._entry_price = 0.0
elif tp > 0.0 and close >= self._entry_price + tp:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if sl > 0.0 and close >= self._entry_price + sl:
self.BuyMarket()
self._entry_price = 0.0
elif tp > 0.0 and close <= self._entry_price - tp:
self.BuyMarket()
self._entry_price = 0.0
if breakout_above:
if self.Position < 0:
self.BuyMarket()
self._entry_price = 0.0
if self.Position <= 0:
self.BuyMarket()
self._entry_price = close
elif breakout_below:
if self.Position > 0:
self.SellMarket()
self._entry_price = 0.0
if self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._previous_high = high
self._previous_low = low
def OnReseted(self):
super(previous_candle_breakout_strategy, self).OnReseted()
self._previous_high = None
self._previous_low = None
self._entry_price = 0.0
def CreateClone(self):
return previous_candle_breakout_strategy()