Ver en GitHub

Estrategia CSPA 1.43

Esta estrategia es una adaptación del asesor experto MQL CSPA-1_43. Mide la fuerza de un par de divisas usando el Índice de Fuerza Relativa (RSI). Cuando el par se vuelve suficientemente fuerte o débil, la estrategia abre una posición en la dirección del momentum predominante y la cierra cuando el momentum se desvanece.

Lógica

  • Suscribirse a velas del valor seleccionado.
  • Calcular el valor del RSI para cada vela completada.
  • Abrir una posición larga cuando el RSI sube por encima del umbral superior.
  • Abrir una posición corta cuando el RSI cae por debajo del umbral inferior.
  • Cerrar la posición actual cuando el RSI regresa a la zona neutral.

Parámetros

Nombre Descripción Predeterminado
StrengthPeriod Período utilizado para el indicador RSI. 14
Threshold Distancia desde el nivel neutral del RSI de 50 utilizada para generar señales. 10
CandleType Marco temporal de las velas. 1 hora

Notas

  • La estrategia utiliza la API de alto nivel con vinculación automática de indicadores.
  • Las órdenes se ejecutan usando órdenes de mercado (BuyMarket y SellMarket).
  • Solo se procesan las velas completadas.
using System;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified currency strength strategy based on RSI.
/// </summary>
public class Cspa143Strategy : Strategy
{
	private readonly StrategyParam<int> _strengthPeriod;
	private readonly StrategyParam<decimal> _threshold;
	private readonly StrategyParam<int> _cooldownBars;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _previousRsi;
	private bool _isInitialized;
	private int _barsSinceTrade;

	/// <summary>
	/// RSI period.
	/// </summary>
	public int StrengthPeriod
	{
		get => _strengthPeriod.Value;
		set => _strengthPeriod.Value = value;
	}

	/// <summary>
	/// RSI distance from 50.
	/// </summary>
	public decimal Threshold
	{
		get => _threshold.Value;
		set => _threshold.Value = value;
	}

	/// <summary>
	/// Bars to wait after a completed trade.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

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

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public Cspa143Strategy()
	{
		_strengthPeriod = Param(nameof(StrengthPeriod), 14)
			.SetDisplay("Strength Period", "RSI period", "Parameters");

		_threshold = Param(nameof(Threshold), 18m)
			.SetDisplay("Threshold", "RSI distance from 50", "Parameters")
			.SetGreaterThanZero();

		_cooldownBars = Param(nameof(CooldownBars), 2)
			.SetDisplay("Cooldown Bars", "Bars to wait after a completed trade", "Parameters");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).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();

		_previousRsi = 0m;
		_isInitialized = false;
		_barsSinceTrade = CooldownBars;
	}

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

		var rsi = new RelativeStrengthIndex { Length = StrengthPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (_barsSinceTrade < CooldownBars)
			_barsSinceTrade++;

		var upper = 50m + Threshold;
		var lower = 50m - Threshold;

		if (!_isInitialized)
		{
			_previousRsi = rsi;
			_isInitialized = true;
			return;
		}

		var longEntry = _previousRsi <= upper && rsi > upper;
		var shortEntry = _previousRsi >= lower && rsi < lower;
		var longExit = Position > 0 && _previousRsi >= 55m && rsi < 55m;
		var shortExit = Position < 0 && _previousRsi <= 45m && rsi > 45m;

		if (longExit)
		{
			SellMarket(Position);
			_barsSinceTrade = 0;
		}
		else if (shortExit)
		{
			BuyMarket(-Position);
			_barsSinceTrade = 0;
		}
		else if (_barsSinceTrade >= CooldownBars)
		{
			if (longEntry && Position <= 0)
			{
				BuyMarket(Volume + Math.Abs(Position));
				_barsSinceTrade = 0;
			}
			else if (shortEntry && Position >= 0)
			{
				SellMarket(Volume + Math.Abs(Position));
				_barsSinceTrade = 0;
			}
		}

		_previousRsi = rsi;
	}
}