Esta estrategia es un port de StockSharp del asesor experto de MetaTrader Exp_XPeriodCandleSystem_Tm_Plus. El robot original se basa en el indicador personalizado XPeriod Candle System, que suaviza los datos de velas y colorea las barras según las rupturas de las Bandas de Bollinger. La versión traducida reproduce este comportamiento aplicando suavizado exponencial a las series OHLC, mapeando los mismos modos de precio aplicado, y ejecutando operaciones a partir de los estados de color resultantes. Una salida basada en tiempo y órdenes de protección configurables complementan la lógica de ruptura.
Lógica de trading
Velas suavizadas – Las medias móviles exponenciales con longitud configurable construyen valores sintéticos de apertura, máximo, mínimo y cierre que aproximan el indicador fuente.
Precio aplicado – El usuario puede seleccionar cualquiera de las doce fórmulas de precio (cierre, apertura, mediana, variaciones de seguimiento de tendencia, Demark, etc.) antes de alimentar los datos en las Bandas de Bollinger.
Análisis de bandas – Un indicador de Bandas de Bollinger (longitud y desviación configurables) procesa la serie de precios suavizados. Se requieren bandas finalizadas antes de evaluar las señales.
Estados de color –
Barra alcista por encima de la banda superior → color 0 (ruptura al alza).
Barra bajista por debajo de la banda inferior → color 4 (ruptura a la baja).
Otras barras alcistas → color 1; otras barras bajistas → color 3.
Un desplazamiento de ruptura configurable (convertido a unidades de precio usando el tamaño de tick del símbolo cuando es posible) evita falsos disparadores.
Entradas – La estrategia analiza la vela definida por SignalBar y su predecesora:
Abrir largo cuando la barra anterior fue una ruptura alcista (0) y la barra de señal no lo es.
Abrir corto cuando la barra anterior fue una ruptura bajista (4) y la barra de señal no lo es.
Salidas –
Cerrar largos cuando la barra de referencia es bajista (> 2).
Cerrar cortos cuando la barra de referencia es alcista (< 2).
Un temporizador de mantenimiento opcional (TimeTrade y HoldingMinutes) cierra posiciones tras los minutos especificados.
Riesgo – StartProtection despliega distancias absolutas opcionales de take-profit y stop-loss para cada operación.
Parámetros
Parámetro
Descripción
Valor predeterminado
OrderVolume
Tamaño de orden base utilizado para entradas de mercado.
0.1
BuyPosOpen / SellPosOpen
Habilitar/deshabilitar entradas largas o cortas.
true
BuyPosClose / SellPosClose
Permitir salidas de posiciones largas o cortas.
true
TimeTrade
Activa el filtro de salida basado en tiempo.
true
HoldingMinutes
Tiempo máximo de mantenimiento antes de que el filtro de tiempo cierre una posición.
960
CandleType
Tipo de datos de velas (marco temporal) solicitado del mercado.
4 horas
Period
Longitud de las medias móviles exponenciales de suavizado.
5
BollingerLength
Número de barras suavizadas dentro de la ventana de cálculo de Bollinger.
20
BandsDeviation
Multiplicador del ancho de banda.
1.001
AppliedPriceMode
Transformación de precio usada antes del indicador Bollinger (cierre, apertura, mediana, seguimiento de tendencia, Demark, etc.).
Close
SignalBar
Índice de la barra usada para evaluar señales (1 = última barra cerrada).
1
StopLoss / TakeProfit
Distancias absolutas (en unidades de precio) utilizadas por el motor de protección.
1000 / 2000
Deviation
Desplazamiento de ruptura extra añadido por encima/debajo de las Bandas de Bollinger.
10
Notas de uso
El paso de suavizado usa medias móviles exponenciales para replicar el cálculo propietario de XPeriod. Períodos más pequeños mantienen las velas sintéticas más cercanas a los precios de mercado, mientras que períodos más grandes enfatizan la estructura de tendencia.
SignalBar debe permanecer dentro del historial almacenado (hasta 14 posiciones después de la barra actual). Valores mayores al historial disponible omitirán automáticamente el trading.
El desplazamiento de ruptura se multiplica por PriceStep cuando el valor expone un tamaño de tick. Esto mantiene el comportamiento similar a la versión MetaTrader donde Deviation se define en puntos.
StopLoss y TakeProfit se especifican en unidades absolutas de precio. Establézcalos en cero para deshabilitar las órdenes de protección manteniendo activa la infraestructura de gestión.
Aún no se proporciona traducción en Python; esta carpeta contiene únicamente la implementación en C#.
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>
/// XPeriod candle system with Bollinger Bands breakout.
/// Buys on close above upper band with bullish candle, sells on close below lower band with bearish candle.
/// </summary>
public class XPeriodCandleSystemTmPlusStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bbWidth;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BbPeriod
{
get => _bbPeriod.Value;
set => _bbPeriod.Value = value;
}
public decimal BbWidth
{
get => _bbWidth.Value;
set => _bbWidth.Value = value;
}
public XPeriodCandleSystemTmPlusStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bbWidth = Param(nameof(BbWidth), 2m)
.SetGreaterThanZero()
.SetDisplay("BB Width", "Bollinger Bands width", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BbPeriod, Width = BbWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bb);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var bb = (BollingerBandsValue)value;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
var close = candle.ClosePrice;
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
// Buy: close above upper band with bullish candle
if (close > upper && isBullish && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell: close below lower band with bearish candle
else if (close < lower && isBearish && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit long at middle band
else if (Position > 0 && close < middle)
{
SellMarket();
}
// Exit short at middle band
else if (Position < 0 && close > middle)
{
BuyMarket();
}
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class x_period_candle_system_tm_plus_strategy(Strategy):
def __init__(self):
super(x_period_candle_system_tm_plus_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._bb_period = self.Param("BbPeriod", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
self._bb_width = self.Param("BbWidth", 2.0) \
.SetDisplay("BB Width", "Bollinger Bands width", "Indicators")
@property
def CandleType(self):
return self._candle_type.Value
@property
def BbPeriod(self):
return self._bb_period.Value
@property
def BbWidth(self):
return self._bb_width.Value
def OnStarted2(self, time):
super(x_period_candle_system_tm_plus_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.BbPeriod
bb.Width = self.BbWidth
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(bb, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def _on_process(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
upper = bb_value.UpBand
lower = bb_value.LowBand
middle = bb_value.MovingAverage
if upper is None or lower is None or middle is None:
return
upper = float(upper)
lower = float(lower)
middle = float(middle)
close = float(candle.ClosePrice)
is_bullish = float(candle.ClosePrice) > float(candle.OpenPrice)
is_bearish = float(candle.ClosePrice) < float(candle.OpenPrice)
# Buy: close above upper band with bullish candle
if close > upper and is_bullish and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell: close below lower band with bearish candle
elif close < lower and is_bearish and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Exit long at middle band
elif self.Position > 0 and close < middle:
self.SellMarket()
# Exit short at middle band
elif self.Position < 0 and close > middle:
self.BuyMarket()
def CreateClone(self):
return x_period_candle_system_tm_plus_strategy()