Ver en GitHub

Impresionante comerciante de divisas

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

  1. 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.
  2. 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.

  1. Las EMA rápidas y lentas se recalculan en cada vela terminada; su diferencia reproduce el histograma oscilante.
  2. 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.
  3. 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.
  4. 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.
  5. 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;
	}
}