Ver en GitHub

CandlesticksBW Strategy

This strategy replicates the Bill Williams CandlesticksBW approach. It colors each candle using Awesome Oscillator (AO) and Accelerator Oscillator (AC) momentum. The strategy opens or closes positions based on transitions between bullish and bearish colors.

How it works

  • Computes AO as the difference between 5- and 34-period SMAs of the median price.
  • Computes AC as AO minus a 5-period SMA of AO.
  • Each candle is classified into six colors depending on AO/AC growth and candle direction.
  • A bullish setup occurs when the penultimate candle is bullish (color 0 or 1). If the last candle's color is above 1, a long position is opened and short positions are closed.
  • A bearish setup occurs when the penultimate candle is bearish (color 4 or 5). If the last candle's color is below 4, a short position is opened and long positions are closed.
  • Stops and targets are applied via StartProtection.

Parameters

  • CandleType – candle timeframe.
  • SignalBar – offset bar for signal evaluation.
  • StopLoss – stop loss distance in points.
  • TakeProfit – take profit distance in points.
  • BuyPosOpen – allow opening long positions.
  • SellPosOpen – allow opening short positions.
  • BuyPosClose – allow closing long positions.
  • SellPosClose – allow closing short positions.

Indicators

  • Awesome Oscillator (derived from SMAs).
  • Accelerator Oscillator.

Trading rules

  • Long entry: penultimate candle color <2 and last color >1.
  • Short entry: penultimate candle color >3 and last color <4.
  • Long exit: on short entry condition if position >0.
  • Short exit: on long entry condition if position <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;
	}
}