Thinking Stuff's ATM

Automated Trading Machine (ATM) makes it simple to remove fear and greed from your trading. Automated trading is no longer just for the rich or nerdy. Our revolutionary software runs on your computer, using your trading rules, but none of your emotions. There's just one requirement - you know how to use a mouse.  Learn more...

Thinking Stuff's ATE

Automated Trading Execution (ATE) is where we run your trading systems for you on our servers. Your system can be exported from ATM, or written in plain English and we'll make it for you. We'll even backtest and suggest improvements if you want us to. This service essentially automates your automated trading.  Learn more...

Thinking Stuff's Groups

Join a group of like-minded individuals, and help each other to trading success. Once you join a group, you will have access to that group's trading systems, ideas, and feedback. And please contribute your own knowledge as much as possible. Or contact us to start your own group.  Learn more...

Creating custom indicators

Video: Creating A Custom Indicator

This tutorial demonstrates how to create a custom indicator, which is then charted.

It assumes:

  1. You started ATM and opened a settings file.
  2. That settings file already has some price bars in it.
  3. ATM is sitting there ready to go.

This tutorial does these things:

  1. Charts some price bars.
  2. Adds an indicator to the chart - the LOW minus 0.3%
  3. Creates a custom indicator implementing the Chandelier Stop.
  4. Adds the Chandelier Stop indicator to the chart.

It's probably better NOT TO WATCH this video tutorial if you are new to ATM, and especially if you're not good with computers. Custom indicators are the hardest things to understand, and you are totally going to get the wrong impression about this software. ATM comes with a whole number of pre-made custom indicators, so most likely you will not need to create one of your own.

On the other hand, if you can understand this then the rest of the software will be a cinch.

Click here to watch the video, and use the browser's back button to come back. Or click here to open in a new window.
 

Column Titles

ATM wants to do as little calculations as possible. If it has already calculated the RSI(14), it doesn't want to do it again. To work out if a calculation has been done already or not, ATM goes by the Column Title.

