View on GitHub

Hedger Strategy

This strategy places a limit order and an opposite stop order to hedge the initial position. It works for both long and short modes and adds several risk controls.

The hedge order protects the main trade if price moves in the wrong direction. A 75-50 trailing rule can move the stop to half of the target once 75% of the profit goal is reached. Optional risk hedging can open a market order against the position after a large adverse move, and the stop can be tightened after a configurable number of ticks.

Details

  • Entry Criteria: Place limit order at EntryPrice and hedge stop at EntryPrice ± Spread.
  • Long/Short: Configured via IsLong.
  • Exit Criteria: Stop loss, take profit, 75-50 rule or risk hedge.
  • Stops: Yes, with optional tightening.
  • Filters: None.

Parameters

  • EntryPrice – price for the pending order.
  • StopLoss – protective stop level.
  • TakeProfit – profit target.
  • Volume – order volume.
  • Spread – distance for hedge order.
  • IsLong – trade long if true, short if false.
  • UseRiskHedge – open opposite market order on strong adverse move.
  • UseRiskSl – tighten stop after adverse move of RiskSlTicks.
  • RiskSlTicks – number of ticks for risk stop tightening.
  • UseRule7550 – enable 75-50 trailing rule.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// EMA crossover strategy.
/// </summary>
public class HedgerStrategy : 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;

	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 HedgerStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicators");

		_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();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fast, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
		var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;

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

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}