Ver en GitHub

Estrategia de Proyección

Esta estrategia calcula el cambio porcentual promedio de las aperturas diarias recientes y proyecta niveles de ruptura alrededor de la apertura del día actual. Las posiciones largas se abren cuando el precio rompe por encima de la proyección superior, mientras que las posiciones cortas se abren cuando rompe por debajo de la proyección inferior. Los stops de protección se colocan cerca del lado opuesto de la proyección.

Detalles

  • Criterios de entrada:
    • Largo: el precio cruza por encima de open + threshold.
    • Corto: el precio cruza por debajo de open - threshold.
  • Criterios de salida:
    • Largo: el precio cae por debajo del stop largo.
    • Corto: el precio sube por encima del stop corto.
  • Stops: sí, basados en el cambio promedio.
  • Parámetros:
    • TargetMultiple – multiplicador del cambio promedio (predeterminado 0.2).
    • Threshold – porcentaje del cambio promedio usado para formar los niveles de ruptura (predeterminado 1.0).
    • CalculationPeriod – número de días en el promedio (predeterminado 5).
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>
/// Projection strategy using EMA crossover.
/// </summary>
public class ProjectionStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

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

	public ProjectionStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

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

		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };

		var prevF = 0m;
		var prevS = 0m;
		var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, f, s) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!fast.IsFormed || !slow.IsFormed)
					return;

				if (!init)
				{
					prevF = f;
					prevS = s;
					init = true;
					return;
				}

				if (candle.OpenTime - lastSignal >= cooldown)
				{
					if (prevF <= prevS && f > s && Position <= 0)
					{
						BuyMarket();
						lastSignal = candle.OpenTime;
					}
					else if (prevF >= prevS && f < s && Position >= 0)
					{
						SellMarket();
						lastSignal = candle.OpenTime;
					}
				}

				prevF = f;
				prevS = s;
			})
			.Start();

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