Esta estrategia reproduce la configuración MetaTrader de MQL/8539, que consta de los indicadores personalizados AwesomeFxTradera.mq4 y t_ma.mq4. El código original pinta el histograma Bill Williams Awesome Oscillator en verde o rojo dependiendo de si el valor está subiendo o bajando, y superpone un promedio móvil ponderado lineal (LWMA) de 34 períodos junto con un clon suavizado de la misma curva. El puerto StockSharp mantiene los mismos cálculos y convierte los colores del indicador en señales comerciales.
Lógica original MQL
AwesomeFxTradera.mq4 calcula dos medias móviles exponenciales aplicadas al precio de apertura con los períodos 8 y 13. Su diferencia se almacena en ExtBuffer0. El búfer se pinta de verde cuando el valor actual es mayor que la barra anterior y de rojo cuando es menor. Esto codifica efectivamente la dirección del impulso, no solo su signo.
t_ma.mq4 traza una LWMA de 34 períodos del precio de apertura (ExtMapBuffer1) y una media móvil simple de 6 períodos de esa LWMA (ExtMapBuffer2). El seguimiento más suave indica si el promedio de la tendencia se acelera o desacelera.
Por lo tanto, el gráfico MetaTrader destaca el impulso alcista cuando el oscilador está por encima de cero y sigue aumentando mientras el precio cotiza por encima de la LWMA suavizada. El impulso bajista es la configuración opuesta.
StockSharp implementación
El AwesomeFxTraderStrategy se suscribe a un tipo de vela configurable (predeterminado M15) y alimenta los indicadores con el precio de apertura de la vela para que coincida con los buffers MetaTrader.
Las EMA rápidas y lentas se recalculan en cada vela terminada; su diferencia reproduce el histograma oscilante.
El LWMA sigue la tendencia de 34 barras y un SMA de 6 barras la suaviza. La comparación de ambas series revela si la curva de tendencia está subiendo o bajando.
El color del oscilador se reconstruye comparando el valor actual del histograma con la barra anterior, siguiendo la lógica bool up de la implementación MQL.
Reglas de entrada:
Entre en largo cuando el oscilador sea positivo, creciente (búfer verde) y el LWMA esté por encima de su nivel más suave.
Entre en corto cuando el oscilador sea negativo, caiga (buffer rojo) y el LWMA esté por debajo de su nivel más suave.
Reglas de salida/inversión: una señal opuesta invierte la posición. El tamaño de la orden aumenta automáticamente según la posición actual absoluta, de modo que los cortos se cierran antes de que se establezca un largo y viceversa.
No se definen niveles adicionales de stop-loss o take-profit en el código fuente, por lo que el puerto se basa únicamente en cambios de impulso para las salidas. Las declaraciones de registro documentan cada activación comercial junto con las lecturas del indicador.
Parámetros
Nombre
Predeterminado
Descripción
FastEmaPeriod
8
Longitud del EMA rápido utilizado en la réplica del oscilador.
SlowEmaPeriod
13
Duración del EMA lenta.
TrendLwmaPeriod
34
Período del filtro de tendencias LWMA tomado de t_ma.mq4.
TrendSmoothingPeriod
6
Ventana del SMA aplicada a los valores LWMA.
CandleType
plazo de 15 minutos
Tipo de datos de vela utilizado para cálculos de impulso y tendencia.
Todos los parámetros se pueden optimizar a través de la interfaz de usuario StockSharp gracias a los metadatos StrategyParam.
Mapeo de archivos
MetaTrader archivo
StockSharp contraparte
Notas
MQL/8539/AwesomeFxTradera.mq4
CS/AwesomeFxTraderStrategy.cs
Recrea el oscilador abierto EMA y su lógica de color ascendente/descendente.
MQL/8539/t_ma.mq4
CS/AwesomeFxTraderStrategy.cs
Implementa la LWMA de 34 períodos con un SMA más suave de 6 períodos para la detección de tendencias.
La versión de Python se omite intencionalmente según lo solicitado.
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>
/// Awesome Fx Trader strategy.
/// Recreates the MetaTrader logic that paints the Awesome Oscillator histogram and trend moving averages.
/// Goes long when the oscillator turns bullish while the linear weighted average stays above its smoother.
/// Opens shorts on the opposite momentum and trend alignment.
/// </summary>
public class AwesomeFxTraderStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<int> _trendLwmaPeriod;
private readonly StrategyParam<int> _trendSmoothingPeriod;
private readonly StrategyParam<DataType> _candleType;
private EMA _fastEma;
private EMA _slowEma;
private WeightedMovingAverage _trendLwma;
private decimal _previousAo;
private bool _hasPreviousAo;
private bool _isAoIncreasing;
private decimal _previousLwma;
/// <summary>
/// Period for the fast EMA used in the oscillator.
/// </summary>
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
/// <summary>
/// Period for the slow EMA used in the oscillator.
/// </summary>
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
/// <summary>
/// Length of the trend linear weighted moving average.
/// </summary>
public int TrendLwmaPeriod
{
get => _trendLwmaPeriod.Value;
set => _trendLwmaPeriod.Value = value;
}
/// <summary>
/// Length of the smoothing simple moving average applied to the trend LWMA.
/// </summary>
public int TrendSmoothingPeriod
{
get => _trendSmoothingPeriod.Value;
set => _trendSmoothingPeriod.Value = value;
}
/// <summary>
/// Type of candles to use for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="AwesomeFxTraderStrategy"/>.
/// </summary>
public AwesomeFxTraderStrategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Period of the fast EMA driving the oscillator", "Awesome Oscillator")
.SetOptimize(4, 20, 1);
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Period of the slow EMA driving the oscillator", "Awesome Oscillator")
.SetOptimize(8, 40, 1);
_trendLwmaPeriod = Param(nameof(TrendLwmaPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Trend LWMA", "Length of the linear weighted trend average", "Trend Filter")
.SetOptimize(20, 80, 2);
_trendSmoothingPeriod = Param(nameof(TrendSmoothingPeriod), 6)
.SetGreaterThanZero()
.SetDisplay("Trend Smoother", "Length of the SMA applied to the trend LWMA", "Trend Filter")
.SetOptimize(3, 10, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time-frame used for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastEma = null;
_slowEma = null;
_trendLwma = null;
_previousAo = 0m;
_hasPreviousAo = false;
_isAoIncreasing = false;
_previousLwma = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastEma = new EMA { Length = FastEmaPeriod };
_slowEma = new EMA { Length = SlowEmaPeriod };
_trendLwma = new WeightedMovingAverage { Length = TrendLwmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(_fastEma, _slowEma, _trendLwma, ProcessCandle).Start();
var priceArea = CreateChartArea();
if (priceArea != null)
{
DrawCandles(priceArea, subscription);
DrawIndicator(priceArea, _trendLwma);
DrawOwnTrades(priceArea);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastEma, decimal slowEma, decimal lwma)
{
if (candle.State != CandleStates.Finished)
return;
var ao = fastEma - slowEma;
if (!_hasPreviousAo)
{
_previousAo = ao;
_hasPreviousAo = true;
_isAoIncreasing = ao >= 0m;
_previousLwma = lwma;
return;
}
if (ao > _previousAo)
_isAoIncreasing = true;
else if (ao < _previousAo)
_isAoIncreasing = false;
var isTrendBullish = lwma > _previousLwma;
var isTrendBearish = lwma < _previousLwma;
var bullishSignal = _isAoIncreasing && ao > 0m && isTrendBullish;
var bearishSignal = !_isAoIncreasing && ao < 0m && isTrendBearish;
if (bullishSignal && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
if (volume <= 0)
volume = 1;
BuyMarket(volume);
}
else if (bearishSignal && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
if (volume <= 0)
volume = 1;
SellMarket(volume);
}
_previousAo = ao;
_previousLwma = lwma;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, WeightedMovingAverage
class awesome_fx_trader_strategy(Strategy):
def __init__(self):
super(awesome_fx_trader_strategy, self).__init__()
self._fast_ema_period = self.Param("FastEmaPeriod", 8) \
.SetDisplay("Fast EMA", "Period of the fast EMA driving the oscillator", "Awesome Oscillator")
self._slow_ema_period = self.Param("SlowEmaPeriod", 13) \
.SetDisplay("Slow EMA", "Period of the slow EMA driving the oscillator", "Awesome Oscillator")
self._trend_lwma_period = self.Param("TrendLwmaPeriod", 34) \
.SetDisplay("Trend LWMA", "Length of the linear weighted trend average", "Trend Filter")
self._trend_smoothing_period = self.Param("TrendSmoothingPeriod", 6) \
.SetDisplay("Trend Smoother", "Length of the SMA applied to the trend LWMA", "Trend Filter")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time-frame used for calculations", "General")
self._fast_ema = None
self._slow_ema = None
self._trend_lwma = None
self._previous_ao = 0.0
self._has_previous_ao = False
self._is_ao_increasing = False
self._previous_lwma = 0.0
@property
def FastEmaPeriod(self):
return self._fast_ema_period.Value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
@property
def TrendLwmaPeriod(self):
return self._trend_lwma_period.Value
@property
def TrendSmoothingPeriod(self):
return self._trend_smoothing_period.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(awesome_fx_trader_strategy, self).OnStarted2(time)
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self.FastEmaPeriod
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self.SlowEmaPeriod
self._trend_lwma = WeightedMovingAverage()
self._trend_lwma.Length = self.TrendLwmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._fast_ema, self._slow_ema, self._trend_lwma, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_ema, slow_ema, lwma):
if candle.State != CandleStates.Finished:
return
fast_ema = float(fast_ema)
slow_ema = float(slow_ema)
lwma = float(lwma)
ao = fast_ema - slow_ema
if not self._has_previous_ao:
self._previous_ao = ao
self._has_previous_ao = True
self._is_ao_increasing = ao >= 0
self._previous_lwma = lwma
return
if ao > self._previous_ao:
self._is_ao_increasing = True
elif ao < self._previous_ao:
self._is_ao_increasing = False
is_trend_bullish = lwma > self._previous_lwma
is_trend_bearish = lwma < self._previous_lwma
bullish_signal = self._is_ao_increasing and ao > 0 and is_trend_bullish
bearish_signal = not self._is_ao_increasing and ao < 0 and is_trend_bearish
if bullish_signal and self.Position <= 0:
volume = self.Volume + Math.Abs(self.Position)
if volume <= 0:
volume = 1
self.BuyMarket(volume)
elif bearish_signal and self.Position >= 0:
volume = self.Volume + Math.Abs(self.Position)
if volume <= 0:
volume = 1
self.SellMarket(volume)
self._previous_ao = ao
self._previous_lwma = lwma
def OnReseted(self):
super(awesome_fx_trader_strategy, self).OnReseted()
self._fast_ema = None
self._slow_ema = None
self._trend_lwma = None
self._previous_ao = 0.0
self._has_previous_ao = False
self._is_ao_increasing = False
self._previous_lwma = 0.0
def CreateClone(self):
return awesome_fx_trader_strategy()