在 GitHub 上查看

Godbot 策略

该策略利用布林带和移动平均线来识别反转以及趋势强度。

逻辑

  • 使用主时间框(默认 30 分钟)。
  • 在该时间框上计算布林带和 EMA。
  • 另外在更高时间框(默认 1 天)上计算 DEMA 以判定总体趋势。
  • 当价格回落到上轨下方时平掉多头仓位。
  • 当价格回升到下轨上方时平掉空头仓位。
  • 当价格上破下轨且 DEMA 与 EMA 均向上时开多。
  • 当价格下破上轨且 DEMA 与 EMA 均向下时开空。

参数

  • Bollinger Period – 布林带周期。
  • Bollinger Deviation – 布林带偏差倍数。
  • EMA Period – 趋势过滤用的 EMA 周期。
  • DEMA Period – 高时间框 DEMA 周期。
  • Candle Type – 计算布林带和 EMA 的时间框。
  • DEMA Candle Type – 计算 DEMA 的更高时间框。

说明

  • 同一时间仅持有一个仓位。
  • 策略使用市价单进出场。
  • 在交易开始前需要累积足够的 DEMA 数据。
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>
/// Strategy based on Bollinger Bands and EMA trend confirmation.
/// Buys when price crosses below lower band with uptrend, sells when above upper band with downtrend.
/// </summary>
public class GodbotStrategy : Strategy
{
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private bool _hasPrevEma;

	public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
	public decimal BollingerDeviation { get => _bollingerDeviation.Value; set => _bollingerDeviation.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public GodbotStrategy()
	{
		_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetGreaterThanZero()
			.SetDisplay("BB Deviation", "Bollinger Bands deviation", "Indicators");

		_maPeriod = Param(nameof(MaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend", "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();
		_prevEma = 0;
		_hasPrevEma = false;
	}

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

		var bb = new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};
		var ema = new ExponentialMovingAverage { Length = MaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, ProcessEma);
		subscription
			.BindEx(bb, ProcessBB)
			.Start();
	}

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

		_prevEma = emaVal;
		_hasPrevEma = true;
	}

	private void ProcessBB(ICandleMessage candle, IIndicatorValue bbValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_hasPrevEma)
			return;

		var bb = (BollingerBandsValue)bbValue;
		if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower || bb.MovingAverage is not decimal middle)
			return;

		var close = candle.ClosePrice;

		// Buy: price below lower band
		if (close < lower && Position <= 0)
			BuyMarket();
		// Sell: price above upper band
		else if (close > upper && Position >= 0)
			SellMarket();
	}
}