MadHatter BBands

Breaking down the MadHatter BBands


In this tutorial we break down how the MadHatter bot utilizes Bollinger Bands. This tutorial follows the default script that is available for everyone in the Script Editor. You can find this script under the name MadHatter BBands in the Select Script menu.

The signal logic in MadHatter BBands can be tricky for a beginner to follow!

This tutorial will not tell you how to create custom commands from scratch. If you are looking for a tutorial that does that, please open the page below:

Opening a script

As the script is already available, we will not re-create it from scratch. Instead, we will open the script and break it down into digestible chunks.

Next, search for the script from the available list by typing the name into the search box, located in the top of Select Script window:

Okay, we found it. Awesome! Click it and you should see its code appear in the editor.

Breaking down inputs

MadHatter's BBands contains several input parameters for full control which can feel overwhelming if you are used to simpler setups. Don't worry though, we will break it up for you.

The first few settings are related to the BBands themselves:

  • Length

    • Period Length of the BBands. This controls how fast or slowly the bands react to price changes.

  • DevUp

    • Deviation (distance multiplier) for the Upper Band. This controls how far upwards the upper band is from the middle line.

  • DevDown

    • Deviation (distance multiplier) for the Lower Band. This controls how far downwards the lower band is from the middle line.

  • MA Type

    • Type of the Moving Average used to calculate middle line. BBands are usually calculated using SMA and EMA.

So that's simple enough, right? These give you a nice control over the BBands.

Next up are the ones related to the tricky logic this indicator holds inside.

  • Require FCC

    • Determines whether or not Full-Candle-Cross is required. If set to true (checked), then the price candle must be both opened and closed inside the bands after visiting outside. If set to false (unchecked), then the price only needs to close back inside the bands to produce a signal.

  • Reset Middle

    • Determines whether or not to reset the signal after crossing middle line. In other words; should it keep producing signals after crossing middle line (false/unchecked), or will they stop (true/checked)?

  • Allow Mid Sells

    • Determines whether or not it is allowed to signal a sell, after crossing above middle line. In some cases this can be beneficial, especially if the price range is big/volatile.

There will be further talk about these last three parameters as we move on.

Acquiring necessary data

This indicator does not take price data as inputs. Instead, it is done built-in. This should be simple enough, so I will just flash that part of the code and move on.

-- Get prices
local prices = ClosePrices(interval)
local open = OpenPrices(interval)
-- Get bbands
local bbandsData = BBANDS(prices, period, devUp, devDn, maType)
local upper = bbandsData[1]
local middle = bbandsData[2]
local lower = bbandsData[3]
-- Plot bands
PlotBBandsChart(chartIndex, 'MHB BBands', upper, middle, lower)

MadHatter ain't mad without a reason: The Signal Logic

Even though the signal logic for this script is fairly simple, it can be quite hard for a beginner to follow and figure out. That is why we will start slow and take small steps through this part.


The idea behind the logic is the following:

  • If price crosses above upper band and then back below, produce a sell signal.

  • If price crosses below lower band and then back above, produce a buy signal.

Okay, that's easy! Now let's add some more to it. As you remember, we had some inputs to spare.

  • If price crosses above upper band and then back below and if FCC is required and if open and clo-....

Eh.. Maybe we will check the code itself and use that instead. Let's move on.

Condition flags

The script contains two condition flags that must be true before a signal is produced. These two are called wentBelow and wentAbove. As the names suggest, these are the condition flags for did price go below lower band and did price go above upper band. Using these flags we can determine if the price across the outside of the bands before crossing back inside.

For this type of logic it is crucial that you remember to Save and Load your condition flags. If you do not do so, your bot will forget the last state of these flags in the next update.

Buy signal

We will start off with this: if price closes below lower band, then set condition flag wentBelow as true. And if resetMiddle is false, we will reset the other condition flag wentAbove to false here.

if prices < lower then
wentBelow = true
if resetMiddle == false then
wentAbove = false

Next, we will check if the prices are above the lower band, but only continue if the wentBelow is also true. If it is, then we will check if requireFCC is set to true, and when it is not we just change the result. If it is, then we will check if the open price is also above the lower band. This is the Full-Candle-Cross.

if prices > lower and wentBelow then
if requireFCC then
if open > lower then
result = SignalBuy
result = SignalBuy

Lastly, if we went below and want to reset middle, we do so once prices cross above the middle line.

if resetMiddle and prices > middle and wentBelow then
wentBelow = false

And that's that for the buy signal. Hopefully it was broken down well enough for you to get the hang of it.

Next up...

Sell Signal

The logic is the exact same for the sell signal; it's just upside down. Instead of checking if prices went below lower and back above, we check if the prices went above the upper band and then back below.

-- Initial condition flag check and
-- set when prices go above upper.
if prices > upper then
wentAbove = true
if resetMiddle == false then
wentBelow = false
-- We came back below upper band?
if prices < upper and wentAbove then
if requireFCC then -- Is FCC required?
if open < upper then -- Is it a FCC?
result = SignalSell -- It is.
-- FCC not required, time for a signal
result = SignalSell
-- Reset flag below middle line,
-- if we ever went above the upper.
if resetMiddle and prices < middle and wentAbove then
wentAbove = false

Allow Mid Sells?

If sells after middle line are allowed and prices are above the line, then we will give a signal for sell:

if allowMidSells and prices > middle then
result = SignalSell

Final signal

There is one trick before we hand out the final signal from this command. If it happens to be a buy signal, we want to check for a green candle: is the OPEN price smaller than CLOSE price?

Other than that, the final part is really simple.

local finalSignal = SignalNone
-- Check if open is smaller than close
if open < prices and result == SignalBuy then
finalSignal = SignalBuy
elseif result == SignalSell then
finalSignal = SignalSell

And that's that! That is the custom command broken down into small chunks and hopefully this was helpful for you.

Seed of thought

Now that you have the idea behind MadHatter's BBands, and digested the logic, you should be able to create similar logic with other indicators. For example, the RSI, MFI and STOCH should work great with this type of logic attached to them as they tend to overshoot above and below the thresholds which then produce early signals for bots.

That said, take it as a challenge and have fun making awesome scripts! You know what to do...