Lesson 12: Modules you reuse
Move functions you use in several scripts into a module, save it in My scripts, and import it into your other scripts by its name and version.
Lesson 12 of 18. When the same function turns up in three of your scripts, a fix has to be made three times. A module keeps it in one place: it is a script of your own that draws nothing and only offers functions and types to your other scripts.
Start with a function in the script#
Write the function in the script that needs it first, and make sure it works:
indicator "Range in percent"
edition = 1
display = pane
fn range_percent(top: float, bottom: float): float = 100 * (top - bottom) / bottom
plot(range_percent(high, low), name = "Bar range %", style = columns, color = color.teal)
plot(tech.sma(range_percent(high, low), 20), name = "Average", color = color.orange)fn name(parameters): type = expression declares a function (Lesson 6 covers functions). Once a function works and you want it in other scripts too, move it into a module.
Write the module#
A module starts with module Name in place of indicator "Name". Only what is marked export can be used by other scripts; everything else stays private to the module. This module keeps a running mean in a record (a type with fields) and offers two methods on it:
// A module: a running mean kept in a record. Other scripts import it by name and version.
module Stats
edition = 1
export type Stats
n: int = 0
total: float = 0
export fn Stats.add(self: Stats, x: float)
self.n += 1
self.total += x
export fn Stats.mean(self: Stats): float = if self.n > 0 then self.total / self.n else naTo keep it:
- Open the editor, choose New script, and replace the example text with the module.
- Press Save. The status beside the name says Library — ready to import when the module compiles.
- A module draws nothing, so there is nothing to add to the chart. It stays in My scripts like your other scripts, and it counts toward the number of scripts your plan keeps.
The other scripts find the module by the name written after module (here Stats), not by the name it is saved under in the list, and upper and lower case do not matter.
Import it#
// Using the module: the running mean of every close so far, drawn next to the close.
indicator "Running mean"
edition = 1
display = price
import Me/Stats@1 as mu
state stats = mu.Stats(n = 0)
stats.add(close)
plot(stats.mean(), name = "Mean of every close so far", color = color.orange)
plot(close, name = "Close", color = color.gray)import Me/Stats@1 as mubrings the module in.Mesays it is your own module; only your own modules can be imported in this release.@1is the version, and it is required.muis the short name you use for what the module exports.mu.Stats(n = 0)makes a record of the module's type;statekeeps it from bar to bar.stats.add(close)andstats.mean()call the module's methods.- Every script that imports a module gets its own memory: two scripts that use
Statsdo not share their running means.
The version cannot be left out:
indicator "An import with no version"
edition = 1
import Me/Stats as mu
plot(close)A name the module does not export is E3172, and a module that imports itself, directly or through other modules, is E-IMPORT-CYCLE. A module that you do not have gives an error that names it. Modules and libraries has all the rules and limits.
Try changing#
- Add a third method to the module,
export fn Stats.count(self: Stats): int = self.n, save it, and plotstats.count()from the importing script. - Remove the word
exportin front offn Stats.meanand save the module. The importing script now shows a problem, becausemeanis no longer offered. - Change
@1to nothing (import Me/Stats as mu) and read the error. - Move
range_percentfrom the first program into a module of your own calledRanges, and import it withimport Me/Ranges@1 as r.
Checkpoint#
- You can write a module with
module Nameand mark what it offers withexport. - You can save it and recognise Library — ready to import.
- You can import it with
import Me/Name@1 as aliasand call what it exports. - You know that a module is found by the name after
module, and that only your own modules can be imported.