La Estrategia WE TRUST Channel es un port de StockSharp de alto nivel del asesor experto de MetaTrader 5 "WE TRUST". El sistema opera pullbacks hacia una media móvil ponderada lineal que está rodeada por bandas de desviación estándar. Cuando el precio cierra fuera de las bandas, la estrategia anticipa una reversión a la media y abre una posición de mercado de vuelta hacia el centro del canal. La inversión de señales, el cierre opcional de trades opuestos y los parámetros de gestión monetaria basados en pips reflejan el experto original.
Lógica de trading
Suscribirse al tipo de vela configurado (velas por hora por defecto) y calcular dos indicadores en la fuente de precio seleccionada:
Una media móvil ponderada lineal (LWMA) con período y desplazamiento configurables.
Una envolvente de desviación estándar con su propio período y desplazamiento.
Convertir los offsets basados en pips en distancias de precio absolutas usando el PriceStep del instrumento. Las cotizaciones de cinco y tres dígitos multiplican el paso por 10 para emular la definición de pip de MetaTrader.
Calcular los límites superior e inferior del canal: LWMA ± StdDev ± ChannelIndentPips (convertidos en unidades de precio).
Evaluar solo velas finalizadas. Cuando el precio de la vela elegida cierra por debajo del canal inferior, la estrategia genera una señal de compra. Cuando cierra por encima del canal superior, genera una señal de venta.
Opcionalmente invertir las señales cuando ReverseSignals está habilitado. Opcionalmente aplanar una posición opuesta antes de actuar sobre una nueva señal cuando CloseOpposite está habilitado.
Enviar órdenes de mercado con el volumen configurado cuando la posición actual está plana o alineada con la dirección de la señal.
Gestión de riesgos
StopLossPips y TakeProfitPips traducen distancias en pips a órdenes protectoras absolutas a través de StartProtection. Establecerlos en 0 para deshabilitar el nivel respectivo.
TrailingStopPips y TrailingStepPips controlan un trailing stop basado en pips que sigue los trades rentables. Ambos parámetros se convierten en distancias de precio usando la misma lógica de tamaño de pip.
Todas las salidas se realizan con órdenes de mercado para permanecer cercanas a la implementación de MQL5.
Parámetros
Parámetro
Descripción
Predeterminado
OrderVolume
Volumen del trade enviado con cada orden de mercado.
0.1
StopLossPips
Distancia de stop-loss expresada en pips (0 deshabilita el stop).
40
TakeProfitPips
Distancia de take-profit expresada en pips (0 deshabilita el objetivo).
60
TrailingStopPips
Distancia de trailing stop en pips.
10
TrailingStepPips
Paso de trailing en pips entre ajustes de stop.
10
MaPeriod
Período de la media móvil ponderada lineal.
60
MaShift
Número de barras que la media móvil se desplaza hacia adelante.
0
StdDevPeriod
Período del cálculo de desviación estándar.
50
StdDevShift
Número de barras que el valor de desviación se desplaza.
0
SignalBarOffset
Número de barras completadas hacia atrás al evaluar señales.
1
ChannelIndentPips
Buffer adicional añadido fuera de las bandas de desviación.
1
ReverseSignals
Invertir la lógica de compra/venta del rompimiento del canal.
false
CloseOpposite
Cerrar una posición opuesta antes de entrar en un nuevo trade.
false
AppliedPrice
Componente de precio de la vela alimentado en ambos indicadores.
Weighted
CandleType
Tipo de datos de vela solicitado al conector.
marco temporal de 1 hora
Notas
La estrategia depende de metadatos válidos de PriceStep. Si el exchange no lo proporciona, el código recurre a Security.Step y finalmente a 1.
Solo la implementación en C# está incluida en este directorio. El port de Python se omite intencionalmente según las instrucciones.
La lógica procesa solo velas finalizadas y no intenta acumular datos de barra parciales.
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 WeTrustChannelStrategy : 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 WeTrustChannelStrategy()
{
_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 we_trust_channel_strategy(Strategy):
def __init__(self):
super(we_trust_channel_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(we_trust_channel_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(we_trust_channel_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 we_trust_channel_strategy()