Открыть на GitHub

Стратегия "10 Pips"

Хеджирующая стратегия одновременно открывает длинную и короткую позиции. Для каждой позиции задаются фиксированные уровни тейк-профита и стоп-лосса в ценовых пунктах, а также возможна защита трейлинг-стопом. При закрытии одной из позиций стратегия немедленно открывает новую в том же направлении, поддерживая обе стороны активными.

Параметры

  • TakeProfitBuy – расстояние тейк-профита для длинных позиций.
  • StopLossBuy – расстояние стоп-лосса для длинных позиций.
  • TrailingStopBuy – расстояние трейлинг-стопа для длинных позиций.
  • TakeProfitSell – расстояние тейк-профита для коротких позиций.
  • StopLossSell – расстояние стоп-лосса для коротких позиций.
  • TrailingStopSell – расстояние трейлинг-стопа для коротких позиций.
  • Volume – объём заявок.

Особенности

  • Открытие позиций происходит рыночными заявками.
  • Защитные заявки регистрируются отдельно для каждого направления.
  • Трейлинг-стоп переносится при движении цены в прибыльную сторону.
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>
/// Simple breakout strategy that enters on momentum moves
/// with fixed take profit and stop loss protection.
/// </summary>
public class TenPipsStrategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<int> _lookback;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private decimal _previousRoc;
	private bool _hasPreviousRoc;

	/// <summary>Take profit distance.</summary>
	public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
	/// <summary>Stop loss distance.</summary>
	public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
	/// <summary>Lookback period for momentum.</summary>
	public int Lookback { get => _lookback.Value; set => _lookback.Value = value; }
	/// <summary>Candle type.</summary>
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public TenPipsStrategy()
	{
		_takeProfit = Param(nameof(TakeProfit), 500m)
			.SetDisplay("Take Profit", "Take profit distance", "Risk")
			.SetGreaterThanZero();
		_stopLoss = Param(nameof(StopLoss), 300m)
			.SetDisplay("Stop Loss", "Stop loss distance", "Risk")
			.SetGreaterThanZero();
		_lookback = Param(nameof(Lookback), 30)
			.SetDisplay("Lookback", "Momentum lookback period", "Indicators")
			.SetGreaterThanZero();
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_entryPrice = 0m;
		_previousRoc = 0m;
		_hasPreviousRoc = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_entryPrice = 0;
		_previousRoc = 0m;
		_hasPreviousRoc = false;

		var roc = new RateOfChange { Length = Lookback };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var close = candle.ClosePrice;
		var buySignal = _hasPreviousRoc && _previousRoc <= 4m && rocValue > 4m;
		var sellSignal = _hasPreviousRoc && _previousRoc >= -4m && rocValue < -4m;

		if (Position == 0)
		{
			if (buySignal)
			{
				BuyMarket();
				_entryPrice = close;
			}
			else if (sellSignal)
			{
				SellMarket();
				_entryPrice = close;
			}
		}
		else if (Position > 0)
		{
			if (close >= _entryPrice + TakeProfit || close <= _entryPrice - StopLoss)
			{
				SellMarket(Math.Abs(Position));
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - TakeProfit || close >= _entryPrice + StopLoss)
			{
				BuyMarket(Math.Abs(Position));
			}
		}

		_previousRoc = rocValue;
		_hasPreviousRoc = true;
	}
}