Ver en GitHub

Pending Order

Strategy that places four pending orders around the current bid and ask during specified hours. It continuously maintains buy limit, sell limit, buy stop, and sell stop orders at a configurable distance from market price. Each pending order uses fixed stop-loss and take-profit offsets.

Details

  • Entry Criteria: Place pending orders at Distance ticks from current bid/ask within allowed hours.
  • Long/Short: Both directions.
  • Exit Criteria: Take-profit or stop-loss relative to entry price.
  • Stops: Yes.
  • Default Values:
    • StartHour = 6
    • EndHour = 20
    • TakeProfit = 20
    • StopLoss = 100
    • Distance = 15
    • CandleType = TimeSpan.FromMinutes(1)
  • Filters:
    • Category: Range
    • Direction: Both
    • Indicators: None
    • Stops: Yes
    • Complexity: Basic
    • Timeframe: Intraday (1m)
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: Low
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that buys or sells based on price breaking above/below
/// a previous candle's range by a configurable offset.
/// </summary>
public class PendingOrderStrategy : Strategy
{
	private readonly StrategyParam<decimal> _distance;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevHigh;
	private decimal? _prevLow;

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

	public PendingOrderStrategy()
	{
		_distance = Param(nameof(Distance), 50m)
			.SetDisplay("Distance", "Offset from prev candle range for entry", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHigh = _prevLow = null;
	}

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

		var sma = new ExponentialMovingAverage { Length = 5 };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(sma, ProcessCandle).Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevHigh = candle.HighPrice;
			_prevLow = candle.LowPrice;
			return;
		}

		if (_prevHigh is decimal ph && _prevLow is decimal pl)
		{
			var breakUp = ph + Distance;
			var breakDown = pl - Distance;

			if (candle.ClosePrice > breakUp && Position <= 0)
				BuyMarket();
			else if (candle.ClosePrice < breakDown && Position >= 0)
				SellMarket();
		}

		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;
	}
}