Ver en GitHub

Estrategia de Inversor Universal

Descripción general

La Estrategia de Inversor Universal utiliza el cruce entre la Media Móvil Exponencial (EMA) y la Media Móvil Ponderada Lineal (LWMA) para determinar la dirección del mercado. Confirma la fuerza de la tendencia verificando que ambas medias se muevan en la misma dirección.

Lógica

  • Entrada de compra: LWMA está por encima de EMA y ambas medias están subiendo.
  • Entrada de venta: LWMA está por debajo de EMA y ambas medias están cayendo.
  • Salida de compra: LWMA cruza por debajo de EMA.
  • Salida de venta: LWMA cruza por encima de EMA.

La estrategia reduce el tamaño de la posición tras operaciones perdedoras consecutivas cuando el factor de reducción está habilitado.

Parámetros

Nombre Descripción
MovingPeriod Longitud para los cálculos de EMA y LWMA.
DecreaseFactor Factor de reducción de lotes tras pérdidas (0 desactiva la reducción).
CandleType Tipo de datos de velas para los cálculos.
Volume Volumen base de operación desde la configuración de la estrategia.

Notas

  • Funciona únicamente con velas cerradas.
  • Utiliza la API de alto nivel de StockSharp con vinculación de indicadores.
  • No se proporciona versión en Python.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on EMA and WMA crossover with trend confirmation.
/// </summary>
public class UniversalInvestorStrategy : Strategy
{
	private readonly StrategyParam<int> _movingPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevLwma;
	private bool _hasPrev;

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

	public UniversalInvestorStrategy()
	{
		_movingPeriod = Param(nameof(MovingPeriod), 23)
			.SetGreaterThanZero()
			.SetDisplay("Moving Period", "Smoothing period for EMA and WMA", "Indicators");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEma = 0;
		_prevLwma = 0;
		_hasPrev = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = MovingPeriod };
		var lwma = new WeightedMovingAverage { Length = MovingPeriod };

		SubscribeCandles(CandleType)
			.Bind(ema, lwma, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevEma = emaValue;
			_prevLwma = lwmaValue;
			_hasPrev = true;
			return;
		}

		var openBuy = lwmaValue > emaValue && lwmaValue > _prevLwma && emaValue > _prevEma;
		var openSell = lwmaValue < emaValue && lwmaValue < _prevLwma && emaValue < _prevEma;
		var closeBuy = lwmaValue < emaValue;
		var closeSell = lwmaValue > emaValue;

		if (Position > 0 && closeBuy)
		{
			SellMarket();
		}
		else if (Position < 0 && closeSell)
		{
			BuyMarket();
		}
		else if (Position == 0)
		{
			if (openBuy && !closeBuy)
				BuyMarket();
			else if (openSell && !closeSell)
				SellMarket();
		}

		_prevEma = emaValue;
		_prevLwma = lwmaValue;
	}
}