TapeHawk Docs
Custom indicators

Examples

The eight starter scripts in the indicator editor's Examples list, each shown and explained line by line.

The Examples… list in the indicator editor loads eight starter scripts. Loading one replaces the script in the dialog and opens it on the Source tab, ready to change and save under a name of your own.

The scripts below are shown without the comments they carry in the editor, which explain the same points more briefly. Each is explained here line by line. Every function and clause is described in the Language reference.

Moving average — one parameter

ema.ind
input len = 20, min 2, max 50plot line = ema(close, len)

The smallest indicator that draws: one setting and one line.

  • input len = 20, min 2, max 50 makes a setting called len, starting at 20. On a panel it becomes a control that accepts 2 to 50 — the bounds you declare can narrow TapeHawk's own, never widen them.
  • plot line = ema(close, len) draws the exponential moving average of the closes over len bars.

The line starts once len bars have closed — on the 20th bar at the default, which is why the editor reports 19 bars of warm-up. A save's warm-up limit is checked at the largest value len may take, 50.

MA ribbon — three lines, one parameter

ma_ribbon.ind
input len = 10, min 2, max 30plot fast = ema(close, len)plot mid  = ema(close, len * 2)plot slow = ema(close, len * 4)

Three averages from one setting: len, twice len and four times len. A window length can be arithmetic on inputs, because it is worked out before the script runs — len * 2 is allowed, while a length read from price is not. With every line a price, the ribbon is drawn over the candles.

Breakout channel — highest and lowest

breakout.ind
input len = 20, min 5, max 100top = highest(high, len)bot = lowest(low, len)plot upper = top, domain priceplot lower = bot, domain price

The channel between the highest high and the lowest low of the last len bars.

  • top and bot are intermediate values: named once, then plotted.
  • domain price on each plot says the line is a price. The checker could work it out here, and saying it keeps the indicator over the candles even after the expression changes.

To test for a close breaking out of the channel, compare with the channel as it stood a bar earlier — close > prev(top) — because top already includes the current bar's high, so close > top is never true. Being told when it happens needs a mark, which a candle script cannot declare — see mark.

Trailing stop — state carried with var

trailing_stop.ind
input pct = 2, min 0.1, max 20band = close * pct / 100var stop = 0 - infif close - band > stop    stop := close - bandif close < stop    stop := close - bandplot line = stop, domain price

A stop that follows price up and never moves down while price stays above it.

  • band is pct percent of the close.
  • var stop = 0 - inf gives stop a starting value on the first bar only — minus infinity, so the first comparison always raises it. After that, stop keeps its value from bar to bar.
  • The first if raises the stop to band below the close whenever that is higher than where the stop already is.
  • The second if resets the stop below the price when a close falls under it, so a new trail starts.
  • := gives an existing name a new value; = would have declared a new one.

Up-bar streak — if, else if and and, or, not

streak.ind
input minLen = 3, min 2, max 20up = close > prev(close)strong = close > openvar run = 0if up and strong    run := run + 1else if not up    run := 0else    run := 1plot line = run, domain count

Counts bars in a row that closed higher than the bar before and above their own open.

  • up and strong are conditions: 1 when true, 0 when false.
  • A strong up bar adds one to run. A bar that did not close higher resets it to 0. An up bar that closed at or below its open starts again at 1.
  • On the first bar prev(close) has no value, so up is false and the count starts at 0 rather than at a made-up number.
  • domain count draws the count in a band of its own.

The minLen input is declared but not used by any line, so changing it changes nothing.

Symbol on a big print — mark on the trade clock

print_mark.ind
@printinput minQty = 1, min 0, max 1000000, step 1notional = qty * pricemark big = notional >= minQty, side aggressor, value qty, cap 10, glyph circle

A circle on every trade whose value reaches a threshold.

  • @print runs the script once per trade instead of once per bar, with the trade's price, qty and aggressor as sources.
  • notional is the trade's value in the quote currency, so the same threshold means the same amount of money on any symbol. Despite its name, minQty is compared with that value.
  • The mark would sit on the side that took the trade (side aggressor), labelled with the trade's size (value qty), at most ten a minute (cap 10), as a circle.

At its default of 1, almost every trade qualifies and the cap does the limiting; raise minQty to keep only large trades.

The preview draws the circles on a heatmap panel. Saved, the script is offered in a heatmap panel's indicator menu under My indicators, where minQty is a setting — see Your indicator on a chart.

Book pressure — resting size on the order book

book_pressure.ind
@book@group flow@title text(name)@desc text(about)@render band, includeZeroinput domFrom = 1, min 0, max 4000, step 1input domTo = 60, min 1, max 4000, step 1input halfLife = enum(15, 30, 60, 120, 300), def 60input weighted = bool falseplot imbalance = book_imb(domFrom, domTo, weighted, halfLife), domain zero, style signed, color "#ef6c00"@text  name  en "Book pressure" vi "Áp lực sổ lệnh"  about en "Which side has more size resting, over a DOM range measured in ticks." vi "Bên nào đang chờ nhiều hơn, đọc trên một dải DOM tính bằng tick."

Which side of the order book has more size waiting, over a range of prices measured in ticks from the middle price.

  • @book runs the script on every order-book update, rather than on trades.
  • domFrom and domTo set the range: domFrom 0 includes the best bid and ask, 1 starts one tick away.
  • book_imb reads +100 when all the size in that range rests on the bid and -100 when it all rests on the ask, smoothed over halfLife seconds; weighted makes levels near the price count more.
  • style signed draws bars coloured by sign, around zero.

It draws on a heatmap panel, in the preview and once saved — see What the preview can draw. The order book is not recorded for replay, so the line starts empty and fills in to the right. What was pulled from the book at each price is a different question, answered by the Liquidity Changes indicator.

Delta, minimal — the trade clock and its warm-up

vdelta_min.ind
@print@group flow@title text(name)@desc text(about)@render band, includeZeroinput halfLife = enum(15, 30, 60, 120, 300), def 60plot line = select(flow_warm(halfLife), flow_delta(halfLife), 0 / 0), domain zero, color "#26a69a"@text  name  en "Delta (minimal)" vi "Delta (bản gọn)"  about en "Aggressive buying minus aggressive selling, decayed over time not over a bar." vi "Mua chủ động trừ bán chủ động, nhạt dần theo THỜI GIAN chứ không theo cây nến."

Aggressive buying minus aggressive selling, fading over time rather than resetting with each bar.

  • flow_delta(halfLife) weighs each trade by how long ago it happened: a trade halfLife seconds old counts half. Only the five listed half-lives exist, and def 60 picks the default.
  • flow_warm(halfLife) is 1 once the measure has run long enough. Until then select gives 0 / 0, which is nan, so the line stays blank instead of climbing out of a zero start. The script would stay blank until then anyway: while a flow_ measure it reads is cold, every line is blank.
  • The lines at the top — @group, @title, @desc, @render — and the @text table at the bottom are how TapeHawk's own indicators describe themselves. For an indicator you save they change nothing on the chart — see Directives. The table gives each text in English and Vietnamese.

On this page