Ver no GitHub

Estratégia cruzada de preços MA

A estratégia MA Price Cross é uma conversão direta do MetaTrader 4 consultor especialista "MA Price Cross" para o StockSharp API de alto nível. Ele espera que a média móvel selecionada cruze o preço atual enquanto a negociação é permitida dentro de uma janela de tempo configurável. Quando o cruzamento acontece por baixo, o algoritmo abre uma posição comprada; quando o cruzamento acontece por cima, abre uma posição curta. As distâncias protetoras de stop-loss e take-profit são definidas em MetaTrader pontos e convertidas automaticamente em compensações de preço absoluto usando o PriceStep do instrumento.

Ao contrário da implementação original MQL, que reage a cada tick, a versão StockSharp funciona com velas finalizadas e usa a assinatura de alto nível SubscribeCandles. Isso garante que as decisões de negociação sejam executadas uma vez por barra e permaneçam compatíveis com o pipeline de vinculação do indicador. A média móvel pode ser configurada para corresponder a todos os quatro modos MetaTrader e aceita diferentes fontes de preços (fechamento, abertura, máximo, mínimo, mediano, típico, ponderado).

Lógica de negociação

  1. Aguarde até que o horário atual caia na janela de negociação [StartTime, StopTime). As janelas noturnas são suportadas por volta da meia-noite.
  2. Processe apenas velas concluídas. Alimente a média móvel configurada com o preço aplicado escolhido.
  3. Armazene o valor da média móvel anterior para emular a lógica de deslocamento iMA usada em MetaTrader.
  4. Quando a média anterior estiver abaixo do preço mais recente e a nova média estiver acima do preço, abra (ou inverta) uma posição longa.
  5. Quando a média anterior estiver acima do preço mais recente e a nova média estiver abaixo do preço, abra (ou inverta) uma posição curta.
  6. Antes de abrir uma nova posição no lado oposto, nivele qualquer exposição existente para espelhar a restrição OrdersTotal() == 0 do código original.
  7. Inicie um stop-loss e um take-profit virtuais com distâncias expressas em MetaTrader pontos multiplicados pelo instrumento atual PriceStep.

Parâmetros padrão

Parâmetro Padrão Descrição
CandleType TimeFrame(1m) Série de velas que orienta todos os cálculos.
MaPeriod 160 Número de barras utilizadas pela média móvel.
MaMethod Simple Tipo de média móvel: Simples, Exponencial, Suavizada ou LinearWeighted.
PriceType Close Fonte de preço encaminhada para média móvel (fechamento/abertura/máxima/mínima/mediana/típica/ponderada).
StartTime 01:00 Hora do dia em que a negociação se torna ativa.
StopTime 22:00 Hora do dia em que novas entradas são interrompidas.
StopLossPoints 200 MetaTrader pontos convertidos em uma distância de parada de proteção absoluta.
TakeProfitPoints 600 MetaTrader pontos convertidos em uma distância alvo de lucro absoluto.
OrderVolume 0.1 Volume padrão enviado com ordens de mercado.

Notas

  • Se StartTime for igual a StopTime, o filtro de horário será desativado e a negociação será permitida o dia todo.
  • Quando StopLossPoints ou TakeProfitPoints é igual a zero, o nível de proteção correspondente não é registrado.
  • O filtro de tempo usa o tempo de fechamento da vela (candle.CloseTime.TimeOfDay) para se adaptar ao fuso horário de troca fornecido pelo MarketDataConnector.
  • Se a segurança não expor PriceStep, as distâncias baseadas em pontos serão usadas diretamente, sem escala.

Referência de estratégia original

  • Fonte: MQL/44133/MA Price Cross.mq4
  • Autor: JBlanked (2023)
using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "MA Price Cross" MetaTrader expert.
/// Enters when SMA crosses above/below the current close price.
/// </summary>
public class MaPriceCrossStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;

	private ExponentialMovingAverage _sma;
	private decimal? _prevAverage;
	private decimal? _prevClose;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public MaPriceCrossStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for MA cross detection", "General");

		_maPeriod = Param(nameof(MaPeriod), 100)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "SMA period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_sma = new ExponentialMovingAverage { Length = MaPeriod };
		_prevAverage = null;
		_prevClose = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_sma, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _sma);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal smaValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_sma.IsFormed)
		{
			_prevAverage = smaValue;
			_prevClose = candle.ClosePrice;
			return;
		}

		if (_prevAverage is null || _prevClose is null)
		{
			_prevAverage = smaValue;
			_prevClose = candle.ClosePrice;
			return;
		}

		var close = candle.ClosePrice;
		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// MA was below price, now crosses above -> sell signal (price goes under MA)
		var sellSignal = _prevClose.Value >= _prevAverage.Value && close < smaValue;
		// MA was above price, now crosses below -> buy signal (price goes above MA)
		var buySignal = _prevClose.Value <= _prevAverage.Value && close > smaValue;

		if (buySignal)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (sellSignal)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevAverage = smaValue;
		_prevClose = close;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_sma = null;
		_prevAverage = null;
		_prevClose = null;

		base.OnReseted();
	}
}