Открыть на GitHub

Стратегия Bulls & Bears Power Cross

Эта стратегия торгует на пересечении индикаторов Bulls Power и Bears Power на четырёхчасовом таймфрейме. Bulls Power показывает давление покупателей выше средней цены, а Bears Power отображает давление продавцов ниже неё. Когда сила покупателей превышает силу продавцов, открывается длинная позиция. При доминировании продавцов открывается короткая позиция.

Тестирование на исторических данных по криптовалютам показывает, что такие пересечения часто предвосхищают краткосрочные развороты. Стратегия всегда находится в позиции и переворачивается при каждом новом пересечении индикаторов.

Детали

  • Условия входа:
    • Покупка: значение Bulls Power пересекает Bears Power снизу вверх.
    • Продажа: значение Bears Power пересекает Bulls Power снизу вверх.
  • Длинные/короткие: Оба направления.
  • Условия выхода: Обратное пересечение, которое переворачивает позицию.
  • Стопы: Нет. Позиции переворачиваются вместо закрытия по стопу.
  • Фильтры:
    • Таймфрейм: свечи по 4 часа.
    • Индикаторы: Bulls Power, Bears Power.
    • Направление: разворот на смене импульса.
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 with RSI filter strategy.
/// </summary>
public class BullsBearsPowerCrossStrategy : 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 BullsBearsPowerCrossStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 13)
			.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;
	}
}