-
Notifications
You must be signed in to change notification settings - Fork 0
Performance and Limits
What actually costs you something when you use this library on a chart. Two of the three sections are about loops; the first is about a limit that turns out not to apply to you at all.
Importing a library does not spend your compiled-token budget. A library compiles as its own unit, and the import does not copy its code into the importing script.
That is measured, not assumed. A probe script importing std_time alongside a
6,000-character string constant, which is about 12,000 compiled tokens on its
own, adds to a chart cleanly. If the library's weight counted, the total would
be roughly 104,000 against a 100,256 cap and the compile would fail. It does
not.
So the numbers below are history, not a tax. They are here because they explain an otherwise baffling piece of the source, and because they matter if you ever publish a library of your own.
TradingView's publish limit is 100,256 compiled tokens, enforced only when a
script is added to a chart and not by the server-side syntax check. String data
costs two compiled tokens per character. std_time compiles at roughly
92,000, but the dated closure tables originally pushed it to 104,509,
over the cap. Re-encoding 1,227 dates as three-character base-36 day numbers
saved 6,135 characters, about 12,000 tokens, and brought it under. That is why
the closure tables are unreadable base-36 keys rather than yyyymmdd.
If your own script ever does hit the cap, your string constants are the first place to look, at two tokens per character.
Most of the library is closed-form arithmetic. These are the ones that iterate, with the bounds the source documents.
| Call | Walks | Bound |
|---|---|---|
plus_trading_days(n, ex) |
Calendar days until n trading days are found |
abs(n) * 2 + 30 days, then raises
|
minus_trading_days(n, ex) |
Same, delegated with -n
|
Same |
adjusted(conv, ex) |
Outward to the nearest trading day | 30 days, then raises |
next_expiry_after(...) |
Forward for a trading day | 30 days, then raises |
trading_day_of_month() |
From the 1st of the month | Up to 31 days |
next_fomc_after(ms) |
Forward through the table | Up to 401 days |
window_before / window_after
|
Backward or forward for a session day |
max_days, default 10 |
The raises are deliberate. Running out means the calendar data is wrong, and returning the cursor would give you neither the answer nor necessarily a trading day.
holidays_between, expiries_between and windows_between all raise when
the span exceeds 20,000 calendar days, roughly 54 years. They do not return
a partial answer.
windows_between documents a companion bound: at most one window per start
date over a scan that begins one date early, so never more than 20,002
entries. That number exists so you can size a drawing pool from it rather than
guessing.
Derive spans from what you are actually drawing:
// bounded by the visible range, not by the whole chart
int from_ms = chart.left_visible_bar_time
int to_ms = chart.right_visible_bar_time
This is the reason a thirty-year count is possible at all.
Asking the calendar day by day costs one full holiday-chain call per day. Over thirty years that is about 11,000 of them, and on the tabled calendars each one searches a table of several kilobytes. That is enough to reach Pine's per-loop time limit, which is a runtime error rather than merely slow.
trading_days_between and holidays_between invert it. They propose the
handful of days a calendar could possibly shut on, test only those with the same
is_holiday every other accessor uses, and subtract from a closed-form weekday
count. In practice that tests between 3 and 16 per cent of the days in a
span.
The proposal is deliberately generous and is allowed to be wrong in one direction only. A day proposed that is not a holiday gets discarded by the filter; a day never proposed would be invisible. So the anchors are a superset over each calendar's whole modelled range, not only the years a reference reaches.
Nothing here allocates per bar unless you ask it to, but the walkers are still work. Three habits cover most of it:
-
Hoist what does not change. A
Sessionor anExchangeis configuration. Build it once withvar, not on every bar. -
Compute date-heavy things on the bars that need them. A holiday scan for a
table you draw once belongs under
barstate.islast, not in the main path. -
Do not put a walker inside a loop.
plus_trading_daysin a loop over bars is the shape that reaches the per-loop time limit.
windows_between and holidays_between return arrays, and Pine caps boxes,
lines and labels at 500 each. The 20,002 bound above is what lets you size a
pool safely; the pool itself is your script's responsibility.
Previous: Verification · Next: Versioning and Data Currency · See also: Scope and Limitations
std_time v1 · API Index · Task Index · Scope and Limitations · Verification
Calendar data current to the horizons on Versioning and Data Currency. Shanghai, Bombay and Singapore answer exactly through 2026.
MPL-2.0 · Copyright (c) 2026 Jesse Sanford · published on TradingView as The_Peaceful_Lizard
Start here
The model
- Core Concepts
- Civil and Exact Arithmetic
- Value Semantics
- Error Model
- Time Zones
- Exchange Calendars
- Trading Days and Day Counts
- Expiries
- Sessions
- Formatting and Parsing
- Choosing the Right Tool
- Pitfalls
Recipes
Reference
- API Index · Task Index
- DateTime
- Session
- Zone
- Exchange
- Period · Interval
- Weekday · Enums
- Free functions
- Glossary
The fine print