Ver no GitHub

Estratégia RoBoost

Esta estratégia é uma adaptação em C# do assessor especialista MQL4 original RoBoostj. Opera em um único instrumento usando sinais baseados em RSI combinados com detecção simples de momentum de preço. A estratégia opera no tipo de vela selecionado (padrão: velas de 1 hora).

Lógica

  • Quando o preço de fechamento anterior é maior que o fechamento atual e o valor do RSI cai abaixo do limiar RSI Down, a estratégia abre uma posição vendida.
  • Quando o preço de fechamento anterior é menor ou igual ao fechamento atual e o valor do RSI sobe acima do limiar RSI Up, a estratégia abre uma posição comprada.
  • As posições ativas são gerenciadas com as seguintes ferramentas de risco:
    • Níveis fixos de Take Profit e Stop Loss medidos em unidades de preço.
    • Trailing stop opcional ativado quando a operação avança no lucro pela distância Trail Start. Após a ativação, o preço de stop segue o preço pela distância Trail Step.

Parâmetros

Nome Descrição
CandleType Série de velas usada para os cálculos.
RsiPeriod Comprimento do período do indicador RSI.
RsiUp Limiar RSI usado para entradas compradas.
RsiDown Limiar RSI usado para entradas vendidas.
TakeProfit Distância de take profit do preço de entrada (pontos).
StopLoss Distância de stop loss do preço de entrada (pontos).
UseTrailing Ativa a lógica de trailing stop.
TrailStart Distância em pontos para ativar o trailing stop.
TrailStep Distância em pontos mantida do preço atual quando o
trailing stop está ativo.

Todas as distâncias são expressas em unidades de preço absolutas e podem exigir ajuste de acordo com o tamanho do tick do instrumento.

Uso

  1. Adicione a estratégia ao seu projeto ou abra-a no StockSharp Designer.
  2. Configure os parâmetros de acordo com suas preferências de trading.
  3. Inicie a estratégia. Ela se inscreverá automaticamente na série de velas escolhida e gerenciará as operações com base nos valores de RSI e fechamentos de velas.

A estratégia é destinada a fins educativos e deve ser testada em dados históricos antes de usar em mercados ao vivo.

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RSI based strategy converted from the original RoBoostj MQL4 robot.
/// Opens long or short positions depending on price momentum and RSI values.
/// Includes optional trailing stop management.
/// </summary>
public class RoBoostStrategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _rsiUp;
	private readonly StrategyParam<int> _rsiDown;
	private readonly StrategyParam<bool> _useTrailing;
	private readonly StrategyParam<decimal> _trailStart;
	private readonly StrategyParam<decimal> _trailStep;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private bool _isLong;
	private decimal _trailingStopPrice;
	private decimal _previousClose;
	private bool _isFirst = true;

	/// <summary>
	/// Take profit distance from entry price.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Stop loss distance from entry price.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// RSI indicator period length.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	/// <summary>
	/// RSI threshold for long entries.
	/// </summary>
	public int RsiUp
	{
		get => _rsiUp.Value;
		set => _rsiUp.Value = value;
	}

	/// <summary>
	/// RSI threshold for short entries.
	/// </summary>
	public int RsiDown
	{
		get => _rsiDown.Value;
		set => _rsiDown.Value = value;
	}

	/// <summary>
	/// Enables trailing stop logic.
	/// </summary>
	public bool UseTrailing
	{
		get => _useTrailing.Value;
		set => _useTrailing.Value = value;
	}

	/// <summary>
	/// Distance at which trailing stop becomes active.
	/// </summary>
	public decimal TrailStart
	{
		get => _trailStart.Value;
		set => _trailStart.Value = value;
	}

	/// <summary>
	/// Distance maintained from current price when trailing stop is active.
	/// </summary>
	public decimal TrailStep
	{
		get => _trailStep.Value;
		set => _trailStep.Value = value;
	}

	/// <summary>
	/// Type of candles used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="RoBoostStrategy"/>.
	/// </summary>
	public RoBoostStrategy()
	{
		_takeProfit = Param(nameof(TakeProfit), 500m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit", "Take profit distance in points", "Risk Management");

		_stopLoss = Param(nameof(StopLoss), 1000m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk Management");

		_rsiPeriod = Param(nameof(RsiPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI calculation length", "Indicator")
			
			.SetOptimize(5, 20, 1);

		_rsiUp = Param(nameof(RsiUp), 50)
			.SetDisplay("RSI Up", "RSI threshold for longs", "Indicator")
			
			.SetOptimize(45, 70, 5);

		_rsiDown = Param(nameof(RsiDown), 50)
			.SetDisplay("RSI Down", "RSI threshold for shorts", "Indicator")
			
			.SetOptimize(30, 55, 5);

		_useTrailing = Param(nameof(UseTrailing), false)
			.SetDisplay("Use Trailing", "Enable trailing stop", "Risk Management");

		_trailStart = Param(nameof(TrailStart), 5m)
			.SetGreaterThanZero()
			.SetDisplay("Trail Start", "Profit distance to activate trailing", "Risk Management");

		_trailStep = Param(nameof(TrailStep), 2m)
			.SetGreaterThanZero()
			.SetDisplay("Trail Step", "Distance between price and trailing stop", "Risk Management");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles used", "General");
	}

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

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

		_entryPrice = 0m;
		_isLong = false;
		_trailingStopPrice = 0m;
		_previousClose = 0m;
		_isFirst = true;
	}

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var currentClose = candle.ClosePrice;

		if (_isFirst)
		{
			_previousClose = currentClose;
			_isFirst = false;
			return;
		}

		if (Position == 0)
		{
			if (_previousClose > currentClose && rsiValue < RsiDown)
			{
				SellMarket();
				_entryPrice = currentClose;
				_isLong = false;
				_trailingStopPrice = 0m;
			}
			else if (_previousClose <= currentClose && rsiValue >= RsiUp)
			{
				BuyMarket();
				_entryPrice = currentClose;
				_isLong = true;
				_trailingStopPrice = 0m;
			}
		}
		else
		{
			ManagePosition(currentClose);
		}

		_previousClose = currentClose;
	}

	private void ManagePosition(decimal currentPrice)
	{
		if (_entryPrice == 0m)
			return;

		if (_isLong)
		{
			var profit = currentPrice - _entryPrice;
			if (profit >= TakeProfit || -profit >= StopLoss)
			{
				SellMarket();
				return;
			}

			if (UseTrailing)
			{
				if (profit >= TrailStart)
				{
					var newStop = currentPrice - TrailStep;
					if (_trailingStopPrice < newStop)
						_trailingStopPrice = newStop;
				}

				if (_trailingStopPrice != 0m && currentPrice <= _trailingStopPrice)
					SellMarket();
			}
		}
		else
		{
			var profit = _entryPrice - currentPrice;
			if (profit >= TakeProfit || -profit >= StopLoss)
			{
				BuyMarket();
				return;
			}

			if (UseTrailing)
			{
				if (profit >= TrailStart)
				{
					var newStop = currentPrice + TrailStep;
					if (_trailingStopPrice == 0m || _trailingStopPrice > newStop)
						_trailingStopPrice = newStop;
				}

				if (_trailingStopPrice != 0m && currentPrice >= _trailingStopPrice)
					BuyMarket();
			}
		}
	}
}