Ver en GitHub

Estrategia semanal de Contrarian Trade MA

Un sistema contrario semanal convertido del asesor experto MQL "Contrarian_trade_MA" original. La estrategia analiza los extremos de las velas semanales junto con una media móvil simple para atenuar los movimientos extendidos al comienzo de una nueva semana.

Lógica de trading

  • Fuente de datos: velas semanales proporcionadas por el parámetro CandleType (el valor predeterminado es un período de tiempo de 7 días).
  • Extremos históricos: Los indicadores Highest y Lowest rastrean los máximos y mínimos de las CalcPeriod semanas completas anteriores, excluyendo la vela evaluada actualmente.
  • Filtro de media móvil: una media móvil simple de longitud MaPeriod aplicada a los cierres semanales actúa como un filtro direccional.
  • Reglas de entrada:
    • Compre cuando el cierre de la semana anterior sea superior al máximo registrado (highest < previousClose) o cuando el promedio móvil esté por encima de la apertura semanal actual.
    • Vender cuando el cierre de la semana anterior sea inferior al mínimo registrado (lowest > previousClose) o cuando el promedio móvil esté por debajo de la apertura semanal actual.
    • Sólo puede haber una posición abierta en cualquier momento; Las señales opuestas se ignoran hasta que se cierra la operación existente.
  • Reglas de salida:
    • La posición se cierra después de mantenerse durante siete días (604.800 segundos) independientemente de la dirección.
    • Se evalúa una parada protectora en cada vela semanal completa. La distancia de parada se calcula a partir de StopLossPoints * PriceStep (vuelve a 1 si los metadatos del instrumento no especifican un paso).

Parámetros

Nombre Predeterminado Descripción
CalcPeriod 4 Número de semanas completadas utilizadas para calcular el máximo más alto y el mínimo más bajo.
MaPeriod 7 Periodo de la media móvil simple aplicada a los cierres semanales.
StopLossPoints 300 Distancia desde el precio de entrada hasta el stop-loss, medida en incrementos de precio. Establezca en 0 para desactivar la parada.
Volume 0.5 Tamaño del pedido en lotes enviados por BuyMarket/SellMarket.
CandleType 7 days Plazo de las velas que impulsan todos los cálculos.

Notas adicionales

  • La estrategia recupera automáticamente el paso de precio de Security.PriceStep. Proporcione este valor en los metadatos del instrumento para una colocación precisa del stop-loss.
  • StartProtection() está habilitado para rastrear cambios de posición inesperados realizados fuera de la estrategia.
  • Debido a que la lógica opera en velas semanales completadas, los llenados se simulan en el cierre semanal de la barra de señal cuando se ejecuta en modo de prueba.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Contrarian MA strategy - mean reversion around SMA.
/// Buys when price crosses below SMA (contrarian dip buy).
/// Sells when price crosses above SMA (contrarian top sell).
/// Uses Highest/Lowest as extreme confirmation.
/// </summary>
public class ContrarianTradeMaWeeklyStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevSma;
	private bool _hasPrev;

	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ContrarianTradeMaWeeklyStrategy()
	{
		_maPeriod = Param(nameof(MaPeriod), 14)
			.SetDisplay("SMA Period", "SMA period", "Indicators");

		_channelPeriod = Param(nameof(ChannelPeriod), 10)
			.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevSma = 0m; _hasPrev = false; }

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

		_hasPrev = false;

		var sma = new SimpleMovingAverage { Length = MaPeriod };
		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, highest, lowest, ProcessCandle)
			.Start();
	}

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

		var close = candle.ClosePrice;

		if (!_hasPrev)
		{
			_prevClose = close;
			_prevSma = sma;
			_hasPrev = true;
			return;
		}

		var mid = (highest + lowest) / 2;

		// Contrarian buy: price crosses below SMA and is near the low
		if (_prevClose >= _prevSma && close < sma && close < mid && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Contrarian sell: price crosses above SMA and is near the high
		else if (_prevClose <= _prevSma && close > sma && close > mid && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevSma = sma;
	}
}