Ver en GitHub

Estrategia iTrade

Esta estrategia es un gestor manual de ventas convertido desde el asesor experto de MetaTrader iTrade. Recrea el flujo de botones del gráfico del EA original: cada vez que el usuario solicita una venta, se abre una posición martingala. Luego la estrategia observa la ganancia flotante de todas las operaciones cortas y liquida los tickets más y menos rentables cuando se alcanzan objetivos de ganancia predefinidos.

Lógica central

  • Las órdenes se abren solo por solicitudes explícitas del usuario. Llame a QueueSellRequest() para simular la pulsación del botón de MetaTrader.
  • La primera posición usa el volumen inicial configurado. Después de cada operación perdedora, el tamaño de la siguiente orden se multiplica por el multiplicador martingala. Las operaciones rentables reinician la secuencia al volumen base.
  • La ganancia flotante se mide usando el mejor precio ask actual. Cuando la ganancia media por operación abierta alcanza el objetivo de ganancia media, la estrategia cierra las operaciones más rentable y menos rentable del lote activo (hasta conteo base de operaciones).
  • Si hay más de conteo base de operaciones posiciones abiertas, se aplica el objetivo de ganancia extendido más estricto antes de cerrar dos operaciones.
  • Los cálculos de ganancia dependen de los valores PriceStep y StepPrice del valor. La estrategia lanza una excepción durante el arranque cuando faltan.

Parámetros

Nombre Descripción
InitialVolume Tamaño de lote base usado para la primera orden martingala.
MartingaleMultiplier Multiplicador aplicado después de cada operación perdedora.
AverageProfitTarget Ganancia flotante media (en divisa) requerida para cerrar operaciones dentro del primer lote.
ExtendedAverageProfitTarget Umbral de ganancia flotante media cuando está activo más que el lote base.
BaseTradeCount Número de operaciones consideradas parte del lote inicial.
ControlInterval Frecuencia de comprobaciones internas (intervalo del temporizador).

Notas de uso

  1. Configure Security, Portfolio y cualquier parámetro deseado antes de iniciar la estrategia.
  2. Llame a QueueSellRequest() cada vez que deba abrirse una nueva venta. La estrategia dimensionará la orden según las reglas martingala y enviará una venta de mercado.
  3. El algoritmo almacena un historial de resultados de operaciones cerradas (hasta 200 entradas) para reproducir el comportamiento martingala original.
  4. Las órdenes de cierre se envían como compras de mercado por el volumen exacto de las operaciones objetivo.

Diferencias con la versión MetaTrader

  • La versión MetaTrader dependía de botones en el gráfico; aquí el usuario dispara ventas programáticamente mediante QueueSellRequest().
  • La ejecución de órdenes se gestiona mediante órdenes de mercado de StockSharp. Las ejecuciones parciales se agregan automáticamente por la estrategia.
  • Los umbrales de ganancia operan sobre valores decimales de divisa usando StepPrice, mientras que el EA original usaba funciones de ganancia de tickets de MetaTrader.
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;

public class ITradeStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ITradeStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}