GitHub で見る

CandlesticksBW戦略

この戦略はBill WilliamsのCandlesticksBWアプローチを再現します。Awesome Oscillator (AO) と Accelerator Oscillator (AC) のモメンタムを使用して各ローソク足に色を付けます。戦略は強気と弱気の色の遷移に基づいてポジションを開閉します。

仕組み

  • AOは中値価格の5期間SMAと34期間SMAの差として計算されます。
  • ACはAOからAOの5期間SMAを引いた値として計算されます。
  • 各ローソク足はAO/ACの増減とローソク足の方向に応じて6つの色に分類されます。
  • 強気の設定は、前から2番目のローソク足が強気(色0または1)のときに発生します。最後のローソク足の色が1より大きい場合、ロングポジションを開きショートポジションを閉じます。
  • 弱気の設定は、前から2番目のローソク足が弱気(色4または5)のときに発生します。最後のローソク足の色が4より小さい場合、ショートポジションを開きロングポジションを閉じます。
  • ストップとターゲットはStartProtectionで適用されます。

パラメーター

  • CandleType – ローソク足の時間軸。
  • SignalBar – シグナル評価のためのオフセットバー。
  • StopLoss – ポイントでのストップロス距離。
  • TakeProfit – ポイントでのテイクプロフィット距離。
  • BuyPosOpen – ロングポジションの開設を許可。
  • SellPosOpen – ショートポジションの開設を許可。
  • BuyPosClose – ロングポジションのクローズを許可。
  • SellPosClose – ショートポジションのクローズを許可。

インジケーター

  • Awesome Oscillator(SMAから導出)。
  • Accelerator Oscillator。

取引ルール

  • ロングエントリー: 前から2番目のローソク足の色 <2 かつ最後の色 >1。
  • ショートエントリー: 前から2番目のローソク足の色 >3 かつ最後の色 <4。
  • ロングエグジット: ポジション>0のときショートエントリー条件で。
  • ショートエグジット: ポジション<0のときロングエントリー条件で。
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>
/// CandlesticksBW strategy based on Bill Williams' color classification of candles.
/// Uses Awesome and Accelerator oscillators to detect momentum shifts.
/// </summary>
public class CandlesticksBwStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

	private SimpleMovingAverage _aoFast;
	private SimpleMovingAverage _aoSlow;
	private SimpleMovingAverage _acMa;

	private decimal _prevAo;
	private decimal _prevAc;
	private bool _hasPrev;
	private int _prevColor = -1;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CandlesticksBwStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Time frame for analysis", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_aoFast = null;
		_aoSlow = null;
		_acMa = null;
		_prevAo = 0;
		_prevAc = 0;
		_hasPrev = false;
		_prevColor = -1;
	}

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

		_prevAo = 0;
		_prevAc = 0;
		_hasPrev = false;
		_prevColor = -1;

		_aoFast = new SimpleMovingAverage { Length = 5 };
		_aoSlow = new SimpleMovingAverage { Length = 34 };
		_acMa = new SimpleMovingAverage { Length = 5 };

		Indicators.Add(_aoFast);
		Indicators.Add(_aoSlow);
		Indicators.Add(_acMa);

		var sma = new SimpleMovingAverage { Length = 1 };

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

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

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

		var hl2 = (candle.HighPrice + candle.LowPrice) / 2m;
		var t = candle.CloseTime;

		var aoFastResult = _aoFast.Process(hl2, t, true);
		var aoSlowResult = _aoSlow.Process(hl2, t, true);

		if (!_aoFast.IsFormed || !_aoSlow.IsFormed)
			return;

		var ao = aoFastResult.GetValue<decimal>() - aoSlowResult.GetValue<decimal>();
		var acMaResult = _acMa.Process(ao, t, true);

		if (!_acMa.IsFormed)
			return;

		var ac = ao - acMaResult.GetValue<decimal>();

		// Bill Williams candle color classification:
		// 0 = green (bullish candle + AO up + AC up)
		// 1 = fade (bearish candle + AO up + AC up)
		// 2 = squat green (bullish, mixed)
		// 3 = squat red (bearish, mixed)
		// 4 = fake (bullish candle + AO down + AC down)
		// 5 = red (bearish candle + AO down + AC down)
		int color;
		if (_hasPrev && ao >= _prevAo && ac >= _prevAc)
			color = candle.OpenPrice <= candle.ClosePrice ? 0 : 1;
		else if (_hasPrev && ao <= _prevAo && ac <= _prevAc)
			color = candle.OpenPrice >= candle.ClosePrice ? 5 : 4;
		else
			color = candle.OpenPrice <= candle.ClosePrice ? 2 : 3;

		_prevAo = ao;
		_prevAc = ac;
		_hasPrev = true;

		if (!IsFormedAndOnline())
		{
			_prevColor = color;
			return;
		}

		if (_prevColor < 0)
		{
			_prevColor = color;
			return;
		}

		// Bullish signal: prev was up momentum (0 or 1), current transitions
		if (_prevColor < 2 && color > 1 && Position <= 0)
			BuyMarket();
		// Bearish signal: prev was down momentum (4 or 5), current transitions
		else if (_prevColor > 3 && color < 4 && Position >= 0)
			SellMarket();

		_prevColor = color;
	}
}