openpinescript 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +332 -2
  3. package/dist/cli.mjs +108691 -0
  4. package/dist/index.cjs +108670 -0
  5. package/dist/index.mjs +108624 -0
  6. package/dist/types/index.d.ts +31 -0
  7. package/dist/types/parser/v1/generated/PineV1Lexer.d.ts +66 -0
  8. package/dist/types/parser/v1/generated/PineV1Parser.d.ts +555 -0
  9. package/dist/types/parser/v1/generated/PineV1ParserVisitor.d.ts +318 -0
  10. package/dist/types/parser/v1/index.d.ts +39 -0
  11. package/dist/types/parser/v2/generated/PineV2Lexer.d.ts +67 -0
  12. package/dist/types/parser/v2/generated/PineV2Parser.d.ts +568 -0
  13. package/dist/types/parser/v2/generated/PineV2ParserVisitor.d.ts +325 -0
  14. package/dist/types/parser/v2/index.d.ts +2 -0
  15. package/dist/types/parser/v3/generated/PineV3Lexer.d.ts +67 -0
  16. package/dist/types/parser/v3/generated/PineV3Parser.d.ts +568 -0
  17. package/dist/types/parser/v3/generated/PineV3ParserVisitor.d.ts +325 -0
  18. package/dist/types/parser/v3/index.d.ts +2 -0
  19. package/dist/types/parser/v4/generated/PineV4Lexer.d.ts +86 -0
  20. package/dist/types/parser/v4/generated/PineV4Parser.d.ts +673 -0
  21. package/dist/types/parser/v4/generated/PineV4ParserVisitor.d.ts +367 -0
  22. package/dist/types/parser/v4/index.d.ts +2 -0
  23. package/dist/types/parser/v5/generated/PineV5Lexer.d.ts +95 -0
  24. package/dist/types/parser/v5/generated/PineV5Parser.d.ts +964 -0
  25. package/dist/types/parser/v5/generated/PineV5ParserVisitor.d.ts +521 -0
  26. package/dist/types/parser/v5/index.d.ts +2 -0
  27. package/dist/types/parser/v6/generated/PineV6Lexer.d.ts +98 -0
  28. package/dist/types/parser/v6/generated/PineV6Parser.d.ts +984 -0
  29. package/dist/types/parser/v6/generated/PineV6ParserVisitor.d.ts +528 -0
  30. package/dist/types/parser/v6/index.d.ts +2 -0
  31. package/dist/types/runtime/v1/Series.d.ts +61 -0
  32. package/dist/types/runtime/v1/broker/Broker.d.ts +325 -0
  33. package/dist/types/runtime/v1/broker/index.d.ts +158 -0
  34. package/dist/types/runtime/v1/broker/val.d.ts +28 -0
  35. package/dist/types/runtime/v1/constDefault.d.ts +11 -0
  36. package/dist/types/runtime/v1/context.d.ts +1705 -0
  37. package/dist/types/runtime/v1/footprint.d.ts +32 -0
  38. package/dist/types/runtime/v1/index.d.ts +7 -0
  39. package/dist/types/runtime/v1/language-spec.d.ts +12 -0
  40. package/dist/types/runtime/v1/openTrades.d.ts +12 -0
  41. package/dist/types/runtime/v1/palette.d.ts +18 -0
  42. package/dist/types/runtime/v1/session.d.ts +482 -0
  43. package/dist/types/runtime/v1/sessions.d.ts +31 -0
  44. package/dist/types/runtime/v1/stateClone.d.ts +19 -0
  45. package/dist/types/runtime/v1/stdlib/alerts.d.ts +31 -0
  46. package/dist/types/runtime/v1/stdlib/arrays.d.ts +133 -0
  47. package/dist/types/runtime/v1/stdlib/barmerge.d.ts +27 -0
  48. package/dist/types/runtime/v1/stdlib/barstate.d.ts +79 -0
  49. package/dist/types/runtime/v1/stdlib/cast.d.ts +81 -0
  50. package/dist/types/runtime/v1/stdlib/chart.d.ts +283 -0
  51. package/dist/types/runtime/v1/stdlib/color.d.ts +51 -0
  52. package/dist/types/runtime/v1/stdlib/core.d.ts +162 -0
  53. package/dist/types/runtime/v1/stdlib/dataset.d.ts +36 -0
  54. package/dist/types/runtime/v1/stdlib/display.d.ts +50 -0
  55. package/dist/types/runtime/v1/stdlib/drawings.d.ts +407 -0
  56. package/dist/types/runtime/v1/stdlib/errors.d.ts +21 -0
  57. package/dist/types/runtime/v1/stdlib/font.d.ts +20 -0
  58. package/dist/types/runtime/v1/stdlib/footprint.d.ts +76 -0
  59. package/dist/types/runtime/v1/stdlib/format.d.ts +57 -0
  60. package/dist/types/runtime/v1/stdlib/index.d.ts +71 -0
  61. package/dist/types/runtime/v1/stdlib/input.d.ts +14 -0
  62. package/dist/types/runtime/v1/stdlib/inputs.d.ts +60 -0
  63. package/dist/types/runtime/v1/stdlib/late_members.d.ts +97 -0
  64. package/dist/types/runtime/v1/stdlib/logging.d.ts +31 -0
  65. package/dist/types/runtime/v1/stdlib/maps.d.ts +55 -0
  66. package/dist/types/runtime/v1/stdlib/math.d.ts +71 -0
  67. package/dist/types/runtime/v1/stdlib/matrix.d.ts +201 -0
  68. package/dist/types/runtime/v1/stdlib/metadata.d.ts +14 -0
  69. package/dist/types/runtime/v1/stdlib/mtf.d.ts +15 -0
  70. package/dist/types/runtime/v1/stdlib/renames.d.ts +117 -0
  71. package/dist/types/runtime/v1/stdlib/renames5.d.ts +113 -0
  72. package/dist/types/runtime/v1/stdlib/renames6.d.ts +81 -0
  73. package/dist/types/runtime/v1/stdlib/request.d.ts +207 -0
  74. package/dist/types/runtime/v1/stdlib/scale.d.ts +19 -0
  75. package/dist/types/runtime/v1/stdlib/session.d.ts +113 -0
  76. package/dist/types/runtime/v1/stdlib/sort_field.d.ts +12 -0
  77. package/dist/types/runtime/v1/stdlib/sources.d.ts +24 -0
  78. package/dist/types/runtime/v1/stdlib/str.d.ts +117 -0
  79. package/dist/types/runtime/v1/stdlib/strategy.d.ts +314 -0
  80. package/dist/types/runtime/v1/stdlib/syminfo.d.ts +209 -0
  81. package/dist/types/runtime/v1/stdlib/ta.d.ts +409 -0
  82. package/dist/types/runtime/v1/stdlib/time.d.ts +158 -0
  83. package/dist/types/runtime/v1/stdlib/trades.d.ts +108 -0
  84. package/dist/types/runtime/v1/stdlib/ui.d.ts +196 -0
  85. package/dist/types/runtime/v1/stdlib/v6_members.d.ts +68 -0
  86. package/dist/types/runtime/v1/timeframes.d.ts +139 -0
  87. package/dist/types/runtime/v1/zones.d.ts +30 -0
  88. package/dist/types/transpiler/common/index.d.ts +51 -0
  89. package/dist/types/transpiler/common/libraries.d.ts +29 -0
  90. package/dist/types/transpiler/common/parseErrors.d.ts +38 -0
  91. package/dist/types/transpiler/common/passes/ScopeAnalysis.d.ts +158 -0
  92. package/dist/types/transpiler/common/passes/TypeRules.d.ts +26 -0
  93. package/dist/types/transpiler/common/profiles/index.d.ts +96 -0
  94. package/dist/types/transpiler/common/version.d.ts +40 -0
  95. package/dist/types/transpiler/v1/ToJsVisitor.d.ts +720 -0
  96. package/dist/types/transpiler/v2/ToJsVisitor.d.ts +72 -0
  97. package/dist/types/transpiler/v3/ToJsVisitor.d.ts +87 -0
  98. package/dist/types/transpiler/v4/ToJsVisitor.d.ts +263 -0
  99. package/dist/types/transpiler/v5/ToJsVisitor.d.ts +1101 -0
  100. package/dist/types/transpiler/v6/ToJsVisitor.d.ts +237 -0
  101. package/dist/types/transpiler/v6/rules.d.ts +94 -0
  102. package/dist/types/utils/v2/common.d.ts +4 -0
  103. package/package.json +92 -4
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Footprint construction for `request.footprint()` — the rows, POC, Value Area
3
+ * and imbalances, from the volume-per-level a host supplies.
4
+ *
5
+ * Outside stdlib/ deliberately: every export of a stdlib module is published
6
+ * as a Pine built-in, and this is a helper. The documented rules, and the
7
+ * undocumented choices made here, are listed in ./stdlib/footprint.ts.
8
+ */
9
+ /** One price level as the host supplies it. */
10
+ export interface FootprintLevel {
11
+ price: number;
12
+ buy: number;
13
+ sell: number;
14
+ }
15
+ export interface Row {
16
+ __builtin: "volume_row";
17
+ down: number;
18
+ up: number;
19
+ buy: number;
20
+ sell: number;
21
+ buyImbalance: boolean;
22
+ sellImbalance: boolean;
23
+ }
24
+ export interface Footprint {
25
+ __builtin: "footprint";
26
+ rows: Row[];
27
+ poc: Row;
28
+ vah: Row;
29
+ val: Row;
30
+ }
31
+ /** Groups levels into rows and derives the footprint, or null when empty. */
32
+ export declare function buildFootprint(levels: readonly FootprintLevel[], rowSize: number, vaPercent: number, imbalancePercent: number): Footprint | null;
@@ -0,0 +1,7 @@
1
+ import { Context } from "./context.js";
2
+ export { Context };
3
+ export declare function run(jsCode: string, ctx: Context, sandbox: any): any;
4
+ export declare function compile(jsCode: string, ctx: Context, sandbox: any): () => any;
5
+ export { Session, runScript, buildRenderModel, PROTOCOL_VERSION, ENGINE_VERSION } from "./session.js";
6
+ export type { Compiled, SimResult, RenderSeries, RenderDelta, EngineError, InputView, Candle, ChartSettings, RunOptions } from "./session.js";
7
+ export type { Drawing, LogEntry, PlotData, FillData, ScriptMeta, SecurityCandle, InputDef, Trade, Position } from "./context.js";
@@ -0,0 +1,12 @@
1
+ import type { PineVersion } from "../../transpiler/common/version.js";
2
+ export interface LanguageSpec {
3
+ version: PineVersion;
4
+ /** Reserved words this version recognises, cumulative. */
5
+ keywords: string[];
6
+ /** Every built-in name, including dotted members like `ta.sma`. */
7
+ builtins: string[];
8
+ /** The leading segment of every dotted name — `ta`, `strategy`, `color`. */
9
+ namespaces: string[];
10
+ }
11
+ /** What `version` knows. Sorted, so the output is stable to diff. */
12
+ export declare function languageSpec(version: PineVersion): LanguageSpec;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The open trades: one per filled entry that has not been fully closed.
3
+ *
4
+ * `strategy.opentrades` is their count and `strategy.opentrades.*(n)` index
5
+ * the same list, oldest first, so both read it from here. It is the broker's
6
+ * `position.entries`; a position with no entries recorded (one a test or a
7
+ * host built by hand) is a single trade described by the position itself.
8
+ *
9
+ * Lives outside ./stdlib/ because every export there becomes a Pine built-in.
10
+ */
11
+ import type { Context, OpenEntry } from "./context.js";
12
+ export declare function openTrades(ctx: Context): readonly OpenEntry[];
@@ -0,0 +1,18 @@
1
+ /**
2
+ * runtime/v1/palette.ts
3
+ * Colour defaults that depend on the script's version. Lives outside stdlib/ so
4
+ * it is not mistaken for a function scripts can call.
5
+ */
6
+ import type { Context } from "./context.js";
7
+ /**
8
+ * A default that Pine documents as a colour constant (`color = color.blue`,
9
+ * `textcolor = color.black`), in the PALETTE OF THE SCRIPT'S OWN VERSION.
10
+ * every version carries its own profile palette (v4 blue #2196F3, v5/v6 blue
11
+ * #2962FF, v5 black #363A45, v1–v3 pure RGB), core.ts's values being only a fallback, exactly as a script's own
12
+ * `color.blue` resolves — see createStdlib in stdlib/index.ts.
13
+ *
14
+ * Evidence for v5: TradingView drew `label.new(x, y, "default colours", style =
15
+ * label.style_label_down)` with a #2962FF bubble and dark text (OpenChartingView
16
+ * e2e/tradingview-drawings/page2.png, targets.json "default colours").
17
+ */
18
+ export declare function paletteColor(ctx: Context, name: "blue" | "black" | "white"): string;
@@ -0,0 +1,482 @@
1
+ import type { PineVersion } from "../../transpiler/common/version.js";
2
+ import type { Context as Ctx, ScriptMeta, SecurityCandle, Drawing, LogEntry, Position, EquityPoint } from "./context.js";
3
+ export declare const PROTOCOL_VERSION = 1;
4
+ export declare const ENGINE_VERSION: "v2";
5
+ export interface EngineError {
6
+ phase: "parse" | "transpile" | "runtime";
7
+ /**
8
+ * The Pine source line and column, 1-based line and 0-based column as the
9
+ * compile errors report them. For a runtime error, where the call that
10
+ * raised it is; absent when the error was raised outside any call.
11
+ */
12
+ line?: number;
13
+ col?: number;
14
+ /**
15
+ * Set when a runtime error was raised inside an imported library: its
16
+ * alias, and the library's own line and column. `line` and `col` then
17
+ * name the call in the user's script that led there.
18
+ */
19
+ library?: {
20
+ alias: string;
21
+ line: number;
22
+ col: number;
23
+ };
24
+ message: string;
25
+ /** For a runtime error from `runHistory`: the bar (0-based index) it was raised on. */
26
+ bar?: number;
27
+ /** The parser's own text, when `message` was rewritten to say what is wrong. */
28
+ detail?: string;
29
+ severity: "error" | "warning";
30
+ }
31
+ export interface InputView {
32
+ id: string;
33
+ title: string;
34
+ type: string;
35
+ default: any;
36
+ current: any;
37
+ overridden: boolean;
38
+ /**
39
+ * The rest of what `input()` was told, so a host can build the control the
40
+ * script asked for rather than guessing one from the type.
41
+ *
42
+ * `input.int(14, "Length", minval = 2, maxval = 50)` is a bounded spinner;
43
+ * `input.string(s, options = [...])` is a dropdown and nothing else will
44
+ * do. The engine has always recorded these — it clamps `minval` and falls
45
+ * back outside `options` — and simply did not pass them on, so every host
46
+ * rendered a bare text box and learnt the bounds by having its value
47
+ * silently changed underneath it.
48
+ */
49
+ minval?: number;
50
+ maxval?: number;
51
+ step?: number;
52
+ options?: any[];
53
+ tooltip?: string;
54
+ /** `group` and `inline` lay the dialog out; they carry no value. */
55
+ group?: string;
56
+ inline?: string;
57
+ confirm?: boolean;
58
+ }
59
+ /** A `strategy()` / `indicator()` argument a host may override. */
60
+ export interface PropertyView {
61
+ key: string;
62
+ title: string;
63
+ type: "float" | "integer" | "string";
64
+ current: number | string;
65
+ declared: number | string;
66
+ /** The only values a string property accepts, for a dropdown. */
67
+ options?: string[];
68
+ /** A unit to show beside the control — "%", "ticks", "contracts". */
69
+ unit?: string;
70
+ minval?: number;
71
+ /** Which block of TradingView's properties tab the row belongs to. */
72
+ group?: string;
73
+ }
74
+ export interface Compiled {
75
+ protocolVersion: number;
76
+ engineVersion: typeof ENGINE_VERSION;
77
+ meta: ScriptMeta | null;
78
+ inputs: InputView[];
79
+ /** Declaration arguments a host may override; empty for a study. */
80
+ properties: PropertyView[];
81
+ errors: EngineError[];
82
+ }
83
+ type SeriesType = "line" | "candle" | "marker" | "arrow" | "bgcolor" | "barcolor";
84
+ /**
85
+ * One drawable point. `color` is present only where the script set a DIFFERENT
86
+ * colour on that bar than the series default — `plot(close, color = close >
87
+ * open ? green : red)` is ordinary Pine, and a per-series colour cannot express
88
+ * it. A host that ignores the field still draws the right shape in the series
89
+ * colour; one that reads it draws what TradingView draws.
90
+ */
91
+ export type RenderPoint = {
92
+ value: number;
93
+ color?: string;
94
+ } | {
95
+ open: number;
96
+ high: number;
97
+ low: number;
98
+ close: number;
99
+ color?: string;
100
+ } | {
101
+ color: string;
102
+ } | null;
103
+ export interface RenderSeries {
104
+ id: string;
105
+ title: string;
106
+ type: SeriesType;
107
+ pane: "main" | "sub";
108
+ timeframe?: string;
109
+ color?: string;
110
+ style?: string | number;
111
+ linewidth?: number;
112
+ /**
113
+ * Where a marker sits: `abovebar`, `belowbar`, `top`, `bottom` or
114
+ * `absolute` — `plotshape`'s own `location` argument. Absent for every
115
+ * other series type. Without it a host cannot place a shape, because the
116
+ * `value` of `plotshape(close > open)` is 1, not a price.
117
+ */
118
+ location?: string;
119
+ /** `plotshape`/`plotchar` text, and its size, when the script set them. */
120
+ text?: string;
121
+ size?: string;
122
+ /**
123
+ * Colour of a marker's text. `plotshape`/`plotchar` `textcolor`, or
124
+ * TradingView's default `color.blue` in the script's own palette when the
125
+ * script gave none (TradingView drew plotshape text with no textcolor in
126
+ * #2962FF on v5; OpenChartingView e2e/tradingview-drawings/page3.png).
127
+ * Present on marker series only.
128
+ */
129
+ textcolor?: string;
130
+ /**
131
+ * The `offset` the script gave `plot`/`plotshape`/`plotchar`, in bars
132
+ * (negative = left). Present only when it is non-zero.
133
+ *
134
+ * INFORMATIONAL: `data` is already shifted. The value computed on bar `n`
135
+ * sits at index `n + offset`, so a negative offset leaves the last
136
+ * |offset| entries null and a positive one extends `data` past the last
137
+ * bar. A host draws `data[i]` at bar `i` and must not shift it again.
138
+ */
139
+ offset?: number;
140
+ data: RenderPoint[];
141
+ }
142
+ export interface SimResult {
143
+ protocolVersion: number;
144
+ engineVersion: typeof ENGINE_VERSION;
145
+ meta: ScriptMeta | null;
146
+ barsProcessed: number;
147
+ series: RenderSeries[];
148
+ fills: Array<{
149
+ plotId1: string;
150
+ plotId2: string;
151
+ color: string;
152
+ title: string;
153
+ /**
154
+ * The fill's colour BAR BY BAR, present only when the script gave it
155
+ * more than one.
156
+ *
157
+ * `fill(a, b, color = spanA > spanB ? green : red)` is how every
158
+ * Ichimoku cloud is written, and a fill carrying one colour cannot
159
+ * express it — the model reported whichever colour happened to come
160
+ * first and the cloud drew in that one colour for the whole chart.
161
+ * `null` at a bar means the fill is not drawn there.
162
+ */
163
+ colors?: Array<string | null>;
164
+ /**
165
+ * `fill(show_last = N)`: the fill covers only the last N bars. Already
166
+ * applied to `colors`, where every earlier bar is `null`; present for
167
+ * a host that wants the number.
168
+ */
169
+ showLast?: number;
170
+ /**
171
+ * The gradient overload, `fill(a, b, top_value, bottom_value, top_color,
172
+ * bottom_color)`: a vertical gradient between the two plots, `top_color`
173
+ * at the price `top_value` and `bottom_color` at `bottom_value`, each
174
+ * bar's own. The arrays are per bar, `null` where the fill is not
175
+ * drawn. `color` means nothing on a gradient fill.
176
+ */
177
+ gradient?: true;
178
+ topValues?: Array<number | null>;
179
+ bottomValues?: Array<number | null>;
180
+ topColors?: Array<string | null>;
181
+ bottomColors?: Array<string | null>;
182
+ }>;
183
+ trades: any[];
184
+ /**
185
+ * The position still OPEN at the last bar, which `trades` by definition
186
+ * does not contain — it holds closed trades only. A strategy that is in
187
+ * the market when the data ends has an entry a host should still draw.
188
+ * `size` is 0 while flat.
189
+ */
190
+ position: Position;
191
+ summary: {
192
+ netProfit: number;
193
+ closedTrades: number;
194
+ winRate: number;
195
+ } | null;
196
+ /**
197
+ * The full performance report, split all / long / short — the rows of
198
+ * TradingView's performance summary tab. Null for a study.
199
+ */
200
+ performance: Performance | null;
201
+ /**
202
+ * Account value at every bar's close, which is what the overview tab
203
+ * plots. Empty for a study.
204
+ */
205
+ equity: EquityPoint[];
206
+ /**
207
+ * Every `line`, `box`, `label`, `table`, `polyline` and `linefill` the
208
+ * script created, in creation order, with the bar each was created on.
209
+ *
210
+ * A host draws these itself — they are objects with coordinates, not a
211
+ * series with one value per bar, so they cannot be expressed as a
212
+ * `RenderSeries`. `props` carries the drawing's own fields verbatim
213
+ * (`x1`/`y1`/`x2`/`y2` for a line, `text`/`style`/`color` for a label).
214
+ */
215
+ drawings: Drawing[];
216
+ /**
217
+ * Everything the script wrote with `log.info` / `log.warning` /
218
+ * `log.error`, each tagged with the bar and timestamp it was emitted on so
219
+ * a host can align it to the chart.
220
+ */
221
+ logs: LogEntry[];
222
+ alerts: any[];
223
+ errors: EngineError[];
224
+ /**
225
+ * Arguments the script passed that this engine does not implement, and so
226
+ * ignored, as `"function(parameter)"` -- `"fill(display)"`. Empty when the
227
+ * run honoured everything it was given. A host can say so beside a result
228
+ * that differs from TradingView's.
229
+ */
230
+ droppedArguments: string[];
231
+ /**
232
+ * Things the host got wrong or left unsaid that change what the script
233
+ * computed, in words a person can act on. Empty when there are none.
234
+ * Today: the chart's timeframe and symbol were never set (`Session.setChart`),
235
+ * and a `request.security` / `security_lower_tf` for data the host never
236
+ * supplied (`Session.provideData`), one note per symbol and timeframe.
237
+ */
238
+ warnings: string[];
239
+ }
240
+ export interface RenderDelta {
241
+ barIndex: number;
242
+ time: number;
243
+ provisional: true;
244
+ series: Array<{
245
+ id: string;
246
+ value?: number;
247
+ ohlc?: [number, number, number, number];
248
+ color?: string;
249
+ }>;
250
+ }
251
+ export interface Candle {
252
+ time: number;
253
+ open: number;
254
+ high: number;
255
+ low: number;
256
+ close: number;
257
+ volume: number;
258
+ }
259
+ /** Options for `Session.runHistory`. */
260
+ export interface RunOptions {
261
+ /**
262
+ * Called as the run advances: `done` bars of `total` have been processed.
263
+ * Roughly every 1% of the bars, and once more at the end. A callback that
264
+ * throws is ignored: a host's progress display cannot fail the run. With
265
+ * no callback the run does nothing extra.
266
+ */
267
+ onProgress?: (done: number, total: number) => void;
268
+ }
269
+ /**
270
+ * One column of TradingView's performance summary, which reports every figure
271
+ * three times: over all trades, over the long ones and over the short ones.
272
+ *
273
+ * Where TradingView publishes a definition this follows it:
274
+ *
275
+ * Profit factor gross profit / gross loss
276
+ * Max drawdown the largest peak-to-trough decline
277
+ * % profitable winning trades / total closed trades
278
+ * Sharpe (MR - RFR) / SD, MR the mean return over a monthly
279
+ * trading period and RFR the `risk_free_rate` argument,
280
+ * 2% a year by default
281
+ *
282
+ * Sortino is the same ratio against downside deviation alone, which is the
283
+ * only part of it TradingView states. A column's run-up and drawdown are
284
+ * measured on the cumulative P&L of that column's trades, so the long column
285
+ * answers "how deep did the long side go" rather than restating the whole
286
+ * account's worst moment three times.
287
+ */
288
+ export interface PerformanceStats {
289
+ netProfit: number;
290
+ netProfitPercent: number;
291
+ grossProfit: number;
292
+ grossLoss: number;
293
+ maxRunup: number;
294
+ maxDrawdown: number;
295
+ maxRunupPercent: number;
296
+ maxDrawdownPercent: number;
297
+ profitFactor: number;
298
+ commissionPaid: number;
299
+ closedTrades: number;
300
+ winningTrades: number;
301
+ losingTrades: number;
302
+ evenTrades: number;
303
+ percentProfitable: number;
304
+ avgTrade: number;
305
+ avgWinningTrade: number;
306
+ avgLosingTrade: number;
307
+ ratioAvgWinAvgLoss: number;
308
+ largestWinningTrade: number;
309
+ largestLosingTrade: number;
310
+ avgBarsInTrades: number;
311
+ avgBarsInWinningTrades: number;
312
+ avgBarsInLosingTrades: number;
313
+ }
314
+ export interface Performance {
315
+ all: PerformanceStats;
316
+ long: PerformanceStats;
317
+ short: PerformanceStats;
318
+ /** Figures that belong to the account rather than to a side of it. */
319
+ initialCapital: number;
320
+ openPL: number;
321
+ openTrades: number;
322
+ maxContractsHeld: number;
323
+ buyHoldReturn: number;
324
+ buyHoldReturnPercent: number;
325
+ sharpeRatio: number;
326
+ sortinoRatio: number;
327
+ }
328
+ /**
329
+ * Sharpe and Sortino over the equity curve.
330
+ *
331
+ * TradingView states the ratio as `(MR - RFR) / SD` with MR "the average
332
+ * return for a monthly trading period", so the curve is reduced to one
333
+ * return per calendar month before anything is averaged. `risk_free_rate` is
334
+ * an ANNUAL percentage — 2 by default — so a month's share of it is
335
+ * `rate / 100 / 12`.
336
+ *
337
+ * Sortino replaces SD with the DOWNSIDE deviation — the same sum of squares,
338
+ * but counting only the shortfall below zero, and still divided by every
339
+ * month rather than by the losing ones. Fewer than two months of data leaves
340
+ * both undefined rather than zero: a single return has no deviation to
341
+ * divide by, and reporting 0 there would read as "no risk".
342
+ *
343
+ * Exported for its own tests. Reaching it through a strategy means finding a
344
+ * fixture whose months are a mix of winners and losers, and the two divisors
345
+ * agree exactly when they are not — so a test driven that way can pass with
346
+ * either formula in place.
347
+ */
348
+ export declare function riskRatios(curve: EquityPoint[], annualRatePercent: number): {
349
+ sharpeRatio: number;
350
+ sortinoRatio: number;
351
+ };
352
+ export declare function buildRenderModel(ctx: Ctx): Omit<SimResult, "protocolVersion" | "engineVersion" | "errors" | "warnings">;
353
+ /**
354
+ * What the host knows about the chart the script is running on, and the engine
355
+ * cannot learn from OHLCV bars: its timeframe and the symbol's facts.
356
+ *
357
+ * `timeframe` is Pine's own spelling — "1", "5", "60", "240", "D", "W", "M",
358
+ * "12M", "1S" — NOT a charting library's ("5m", "1H"). Everything else is
359
+ * optional and falls back to the engine's defaults (see Context.provideSymbolInfo).
360
+ */
361
+ export interface ChartSettings {
362
+ symbol: string;
363
+ timeframe: string;
364
+ mintick?: number;
365
+ type?: string;
366
+ currency?: string;
367
+ basecurrency?: string;
368
+ description?: string;
369
+ /** The exchange's IANA zone; `time(tf, session)` evaluates sessions in it. */
370
+ timezone?: string;
371
+ pointvalue?: number;
372
+ session?: string;
373
+ mincontract?: number;
374
+ root?: string;
375
+ }
376
+ /** Message carried by `SimResult.warnings` when the host never called `setChart`. */
377
+ export declare const CHART_NOT_SET_WARNING = "chart not set: timeframe defaults to D and symbol to SYMBOL \u2014 call Session.setChart";
378
+ export declare class Session {
379
+ private js;
380
+ private meta;
381
+ private inputValues;
382
+ private propertyValues;
383
+ private securities;
384
+ private ctx;
385
+ private exec;
386
+ private profile;
387
+ /** Pine Script version detected in the last compile(). */
388
+ pineVersion: PineVersion;
389
+ private chart;
390
+ /**
391
+ * Tell the engine which chart it is running on: the timeframe and the
392
+ * symbol's facts. A host MUST call this — none of it can be derived from
393
+ * bars, and scripts branch on it (`timeframe.period`, `syminfo.type`,
394
+ * session windows in the exchange's `timezone`). It applies to the compile
395
+ * dry run and every `runHistory`; call it again to change the chart.
396
+ * Throws on a timeframe that is not in Pine's format.
397
+ */
398
+ setChart(chart: ChartSettings): void;
399
+ /**
400
+ * Transpile + validate; a 1-bar dry run on a throwaway context discovers inputs + metadata.
401
+ *
402
+ * `opts.libraries`: sources for the libraries the script imports, keyed by
403
+ * `user/name/version` (see `requiredLibraries` for finding which). An
404
+ * import with no source is a compile error naming the library.
405
+ */
406
+ compile(source: string, opts?: {
407
+ libraries?: Readonly<Record<string, string>>;
408
+ }): Compiled;
409
+ setInputs(values: Record<string, any>): void;
410
+ /**
411
+ * Override `strategy()` declaration arguments — starting capital,
412
+ * pyramiding — the way TradingView's properties panel does.
413
+ *
414
+ * Unlike `setInputs`, this cannot be applied to a run already in progress:
415
+ * `cash` moves with the first fill, so it is seeded when the script
416
+ * declares itself and never afterwards. The next `runHistory` picks it up.
417
+ */
418
+ setProperties(values: Record<string, any>): void;
419
+ private currencyRates;
420
+ /**
421
+ * Supplies the daily conversion rate from one currency to another (what
422
+ * `request.currency_rate(from, to)` answers), as `{ time, value }` samples
423
+ * where `time` is the start of the day in ms. A strategy whose
424
+ * `strategy(currency = to)` differs from `syminfo.currency` (= `from`)
425
+ * books its closed trades at the rate in effect at the exit bar.
426
+ */
427
+ provideCurrencyRate(from: string, to: string, samples: Array<{
428
+ time: number;
429
+ value: number;
430
+ }>): void;
431
+ provideData(symbol: string, resolution: string, candles: SecurityCandle[]): void;
432
+ /**
433
+ * Full historical pass; returns the render model. Builds a FRESH context so
434
+ * the sandbox's series references always match (ctx.reset() would re-create
435
+ * the base series and orphan the sandbox bindings).
436
+ */
437
+ runHistory(candles: Candle[], opts?: RunOptions): SimResult;
438
+ /** One pass of `runHistory`; null when it must start over (see there). */
439
+ private runHistoryOnce;
440
+ /** The forming bar's latest tick, replayed by `commit()` when no final candle is given. */
441
+ private lastTick;
442
+ /** Live tick on the forming bar (P3). Honors calc_on_every_tick. */
443
+ tick(candle: Candle): RenderDelta;
444
+ /**
445
+ * Close the forming bar. TradingView runs the script one more time as the bar
446
+ * closes: a rollback re-execution on the bar's FINAL candle with
447
+ * `barstate.isconfirmed` true and `isnew` false (rt-confirmed-v6/v5 probes).
448
+ * `finalCandle` is that final OHLCV; without it the last tick's values are used
449
+ * (a bar that never ticked gets no closing execution). A strategy with
450
+ * calc_on_every_tick off executes only here, so this is its first execution
451
+ * (`isnew` true) as well as its confirmed one.
452
+ */
453
+ commit(finalCandle?: Candle): {
454
+ barIndex: number;
455
+ };
456
+ private deltaForFormingBar;
457
+ }
458
+ /**
459
+ * `let` declarations in the emitted JS as `var`, and nothing else.
460
+ *
461
+ * A scanner, not a regex: string literals, comments and template literals
462
+ * (including code inside `${…}`) are tracked, and only a whole identifier
463
+ * `let` in code is rewritten -- not `$let`, not `x.let`, not the "let it be"
464
+ * in a script's or an inlined library's string.
465
+ */
466
+ export declare function letToVar(js: string): string;
467
+ /** One-shot convenience: compile + runHistory. */
468
+ export declare function runScript(source: string, opts?: {
469
+ candles: Candle[];
470
+ inputs?: Record<string, any>;
471
+ properties?: Record<string, any>;
472
+ securities?: Array<{
473
+ symbol: string;
474
+ resolution: string;
475
+ candles: SecurityCandle[];
476
+ }>;
477
+ /** Library sources by import path, as for `Session.compile`. */
478
+ libraries?: Readonly<Record<string, string>>;
479
+ /** The chart, as for `Session.setChart`. Without it the result carries a warning. */
480
+ chart?: ChartSettings;
481
+ }): SimResult;
482
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Where one trading session ends and the next begins.
3
+ *
4
+ * Lives outside `stdlib/` deliberately: everything in that directory is scanned
5
+ * by scripts/common/generate-metadata.ts and anything taking a `ctx` first
6
+ * parameter becomes a BUILT-IN. `opensDay` is a shared helper, not a name any
7
+ * Pine script may call, so it cannot live there.
8
+ *
9
+ * Two built-ins need the same answer and must not drift apart:
10
+ *
11
+ * - `session.isfirstbar` / `session.islastbar`
12
+ * - `ta.vwap`, which restarts its accumulation every session
13
+ *
14
+ * ── Day boundaries ──────────────────────────────────────────────────────────
15
+ *
16
+ * "the day's session" is a calendar day in the EXCHANGE's timezone, and this
17
+ * engine has no timezone. It compares UTC dates, matching ./stdlib/time.ts,
18
+ * whose header states the same convention and the same remedy: a host that
19
+ * supplies bar timestamps already shifted to the exchange timezone gets
20
+ * agreement.
21
+ *
22
+ * This models a 24-hour session, which is right for crypto and wrong for an
23
+ * equity whose session opens at 09:30 — there, an intraday VWAP would restart
24
+ * at midnight instead of at the open. On DAILY and higher timeframes the
25
+ * question does not arise: every bar falls on its own calendar day, so every
26
+ * bar opens a session, and that falls out of the date comparison rather than
27
+ * being special-cased.
28
+ */
29
+ import { Context } from "./context.js";
30
+ /** Is this bar on a different calendar day from the one before it? */
31
+ export declare function opensDay(ctx: Context): boolean;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copies a built-in's persistent state for the per-bar rollback point.
3
+ *
4
+ * Every stateful call site is snapshotted on every bar (see `call` in
5
+ * ./context.ts), and a state is usually a rolling buffer: `ta.sma` keeps up to
6
+ * 5,000 values. `structuredClone` of that, once per site per bar, was most of
7
+ * the run on a 110,000-bar chart (70% for a script with a few moving averages).
8
+ *
9
+ * States are plain data, so a plain copy does the same job: objects of
10
+ * primitives, arrays of primitives, and those nested. Anything else — a Map, a
11
+ * class instance, a function (which `structuredClone` refuses, and the caller
12
+ * reports), a value reachable twice (whose sharing `structuredClone` keeps) —
13
+ * hands the WHOLE value to `structuredClone`, so what it copies, and what it
14
+ * throws on, is unchanged.
15
+ *
16
+ * Not in stdlib/, where every export becomes a Pine built-in.
17
+ */
18
+ /** What `structuredClone(v)` returns, faster for plain data. */
19
+ export declare function cloneState<T>(v: T): T;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The `alert.*` constants.
3
+ *
4
+ * ── Why they are not in ui.ts beside alert() ────────────────────────────────
5
+ *
6
+ * Pine spells `alert` as BOTH a function and a namespace — `alert(msg, freq)`
7
+ * and `alert.freq_all`. The registry generator takes a namespace from the NAME
8
+ * of an exported object, and one module cannot export both a function and an
9
+ * object called `alert`.
10
+ *
11
+ * So the pair is split across two files, exactly as `input` already is:
12
+ * ./input.ts holds `input()` and ./inputs.ts holds the `input` object. The
13
+ * merge in ./index.ts then hangs these members off the function object, which
14
+ * is what makes `alert.freq_all` resolvable at the same time as `alert(…)`.
15
+ *
16
+ * ── What the values mean ────────────────────────────────────────────────────
17
+ *
18
+ * They select how often ONE alert() call may re-fire within a single realtime
19
+ * bar. They are recorded on the alert rather than enforced — see the note on
20
+ * alert() in ./ui.ts for why that depends on a tick feed the host supplies.
21
+ *
22
+ * Source: https://www.tradingview.com/pine-script-docs/v4/essential/alerts/
23
+ */
24
+ export declare const alert: {
25
+ /** Only the first call per realtime bar triggers. TradingView's default. */
26
+ freq_once_per_bar: string;
27
+ /** Triggers only when the realtime bar closes. */
28
+ freq_once_per_bar_close: string;
29
+ /** Every call during the realtime bar triggers. */
30
+ freq_all: string;
31
+ };