-
Notifications
You must be signed in to change notification settings - Fork 249
Introduction to scripting
Indicator scripting is just javascript with a sprinkles of aggr specific things in it.
I will be executed everytime the chart need a refresh, default is 1s, see refresh rate
in the chart options.
So the goal when writing those is to go straight to the point, and void loops, conditions as much as possible.
vbuy
amount of buys (reported amount of buys at market)
vsell
amount of sells (reported amount of sells at market)
cbuy
number of market orders executed on buy side
csell
number of market orders executed on sell side
lbuy
amount of short liquidations
lsell
amount of long liquidations
time
alias for renderer.localTimestamp
renderer
(or bar
, alias of renderer
) internal object describing the current state of the chart
{
type: 'time' | 'tick' // type of timescale
timeframe: number // current timeframe in second for time type, number of ticks for tick type
timestamp: number // epoch time for time type, origin bar epoch time + number of ticks for tick type
localTimestamp: number // timestamp adjusted with timezone offset
length: number // number of bars drawn (including this one)
bar: Bar // simplified bar with volume sums of each activated sources
sources: { [name: string]: Bar } // all sources bars (including the hidden ones)
}
series
internal array containing the series API of the current indicator
fns
internal array containing all utility function states
-
avg_close(bar: Bar)
: number
return the averaged close of all activated sources in the given bar object -
avg_ohlc(bar: Bar)
: {OHLC}
return the averaged ohlc object of all activated sources in the given bar object -
avg_heikinashi(bar: Bar)
: {OHLC}
return the averaged Heikin Ashi ohlc object of all activated sources in the given bar object -
ohlc(value: number)
: {OHLC}
create a ohlc object out of a single value
wicks will only be visible using realtime data (as the script will be executed multiple for each bars) -
cum(value: number)
: number
return the current value + value of the previous candle -
cum_ohlc(value: number)
: {OHLC}
same asohlc
except the output is cumulative -
highest(value: number, length: number)
: number
return the highest value within the last n bars -
lowest(value: number, length: number)
: number
return the lowest value within the last n bars -
pivot_high(value: number, length: number)
: number | null
using length as the total range of bars to cover, left and right being equal to length / 2 search for a value greater n bars on the left and n bars on the right -
pivot_low(value: number, length: number)
: number | null
same as pivot_high but instead will search for the low -
avg(value: number[])
: number
simple average of a given set of values -
sum(value: number, length: number)
: number
return the sum of the last n values -
linreg(value: number, length: number)
: number
return the linear regression of a source (non optimized) -
ema(value: number, length: number)
: number
return the exponential moving average of a source -
sma(value: number, length: number)
: number
return the simple moving average of a source
-
line(value: number)
Plot line -
candlestick(ohlc: OHLC)
-
candlestick(open: number, high: number, low: number, close: number)
Plot candles -
bar(ohlc: OHLC)
-
bar(open: number, high: number, low: number, close: number)
Plot OHLC (the one without body) -
histogram(value: number)
Plot histogram bars, supports dynamic coloring -
area(value: number)
Plot line with a gradient fill below it (from 0 to line) -
cloudarea(lowerValue: number, higherValue: number)
Fill a continuous range, supports dynamic coloring
Used for ichimoku, ma ribbon, bb -
brokenarea(lowerValue: number, higherValue: number)
Same as cloudarea except it can have breaks (much like floating rectangles) Used to plot S/R, pivot points
All plotting functions takes options arguments that you add after the ones described above. All series options are documented here.
Simple line coloring and a title
line($price.close, color=red, title=BTCUSD)
Simple line with custom color and width using option
line($price.close, color=options.color, lineWidth=4)
The histogram series custom coloring require that you enter the full plot object into the plotting function
histogram({
time: time,
value: vbuy - vsell,
color: vbuy > vsell ? 'green' : 'red'
})
Cloud area use dedicated option for when higherValue is above or below lowerValue
ma50=sma($price.close, 50)
ma20=sma($price.close, 20)
cloudarea(ma50, ma20, positiveColor=options.bullColor, negativeColor=options.bearColor)
Note that all series options are set when the serie is created and CANNOT change during it's execution.
Because of that, sadly, the following script won't work :
var change = myvar - myvar[1]
var color = myvar > 0 ? 'green' : 'red'
line($price.close, color=color)
Accessing the series API let you use the priceLine feature from Lightweight Charts. You can come up with a script showing current support and resistance and use :
if (certainConditionMatch) {
if (buyhere) {
// remove previous line
series[0].removePriceLine(buyhere)
}
buyhere = series[0].createpriceline({
price: 41365, // y
index: bar.length, // x
title: 'right there'
})`
}
You attach horizontal lines to an existing series. The serie will define which scale the lines will use.
See price line documentation for details about horizontal lines.
Within an indicator, the first plotted series is below the last plotted one.
Accross multiple indicators, the first one to get processed will be in back, last in front.
Note that an indicator being required by another will always get processed before the other, and plotted before as well meaning it will be shown below the one requiring it.
Grouping all your plots in the same indicator is the only way around it ATM.
// first get the avg price ohlc
var price = avg_ohlc(bar)
// do whatever with it
line(sma(price.close, 50))
line(sma(price.close, 100))
line(sma(price.close, 200))
// then plot price
candlestick(price)
All occurences of 'options.youOptionName
from the script is automatically attached to an setting in the indicator window.
The value and name of the option will determine the type of input that will appear in the indicator window, according to the following rules :
- an hex / rgb color as a value will show a color picker
- if the name start with "show" or "toggle" the option is a checkbox
- a default value of
14
if option name end with the word 'length' - a default color of
#c3a87a
if option name end with the word 'color' - otherwise it's a simple number input which reacts to mouse wheel, up/down arrow etc)
Define a variable by writing an alphanumeric string (no dash, no underscore) in front of the =
sign.
The declaration will not work if the variable is wrapped.
myvar=1
console.log(myvar) // 1
myvar
is now accessible and stored in the indicator state.
From there, you can use it in any operations or plot :
if (time % (60 * 60) === 0) {
myvar = 0
}
myvar += 1
line(sma(myvar, 14))
or and access its previous value
myvar=$price.close
var change = myvar - myvar[1]
histogram(sma(change, 14))
console.log(change) // output the difference
console.log(myvar) // output the last close
console.log(myvar[0]) // same
console.log(myvar[1]) // output previous close
console.log(#myvar) // prefixing the var name with a '#' will give you the full values of that var [number, number]
console.log(avg(#myvar)) // the # is perfect for avg function which require a set of values
The moment you start accessing past value of a variable, it becomes an array with length = the maximum bars that will get requested in the script.
myvar=$price.close
console.log(myvar[0], myvar[1], myvar[10])
console.log(#myvar.length) // 11 assuming the chart have more than 10 bars in it
You can force a variable to retain a certain number of values by wrapping the length in parenthesis when declaring it
myvar(10)=$price.close
console.log(avg(#myvar)) // average of last 10 bars
If a variable is only temporary and has no persistance requirement it is recommended to prefix it with a var
.
This way it won't be included in the indicator state, in this example myvar is always undefined at the beginning of the script.
var myvar=vbuy+vsell
And WILL improve the memory footprint of your script.
Indicator's variables and functions have their own state, which is used by the chart to know what the previous values was
All periodic functions (like sma, ema, sum etc) have a "sum", "count", and "points" state as described here.
Even tho you won't need it most of the time these states can be mutated from the indicator script itself.
// hourly VWAP
if (time % (60 * 60) === 0) {
// top of the hour
// clear both 'sum' fns states
// bit hacky but it works 🤡
fns[0].state.sum=fns[1].state.sum=0
fns[0].state.count=fns[1].state.count=0
fns[0].state.points=fns[1].state.points=[]
}
vol = vbuy + vsell
pricevol = $price.close * vol
line(sum(pricevol, options.length) / sum(vol, options.length))
In aggr term a source
is a market
aka an association of exchange
+ symbol
where the symbol is a association of base currency
and quote currency
.
COINBASE:BTC-USD
You can reference those in the script as long as the pane is listening to it.
On runtime the given source is transformed to an reference of the bar source object
renderer.sources['COINBASEBTC-USD']
Which contains the following properties
{
open: number,
high: number,
low: number,
close: number,
vbuy: number,
vsell: number,
csell: number,
csell: number,
lbuy: number,
lsell: number,
pair: string,
exchange: string,
active: boolean,
empty: boolean,
}
This ensure only the coinbase price is plotted
line(COINBASE:BTC-USD.close, title=BTCUSD)
Same as above but in the form of candlesticks
candlestick(COINBASE:BTC-USD.open, COINBASE:BTC-USD.high, COINBASE:BTC-USD.low, COINBASE:BTC-USD.close)
Creating custom indexes
candlestick(ohlc((COINBASE:BTC-USD.close + BITSTAMP:btcusd.close + BITFINEX:BTCUSD.close) / 3), title=CustomIndex)
Plots reference is crucial to getting a decent performance score on the chart.
For example I wouldn't call avg_ohlc
more than once on the whole chart.
Indicator has a name
and an id
which is generated from the name (special characters are replaced with dash, always lowercase, and unique across all indicators)
Prefix the id of another indicator with a $
to get his value. Assuming you have a "Price" indicator which is enabled by default, you can create an indicator and do that :
line($price.close)
It will work because the indicator Price only have one plot, in that case l'ID of the plot become the indicator ID.
But you might have many plots in a single indicator. In that case best option is to pass an id option in the plotting function.
In indicator 1
plotcandlestick(avg_ohlc(bar), id=test)
In indicator 2
line($test.close)