You have to provide enough information for your Column Title to be unique amongst all other Columns (yours and everyone else's).

Here's an example with the Simple Moving Average. We could have just used a Column Title of "SMA". Someone uses the SMA(CLOSE, 20) in the trading system. So ATM creates a column and gives it a title of "SMA". But then that person adds another SMA to their trading system - this time SMA(CLOSE, 50). ATM checks to see if the "SMA" column already exists, and it does, so ATM doesn't calculate again. But here, there are actually 2 different SMAs. Let's try again.

This time we change the Column Title to "SMA_Setting01". Now ATM would correctly create 2 Columns - 1 titled "SMA_20", and the other titled "SMA_50". Fixed? No. The person decides they want another SMA in there - this time SMA(HIGH, 20). That would create the Column Title of "SMA_20", which already exists. But SMA(CLOSE, 20) is different to SMA(HIGH, 20). So the correct Column Title to use in this case is "SMA_OHLC_Setting01".

OHLC will get substituted with "CLOSE" or "HIGH", and Setting01 will be substituted with "20" or "50". That gives us 3 different Column Titles: SMA_CLOSE_20, SMA_CLOSE_50, SMA_HIGH_20.

But if the person used SMA(CLOSE, 20) three different times, then the SMA_CLOSE_20 column will only be calculated once.

The message is - your Column Title needs to work out to be unique based on the options available.

Lastly, don't use any of Column01-Column20 in the title.

See also:

Creating Indicators

Custom Indicators have 2 parts - their Columns, and the Indicators that correspond to those Columns. So creating the Indicators is the second part of a two part process. The first step is to create the Columns.

With the required Columns done, create an Indicator for each Column that you want to be able to chart / use in trading rules / use in alerting rules.

You'll need to give each Indicator 3 different names:

  1. A name that the user will see in the list of indicators.
  2. A name that will have the specific parameters the user chose substituted into it, for display in the Alert and Trading System windows.
  3. A name that will have the specific parameters the user chose substituted into it, for display on the Charts window.

Here's an example:

  1. Simple Moving Average
  2. Simple Moving Average(OHLC; Setting01) becomes Simple Moving Average(CLOSE, 20)
  3. SMA(OHLC; Setting01) becomes SMA(CLOSE, 20)

Generally you want the Chart description to be as short as possible. Also, the chart doesn't handle full-stops/periods/decimal points very well, so don't use those in the name.

Also, don't use any of Column01-Column20 in any of the titles.

Next are the options to choose from which describe what that Indicator does. Is this an overlay? Does the user have to choose the OHLC? Are they allowed to multiply or add to the result? And so on. I think self-explanatory.
 

Settings

Then come settings. Each Indicator is allowed 6 settings. And what these settings do are feed values into the Columns.

Some functions need parameters. The Simple Moving Average needs a column to average, plus a period. E.g. SMA(CLOSE, 20). The user gives the parameters to the Indicator, the Indicator passes them to its corresponding Column, and the Column passes them to whatever function is being used in that Column.

It is up to you then, as the creator of a Custom Indicator, to ensure that the settings you setup for the Indicator match those that are required by the Column.

Whether the user needs to select the OHLC or not; how many settings are required; how many decimal points each setting has; are all set on the Indicator, not the Column.

When used in expressions or formula, settings are written as Setting01, Setting02... Setting06.

E.g. here you as the creator of the custom indicator are explicitly setting Column01 to equal the Simple Moving Average of period 20 of the CLOSE:

Column01 = SMA(CLOSE, 20)

Whereas if you wanted to let the user decide what the period should be, it would look like this:

Column01 = SMA(CLOSE, Setting01)

You then specify on the Indicator that Setting01 is required, and fill in the rest of its details (e.g. zero decimal places, and default value is 20).

If you also wanted to let the user choose any of the open, high, low, or close to take the average of, on the Indicator there is a setting for that - "OHLC required". Choose that option, and your formula looks like this:

Column01 = SMA(OHLC, Setting01)

Similarly, a simple moving average of the Commodity Channel Index is:

Column01 = CCI(Setting01)
Column02 = SMA(Column01, Setting02)

On the Indicator you set up both Setting01 (the period for the CCI - zero decimals, default 50) and Setting02 (the period for the SMA - zero decimals, default 20). OHLC not required.

See also:

Bars Required Formula

Less bars means faster processing, and so ATM tries to retrieve the minimum possible. When something like a simple moving average (SMA) is used, it's pretty easy to work out how many bars are required - if it's SMA(20) then ATM retrieves 20 bars.

And this is what the Bars required formula is used to calculate. In our example, just enter:

Setting01

You would use Setting01 because that's the setting where the Indicator gets the SMA period. All good? How about this example:

Column01 = RSI(Setting01)
Column02 = SMA(Column01, Setting02)
Column03 = Column02 * Setting03

There are potentially 3 indicators here:

  1. Points to Column01 - the RSI over a user-defined period
  2. Points to Column02 - the user-defined average of that RSI
  3. Points to Column03 - multiply the average by some value as set by the user

For Indicator #1, the bars required formula is simply:

Setting01

For Indicator #2, the bars required formula is like this:

Setting01 + Setting02 - 1

You need X number of bars to calculate the RSI, then you need Y RSI values to calculate its average. As it turns out, the total number of bars required equals X + Y - 1. Now, you could just enter:

Setting01 + Setting02

Because seriously, 1 extra bar will make zero difference. And this second formula feels logical enough.

For Indicator #3, the bars required formula is the same as for Indicator #2. Setting03 is just used as a multiplier and so doesn't add anything as far as the bars required is concerned.

Lastly, don't use any of Column01-Column20 in this formula. In fact no column names should be required. This is calculated the same as an expression column though, so any mathematical formula is fine, as is obviously Setting01-Setting06.

See also:

Expressions and Aggregates

A Column can either be an expression, or an aggregate.

An expression works only on values in the same row as each other.

An aggregate could work on 1 or more row.

From our previous example, we had 2 Columns:

  1. D = B - C
  2. E = AVG(D1:D12)

Column D is an expression column. Column E is an aggregate.

As another example, here's an expression column which adds 10 to the value in Column01, divides it by 5, and the subtracts from it the value in Column02:

((Column01 + 10) / 5) - Column02

And here's an aggregate column which gets the maximum close over the last 20 bars:

MAX(CLOSE, 20)

You can't mix the two. Columns are either one or the other.
 

Expression Columns

Expressions can be as complex and have as many brackets as you like, just as long as only values in the same row are being used. E.g.:

(((Column01 * 1.015) + (Column01 / 1.015)) - (Column02 / Column01)) / 3
 

Aggregate Columns

Aggregate columns can have only one function, and in the parameters field you are not allowed to type any brackets. Whereas normally you might think of a function being written like this:

SMA(CLOSE, 20)

And in fact that's how we write them on this website, in ATM you select the SMA as being the function to use, and then in the parameters field you just type:

CLOSE, 20

You also cannot use a formula like:

SMA(RSI(14), 20) * 1.015

While mathematically correct, ATM is rather dumb in that regard. Firstly, there are 2 functions being used - SMA and RSI, and we just mentioned that only 1 function is allowed per aggregate column. And secondly, multiplying by 1.015 makes it a combination of aggregate and expression - also not allowed.

Instead, use multiple columns:

Column01 = RSI(14)
Column02 = SMA(Column01, 20)
Column03 = Column02 * 1.015

Another example:

(MAX(CLOSE, 20) - MIN(CLOSE, 20))/20

Should be:

Column01 = MAX(CLOSE, 20)
Column02 = MIN(CLOSE, 20)
Column03 = (Column01 - Column02)/20

And then of course you are free to add more calculations, e.g:

Column04 = SMA(Column03, 50)
Column05 = SMA(Column03, 100)
Column06 = Column05 - Column04
Column07 = STDDEV(Column06, 14)
etc...
 

PREV

What if you don't want to SUM or SMA the last 20 rows or something like that - you just want to get a value from a previous row, e.g. CLOSE of the current bar minus the CLOSE of the previous bar:

CLOSE(k) - CLOSE(k-1)

For this there is a PREV function, and being a function, you need to use an aggregate column. So in this particular example of using the close price of 1 bar ago you'd need to:

Column01 = PREV(CLOSE, 1)
Column02 = CLOSE - Column01

Here, Column01 is used to pull the previous value into the same row (but a different column), and Column02 finally does the calculation you wanted.
 

Restriction

While the PREV function can get a value from a previous row, it only works when you're getting that value from a different Column. You cannot create a Column which references its own previous values (self-referential). Welles Wilder Moving Average, Exponential Moving Average, etc, build upon their own previous values. You won't be able to make such an indicator yourself. If the current aggregate formulas aren't enough for you, then you will need to contact us so we can add a new one for you.
 

Allowed operators

For expression columns, you are free to use any combination of these:

  • + (addition)
  • - (subtraction)
  • * (multiplication)
  • / (division)
  • ( ) (brackets) - of course opening and closing brackets must match

For aggregate columns, you are provided with a list of aggregate functions in the window. To have further aggregate functions added you would need to contact us. Most formula are provided by a free 3rd-party tool from http://ta-lib.org

Any function that wants a column name for a parameter (e.g. "Source column", "High column", etc), you can use:

  • Any of the calculated columns (Column01 to Column20)
  • OPEN (ATM decides whether to use OPENBID or OPENASK)
  • HIGH (ATM decides whether to use HIGHBID or HIGHASK)
  • LOW (ATM decides whether to use LOWBID or LOWASK)
  • CLOSE (ATM decides whether to use CLOSEBID or CLOSEASK)
  • OPENBID (you explicity want to use OPENBID)
  • OPENASK (you explicity want to use OPENASK)
  • HIGHBID (you explicity want to use HIGHBID)
  • HIGHASK (you explicity want to use HIGHASK)
  • LOWBID (you explicity want to use LOWBID)
  • LOWASK (you explicity want to use LOWASK)
  • CLOSEBID (you explicity want to use CLOSEBID)
  • CLOSEASK (you explicity want to use CLOSEASK)
  • VOLUME
  • OHLC (let's the user decide whether to use OPEN/HIGH/LOW/CLOSE)

E.g. a simple moving average of the CLOSE is:

Column01 = SMA(CLOSE, 20)

And a simple moving average of the Commodity Channel Index is:

Column01 = CCI(50)
Column02 = SMA(Column01, 20)
 

Columns which use other columns

Make sure if a Column uses the result of other Columns, that those being used go first. i.e:

Column03 = Column01 + Column02

Not this:

Column01 = Column03 + Column02
 

ISNULL and IIF

There are actually 2 substitution functions which will work in expression columns: ISNULL and IIF.

ISNULL lets you substitute a default value if the column you are working on doesn't have any values yet. The whole formula is:

ISNULL(column_to_check, value_if_empty, value_if_not_empty)

The raw data will never be empty, but you might need ISNULL if you are basing the calculation on another calculated column. Take this example:

Column01 = SMA(CLOSE, 20)
Column02 = Column01 - CLOSE

The first 19 cells in Column01 will be empty (NULL). The first 19 cells of Column02 then, will have an invalid result ("empty" minus 1.2345 equals computer crash). Try this instead:

Column01 = SMA(CLOSE, 20)
Column02 = ISNULL(Column01, 0, Column01 - CLOSE)

Or this, depending on what you want the result to be for those first 19 cells:

Column01 = SMA(CLOSE, 20)
Column02 = ISNULL(Column01, 0, Column01) - CLOSE

Note the changed location of the closing bracket. The first example sets the entire result to zero if Column01 is empty. The second example just uses zero for Column01 if it happens to be empty. Completely different results.

And remember that we can only do it the second way because ISNULL is one of the two substitution functions that can be used in expression columns. You can't do this:

SMA(CLOSE, 20) - CLOSE

For reasons outlined a few times in the paragraphs above.

IIF similarly lets you substitute in a value, but not restricted to only when a column is empty. The whole formula is:

IIF(condition_to_check, value_if_true, value_if_false)

As an example, let's turn all negative values into positive ones. If Column01 is already positive then leave it alone. Otherwise multiply by -1:

Column01 = OPEN - CLOSE
Column02 = IIF(Column01 > 0, Column01, -1 * Column01)

Let's expand on that example, and say that you want to multiply the result by 100. Because IIF can be used in expression columns you have 3 choices. This:

Column01 = OPEN - CLOSE
Column02 = IIF(Column01 > 0, Column01 * 100, -1 * Column01 * 100)

Or this:

Column01 = OPEN - CLOSE
Column02 = IIF(Column01 > 0, Column01, -1 * Column01) * 100

Or this:

Column01 = OPEN - CLOSE
Column02 = IIF(Column01 > 0, Column01, -1 * Column01)
Column03 = Column02 * 100
 

Summary

With 20 columns, and a mixture of expressions and aggregates, you should be able to make up just about any formula required. Just each individual column's formula has to be fairly trivial.
 
See also:

Upper Limit Of Columns And Indicators

You can create up to 20 columns. They are referred to as Column01, Column02, Column03... Column10, Column11... Column20. When using the column names in formulas, you can't write "Column1" - it has to be written "Column01".

There is no theoretical limit to the number of Indicators you can create. But because each Indicator corresponds to one Column, it wouldn't make much sense to create more than 20 Indicators. (Unless you wanted to give the same line different names).
 

Custom Indicators Are Like Spreadsheets

A spreadsheet, like Microsoft Excel, is simply a series of rows and columns. In a spreadsheet you normally have columns filled with "raw" data, and next to those you have calculated columns. Take for example a spreadsheet you might set up to track your savings. Each month you enter how much money you earned during the month (income) and also how much money you spent during the month (expenses). The column headings for the raw data would be something like:

  • A: Date
  • B: Income
  • C: Expenses

The column headings for the calculated columns might be:

  • D: Monthly Saving = Income - Expenses
    D = B - C
  • E: Average Monthly Saving over the last 12 months
    E = AVG(D1:D12)

And there you have it - 3 columns of raw data, and 2 calculated columns. As you fill in the raw data, the calculated columns are filled in for you.

You could even create a chart of "Date vs Monthly Savings", and/or "Date vs Average Monthly Saving".

And that is pretty much how custom indicators work...
 

Just think of a spreadsheet

The raw data is the date, open, high, low, close, and volume of each price bar.

You create the calculated columns (referred to simply as Columns). Just like the spreadsheet example above. Sometimes the calculations are very simple, like D = B - C. And sometimes there's a formula involved, like E = AVG(D1:D12). That's it. Easy. Well actually there is one more step...

Here's where we diverge from the example a little bit... For any Column that you want to be able to chart (or use in trading systems or alerts), you need to create a corresponding Indicator. An Indicator points to just one Column, so it means the Indicator corresponds to one line on a chart.

If you think of the Bollinger Band indicator, you normally think of 3 lines - upper, middle, and lower. But for our purposes, those are actually 3 different Indicators:

  1. Bollinger Band Upper Line
  2. Bollinger Band Middle Line
  3. Bollinger Band Lower Line

Why wouldn't every Column be considered an Indicator? Because sometimes you need to use several Columns to do sub-calculations before finally being able to calculate the indicator proper. There is of course no harm in creating an Indicator for all Columns - it only makes the Indicator available for charting or for using as a trading/alerting rule - it doesn't mean you have to use it.

See also:

Using Indicators With Non-Standard OHLC

All of the pre-made custom indicators use the standard Open, High, Low, Close, Volume columns for their calculations (where those columns are required).

You can though, if you wish, create new custom indicators which use any column of your choosing.

For example, let's say that you want to check for the "Three Black Crows" candlestick patterns on Heikin-Ashi bars, rather than the standard OHLC bars.

For this you will need to use a total of 5 columns - the first 4 create the Heikin-Ashi bars, the 5th is for the candlestick. The easiest way to set this up is to export the "Heikin-Ashi" custom indicator (or the one closest to what you want to do). Then re-import, changing the ID and name of the custom indicator.

This is now your indicator and you can modify it however you like. As it already creates the Heikin-Ashi bars in the first 4 columns, all we have to do is add the 5th column with our candlestick calculations:

  1. Edit the column.
  2. Click the "Is Required" box.
  3. Select the function name of "Three Black Crows"

Now that we have done that, the required arguments are written out for us in the field:

Open column, High column, Low column, Close column

What we have to do is replace those arguments with the column names we want to use. In the pre-made custom indicator for candlesticks, we always use:

OPEN, HIGH, LOW, CLOSE

However, in this example you want to use the Heikin-Ashi bars instead. So for the open column, type "Column01". This corresponds to the column where the Open price of the Heikin-Ashi bar is calculated. For the high, type "Column02", and so on. So the arguments field now reads as:

Column01, Column02, Column03, Column04

The candlestick calculations will now check the Heikin-Ashi bars instead of the standard OHLC bars. But there's one step left. We have to make the column title unique. The standard title is:

CDL3BLACKCROWS

If you choose the same column title, then it will cause problems if someone uses both the standard Three Black Crows candlestick pattern and your new one in the same trading system, alert, or chart (which you are likely to do when testing your new indicator). So name it something like:

CDL3BLACKCROWS_ASHI

Anything really - as long as it's unique.

That's the column finished. Then you create the Indicator which points to this column (points to Column05 in this example). Test that it works on the "Indicator Test" window. And finally chart. If you're happy then you can use it in your trading systems.

See also:

Bar Swings, SMA Swings

 
Bar Swings

Look at two bars which are next to each other. We'll call them Bar #1 and Bar #2.

It's a "Bar Swing Up" when the High of Bar #2 is higher than the High of Bar #1.

It's a "Bar Swing Down" when the Low of Bar #2 is lower than the Low of Bar #1.

Should both conditions be met, that is there is an "outside bar", it's:

  • a Bar Swing Up when the Close of Bar #2 is in the upper half of the candle; and
  • a Bar Swing Down when the Close of Bar #2 is in the lower half of the candle.

If none of those conditions are met, it's neither a Bar Swing Up nor Down.

A Swing Up is always followed by a Swing Down, and vice versa. There is never a Swing Up followed by another Swing Up.

When a Bar Swing Up occurs, you can also calculate the "Bar Swing Low". That's the lowest price between this Bar Swing Up and the Bar Swing Down immediately before it.

When a Bar Swing Down occurs, you can also calculate the "Bar Swing High". That's the highest price between this Bar Swing Down and the Bar Swing Up immediately before it.
 

SMA Swings

A Bar Swing but where the price also closes above/below the simple moving average (SMA). Perhaps a strong signal as Bar Swings can happen every few bars, whereas SMA Swings happen far less often.

The truth is that this can be applied to any overlay - not just the simple moving average. The "SMA Swings" custom indicator is provided as an example. If you wanted to use a different overlay, like the Upper Bollinger Line, or a Fibonacci Level, then copy this custom indicator and just change the calculation of Column #1.