Bollinger bands are calculated using the standard deviation of the difference between prices and a central moving average line. Since Bollinger bands use standard deviations, they move apart during volatile price times, and get narrower during quiet price movement times. Since range trading is basically a volatility technique (you trade edges against a center line), it works well in sideways markets where your open trades are not exposed to very much trending price action. That is, in sideways markets, there is a lower probability that your trade will go against you. But be aware, if a breakout occurs against your range trade, you can lose lots of money if you don’t have a stop loss in place. The implementation shown here does not use stop losses, so it has no downside protection. In the code that follows, the strategy tries to trade long by buying at the lower Bollinger band limit and selling when prices go up and reach the moving average line. The strategy constantly watches prices (bars), so it can update both the buy point and sell point as prices move around. The strategy constantly updates the buy limit order at the broker while no position is open. When a buy occurs, the OnPositionOpened event handler is called to issue a sell limit order. From that point on, the strategy updates only the exit limit order, until the sell point is reached and the position is closed. Then the cycle repeats. 38 This strategy is effective in sideways markets and upward trending markets, if false breakouts and down trending markets don’t go against you too often. Of course you should add a stop loss mechanism to this strategy for downside protection before using it in real life. Also pay close attention to transaction costs, because small price moves don’t usually provide much profit.

using OpenQuant.API;
using OpenQuant.API.Indicators;

using System.Drawing;

public class MyStrategy : Strategy
{
	[Parameter("Order quantity (number of contracts to trade)")]
	double Qty = 100;
	
	[Parameter("Length of SMA")]
	int SMALength = 20;
	
	[Parameter("Order of BBL")]
	double BBLOrder = 2;

	// indicators
	BBL bbl;
	SMA sma;	

	Order buyOrder;
	Order sellOrder;

	public override void OnStrategyStart()
	{
		// set up the moving averages 
		sma = new SMA(Bars, SMALength);
		sma.Color = Color.Yellow;
		Draw(sma, 0);
		// set up bollinger bands
		bbl = new BBL(Bars, SMALength, BBLOrder);
		bbl.Color = Color.Pink;
		Draw(bbl, 0);
	}

	public override void OnBar(Bar bar)
	{
		// always a good practice to be sure a series contains
		// a bar for a particular date before you try to use it
		if (bbl.Contains(bar.DateTime))
		{
			// We are always trying to buy at the lower Bollinger
			// limit, and sell when the price goes up to the 
			// latest SMA value. So we are constantly
			// updating both the buy point and the sell point.

			// if we don't have an open position in this instrument,
			// update the buy point to the latest lower bbl limit 
			if (!HasPosition)
			{
				if (buyOrder != null)
					buyOrder.Cancel();

				buyOrder = BuyLimitOrder(Qty, bbl.Last, "Entry");				
				buyOrder.Send();
			}

				// else if we already have a position going, update 
				// the sell point to follow the latest SMA value 
			else
				UpdateExitLimit();
		}
	}

	public override void OnPositionOpened()
	{
		UpdateExitLimit();
	}

	private void UpdateExitLimit()
	{
		// cancel old exit point order, if it exists
		if (sellOrder != null)
			sellOrder.Cancel();
		// Issue a new order with the latest SMA value. This is 
		// kind of a "trailing SMA sell order" that follows the SMA.
		sellOrder = SellLimitOrder(Qty, sma.Last, "Exit");		
		sellOrder.Send();
	}
}