Открыть на GitHub

Стратегия BuySellOnYourPrice

Обзор

  • Конвертация эксперта MetaTrader BuySellonYourPrice.mq5 (id 35391) на высокоуровневый API StockSharp.
  • При запуске выставляет только одну заявку и делает это лишь при отсутствии активных ордеров и позиций, как и оригинал.
  • Поддерживает рыночные, лимитные и стоповые заявки, параметры стоп-лосса и тейк-профита задаются в абсолютных ценах.
  • При наличии корректных уровней автоматически включает StartProtection, чтобы задействовать стандартную защиту StockSharp.

Параметры

Имя Описание Значение по умолчанию
Mode Тип заявки (None, Buy, Sell, BuyLimit, SellLimit, BuyStop, SellStop). None
OrderVolume Объём отправляемой заявки. 1
EntryPrice Цена входа для отложенных заявок; для рынка игнорируется. 0
StopLossPrice Абсолютный уровень стоп-лосса. 0
TakeProfitPrice Абсолютный уровень тейк-профита. 0

Логика работы

  1. В момент запуска стратегия проверяет:
    • выбран ли режим, отличный от None;
    • положительный ли объём OrderVolume;
    • отсутствие текущей позиции и активных заявок (аналог условий OrdersTotal()==0 и PositionsTotal()==0).
  2. Определяется цена входа:
    • для рыночных заявок берутся лучшие бид/аск, при их отсутствии — последняя цена или EntryPrice;
    • для отложенных заявок требуется EntryPrice > 0.
  3. На основании уровней стоп-лосса и тейк-профита рассчитываются расстояния. Только положительные значения передаются в StartProtection.
  4. Отправляется выбранный тип заявки (BuyMarket, SellLimit, BuyStop и т.д.) и в лог выводится сообщение об операции.

Отличия от оригинала

  • Сообщения выводятся через AddInfoLog вместо Print.
  • Защитные ордера подключаются только при наличии корректных расстояний, чтобы исключить неверные настройки.
  • Для рыночных ордеров используется поток Level1; если котировка ещё не получена, заявка не отправляется.

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

  • Перед запуском назначьте инструмент стратегии и убедитесь в получении данных Level1 для рыночных сделок.
  • Для отложенных ордеров заранее задайте EntryPrice, StopLossPrice и TakeProfitPrice в абсолютных ценах.
  • Значение Mode = None позволяет временно отключить торговлю без удаления стратегии.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Buy Sell On Your Price strategy: Keltner Channel breakout.
/// Buys when close breaks above upper Keltner band, sells when close breaks below lower band.
/// </summary>
public class BuySellOnYourPriceStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;

	private decimal _prevClose;
	private decimal _prevEma;
	private bool _hasPrev;

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

	public BuySellOnYourPriceStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevEma = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = 0;
		_prevEma = 0;
		_hasPrev = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevClose <= _prevEma && candle.ClosePrice > emaValue && Position <= 0)
				BuyMarket();
			else if (_prevClose >= _prevEma && candle.ClosePrice < emaValue && Position >= 0)
				SellMarket();
		}

		_prevClose = candle.ClosePrice;
		_prevEma = emaValue;
		_hasPrev = true;
	}
}