Estratégia de rompimento construída em torno do indicador de canal personalizado CandleStop. O sistema calcula continuamente bandas de máxima-máxima e mínima-mínima atrasadas, aguarda um candle completo fechar além dessas bandas e reage na barra seguinte. Opcionalmente impõe um tempo de vida máximo de posição e usa stops de proteção baseados em pontos.
Detalhes
Critérios de entrada: O candle completo anterior fecha acima do canal superior atrasado (para comprados) ou abaixo do canal inferior atrasado (para vendidos), enquanto a barra atual permanece de volta dentro do canal para evitar duplos gatilhos.
Comprado/Vendido: Lógica simétrica para operações compradas e vendidas com flags de habilitação independentes.
Critérios de saída: Rompimentos CandleStop de cor oposta fecham posições existentes; a saída opcional baseada em tempo fecha operações que permanecem abertas além do número configurado de minutos.
Stops: Usa níveis de stop-loss e take-profit baseados em passo de câmbio via StartProtection.
Valores padrão:
OrderVolume = 1
UpTrailPeriods = 5, UpTrailShift = 5
DownTrailPeriods = 5, DownTrailShift = 5
SignalBar = 1
StopLossPoints = 1000, TakeProfitPoints = 2000
MaxPositionMinutes = 1920
CandleType = período de 8 horas
Filtros:
Categoria: Rompimento
Direção: Ambos
Indicadores: Canais CandleStop atrasados
Stops: Sim
Complexidade: Intermediário
Período: Multi-hora
Sazonalidade: Não
Redes neurais: Não
Divergência: Não
Nível de risco: Médio
Parâmetros
OrderVolume: Quantidade para cada entrada de mercado quando uma nova posição é aberta.
EnableLongEntry / EnableShortEntry: Alternadores que permitem desabilitar novas posições compradas ou vendidas de forma independente.
CloseLongOnBearishBreak / CloseShortOnBullishBreak: Se fechar posições existentes quando a cor de rompimento CandleStop oposta aparecer.
EnableTimeExit: Ativa o filtro de tempo máximo de manutenção.
MaxPositionMinutes: Número de minutos antes que uma operação aberta seja forçosamente fechada; definir como zero para desabilitar mesmo quando EnableTimeExit for verdadeiro.
UpTrailPeriods e UpTrailShift: Comprimento de lookback e deslocamento para trás para o canal CandleStop altista. O deslocamento atrasa a banda estilo Donchian em várias barras para emular o timing do indicador original.
DownTrailPeriods e DownTrailShift: Parâmetros equivalentes para o canal baixista.
SignalBar: Índice da barra inspecionada para cor de rompimento (1 = candle completo anterior). A próxima barra mais antiga é usada como confirmação, assim como na versão MQL.
StopLossPoints / TakeProfitPoints: Distâncias de stop de proteção expressas em passos de preço. Passadas para StartProtection para gerenciar automaticamente as saídas.
CandleType: Série de candles primária usada para a estratégia. Padrão de 8 horas para corresponder ao script fonte.
Notas de implementação
Os valores do canal são calculados com indicadores Highest e Lowest combinados com Shift para reproduzir as bandas atrasadas do indicador CandleStop original.
Cores de sinal são armazenadas em um buffer circular para imitar as chamadas CopyBuffer da estratégia MQL e evitar entradas duplicadas em candles consecutivos.
Antes de colocar ordens, a estratégia verifica saídas baseadas em tempo, fecha posições opostas se necessário, e então emite novas ordens de mercado usando o volume configurado.
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>
/// CandleStop channel breakout strategy.
/// Uses Highest/Lowest channel to detect breakouts and trades on direction changes.
/// </summary>
public class CandleStopSystemTmPlusStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevUpper;
private decimal? _prevLower;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
public CandleStopSystemTmPlusStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 10)
.SetGreaterThanZero()
.SetDisplay("Period", "Channel lookback period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevUpper = null;
_prevLower = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevUpper = null;
_prevLower = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal upper, decimal lower)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevUpper = upper;
_prevLower = lower;
return;
}
var close = candle.ClosePrice;
if (_prevUpper == null || _prevLower == null)
{
_prevUpper = upper;
_prevLower = lower;
return;
}
// Breakout above previous upper channel
if (close > _prevUpper.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakdown below previous lower channel
else if (close < _prevLower.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevUpper = upper;
_prevLower = lower;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class candle_stop_system_tm_plus_strategy(Strategy):
def __init__(self):
super(candle_stop_system_tm_plus_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 10) \
.SetDisplay("Period", "Channel lookback period", "Indicators")
self._prev_upper = None
self._prev_lower = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(candle_stop_system_tm_plus_strategy, self).OnReseted()
self._prev_upper = None
self._prev_lower = None
def OnStarted2(self, time):
super(candle_stop_system_tm_plus_strategy, self).OnStarted2(time)
self._prev_upper = None
self._prev_lower = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, upper_value, lower_value):
if candle.State != CandleStates.Finished:
return
uv = float(upper_value)
lv = float(lower_value)
close = float(candle.ClosePrice)
if self._prev_upper is None or self._prev_lower is None:
self._prev_upper = uv
self._prev_lower = lv
return
# Breakout above previous upper channel
if close > self._prev_upper and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Breakdown below previous lower channel
elif close < self._prev_lower and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_upper = uv
self._prev_lower = lv
def CreateClone(self):
return candle_stop_system_tm_plus_strategy()