Ver no GitHub

Trader FX incrível

Esta estratégia reproduz a configuração MetaTrader de MQL/8539, que consiste nos indicadores personalizados AwesomeFxTradera.mq4 e t_ma.mq4. O código original pinta o histograma Bill Williams Awesome Oscillator em verde ou vermelho, dependendo se o valor está subindo ou descendo, e sobrepõe uma média móvel ponderada linear de 34 períodos (LWMA) ao lado de um clone suavizado da mesma curva. A porta StockSharp mantém os mesmos cálculos e converte as cores dos indicadores em sinais de negociação.

Lógica MQL original

  1. AwesomeFxTradera.mq4 calcula duas médias móveis exponenciais aplicadas ao preço de abertura com os períodos 8 e 13. Sua diferença é armazenada em ExtBuffer0. O buffer é pintado de verde quando o valor atual é maior que a barra anterior e de vermelho quando é menor. Isto codifica efetivamente a direção do momento, não apenas o seu sinal.
  2. t_ma.mq4 traça um LWMA de 34 períodos do preço de abertura (ExtMapBuffer1) e uma média móvel simples de 6 períodos desse LWMA (ExtMapBuffer2). O mais suave monitora se a média da tendência acelera ou desacelera.

O gráfico MetaTrader, portanto, destaca o impulso de alta quando o oscilador está acima de zero e continua aumentando enquanto o preço é negociado acima do LWMA suavizado. O momentum de baixa é a configuração oposta.

StockSharp implementação

O AwesomeFxTraderStrategy assina um tipo de vela configurável (padrão M15) e alimenta os indicadores com o preço de abertura da vela para corresponder aos buffers MetaTrader.

  1. As EMAs rápidas e lentas são recalculadas em cada vela finalizada; sua diferença reproduz o histograma oscilante.
  2. O LWMA rastreia a tendência de 34 barras e um SMA de 6 barras a suaviza. A comparação das duas séries revela se a curva de tendência está subindo ou descendo.
  3. A cor do oscilador é reconstruída comparando o valor atual do histograma com a barra anterior, seguindo a lógica bool up da implementação MQL.
  4. Regras de entrada:
    • Insira longo quando o oscilador estiver positivo, subindo (buffer verde) e o LWMA estiver acima do seu nível mais suave.
    • Entre em posição curta quando o oscilador estiver negativo, caindo (buffer vermelho) e o LWMA estiver abaixo do seu nível mais suave.
  5. Regras de saída/reversão: um sinal oposto inverte a posição. O tamanho da ordem é aumentado automaticamente pela posição atual absoluta, de modo que as posições vendidas sejam fechadas antes que uma posição comprada seja estabelecida e vice-versa.

Nenhum nível extra de stop-loss ou take-profit é definido no código-fonte, portanto, a porta depende apenas de mudanças de impulso para saídas. As declarações de registro documentam cada gatilho de negociação junto com as leituras dos indicadores.

Parâmetros

Nome Padrão Descrição
FastEmaPeriod 8 Comprimento do EMA rápido usado na réplica do oscilador.
SlowEmaPeriod 13 Comprimento da lentidão EMA.
TrendLwmaPeriod 34 Período do filtro de tendência LWMA retirado de t_ma.mq4.
TrendSmoothingPeriod 6 Janela do SMA aplicada aos valores LWMA.
CandleType Período de 15 minutos Tipo de dados Candle usado para cálculos de impulso e tendência.

Todos os parâmetros podem ser otimizados por meio da IU do StockSharp graças aos metadados do StrategyParam.

Mapeamento de arquivos

arquivo MetaTrader StockSharp contraparte Notas
MQL/8539/AwesomeFxTradera.mq4 CS/AwesomeFxTraderStrategy.cs Recria o oscilador EMA-on-open e sua lógica de cores ascendente/descendente.
MQL/8539/t_ma.mq4 CS/AwesomeFxTraderStrategy.cs Implementa o LWMA de 34 períodos com um SMA mais suave de 6 períodos para detecção de tendências.

A versão Python foi omitida intencionalmente conforme 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;
	}
}