Открыть на GitHub

TraderToolEA – панель ручного управления (порт StockSharp)

Краткое описание

MetaTrader 4 советник TraderToolEA v1.8 представляет собой не автономного робота, а торговую панель для ручного управления ордерами, сетками и защитой. В версии для StockSharp панель превращена в набор параметров стратегии: каждое переключение соответствует кнопке в исходном интерфейсе. Переведённый функционал:

  • Быстрые команды открытия/закрытия длинных и коротких позиций по рынку.
  • Автоматическая постановка симметричных сеток отложенных стоп- и лимитных ордеров.
  • Выборочное удаление отложенных ордеров (покупка/продажа/все) с опцией очистки «осиротевших» заявок.
  • Виртуальные стоп-лосс, тейк-профит, трейлинг-стоп и перевод в безубыток на основе котировок Level1.
  • Авторасчёт объёма по формуле Баланс / LotSize * RiskFactor, повторяющей оригинальный алгоритм.

Стратегия использует только высокоуровневое API: подписку на Level1, методы BuyStop, SellLimit, CancelOrder и встроенную систему логирования.

Параметры

Имя Описание
Use Auto Volume При true объём заявок вычисляется от текущего баланса портфеля и множителя Risk Factor; иначе используется фиксированный Order Volume.
Risk Factor Множитель, применяемый при авторасчёте объёма. Полный аналог параметра MT4.
Order Volume Ручной объём каждой рыночной и отложенной заявки при отключённом авторасчёте.
Distance (pips) Шаг сетки в «пунктах» MetaTrader для стоп- и лимит-ордеров.
Layers Количество дополнительных ордеров, создаваемых за одну команду (эмулирует многократное нажатие кнопки).
Delete Orphans При включении стратегия автоматически удаляет лишние ордера, чтобы сетка оставалась симметричной после частичных исполнений.
Enable Stop Loss / Stop Loss (pips) Активация контроля стоп-лосса в пунктах относительно средней цены входа.
Enable Take Profit / Take Profit (pips) Аналогичный контроль тейк-профита.
Enable Trailing / Trailing (pips) Виртуальный трейлинг-стоп, который включается только при движении цены минимум на Trailing пунктов в прибыль.
Enable Break-Even / Break-Even Trigger / Break-Even Lock После прохождения цены на заданное расстояние стоп переносится в безубыток с указанным запасом.
Триггеры (Open Buy, Place Buy Stops, Delete Sell Limits, …) Булевы параметры, выполняющие действия панели. После обработки возвращаются в false.

Последовательность работы

  1. Источник данных. Подписка на DataType.Level1; именно изменения bid/ask инициируют защиту и постановку сеток.
  2. Нормализация объёма. Перед отправкой заявок объём округляется по VolumeStep и ограничивается диапазоном [MinVolume; MaxVolume]. При отсутствии метаданных используется исходное значение.
  3. Сетки ордеров. Цены рассчитываются от последнего bid/ask и приводятся к шагу цены инструмента.
  4. Удаление «осиротевших» ордеров. При активном Delete Orphans стратегия сравнивает количество buy и sell ордеров и отменяет лишние. Отдельно обрабатываются стоп- и лимит-сетки.
  5. Виртуальная защита. Стоп-лосс, тейк-профит, трейлинг и безубыток реализованы как виртуальные правила. При срабатывании отправляется рыночная заявка на закрытие оставшегося объёма, после чего внутреннее состояние защиты сбрасывается.

Отличия от версии для MetaTrader

  • Графические элементы (кнопки, поля ввода, цвета, звуки) заменены параметрами и логами StockSharp.
  • Защитные механизмы закрывают позиции маркет-заявками, не модифицируя стоп-уровни в отдельных ордерах. Это гарантирует одинаковое поведение на площадках без MT4-стопов.
  • Режимы ManageOrders (по magic, все, ручные, собственные) сведены к управлению только заявками самой стратегии.
  • Авторасчёт объёма использует текущую стоимость портфеля, но повторяет исходную формулу и правила округления.

Рекомендации по использованию

  1. Убедитесь, что у инструмента задан корректный PriceStep, VolumeStep, MinVolume, LotSize – от них зависит пересчёт пунктов и допустимых объёмов.
  2. Привяжите булевы параметры к горячим клавишам или кнопкам в интерфейсе StockSharp, чтобы сохранить привычную логику работы панели. После выполнения команды параметр автоматически сбрасывается.
  3. Включайте Delete Orphans при работе с симметричными сетками, чтобы стратегия удаляла оставшиеся ордера противоположной стороны.
  4. Следите за информационными логами: при пропуске действия (нет bid/ask, объём равен нулю и т.д.) выводится предупреждение с причиной.
  5. Поскольку защита виртуальная, стратегия должна быть запущена, пока есть открытые позиции – закрытие происходит через рыночные заявки.

Заметки по портированию

  • Размер пункта вычисляется по правилу MetaTrader: для инструментов с 3/5 знаками шаг цены умножается на 10.
  • Логика трейлинга и безубытка повторяет MQL-код: активация только после появления прибыли, сброс после закрытия или разворота позиции.
  • В оригинале повторное нажатие кнопок расширяло сетку. Параметр Layers реализует то же поведение одним переключателем.
  • Все управляющие параметры получают SetCanOptimize(false), чтобы не запускать команды во время оптимизаций.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trader Tool Manager strategy: EMA + Momentum trend follower.
/// Buys when close crosses above EMA and momentum > 100.
/// Sells when close crosses below EMA and momentum < 100.
/// </summary>
public class TraderToolEaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _momPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public int MomPeriod
	{
		get => _momPeriod.Value;
		set => _momPeriod.Value = value;
	}

	public TraderToolEaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_emaPeriod = Param(nameof(EmaPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");

		_momPeriod = Param(nameof(MomPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Momentum", "Momentum period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var mom = new Momentum { Length = MomPeriod };

		decimal? prevClose = null;
		decimal? prevEma = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, mom, (candle, emaVal, momVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (prevClose.HasValue && prevEma.HasValue)
				{
					var crossUp = prevClose.Value <= prevEma.Value && close > emaVal;
					var crossDown = prevClose.Value >= prevEma.Value && close < emaVal;

					if (crossUp && momVal > 100m && Position <= 0)
						BuyMarket();
					else if (crossDown && momVal < 100m && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevEma = emaVal;
			})
			.Start();

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