Ver en GitHub

BuySellOnYourPrice Strategy

Overview

  • Converts the MetaTrader expert advisor BuySellonYourPrice.mq5 (id 35391) to the StockSharp high-level API.
  • Sends exactly one order on start, matching the original logic that requires no active orders or positions.
  • Supports market, limit, and stop entries with optional stop-loss and take-profit levels expressed as absolute prices.
  • Automatically configures StockSharp protective orders when valid stop-loss / take-profit distances can be derived from the provided price levels.

Parameters

Name Description Default
Mode Order type to submit (None, Buy, Sell, BuyLimit, SellLimit, BuyStop, SellStop). None
OrderVolume Volume for the generated order. 1
EntryPrice Price used for pending orders; ignored for market orders. 0
StopLossPrice Absolute price level for the stop-loss. 0
TakeProfitPrice Absolute price level for the take-profit. 0

Trading Logic

  1. When the strategy starts it checks that:
    • A valid Mode different from None is selected.
    • OrderVolume is positive.
    • There is no current position and no active orders. If either is present, the order is not sent (same as OrdersTotal()==0 and PositionsTotal()==0 check in MQL).
  2. The entry price is resolved:
    • Market modes use the best bid/ask, falling back to last price or EntryPrice when no market data is available yet.
    • Pending modes require EntryPrice > 0.
  3. Protective distances are derived from the specified stop-loss and take-profit levels. Only valid, positive distances are passed to StartProtection to emulate the EA parameters.
  4. The selected order type is sent (BuyMarket, SellLimit, BuyStop, etc.) exactly once and informational logs are produced to reflect the action.

Differences from the Original EA

  • Logging is performed through AddInfoLog instead of Print.
  • Protective orders are registered via StartProtection when both the entry price and the stop-loss/take-profit allow computing a positive distance.
  • Market price resolution uses current Level1 data (BestBid, BestAsk, LastPrice) and postpones order submission if no quote is available yet.

Usage Notes

  • Assign the desired security before starting the strategy and ensure Level1 data is available for market orders.
  • Set EntryPrice, StopLossPrice, and TakeProfitPrice in absolute terms when using pending orders.
  • Leave Mode as None to disable trading without removing the strategy from the environment.
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;
	}
}