GitHub で見る

Color Bears戦略

この戦略は二重平滑化されたBears Powerオシレーターを構築し、その傾きの変化に基づいて取引します。

アイデア

  1. 終値の指数移動平均(MA1)を計算する。
  2. Bears Powerをローソク足の安値とMA1の差として計算する。
  3. Bears PowerをもうひとつのEMA(MA2)でさらに平滑化する。
  4. 平滑化された値の上昇・下降を追跡し、傾きの反転に反応する。

取引ルール

  • インジケーターが上昇から下降に転換した場合(色 0 → 2)、ショートポジションを決済してロングポジションを開く。
  • インジケーターが下降から上昇に転換した場合(色 2 → 0)、ロングポジションを決済してショートポジションを開く。
  • 各ポジションの注文サイズには戦略のVolumeプロパティを使用する。

パラメーター

名前 説明
Ma1Period Bears Power構築に使用する最初のEMAの期間。
Ma2Period 平滑化EMAの期間。
CandleType 計算に使用するローソク足の時間軸。

備考

このC#実装はMQLエキスパート「ColorBears」(フォルダ MQL/14314)から移植されています。 アルゴリズムはStockSharpの標準インジケーターと高レベルAPIバインディングを使用しています。

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>
/// Strategy based on a double-smoothed Bears Power indicator.
/// Opens a long position when the indicator turns down after rising,
/// and opens a short position when it turns up after falling.
/// </summary>
public class ColorBearsStrategy : Strategy
{
	private readonly StrategyParam<int> _ma1Period;
	private readonly StrategyParam<int> _ma2Period;
	private readonly StrategyParam<DataType> _candleType;

	private ExponentialMovingAverage _ma1;
	private ExponentialMovingAverage _ma2;
	private decimal? _prevValue;
	private int? _prevColor;

	/// <summary>
	/// Length of the first moving average.
	/// </summary>
	public int Ma1Period
	{
		get => _ma1Period.Value;
		set => _ma1Period.Value = value;
	}

	/// <summary>
	/// Length of the second moving average.
	/// </summary>
	public int Ma2Period
	{
		get => _ma2Period.Value;
		set => _ma2Period.Value = value;
	}

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

	/// <summary>
	/// Initializes a new instance of <see cref="ColorBearsStrategy"/>.
	/// </summary>
	public ColorBearsStrategy()
	{
		_ma1Period = Param(nameof(Ma1Period), 12)
			.SetGreaterThanZero()
			.SetDisplay("MA1", "First MA length", "Parameters")
			.SetOptimize(5, 30, 1);

		_ma2Period = Param(nameof(Ma2Period), 5)
			.SetGreaterThanZero()
			.SetDisplay("MA2", "Second MA length", "Parameters")
			.SetOptimize(2, 20, 1);

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

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

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

		_ma1 = new ExponentialMovingAverage { Length = Ma1Period };
		_ma2 = new ExponentialMovingAverage { Length = Ma2Period };

		Indicators.Add(_ma1);
		Indicators.Add(_ma2);

		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;

		var ma1Input = new DecimalIndicatorValue(_ma1, candle.ClosePrice, candle.OpenTime) { IsFinal = true };
		var ma1Value = _ma1.Process(ma1Input);
		if (!_ma1.IsFormed)
			return;

		var bears = candle.LowPrice - ma1Value.ToDecimal();
		var ma2Input = new DecimalIndicatorValue(_ma2, bears, candle.OpenTime) { IsFinal = true };
		var ma2Value = _ma2.Process(ma2Input);
		if (!_ma2.IsFormed)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var current = ma2Value.ToDecimal();
		var color = 1;
		if (_prevValue != null)
		{
			if (_prevValue < current)
				color = 0;
			else if (_prevValue > current)
				color = 2;

			if (_prevColor == 0 && color == 2)
			{
				if (Position < 0)
					BuyMarket();
				if (Position <= 0)
					BuyMarket();
			}
			else if (_prevColor == 2 && color == 0)
			{
				if (Position > 0)
					SellMarket();
				if (Position >= 0)
					SellMarket();
			}
		}

		_prevColor = color;
		_prevValue = current;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_ma1 = default;
		_ma2 = default;
		_prevValue = null;
		_prevColor = null;
	}
}