Ver no GitHub

Estratégia iTrade

Esta estratégia é um gestor manual de vendas convertido do expert advisor do MetaTrader iTrade. Ela recria o fluxo de botões no gráfico do EA original: sempre que o usuário solicita uma venda, uma posição martingale é aberta. A estratégia então observa o lucro flutuante de todas as operações vendidas e liquida os tickets mais e menos lucrativos quando alvos de lucro predefinidos são atingidos.

Lógica central

  • Ordens são abertas apenas por solicitações explícitas do usuário. Chame QueueSellRequest() para simular o pressionamento do botão no MetaTrader.
  • A primeira posição usa o volume inicial configurado. Após cada operação perdedora, o tamanho da próxima ordem é multiplicado pelo multiplicador martingale. Operações lucrativas redefinem a sequência para o volume base.
  • Lucro flutuante é medido usando o melhor preço ask atual. Quando o lucro médio por operação aberta atinge o alvo de lucro médio, a estratégia fecha as operações mais e menos lucrativas do lote ativo (até contagem base de operações).
  • Se mais de contagem base de operações posições estiverem abertas, o alvo de lucro estendido mais rigoroso é aplicado antes de fechar duas operações.
  • Cálculos de lucro dependem dos valores PriceStep e StepPrice do ativo. A estratégia lança uma exceção durante a inicialização quando eles estão ausentes.

Parâmetros

Nome Descrição
InitialVolume Tamanho de lote base usado para a primeira ordem martingale.
MartingaleMultiplier Multiplicador aplicado após cada operação perdedora.
AverageProfitTarget Lucro flutuante médio (em moeda) exigido para fechar operações dentro do primeiro lote.
ExtendedAverageProfitTarget Limite de lucro flutuante médio quando mais que o lote base está ativo.
BaseTradeCount Número de operações consideradas parte do lote inicial.
ControlInterval Frequência das verificações internas (intervalo do temporizador).

Notas de uso

  1. Defina Security, Portfolio e quaisquer parâmetros desejados antes de iniciar a estratégia.
  2. Chame QueueSellRequest() sempre que uma nova venda deve ser aberta. A estratégia dimensionará a ordem segundo as regras martingale e enviará uma venda a mercado.
  3. O algoritmo armazena um histórico de resultados de operações fechadas (até 200 entradas) para reproduzir o comportamento martingale original.
  4. Ordens de fechamento são enviadas como compras a mercado pelo volume exato das operações alvo.

Diferenças em relação à versão MetaTrader

  • A versão MetaTrader dependia de botões no gráfico; aqui o usuário aciona vendas programaticamente via QueueSellRequest().
  • A execução de ordens é tratada por ordens a mercado do StockSharp. Execuções parciais são agregadas automaticamente pela estratégia.
  • Limites de lucro operam sobre valores decimais de moeda usando StepPrice, enquanto o EA original usava funções de lucro de tickets do 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;
	}
}