millionchart
فارسی

Lesson 9: Sessions and a small table

Mark a trading session, keep a value that starts again each day, show the numbers in a table, and handle bars that have no value yet.

Lesson 9 of 18. Markets have hours. This lesson names a session, measures it, restarts a counter every trading day, prints the result in a table in the corner of the chart, and deals with the empty values that every indicator has on its first bars.

A session#

A session is a daily window of time in a time zone. You declare it once at the top of the file, and then read it through its members.

Cuprel
indicator "London range"
    edition = 1
    display = price

session london = 08:00 .. 16:30 @ "Europe/London"
plot(london.high, name = "London high", color = color.green)
plot(london.low, name = "London low", color = color.red)
chart.background(if london.active then color.fade(color.blue, 92) else na, name = "London open")
  • london.active is true on the bars that open inside the session.
  • london.high and london.low are the highest high and lowest low of the latest session. They run while the session is open and keep their value after it ends, until the next one starts.
  • The time zone is written in the script. Winter and summer time follow the zone, so the session stays at 08:00 London time all year.

A value that starts again each day#

state keeps a value from bar to bar. state day starts it again at the beginning of each trading day, which is the symbol's own day, not midnight.

Cuprel
indicator "Change since the day opened"
    edition = 1

state day day_open = close
plot(close - day_open, name = "Change today", style = histogram)

state day day_open = close takes the close of the first bar of the day and keeps it until the next day starts. A plain state would keep the first close of the whole chart. Trading day and sessions says where a trading day starts.

A small table#

A table is drawn once, on the last bar, in a corner of the chart.

Cuprel
indicator "Range table"
    edition = 1
    display = price

session asia = 00:00 .. 08:00 @ "Asia/Tokyo"
if bar.is_last
    let t = table.new(top_right, 2, 3)
    table.cell(t, 0, 0, "Asia high")
    table.cell(t, 1, 0, f"{asia.high:price}")
    table.cell(t, 0, 1, "Asia low")
    table.cell(t, 1, 1, f"{asia.low:price}")
    table.cell(t, 0, 2, "Range")
    table.cell(t, 1, 2, f"{asia.high - asia.low:price}")
plot(close)

table.new(position, columns, rows) makes the table; table.cell(table, column, row, text) writes a cell. Columns and rows are counted from 0. bar.is_last is true only on the last bar, so the table is built once instead of on every bar.

Bars with no value#

A moving average of 20 bars has nothing to say on the first 19 bars. Those bars hold na, which means "no value". A plot leaves a gap where the value is na.

Three tools deal with it:

  • is_na(x) is true when x is na.
  • In an f-text, {x:.2f?'n/a'} writes a text in place of a number that is na (the table below uses it).
  • a ?? b is a, or b when a is na.
Cuprel
indicator "Distance from average"
    edition = 1

input length: int = 50, name = "Length", min = 2
let average = tech.sma(close, length)
let distance = close - average
plot(distance ?? 0, name = "Distance (0 until there is an average)")
if bar.is_last
    let t = table.new(top_right, 2, 1)
    table.cell(t, 0, 0, "Distance")
    table.cell(t, 1, 0, f"{distance:.2f?'n/a'}")

In the table, {distance:.2f?'n/a'} writes the number with two decimals, or the text n/a when there is none.

Cuprel · warning W-NA-COMPARE
indicator "Wrong na test"
    edition = 1

let average = tech.sma(close, 20)
plot(if average == na then 0 else average)

Try changing#

  • In "London range", follow New York instead: session new_york = 09:30 .. 16:00 @ "America/New_York", and write new_york.high, new_york.low and new_york.active in the three lines below it.
  • In "Change since the day opened", write state day_open = close (without day): the value now counts from the first bar of the whole chart.
  • In "Range table", move the table with table.new(bottom_left, 2, 4) and add a fourth row: table.cell(t, 0, 3, "Close") and table.cell(t, 1, 3, f"{close:price}").
  • In "Distance from average", plot distance instead of distance ?? 0: the line now starts with a gap on the first bars.

Checkpoint#

  • You can declare a session with its hours and time zone and read .active, .high and .low.
  • You can keep a value that starts again every trading day with state day.
  • You can build a table once, on the last bar, and write numbers into its cells.
  • You can handle na with is_na, ?? and the f-text fallback.

See also: Trading day and sessions, Tables, na, errors and arithmetic.

Next: Lesson 10: Other timeframes and symbols