Ver no GitHub

Estratégia JS Signal Baes

Visão geral

Esta estratégia é um port do StockSharp do expert advisor do MetaTrader "JS Signal Baes". Ela avalia seis períodos diferentes simultaneamente (M1, M5, M15, M30, H1, H4 por padrão) e aguarda até que todos os indicadores monitorados concordem na mesma direção de mercado antes de abrir uma posição. Os sinais podem ser invertidos através do parâmetro Reverse para usuários que querem negociar contra a tendência detectada.

Indicadores e confirmações

Os seguintes indicadores são calculados em cada um dos seis períodos:

  • Duas Médias Móveis usando o método de suavização selecionado (simples, exponencial, suavizado ou ponderado linearmente).
  • MACD (Moving Average Convergence Divergence) usando comprimentos configuráveis de rápido, lento e sinal.
  • RSI (Relative Strength Index) com um parâmetro de período dedicado.
  • CCI (Commodity Channel Index) com seu próprio comprimento de lookback.
  • Oscilador Stochastic definido por períodos K, D e suavização.

Um período é considerado altista quando:

  1. MA Rápida > MA Lenta.
  2. Linha principal MACD > Linha de sinal MACD.
  3. RSI > 50.
  4. CCI > 0.
  5. Stochastic %K > 40.

Um período é considerado baixista quando:

  1. MA Rápida < MA Lenta.
  2. Linha principal MACD < Linha de sinal MACD.
  3. RSI < 50.
  4. CCI < 0.
  5. Stochastic %K < 60.

Regras de negociação

Uma nova posição líquida é aberta apenas quando o período primário (padrão M1) fecha e todos os seis períodos são simultaneamente altistas ou baixistas:

  • Entrada longa: todo período é altista. Se Reverse estiver habilitado, o sinal se torna uma entrada curta.
  • Entrada curta: todo período é baixista. Se Reverse estiver habilitado, o sinal se torna uma entrada longa.

As posições não são piramidadas. A estratégia aguarda até que a posição existente seja fechada externamente antes de agir em um novo sinal. Não há saídas automáticas além da lógica de sinal oposto do expert advisor original.

Parâmetros

Parâmetro Padrão Descrição
CciPeriod 13 Comprimento de lookback para o Commodity Channel Index.
FastMaPeriod 5 Comprimento da média móvel rápida.
SlowMaPeriod 9 Comprimento da média móvel lenta.
MaMethod LinearWeighted Tipo de suavização de média móvel aplicado a ambas as médias.
MacdFastPeriod 8 Comprimento EMA rápido usado pelo MACD.
MacdSlowPeriod 17 Comprimento EMA lento usado pelo MACD.
MacdSignalPeriod 9 Comprimento da linha de sinal usado pelo MACD.
StochasticKPeriod 5 Período K para o oscilador stochastic.
StochasticDPeriod 3 Período D para o oscilador stochastic.
StochasticSmoothing 3 Fator de suavização para o oscilador stochastic.
RsiPeriod 9 Comprimento de lookback do RSI.
ReverseSignals false Inverter a direção de cada sinal de negociação.
TimeFrame1..6 M1, M5, M15, M30, H1, H4 Séries de velas atribuídas a cada período.

Notas

  • Os parâmetros padrão replicam a configuração embutida na versão do MetaTrader.
  • Gestão monetária, stop-loss, take-profit e lógica de trailing do código original não são reproduzidos; use controles de risco no nível do portfólio se necessário.
  • Certifique-se de que dados históricos estejam disponíveis para cada período selecionado para que os indicadores possam se aquecer antes de negociar.
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 JsSignalBaesStrategy : 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 JsSignalBaesStrategy()
	{
		_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;
	}
}