Ver en GitHub

JSatl Sistema Digit

El JSatl Sistema Digit utiliza una Media Móvil Jurik (JMA) para determinar la dirección de la tendencia. La estrategia mide la pendiente de la JMA y abre una posición cuando el precio confirma la dirección de la pendiente.

Se abre una posición larga cuando la JMA está subiendo y el precio de cierre está por encima de la media. Se abre una posición corta cuando la JMA está bajando y el precio de cierre está por debajo de la media. Las señales opuestas cierran cualquier posición abierta.

Detalles

  • Criterios de entrada: Pendiente de la JMA con confirmación de precio.
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida: Señal opuesta.
  • Stops: No.
  • Valores predeterminados:
    • JmaLength = 14
    • CandleType = TimeSpan.FromHours(4)
  • Filtros:
    • Categoría: Tendencia
    • Dirección: Ambos
    • Indicadores: JMA
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: Swing (4h)
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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>
/// JSatl Digit System based on Jurik Moving Average slope.
/// Opens long when JMA rises and price is above the average.
/// Opens short when JMA falls and price is below the average.
/// </summary>
public class JsAtlDigitSystemStrategy : Strategy
{
	private readonly StrategyParam<int> _jmaLength;
	private readonly StrategyParam<DataType> _candleType;

	private bool _isFirstValue = true;
	private decimal _prevJma;

	/// <summary>
	/// Period length for Jurik Moving Average.
	/// </summary>
	public int JmaLength
	{
		get => _jmaLength.Value;
		set => _jmaLength.Value = value;
	}

	/// <summary>
	/// Candle type used for analysis.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="JsAtlDigitSystemStrategy"/>.
	/// </summary>
	public JsAtlDigitSystemStrategy()
	{
		_jmaLength = Param(nameof(JmaLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("JMA Length", "Period of Jurik moving average", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_isFirstValue = true;
		_prevJma = 0m;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_isFirstValue = true;
		_prevJma = 0m;

		var jma = new JurikMovingAverage { Length = JmaLength };

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

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

		if (_isFirstValue)
		{
			_prevJma = jmaValue;
			_isFirstValue = false;
			return;
		}

		var price = candle.ClosePrice;
		var slope = jmaValue - _prevJma;

		if (slope > 0m && price > jmaValue)
		{
			// JMA rising and price above average -> open long or close short
			if (Position <= 0m)
				BuyMarket();
		}
		else if (slope < 0m && price < jmaValue)
		{
			// JMA falling and price below average -> open short or close long
			if (Position >= 0m)
				SellMarket();
		}

		_prevJma = jmaValue;
	}
}