Открыть на GitHub

Стратегия GTerminal

Обзор

GTerminal — это порт эксперта MetaTrader 4 GTerminal_V5a на C#. В оригинальной версии трейдер управлял входами и выходами, рисуя на графике горизонтальные линии. В StockSharp та же логика реализована через набор параметров: каждая виртуальная линия соответствует отдельному параметру. Когда цена закрытия выбранного свечного ряда пересекает такую линию, стратегия открывает, закрывает или переворачивает позицию так же, как это делал скрипт на MQL4. Дополнительные уровни защиты имитируют вспомогательные линии "tpinit" и "slinit" из первоначальной реализации.

Логика стратегии

Отбор цен

  • Стратегия работает с завершёнными свечами заданного типа (CandleType).
  • StartShift задаёт, какая свеча используется в расчёте: 0 — текущая, 1 — предыдущая и т.д. Тем самым всегда анализируются две соседние свечи, что полностью повторяет алгоритм MetaTrader.
  • CrossMethod соответствует входному параметру MQL4:
    • 0 — жёсткое пересечение: предыдущая свеча должна находиться по одну сторону от уровня, а текущая закрыться по другую.
    • 1 — мгновенный триггер: достаточно, чтобы текущая свеча закрылась за уровнем. Чтобы исключить повторные срабатывания на той же свече, порт дополнительно проверяет положение предыдущей свечи, добиваясь привычного эффекта “однократного” пересечения.

Правила входа

  • Линия Buy Stop — при переходе цены из области ниже BuyStopLevel в область выше линия открывает покупку. Если есть короткая позиция, объём ордера включает лоты на её закрытие плюс объём Volume для новой длинной позиции.
  • Линия Buy Limit — при падении цены через BuyLimitLevel также открывается длинная позиция с тем же расчётом объёма.
  • Линия Sell Stop — при переходе цены сверху вниз через SellStopLevel открывается короткая позиция (и закрываются имеющиеся лонги).
  • Линия Sell Limit — при подъёме цены через SellLimitLevel открывается шорт.
  • Входы пропускаются, если Volume равен нулю или включён флаг PauseTrading.

Правила выхода

  • Направленные выходы — уровни LongStopLevel/LongTakeProfitLevel закрывают длинные позиции, когда цена пересекает линию. ShortStopLevel/ShortTakeProfitLevel выполняют аналогичные действия для коротких позиций.
  • Глобальные выходыAllLongStopLevel и AllLongTakeProfitLevel закрывают все длинные позиции независимо от их происхождения. AllShortStopLevel и AllShortTakeProfitLevel делают то же самое для коротких позиций.
  • Первичная защита — если UseInitialProtection включён, уровни InitialLongStopLevel, InitialLongTakeProfitLevel, InitialShortStopLevel и InitialShortTakeProfitLevel применяются сразу после заполнения ордера. Эти уровни полностью повторяют работу линий "slinit"/"tpinit" в оригинале и действуют до закрытия позиции или изменения параметра.
  • За один бар выполняется только одно выходное действие. После срабатывания любого условия стратегия отправляет закрывающий ордер и не проверяет остальные условия до следующей свечи, что соответствует поведению MQL4-скрипта после удаления сработавшей линии.

Управление паузой

  • Параметр PauseTrading реализует функциональность линии "PAUSE" из MetaTrader. При включении торговая логика полностью останавливается и может быть возобновлена вручную без перезапуска стратегии.

Параметры

  • Volume — объём заявок для новых входов. При развороте автоматически добавляется объём, необходимый для закрытия противоположной позиции.
  • Cross Method — выбор алгоритма пересечения (0 — строгое, 1 — мгновенное).
  • Start Shift — смещение свечи, используемой в расчёте пересечения.
  • Pause Trading — при значении true блокирует все торговые действия.
  • Use Initial Protection — включает автоматическое применение первоначальных уровней стопа и тейк-профита после каждой сделки.
  • Buy Stop Level / Buy Limit Level — уровни, запускающие открытие длинных позиций.
  • Sell Stop Level / Sell Limit Level — уровни, запускающие открытие коротких позиций.
  • Long Stop Level / Long Take Profit — линии закрытия текущей длинной позиции.
  • Short Stop Level / Short Take Profit — линии закрытия текущей короткой позиции.
  • All Long Stop / All Long Take Profit — глобальные уровни закрытия всех длинных позиций.
  • All Short Stop / All Short Take Profit — глобальные уровни закрытия всех коротких позиций.
  • Initial Long Stop / Initial Long Take Profit — уровни, применяемые к новым длинным позициям при активной начальной защите.
  • Initial Short Stop / Initial Short Take Profit — уровни, применяемые к новым коротким позициям при активной начальной защите.
  • Candle Type — тип свечей, по закрытию которых выполняются сравнения.

Особенности реализации

  • Вместо графических объектов линии задаются параметрами, которые можно менять в рабочем окне параметров, что повторяет опыт перетаскивания линий на графике MetaTrader.
  • Связь с индикаторами (RSI, CCI, Momentum и др.), присутствовавшая в MQL4-версии, не реализована. Все сигналы основаны только на цен закрытия. При необходимости индикаторную логику можно добавить через другие компоненты StockSharp.
  • Стратегия использует только рыночные заявки (BuyMarket, SellMarket), как и оригинальный скрипт, который отправлял рыночные ордера после срабатывания линий.
  • В комплект входит только реализация на C#, Python-версия отсутствует.
using System;

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

namespace StockSharp.Samples.Strategies;

public class GTerminalStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public GTerminalStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 9).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 26).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldown = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

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

		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
		if (_cooldown > 0)
		{
			_cooldown--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			var volume = Volume + Math.Abs(Position);
			BuyMarket(volume);
			_cooldown = 2;
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			var volume = Volume + Math.Abs(Position);
			SellMarket(volume);
			_cooldown = 2;
		}

		_prevFast = fast; _prevSlow = slow;
	}
}