Edgoro
Library · Language features

Pine Script library: export and import functions (v6)

Write a Pine Script v6 library with export, publish it, and import it into an indicator with import user/name/version: rules for types, methods and versions.

Short answer

A library is a script declared with library("Name") whose reusable functions, types and methods start with export; once you publish it (privately is enough), any script can load it with import YourUsername/Name/1 as alias and call alias.functionName(). Every parameter of an exported function needs a type, and the version number in the import is required.

The script

A small library of risk helpers: position size from a stop, rounding to a step, a percent distance, and an exported type with a method. Paste it into a new library in the Pine Editor and publish it.

Pine Script v6
//@version=6
//@description Risk and price helpers: position size from a stop, rounding to a step, percent distance.
library("RiskTools")

//@function Units to trade so that a stop stopDistance away loses riskCash.
//@param riskCash Cash to risk, in the symbol's currency.
//@param stopDistance Distance from entry to stop, in price.
//@returns The quantity, or na when the stop distance isn't positive.
export qtyForRisk(float riskCash, float stopDistance) =>
    stopDistance > 0 ? riskCash / (stopDistance * syminfo.pointvalue) : na

//@function Rounds a quantity down to a multiple of step (1 for whole shares).
//@param qty The quantity to round.
//@param step The smallest tradable increment.
//@returns The rounded quantity.
export roundDown(float qty, float step) =>
    step > 0 ? math.floor(qty / step) * step : qty

//@function Percent distance from one price to another.
//@param fromPrice The reference price.
//@param toPrice The price to measure.
//@returns The distance in percent, or na when the reference is 0.
export pctChange(float fromPrice, float toPrice) =>
    fromPrice != 0 ? (toPrice - fromPrice) / fromPrice * 100 : na

//@type A price level and the bar it was set on.
//@field price The level.
//@field barIdx The bar_index where it was set.
export type Level
    float price
    int   barIdx

//@function Percent distance from the level to a price.
//@param lvl The level.
//@param price The price to measure.
//@returns The distance in percent.
export method distancePct(Level lvl, float price) =>
    pctChange(lvl.price, price)

// Drawn only when the library itself is added to a chart, as a quick visual test
plot(pctChange(close[1], close), "Bar change %")

How it works

  • library("RiskTools"). The title is also the name used in imports, so it must be an identifier: letters, digits and underscores, not starting with a digit.
  • export makes a function, type or method visible to scripts that import the library. Everything else (helpers, the test plot()) stays private.
  • Typed parameters. In an exported function every parameter needs a type (float riskCash). Qualifiers simple and series are allowed; the function's body can't depend on input.*() calls or on global variables, but it can use built-ins such as syminfo.pointvalue.
  • Annotations. //@description, //@function, //@param, //@returns, //@type and //@field comments are shown in the library's documentation and in the Pine Editor's autocomplete for people who import it.
  • The exported type and method. Level and distancePct() are used in the importing script as rt.Level.new(...) and lastLow.distancePct(close): the alias prefixes the type, and a method is called on the object.
  • Publishing. In the Pine Editor, publish the library (a private publication is enough for your own scripts). Each new publication increments the version number.

Importing the library

Once RiskTools is published, an indicator imports it by your username, its name and its version. This script only compiles after you publish the library and replace YourUsername with your TradingView username.

Pine Script v6
//@version=6
indicator("Risk per trade (library demo)", overlay = true)
// Replace YourUsername with the TradingView username that published RiskTools, and 1 with its current version
import YourUsername/RiskTools/1 as rt

riskCash = input.float(100, "Cash to risk per trade (symbol currency)", minval = 1)
atrMult  = input.float(2, "Stop distance (x ATR)", minval = 0.5, step = 0.5)
qtyStep  = input.float(1, "Quantity step", minval = 0)

float stopDist = atrMult * ta.atr(14)
float qty = rt.roundDown(rt.qtyForRisk(riskCash, stopDist), qtyStep)

pl = ta.pivotlow(low, 5, 5)
var rt.Level lastLow = rt.Level.new(na, na)
if not na(pl)
    lastLow := rt.Level.new(pl, bar_index - 5)

plot(close - stopDist, "Long stop", color.red)
plot(qty, "Quantity for the risk", display = display.data_window)
plot(lastLow.distancePct(close), "% above the last swing low", display = display.data_window)

Pitfalls

  • Importing before publishing. An import only works for a published library, with its exact username, name and version. A typo in the import line, or an alias you don't use when calling, leaves the functions unknown (Could not find function or function reference).
  • Untyped parameters. export qtyForRisk(riskCash, stopDistance) => doesn't compile in a library: every exported parameter needs a type.
  • Inputs and globals in exported code. An exported function can't depend on input.*() calls or on a non-constant global variable. Pass the values as parameters. Only constants can be exported as values, with export const.
  • Versions don't update themselves. import YourUsername/RiskTools/1 keeps using version 1 after you publish version 2. Change the number in each importing script when you want the update.
  • Visibility. Libraries are always open source, and a script published publicly can only import public libraries. Keep anything you don't want to share out of them.

Variations

Constants. export const float RISK_DEFAULT = 1.0 exports a value; importers read it as rt.RISK_DEFAULT. Allowed types are int, float, bool, color and string.

Data requests in a library. An exported function can call request.security() only if the library is declared with library("Name", dynamic_requests = true), and the requested expression can't depend on the function's parameters (the symbol and timeframe can).

Not ready to publish? Keep the functions at the top of each script that uses them, as in the functions and methods example, and move them to a library once they've settled.

Questions

Do I have to publish a Pine Script library to use it?

Yes. A script can only import a published library. If you don't want it public, publish it privately: your own scripts can import private libraries, but public scripts can only import public ones.

Do scripts get library updates automatically?

No. The import line names a version, such as import YourUsername/RiskTools/1 as rt, and the script keeps using that version until you change the number.

Can a Pine Script library export variables?

Only constants, declared with export const and an int, float, bool, color or string type. Anything that changes from bar to bar has to be returned by an exported function instead.

Every script on this page was checked with Edgoro Pine Check (Pine Script v6 rules). Pine Check is a static checker, not TradingView's compiler: TradingView compiles the script when you save it in the Pine Editor. The scripts are examples to learn from, not trading systems. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.

Need a different version of this script?

Describe the change in plain English and Edgoro writes the Pine Script v6 for you, checked with Pine Check. For example:

“Turn my position sizing, stop and target calculations into a Pine Script library with typed, documented exported functions, and show me the import line for my strategy.”