Creating a library
//@version=1
library("MyMa")
export smooth(float source, int length) =>
ta.ema(source, length)
export method square(float this) =>
this * this
export type Pivot
int bar
float price
bool isHigh
Rules the compiler enforces
- The declaration must be
library("Name"). The name must match[A-Za-z0-9_]+— library names ride import paths. - At least one
exportfunction, type, or enum is required. - Every exported function parameter needs an explicit type keyword (
float,int,bool,string,color, a UDT, an enum, an array/map/matrix type). - Exported function bodies cannot call
input.*()or reference globals initialised frominput.*(). Inputs belong to the consuming script. alert()is allowed inside exported bodies; the consumer surfaces the alerts.request.*()is allowed when the library's declaration keepsdynamic_requestsattrue.
Publishing
A library is a script, so publishing is the normal "▷ Publish library" flow from the editor. The result lives at:
<ownerId>/<Name>/<version>
Each save bumps the version — a library at /1 cannot be edited in place; the next save becomes /2. Consumers pin a specific version (import ownerId/Name/1 as m), so your updates never silently reach them.
Importing a library
//@version=1
indicator("Uses MyMa")
import 1000000072/MyMa/1 as m
plot(m.smooth(close, 20), "smoothed")
plot((5.0).square())
- The import path's owner id can be alphanumeric or fully numeric (your platform client id —
1000000072). as aliasis optional; omitted → the alias defaults to the library name.- Imports are top level only. They cannot live inside a function or a conditional.
- Imports are version-pinned:
import x/MyMa/1andimport x/MyMa/2are separate libraries that can coexist in one script.
Libraries importing libraries
A library can import other libraries. The chain is resolved recursively; names imported inside a nested library are available to it under its own alias:
//@version=1
library("Outer")
import 1000000072/Signal/1 as sig
export wrap(float s) =>
sig.smooth(s, 5)
The consumer only sees Outer's exports — the inner Signal import is a private detail.
Circular imports are detected and rejected with the full chain shown.
Visibility
- A library created in your account is private by default — only you can import it.
- Making a library public exposes it to the marketplace's
kind=librarylisting.
Private libraries can still be imported from the editor's "Import library…" dialog by their owner.
Idiomatic style
- Keep library functions pure: a result depends only on its arguments plus the current bar's series values.
- Export every type a function signature references — the compiler enforces this for UDTs and enums.
- Group related helpers in one library rather than splitting fine-grained libraries.
- Document each export with a comment above the
exportline.
Example — a reusable zone helper
//@version=1
library("Zones")
export type Zone
int leftBar
float top
float bottom
color col
export method draw(Zone this) =>
box.new(this.leftBar, this.top, bar_index, this.bottom,
bgcolor = color.new(this.col, 85),
border_color = this.col)
export of(bool isDemand, float px, float atrSize) =>
isDemand ? Zone.new(bar_index, px, px - atrSize * 2, color.lime)
: Zone.new(bar_index, px + atrSize * 2, px, color.red)
Consumer:
//@version=1
indicator("Zone user", overlay=true)
import 1000000072/Zones/1 as zones
zone = zones.of(close > open, close, ta.atr(14))
zone.draw()