La Estrategia FiboChannel Line es una conversión del asesor experto MetaTrader "FIBOCHANNEL". El robot original dependía de la dirección de un canal de Fibonacci dibujado manualmente, oscilaciones de Momentum en una temporalidad superior, y una combinación de medias móviles ponderadas linealmente y señales MACD. El puerto de StockSharp mantiene el mismo espíritu aprovechando vínculos de indicadores de alto nivel y gestión de riesgos integrada.
Ideas clave:
Seguir la tendencia dominante usando un par de medias móviles ponderadas linealmente (LWMA).
Confirmar picos de Momentum alrededor del nivel neutro del oscilador Momentum.
Filtrar trades con la relación línea MACD vs. línea de señal.
Verificar la pendiente de un canal de regresión lineal en lugar de leer objetos del gráfico.
Gestionar posiciones mediante protección porcentual automática.
La estrategia funciona en cualquier instrumento que admita la agregación de velas. La temporalidad predeterminada son velas de 30 minutos, lo que proporciona un equilibrio entre la capacidad de respuesta y la estabilidad del indicador.
Lógica de trading
Filtro de tendencia – cuando la LWMA rápida cierra por encima de la LWMA lenta, el mercado se considera alcista y solo se evalúan trades largos. Cuando está por debajo, solo se consideran cortos.
Requisito de Momentum – una ventana deslizante de las tres lecturas de Momentum más recientes debe mostrar que al menos un valor se desvió del nivel neutro 100 por el umbral configurado. Esto replica las verificaciones de fortaleza de Momentum de múltiples barras de la versión MQL.
Filtro MACD – los largos requieren que la línea MACD esté por encima de la línea de señal; los cortos requieren lo contrario.
Dirección del canal – la pendiente de regresión lineal debe ser positiva (para largos) o negativa (para cortos) más allá del Slope Threshold. Esto imita la validación del canal ascendente/descendente del experto original que comparaba puntos de anclaje de un objeto de canal de Fibonacci.
Entradas y reversiones – si todas las condiciones se alinean y no hay ninguna posición existente en esa dirección, la estrategia cancela las órdenes activas y envía una orden de mercado con tamaño Volume + |Position|. Esto permite reversiones suaves.
Salidas – si la dirección del canal o el filtro MACD deja de apoyar el trade abierto, la posición se cierra después de cancelar las órdenes pendientes. Adicionalmente, las reglas de stop-loss protector, take-profit y drawdown máximo se configuran a través de StartProtection.
Parámetros
Parámetro
Descripción
Predeterminado
Candle Type
Agregación de velas utilizada para todos los indicadores.
Marco temporal de 30 minutos
Fast LWMA
Longitud de la media móvil ponderada linealmente rápida.
6
Slow LWMA
Longitud de la media móvil ponderada linealmente lenta.
85
Momentum Period
Número de barras para el indicador Momentum.
14
Momentum Threshold
Desviación absoluta mínima de 100 requerida dentro del buffer de Momentum.
0.3
Channel Length
Barras utilizadas para calcular la pendiente de regresión lineal.
50
Slope Threshold
Valor mínimo de pendiente absoluta para confirmar la dirección de tendencia.
0.0
MACD Fast
Período EMA rápida dentro del cálculo MACD.
12
MACD Slow
Período EMA lenta dentro del cálculo MACD.
26
MACD Signal
Período de línea de señal del MACD.
9
Take Profit %
Distancia del take-profit protector en porcentaje.
2
Stop Loss %
Distancia del stop-loss protector en porcentaje.
1
Equity Risk %
Drawdown máximo de capital de cuenta permitido antes de aplanar todas las posiciones.
3
Todos los parámetros numéricos exponen sugerencias de optimización que reflejan los rangos típicos de las entradas MQL.
Gestión de riesgos
StartProtection está configurado para aplicar:
Stop-loss y take-profit basados en porcentaje relativos al precio de entrada.
Guardia de drawdown de capital que aplana la estrategia si la pérdida supera el porcentaje configurado.
Estas protecciones sustituyen las numerosas rutinas de balance, trailing y punto de equilibrio del experto original, proporcionando un comportamiento más claro y seguro dentro de StockSharp.
Diferencias respecto a la versión MetaTrader
Las lecturas de objetos del gráfico fueron reemplazadas por un filtro de pendiente de regresión porque las estrategias de StockSharp no interactúan con canales de Fibonacci manuales.
En lugar de una mezcla de lógica de trailing basada en dinero, la estrategia depende de StartProtection.
El conjunto de indicadores sigue siendo el mismo (LWMA, Momentum, MACD), pero se implementa usando vínculos de alto nivel y sin sondeo directo de valores de indicadores.
Las alertas, correos electrónicos y notificaciones push fueron eliminados ya que el entorno StockSharp ya proporciona registro consolidado.
Notas de uso
Adjunte la estrategia a una cartera y un valor, configure el tamaño del lote a través de la propiedad Volume y ajuste los parámetros según sea necesario.
Asegúrese de que los datos históricos estén disponibles para el tipo de vela seleccionado para que el buffer de Momentum y el indicador de pendiente puedan formarse correctamente.
Ejecute primero en trading de papel para ajustar el umbral de Momentum y los parámetros de riesgo según la volatilidad del instrumento operado.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class FiboChannelLineStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public FiboChannelLineStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fibo_channel_line_strategy(Strategy):
def __init__(self):
super(fibo_channel_line_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(fibo_channel_line_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(fibo_channel_line_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return fibo_channel_line_strategy()