Открыть на GitHub

Стратегия JS Signal Baes

Обзор

Это порт советника MetaTrader "JS Signal Baes" на платформу StockSharp. Стратегия одновременно анализирует шесть таймфреймов (по умолчанию M1, M5, M15, M30, H1, H4) и открывает позицию только тогда, когда все подключённые индикаторы указывают на одно и то же направление. При необходимости направление сигналов можно инвертировать параметром Reverse.

Индикаторы и фильтры

На каждом таймфрейме рассчитываются:

  • Две скользящие средние с выбранным типом сглаживания (простая, экспоненциальная, сглаженная или линейно-взвешенная).
  • MACD с настраиваемыми периодами fast, slow и signal.
  • RSI с собственным периодом.
  • CCI с отдельным окном расчёта.
  • Стохастик с параметрами K, D и сглаживанием.

Таймфрейм считается бычьим, если выполняются все условия:

  1. Быстрая MA выше медленной MA.
  2. Линия MACD выше сигнальной линии.
  3. RSI выше 50.
  4. CCI больше 0.
  5. Стохастик %K выше 40.

Таймфрейм считается медвежьим, если выполняются условия:

  1. Быстрая MA ниже медленной MA.
  2. Линия MACD ниже сигнальной линии.
  3. RSI ниже 50.
  4. CCI меньше 0.
  5. Стохастик %K ниже 60.

Правила торговли

Проверка сигналов выполняется по закрытию бара на основном таймфрейме (по умолчанию M1). Сделка открывается только при полном согласовании всех шести таймфреймов:

  • Покупка: каждый таймфрейм бычий. Если активирован Reverse, вместо покупки выполняется продажа.
  • Продажа: каждый таймфрейм медвежий. При включённом Reverse сигнал меняется на покупку.

Наращивание позиции не используется. Пока открыта позиция, новые сигналы игнорируются. Автоматическое выставление стопов и тейк-профитов не реализовано — защиту следует организовать на уровне портфеля или вручную.

Параметры

Параметр Значение по умолчанию Описание
CciPeriod 13 Окно расчёта индикатора CCI.
FastMaPeriod 5 Длина быстрой скользящей средней.
SlowMaPeriod 9 Длина медленной скользящей средней.
MaMethod LinearWeighted Тип сглаживания для обеих средних.
MacdFastPeriod 8 Период быстрой EMA в MACD.
MacdSlowPeriod 17 Период медленной EMA в MACD.
MacdSignalPeriod 9 Период сигнальной линии MACD.
StochasticKPeriod 5 Период K стохастика.
StochasticDPeriod 3 Период D стохастика.
StochasticSmoothing 3 Параметр сглаживания стохастика.
RsiPeriod 9 Период RSI.
ReverseSignals false Инверсия направления сигналов.
TimeFrame1..6 M1, M5, M15, M30, H1, H4 Таймфреймы для каждой группы индикаторов.

Примечания

  • Значения параметров повторяют настройки из исходного MQL5-советника.
  • Денежный менеджмент, стоп-лосс, тейк-профит и трейлинг из оригинала не перенесены.
  • Перед запуском убедитесь, что история доступна для всех выбранных таймфреймов — индикаторам требуется разогрев.
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;
	}
}