在 GitHub 上查看

公牛熊眼策略

概述

该策略使用 Bulls PowerBears Power 指标衡量多头与空头的力量对比。两个指标被组合成一个范围在0到100之间的振荡器,数值越高代表买方越强,数值越低代表卖方越强。

交易信号基于阈值判断,与原始的 BullsBearsEyes 专家顾问类似。当振荡器从下方穿越超买水平时,策略开多并平掉已有空单;当振荡器从上方跌破超卖水平时,策略开空并平掉已有多单。处于阈值之间的中性区域时,仅平掉反向仓位,不会开新仓。

参数

  • Period – Bulls/Bears Power 的计算周期(默认:13)。
  • High Level – 触发做多信号的超买阈值(默认:75)。
  • Middle Level – 用于解释趋势的中间水平(默认:50)。
  • Low Level – 触发做空信号的超卖阈值(默认:25)。
  • Candle Type – 策略处理的K线周期(默认:4小时)。

入场与出场规则

  1. 对每根K线计算 Bulls Power 与 Bears Power,并生成0到100之间的振荡器数值。
  2. 做多入场:振荡器自下而上突破 High Level,开多并平掉空单。
  3. 做空入场:振荡器自上而下跌破 Low Level,开空并平掉多单。
  4. 平仓:振荡器跨越中间区域并改变方向时,平掉反向仓位。

振荡器会与K线一起绘制,便于可视化分析。

备注

  • 策略使用高级的 SubscribeCandlesBind API 处理指标。
  • 在启动时通过 StartProtection() 启用保护机制。
  • 仅在K线收盘后进行计算,避免提前产生信号。
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 BullsBearsEyesStrategy : 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 BullsBearsEyesStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Parameters");
		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Parameters");
		_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;
	}
}