在 GitHub 上查看

Bleris 策略

概述

Bleris 策略通过分析最近价格极值的走势来顺势开仓。 价格被划分为三个长度相等的区间,并比较每个区间的最高价和最低价。

  • 指标:Highest、Lowest
  • 参数
    • SignalBarSample – 每个区间的蜡烛数量。
    • CounterTrend – 反向交易信号。
    • Lots – 订单手数。
    • CandleType – 使用的蜡烛时间框架。
    • AnotherOrderPips – 同方向再次开仓的最小点数间隔。

工作原理

  1. Highest 与 Lowest 指标计算最近 SignalBarSample 根蜡烛的极值。
  2. 连续下降的高点表示下行趋势;连续上升的低点表示上行趋势。
  3. 上行趋势时策略买入,下行趋势时策略卖出;当启用 CounterTrend 时方向相反。
  4. 如果最近一次开仓价格与当前价格的差距小于 AnotherOrderPips,则忽略新的同向订单。

该示例使用 StockSharp 的高级 API,仅用于教学演示。

using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bleris strategy based on comparisons of consecutive highest highs and lowest lows.
/// </summary>
public class BlerisStrategy : Strategy
{
	private readonly StrategyParam<int> _signalBarSample;
	private readonly StrategyParam<bool> _counterTrend;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<decimal> _highs = new();
	private readonly List<decimal> _lows = new();

	private decimal _prevHigh1;
	private decimal _prevHigh2;
	private decimal _prevLow1;
	private decimal _prevLow2;

	/// <summary>
	/// Number of candles for each segment of trend detection.
	/// </summary>
	public int SignalBarSample { get => _signalBarSample.Value; set => _signalBarSample.Value = value; }

	/// <summary>
	/// Reverse trading direction when true.
	/// </summary>
	public bool CounterTrend { get => _counterTrend.Value; set => _counterTrend.Value = value; }

	/// <summary>
	/// Candle type used for analysis.
	/// </summary>
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public BlerisStrategy()
	{
		_signalBarSample = Param(nameof(SignalBarSample), 24)
			.SetDisplay("Signal bar sample", "Signal bar sample", "General");

		_counterTrend = Param(nameof(CounterTrend), false)
			.SetDisplay("Counter trend", "Counter trend", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle type", "Candle type", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_highs.Clear();
		_lows.Clear();
		_prevHigh1 = 0;
		_prevHigh2 = 0;
		_prevLow1 = 0;
		_prevLow2 = 0;
	}

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

		StartProtection(null, null);

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

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

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

		_highs.Add(candle.HighPrice);
		_lows.Add(candle.LowPrice);

		if (_highs.Count > SignalBarSample)
			_highs.RemoveAt(0);
		if (_lows.Count > SignalBarSample)
			_lows.RemoveAt(0);

		if (_highs.Count < SignalBarSample)
			return;

		var highest = decimal.MinValue;
		var lowest = decimal.MaxValue;
		for (var i = 0; i < _highs.Count; i++)
		{
			if (_highs[i] > highest) highest = _highs[i];
			if (_lows[i] < lowest) lowest = _lows[i];
		}

		var uptrend = _prevLow2 > 0 && _prevLow2 < _prevLow1 && _prevLow1 < lowest;
		var downtrend = _prevHigh2 > 0 && _prevHigh2 > _prevHigh1 && _prevHigh1 > highest;

		_prevHigh2 = _prevHigh1;
		_prevHigh1 = highest;
		_prevLow2 = _prevLow1;
		_prevLow1 = lowest;

		if (uptrend && !downtrend)
		{
			if (CounterTrend)
			{
				if (Position >= 0)
				{
					if (Position > 0) SellMarket();
					SellMarket();
				}
			}
			else
			{
				if (Position <= 0)
				{
					if (Position < 0) BuyMarket();
					BuyMarket();
				}
			}
		}
		else if (downtrend && !uptrend)
		{
			if (CounterTrend)
			{
				if (Position <= 0)
				{
					if (Position < 0) BuyMarket();
					BuyMarket();
				}
			}
			else
			{
				if (Position >= 0)
				{
					if (Position > 0) SellMarket();
					SellMarket();
				}
			}
		}
	}
}