oakscriptjs 0.10.1 → 0.11.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 (271) hide show
  1. package/dist/cjs/array/index.d.ts +8 -2
  2. package/dist/cjs/array/index.d.ts.map +1 -1
  3. package/dist/cjs/array/index.js +2 -1
  4. package/dist/cjs/array/index.js.map +2 -2
  5. package/dist/cjs/box/index.d.ts.map +1 -1
  6. package/dist/cjs/box/index.js +7 -1
  7. package/dist/cjs/box/index.js.map +2 -2
  8. package/dist/cjs/callsite/index.d.ts +73 -32
  9. package/dist/cjs/callsite/index.d.ts.map +1 -1
  10. package/dist/cjs/callsite/index.js +69 -65
  11. package/dist/cjs/callsite/index.js.map +2 -2
  12. package/dist/cjs/drawing/registry.d.ts +84 -0
  13. package/dist/cjs/drawing/registry.d.ts.map +1 -1
  14. package/dist/cjs/drawing/registry.js +153 -6
  15. package/dist/cjs/drawing/registry.js.map +2 -2
  16. package/dist/cjs/index.d.ts +8 -2
  17. package/dist/cjs/index.d.ts.map +1 -1
  18. package/dist/cjs/index.js +33 -1
  19. package/dist/cjs/index.js.map +2 -2
  20. package/dist/cjs/input.d.ts +9 -1
  21. package/dist/cjs/input.d.ts.map +1 -1
  22. package/dist/cjs/input.js +16 -0
  23. package/dist/cjs/input.js.map +2 -2
  24. package/dist/cjs/label/index.d.ts.map +1 -1
  25. package/dist/cjs/label/index.js +3 -0
  26. package/dist/cjs/label/index.js.map +2 -2
  27. package/dist/cjs/line/index.d.ts +10 -27
  28. package/dist/cjs/line/index.d.ts.map +1 -1
  29. package/dist/cjs/line/index.js +11 -22
  30. package/dist/cjs/line/index.js.map +2 -2
  31. package/dist/cjs/linefill/index.d.ts +3 -0
  32. package/dist/cjs/linefill/index.d.ts.map +1 -1
  33. package/dist/cjs/linefill/index.js +15 -1
  34. package/dist/cjs/linefill/index.js.map +3 -3
  35. package/dist/cjs/math/index.d.ts.map +1 -1
  36. package/dist/cjs/math/index.js +2 -0
  37. package/dist/cjs/math/index.js.map +2 -2
  38. package/dist/cjs/polyline/index.d.ts.map +1 -1
  39. package/dist/cjs/polyline/index.js +3 -0
  40. package/dist/cjs/polyline/index.js.map +2 -2
  41. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +1 -1
  42. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +2 -2
  43. package/dist/cjs/runtime/index.d.ts +1 -1
  44. package/dist/cjs/runtime/index.d.ts.map +1 -1
  45. package/dist/cjs/runtime/index.js +1 -0
  46. package/dist/cjs/runtime/index.js.map +2 -2
  47. package/dist/cjs/runtime/inputs.d.ts +9 -0
  48. package/dist/cjs/runtime/inputs.d.ts.map +1 -1
  49. package/dist/cjs/runtime/inputs.js +8 -0
  50. package/dist/cjs/runtime/inputs.js.map +2 -2
  51. package/dist/cjs/runtime/types.d.ts +1 -1
  52. package/dist/cjs/runtime/types.d.ts.map +1 -1
  53. package/dist/cjs/runtime/types.js.map +1 -1
  54. package/dist/cjs/script/index.d.ts +91 -21
  55. package/dist/cjs/script/index.d.ts.map +1 -1
  56. package/dist/cjs/script/index.js +207 -19
  57. package/dist/cjs/script/index.js.map +3 -3
  58. package/dist/cjs/security/other.d.ts +92 -0
  59. package/dist/cjs/security/other.d.ts.map +1 -0
  60. package/dist/cjs/security/other.js +164 -0
  61. package/dist/cjs/security/other.js.map +7 -0
  62. package/dist/cjs/session/bars.d.ts +24 -1
  63. package/dist/cjs/session/bars.d.ts.map +1 -1
  64. package/dist/cjs/session/bars.js +56 -7
  65. package/dist/cjs/session/bars.js.map +3 -3
  66. package/dist/cjs/session/calendar.d.ts +13 -2
  67. package/dist/cjs/session/calendar.d.ts.map +1 -1
  68. package/dist/cjs/session/calendar.js +39 -9
  69. package/dist/cjs/session/calendar.js.map +2 -2
  70. package/dist/cjs/session/context.d.ts +76 -0
  71. package/dist/cjs/session/context.d.ts.map +1 -0
  72. package/dist/cjs/session/context.js +114 -0
  73. package/dist/cjs/session/context.js.map +7 -0
  74. package/dist/cjs/str/floatingdecimal.d.ts +31 -0
  75. package/dist/cjs/str/floatingdecimal.d.ts.map +1 -0
  76. package/dist/cjs/str/floatingdecimal.js +298 -0
  77. package/dist/cjs/str/floatingdecimal.js.map +7 -0
  78. package/dist/cjs/str/index.d.ts +4 -1
  79. package/dist/cjs/str/index.d.ts.map +1 -1
  80. package/dist/cjs/str/index.js +2 -1
  81. package/dist/cjs/str/index.js.map +2 -2
  82. package/dist/cjs/str/numberformat.d.ts +7 -3
  83. package/dist/cjs/str/numberformat.d.ts.map +1 -1
  84. package/dist/cjs/str/numberformat.js +4 -3
  85. package/dist/cjs/str/numberformat.js.map +2 -2
  86. package/dist/cjs/ta/index.d.ts +67 -34
  87. package/dist/cjs/ta/index.d.ts.map +1 -1
  88. package/dist/cjs/ta/index.js +202 -145
  89. package/dist/cjs/ta/index.js.map +2 -2
  90. package/dist/cjs/ta/limits.d.ts +35 -0
  91. package/dist/cjs/ta/limits.d.ts.map +1 -0
  92. package/dist/cjs/ta/limits.js +64 -0
  93. package/dist/cjs/ta/limits.js.map +7 -0
  94. package/dist/cjs/ta/running-sum.d.ts +0 -16
  95. package/dist/cjs/ta/running-sum.d.ts.map +1 -1
  96. package/dist/cjs/ta/running-sum.js +2 -0
  97. package/dist/cjs/ta/running-sum.js.map +2 -2
  98. package/dist/cjs/ta-series.d.ts +8 -8
  99. package/dist/cjs/ta-series.d.ts.map +1 -1
  100. package/dist/cjs/ta-series.js +10 -8
  101. package/dist/cjs/ta-series.js.map +2 -2
  102. package/dist/cjs/table/index.d.ts +3 -1
  103. package/dist/cjs/table/index.d.ts.map +1 -1
  104. package/dist/cjs/table/index.js +1 -0
  105. package/dist/cjs/table/index.js.map +3 -3
  106. package/dist/cjs/time/index.d.ts +5 -2
  107. package/dist/cjs/time/index.d.ts.map +1 -1
  108. package/dist/cjs/time/index.js +2 -2
  109. package/dist/cjs/time/index.js.map +2 -2
  110. package/dist/cjs/time/session.d.ts +26 -1
  111. package/dist/cjs/time/session.d.ts.map +1 -1
  112. package/dist/cjs/time/session.js +94 -12
  113. package/dist/cjs/time/session.js.map +3 -3
  114. package/dist/cjs/time/timezone.d.ts +6 -1
  115. package/dist/cjs/time/timezone.d.ts.map +1 -1
  116. package/dist/cjs/time/timezone.js +2 -2
  117. package/dist/cjs/time/timezone.js.map +2 -2
  118. package/dist/cjs/types/metadata.d.ts +28 -4
  119. package/dist/cjs/types/metadata.d.ts.map +1 -1
  120. package/dist/cjs/types/metadata.js.map +1 -1
  121. package/dist/esm/array/index.d.ts +8 -2
  122. package/dist/esm/array/index.d.ts.map +1 -1
  123. package/dist/esm/array/index.js +12 -3
  124. package/dist/esm/array/index.js.map +1 -1
  125. package/dist/esm/box/index.d.ts.map +1 -1
  126. package/dist/esm/box/index.js +8 -2
  127. package/dist/esm/box/index.js.map +1 -1
  128. package/dist/esm/callsite/index.d.ts +73 -32
  129. package/dist/esm/callsite/index.d.ts.map +1 -1
  130. package/dist/esm/callsite/index.js +143 -106
  131. package/dist/esm/callsite/index.js.map +1 -1
  132. package/dist/esm/drawing/registry.d.ts +84 -0
  133. package/dist/esm/drawing/registry.d.ts.map +1 -1
  134. package/dist/esm/drawing/registry.js +260 -6
  135. package/dist/esm/drawing/registry.js.map +1 -1
  136. package/dist/esm/index.d.ts +8 -2
  137. package/dist/esm/index.d.ts.map +1 -1
  138. package/dist/esm/index.js +13 -2
  139. package/dist/esm/index.js.map +1 -1
  140. package/dist/esm/input.d.ts +9 -1
  141. package/dist/esm/input.d.ts.map +1 -1
  142. package/dist/esm/input.js +16 -0
  143. package/dist/esm/input.js.map +1 -1
  144. package/dist/esm/label/index.d.ts.map +1 -1
  145. package/dist/esm/label/index.js +4 -1
  146. package/dist/esm/label/index.js.map +1 -1
  147. package/dist/esm/line/index.d.ts +10 -27
  148. package/dist/esm/line/index.d.ts.map +1 -1
  149. package/dist/esm/line/index.js +22 -60
  150. package/dist/esm/line/index.js.map +1 -1
  151. package/dist/esm/linefill/index.d.ts +3 -0
  152. package/dist/esm/linefill/index.d.ts.map +1 -1
  153. package/dist/esm/linefill/index.js +20 -1
  154. package/dist/esm/linefill/index.js.map +1 -1
  155. package/dist/esm/math/index.d.ts.map +1 -1
  156. package/dist/esm/math/index.js +3 -0
  157. package/dist/esm/math/index.js.map +1 -1
  158. package/dist/esm/polyline/index.d.ts.map +1 -1
  159. package/dist/esm/polyline/index.js +5 -1
  160. package/dist/esm/polyline/index.js.map +1 -1
  161. package/dist/esm/runtime/adapters/SimpleInputAdapter.js +1 -1
  162. package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -1
  163. package/dist/esm/runtime/index.d.ts +1 -1
  164. package/dist/esm/runtime/index.d.ts.map +1 -1
  165. package/dist/esm/runtime/index.js +1 -1
  166. package/dist/esm/runtime/index.js.map +1 -1
  167. package/dist/esm/runtime/inputs.d.ts +9 -0
  168. package/dist/esm/runtime/inputs.d.ts.map +1 -1
  169. package/dist/esm/runtime/inputs.js +15 -0
  170. package/dist/esm/runtime/inputs.js.map +1 -1
  171. package/dist/esm/runtime/types.d.ts +1 -1
  172. package/dist/esm/runtime/types.d.ts.map +1 -1
  173. package/dist/esm/script/index.d.ts +91 -21
  174. package/dist/esm/script/index.d.ts.map +1 -1
  175. package/dist/esm/script/index.js +259 -28
  176. package/dist/esm/script/index.js.map +1 -1
  177. package/dist/esm/security/other.d.ts +92 -0
  178. package/dist/esm/security/other.d.ts.map +1 -0
  179. package/dist/esm/security/other.js +211 -0
  180. package/dist/esm/security/other.js.map +1 -0
  181. package/dist/esm/session/bars.d.ts +24 -1
  182. package/dist/esm/session/bars.d.ts.map +1 -1
  183. package/dist/esm/session/bars.js +75 -6
  184. package/dist/esm/session/bars.js.map +1 -1
  185. package/dist/esm/session/calendar.d.ts +13 -2
  186. package/dist/esm/session/calendar.d.ts.map +1 -1
  187. package/dist/esm/session/calendar.js +54 -10
  188. package/dist/esm/session/calendar.js.map +1 -1
  189. package/dist/esm/session/context.d.ts +76 -0
  190. package/dist/esm/session/context.d.ts.map +1 -0
  191. package/dist/esm/session/context.js +124 -0
  192. package/dist/esm/session/context.js.map +1 -0
  193. package/dist/esm/str/floatingdecimal.d.ts +31 -0
  194. package/dist/esm/str/floatingdecimal.d.ts.map +1 -0
  195. package/dist/esm/str/floatingdecimal.js +272 -0
  196. package/dist/esm/str/floatingdecimal.js.map +1 -0
  197. package/dist/esm/str/index.d.ts +4 -1
  198. package/dist/esm/str/index.d.ts.map +1 -1
  199. package/dist/esm/str/index.js +9 -2
  200. package/dist/esm/str/index.js.map +1 -1
  201. package/dist/esm/str/numberformat.d.ts +7 -3
  202. package/dist/esm/str/numberformat.d.ts.map +1 -1
  203. package/dist/esm/str/numberformat.js +11 -5
  204. package/dist/esm/str/numberformat.js.map +1 -1
  205. package/dist/esm/ta/index.d.ts +67 -34
  206. package/dist/esm/ta/index.d.ts.map +1 -1
  207. package/dist/esm/ta/index.js +284 -240
  208. package/dist/esm/ta/index.js.map +1 -1
  209. package/dist/esm/ta/limits.d.ts +35 -0
  210. package/dist/esm/ta/limits.d.ts.map +1 -0
  211. package/dist/esm/ta/limits.js +67 -0
  212. package/dist/esm/ta/limits.js.map +1 -0
  213. package/dist/esm/ta/running-sum.d.ts +0 -16
  214. package/dist/esm/ta/running-sum.d.ts.map +1 -1
  215. package/dist/esm/ta/running-sum.js +2 -0
  216. package/dist/esm/ta/running-sum.js.map +1 -1
  217. package/dist/esm/ta-series.d.ts +8 -8
  218. package/dist/esm/ta-series.d.ts.map +1 -1
  219. package/dist/esm/ta-series.js +11 -8
  220. package/dist/esm/ta-series.js.map +1 -1
  221. package/dist/esm/table/index.d.ts +3 -1
  222. package/dist/esm/table/index.d.ts.map +1 -1
  223. package/dist/esm/table/index.js +6 -1
  224. package/dist/esm/table/index.js.map +1 -1
  225. package/dist/esm/time/index.d.ts +5 -2
  226. package/dist/esm/time/index.d.ts.map +1 -1
  227. package/dist/esm/time/index.js +6 -3
  228. package/dist/esm/time/index.js.map +1 -1
  229. package/dist/esm/time/session.d.ts +26 -1
  230. package/dist/esm/time/session.d.ts.map +1 -1
  231. package/dist/esm/time/session.js +141 -16
  232. package/dist/esm/time/session.js.map +1 -1
  233. package/dist/esm/time/timezone.d.ts +6 -1
  234. package/dist/esm/time/timezone.d.ts.map +1 -1
  235. package/dist/esm/time/timezone.js +8 -2
  236. package/dist/esm/time/timezone.js.map +1 -1
  237. package/dist/esm/types/metadata.d.ts +28 -4
  238. package/dist/esm/types/metadata.d.ts.map +1 -1
  239. package/package.json +1 -1
  240. package/src/array/index.ts +11 -3
  241. package/src/box/index.ts +8 -2
  242. package/src/callsite/index.ts +150 -100
  243. package/src/drawing/registry.ts +278 -5
  244. package/src/index.ts +44 -1
  245. package/src/input.ts +18 -1
  246. package/src/label/index.ts +4 -1
  247. package/src/line/index.ts +22 -64
  248. package/src/linefill/index.ts +20 -1
  249. package/src/math/index.ts +2 -0
  250. package/src/polyline/index.ts +3 -1
  251. package/src/runtime/adapters/SimpleInputAdapter.ts +1 -1
  252. package/src/runtime/index.ts +1 -0
  253. package/src/runtime/inputs.ts +16 -0
  254. package/src/runtime/types.ts +1 -1
  255. package/src/script/index.ts +355 -34
  256. package/src/security/other.ts +269 -0
  257. package/src/session/bars.ts +70 -6
  258. package/src/session/calendar.ts +60 -10
  259. package/src/session/context.ts +162 -0
  260. package/src/str/floatingdecimal.ts +268 -0
  261. package/src/str/index.ts +8 -2
  262. package/src/str/numberformat.ts +13 -6
  263. package/src/ta/index.ts +304 -248
  264. package/src/ta/limits.ts +74 -0
  265. package/src/ta/running-sum.ts +2 -0
  266. package/src/ta-series.ts +19 -16
  267. package/src/table/index.ts +4 -1
  268. package/src/time/index.ts +6 -3
  269. package/src/time/session.ts +137 -15
  270. package/src/time/timezone.ts +9 -2
  271. package/src/types/metadata.ts +28 -4
@@ -9,10 +9,11 @@
9
9
  * - {@link whenCalled}: vectorized, when the bars of the calls are known in advance.
10
10
  * - {@link crossover} / {@link crossunder} / {@link cross} / {@link barssince}: one stateful call site for bar
11
11
  * loops, called only on the bars where the Pine call runs.
12
- * - {@link lowest} / {@link highest}: `ta.lowest` / `ta.highest` with a series length (a different length on each
13
- * call), which PineScript computes with a state kept between calls.
14
- * - {@link lowestByBar} / {@link highestByBar} / {@link linreg}: `ta.lowest` / `ta.highest` / `ta.linreg` in a
15
- * conditional block, whose history is kept by bar (not by call).
12
+ * - {@link lowestByBar} / {@link highestByBar} / {@link lowestbars} / {@link highestbars} / {@link pivothigh} /
13
+ * {@link pivotlow}: `ta.lowest` / `ta.highest` / `ta.lowestbars` / `ta.highestbars` / `ta.pivothigh` /
14
+ * `ta.pivotlow` in a conditional block or a loop, also with a length that changes on each call. They keep the
15
+ * non-na values of their calls; {@link lowest} / {@link highest} are the same sites called with `(value, length)`.
16
+ * - {@link linreg}: `ta.linreg` in a conditional block, whose history is kept by bar (not by call).
16
17
  * - {@link sum} / {@link sma}: `math.sum` / `ta.sma` in a `for` / `while` loop, called several times on one bar.
17
18
  *
18
19
  * Since PineScript v6, `and` / `or` are lazy: the right operand runs only when the left operand does not decide
@@ -74,16 +75,9 @@ export declare function barssince(): (condition: boolean | number) => number;
74
75
  */
75
76
  export declare function cross(): (a: number, b: number) => boolean;
76
77
  /**
77
- * One `ta.lowest(source, length)` call site with a series length (a different length on each call), called with
78
- * `(value, length)`.
79
- *
80
- * PineScript rules (measured with a length that changes on each bar):
81
- * - the extreme is kept with its bar; a new value that passes it replaces it; when the kept extreme is `length`
82
- * calls old, the last `length` values are scanned again (na skipped, the oldest wins a tie)
83
- * - a length smaller than on the previous call: the last `length` values are scanned again
84
- * - a length larger than on the previous call: the values that enter the window at its old end are compared with the
85
- * extreme; when one of them is na, the extreme restarts from the current value (the values in between are not read)
86
- * - an na value gives na and resets the extreme; na before call `length - 1`
78
+ * One `ta.lowest(source, length)` call site, called with `(value, length, barIndex?)`: the same site as
79
+ * {@link lowestByBar} (same rules). Pass the bar index when the call does not run on every bar; without it every
80
+ * call counts as one bar, which is right for a call on every bar (for example with a length that changes).
87
81
  *
88
82
  * @example
89
83
  * ```typescript
@@ -92,26 +86,28 @@ export declare function cross(): (a: number, b: number) => boolean;
92
86
  * const out = closes.map((_, i) => lowPrice(i > 0 ? closes[i - 1]! : NaN, lookback[i]!));
93
87
  * ```
94
88
  */
95
- export declare function lowest(): (value: number, length: number) => number;
89
+ export declare function lowest(): (value: number, length: number, barIndex?: number) => number;
96
90
  /**
97
- * One `ta.highest(source, length)` call site with a series length (a different length on each call), called with
98
- * `(value, length)`. Same rules as {@link lowest}.
91
+ * One `ta.highest(source, length)` call site, called with `(value, length, barIndex?)`. Same rules as
92
+ * {@link lowest}.
99
93
  */
100
- export declare function highest(): (value: number, length: number) => number;
94
+ export declare function highest(): (value: number, length: number, barIndex?: number) => number;
101
95
  /**
102
- * One `ta.lowest(source, length)` call site in a conditional block whose history is kept by bar (not by call), called
103
- * with `(barIndex, value, length)` on the bars where the Pine call runs.
96
+ * One `ta.lowest(source, length)` call site in a conditional block or a loop, called with
97
+ * `(barIndex, value, length)` on the bars (and loop turns) where the Pine call runs. The length can change from one
98
+ * call to the next.
104
99
  *
105
- * PineScript rules (measured on a call in a ternary branch, length 6):
106
- * - the values are kept in a ring of `length + 1` slots indexed by the bar index, filled with 0 at the start and
107
- * written only on the bars where the call runs: a bar before the first call counts as 0, and a bar without a call
108
- * holds the value of the call `length + 1` bars earlier (0 if there was none)
109
- * - on a call, the value replaces the kept extreme when there is none or when it is strictly lower; only otherwise,
110
- * when the kept extreme is `length` bars old, the last `length` bars are read again from the ring (the oldest bar
111
- * wins a tie)
112
- * - na before bar `length - 1` (by bar, not by call)
100
+ * PineScript rules (measured in `if` blocks, ternaries, user functions and `for` loops, with constant lengths and
101
+ * lengths that change, on sources with and without na):
102
+ * - the call site keeps the non-na values it received, each with its bar; nothing is kept for a bar without a call
103
+ * or for an na value
104
+ * - the result is na while `barIndex < length - 1` (by bar, not by call) and while no value was received
105
+ * - otherwise it is the lowest of the last `length` kept values, or of all of them when there are fewer: the first
106
+ * call after bar `length - 1` gives its own value. A call with an na value also gives this result
107
+ * - in a loop (several calls on one bar), a bar has one kept value: each call replaces the value of the earlier
108
+ * calls of that bar, so a call gives the lowest of its value and the values of the bars before
113
109
  *
114
- * {@link lowest} keeps the history by call instead; both rules were measured, on different scripts.
110
+ * Called on every bar, it equals `ta.lowest`.
115
111
  *
116
112
  * @example
117
113
  * ```typescript
@@ -122,11 +118,56 @@ export declare function highest(): (value: number, length: number) => number;
122
118
  */
123
119
  export declare function lowestByBar(): (barIndex: number, value: number, length: number) => number;
124
120
  /**
125
- * One `ta.highest(source, length)` call site in a conditional block whose history is kept by bar, called with
126
- * `(barIndex, value, length)`. Same rules as {@link lowestByBar} (a value replaces the kept extreme when it is
127
- * strictly higher).
121
+ * One `ta.highest(source, length)` call site in a conditional block or a loop, called with
122
+ * `(barIndex, value, length)`. Same rules as {@link lowestByBar}.
128
123
  */
129
124
  export declare function highestByBar(): (barIndex: number, value: number, length: number) => number;
125
+ /**
126
+ * One `ta.lowestbars(source, length)` call site in a conditional block or a loop, called with
127
+ * `(barIndex, value, length)`: the offset (0 or negative) from this bar to the bar of the lowest of the last `length`
128
+ * kept values, the newest one on equal values. The values are kept as in {@link lowestByBar}; the offset counts
129
+ * bars, not calls, so it can be below `-(length - 1)`.
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Pine: off = cond ? ta.lowestbars(low, 10) : na
134
+ * const site = callsite.lowestbars();
135
+ * const off = lows.map((v, i) => (cond[i] ? site(i, v, 10) : NaN));
136
+ * ```
137
+ */
138
+ export declare function lowestbars(): (barIndex: number, value: number, length: number) => number;
139
+ /**
140
+ * One `ta.highestbars(source, length)` call site in a conditional block or a loop, called with
141
+ * `(barIndex, value, length)`. Same rules as {@link lowestbars}.
142
+ */
143
+ export declare function highestbars(): (barIndex: number, value: number, length: number) => number;
144
+ /**
145
+ * One `ta.pivothigh(source, leftbars, rightbars)` call site in a conditional block, called with
146
+ * `(barIndex, value, leftbars, rightbars)` on the bars where the Pine call runs. The lengths can change from one call
147
+ * to the next (the lengths of the current call are used).
148
+ *
149
+ * PineScript rules (measured in `if` blocks and ternaries, and on sources with na):
150
+ * - the call site keeps the non-na values it received, each with its bar
151
+ * - on a call it takes the last `leftbars + rightbars + 1` kept values (all of them when there are fewer) and finds
152
+ * the highest, the newest one on equal values
153
+ * - there is a pivot only when that value is on the bar `rightbars` BARS back (by bar index, not by call); the
154
+ * result is its value, na otherwise and before bar `leftbars + rightbars`
155
+ *
156
+ * Called on every bar, it equals `ta.pivothigh`.
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * // Pine: ph = useFilter ? ta.pivothigh(src, 5, 5) : na
161
+ * const site = callsite.pivothigh();
162
+ * const ph = src.map((v, i) => (useFilter[i] ? site(i, v, 5, 5) : NaN));
163
+ * ```
164
+ */
165
+ export declare function pivothigh(): (barIndex: number, value: number, leftbars: number, rightbars: number) => number;
166
+ /**
167
+ * One `ta.pivotlow(source, leftbars, rightbars)` call site in a conditional block, called with
168
+ * `(barIndex, value, leftbars, rightbars)`. Same rules as {@link pivothigh} (the lowest value).
169
+ */
170
+ export declare function pivotlow(): (barIndex: number, value: number, leftbars: number, rightbars: number) => number;
130
171
  /**
131
172
  * One `ta.linreg(source, length, offset)` call site in a conditional block, called with
132
173
  * `(barIndex, value, length, offset)` on the bars where the Pine call runs.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/callsite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAKhD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,OAAO,EACnD,MAAM,EAAE,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC,EACnC,EAAE,EAAE,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAC3C,GAAG,OAAO,EAAE,MAAM,EAAE,GACnB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,CASnB;AAmBD;;;GAGG;AACH,wBAAgB,SAAS,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAE7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAE9D;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,KAAK,MAAM,CAOnE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CASzD;AA2CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAEnE;AAgCD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAEzF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAE1F;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,MAAM,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAUrG;AAqCD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAGjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAGjF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,MAAM,CAUrG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,MAAM,CAE3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/callsite/index.ts"],"names":[],"mappings":"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"}
@@ -24,9 +24,13 @@ __export(callsite_exports, {
24
24
  crossunder: () => crossunder,
25
25
  highest: () => highest,
26
26
  highestByBar: () => highestByBar,
27
+ highestbars: () => highestbars,
27
28
  linreg: () => linreg,
28
29
  lowest: () => lowest,
29
30
  lowestByBar: () => lowestByBar,
31
+ lowestbars: () => lowestbars,
32
+ pivothigh: () => pivothigh,
33
+ pivotlow: () => pivotlow,
30
34
  random: () => random,
31
35
  sma: () => sma,
32
36
  stdev: () => stdev,
@@ -36,6 +40,7 @@ __export(callsite_exports, {
36
40
  module.exports = __toCommonJS(callsite_exports);
37
41
  var import_ta = require("../ta/index.js");
38
42
  var import_running_sum = require("../ta/running-sum.js");
43
+ var import_limits = require("../ta/limits.js");
39
44
  var import_math = require("../math/index.js");
40
45
  function whenCalled(called, fn, ...sources) {
41
46
  const bars = [];
@@ -83,84 +88,82 @@ function cross() {
83
88
  return result;
84
89
  };
85
90
  }
86
- function extremeSite(isLowest) {
87
- const better = isLowest ? (a, b) => a < b : (a, b) => a > b;
88
- const values = [];
89
- let extreme = NaN;
90
- let extremeAt = -1;
91
- let prevLength = NaN;
92
- const keep = (v, at) => {
93
- extreme = v;
94
- extremeAt = at;
95
- };
96
- const rescan = (i, length) => {
97
- extreme = NaN;
98
- for (let b = i; b > i - length && b >= 0; b--) {
99
- const v = values[b];
100
- if (!Number.isNaN(v) && (Number.isNaN(extreme) || !better(extreme, v))) keep(v, b);
91
+ class KeptCalls {
92
+ values = [];
93
+ bars = [];
94
+ /** Keeps a non-na value; a later call on the same bar (a loop) replaces the value of that bar. */
95
+ add(barIndex, value) {
96
+ if (Number.isNaN(value)) return;
97
+ const last = this.values.length - 1;
98
+ if (last >= 0 && this.bars[last] === barIndex) this.values[last] = value;
99
+ else {
100
+ this.values.push(value);
101
+ this.bars.push(barIndex);
101
102
  }
102
- };
103
- return (value, length) => {
104
- const i = values.length;
105
- values.push(value);
106
- if (Number.isNaN(value)) {
107
- extreme = NaN;
108
- prevLength = length;
109
- return NaN;
103
+ }
104
+ /** Position of the best of the last `count` kept values (the newest one on ties), -1 when there is none. */
105
+ best(count, isLowest) {
106
+ const last = this.values.length - 1;
107
+ if (last < 0 || !(count >= 1)) return -1;
108
+ let best = last;
109
+ for (let k = last - 1; k >= 0 && k > last - count; k--) {
110
+ if (isLowest ? this.values[k] < this.values[best] : this.values[k] > this.values[best]) best = k;
110
111
  }
111
- if (length > prevLength) {
112
- const from = Math.max(0, i - length + 1);
113
- const to = Math.max(0, i - prevLength + 1);
114
- if (values.slice(from, to).some(Number.isNaN)) keep(value, i);
115
- else {
116
- for (let b = from; b < to; b++) if (Number.isNaN(extreme) || better(values[b], extreme)) keep(values[b], b);
117
- if (Number.isNaN(extreme) || better(value, extreme)) keep(value, i);
118
- }
119
- } else if (length < prevLength || Number.isNaN(extreme) || i - extremeAt >= length) rescan(i, length);
120
- else if (better(value, extreme)) keep(value, i);
121
- prevLength = length;
122
- return i < length - 1 ? NaN : extreme;
112
+ return best;
113
+ }
114
+ }
115
+ function extremeByBarSite(isLowest, offsets) {
116
+ const kept = new KeptCalls();
117
+ const name = (isLowest ? "lowest" : "highest") + (offsets ? "bars" : "");
118
+ return (barIndex, value, length) => {
119
+ (0, import_limits.checkWindowLength)(name, length, barIndex);
120
+ kept.add(barIndex, value);
121
+ const len = Math.trunc(length);
122
+ if (barIndex < len - 1) return NaN;
123
+ const best = kept.best(len, isLowest);
124
+ if (best < 0) return NaN;
125
+ return offsets ? -(barIndex - kept.bars[best]) : kept.values[best];
123
126
  };
124
127
  }
128
+ function extremeSite(isLowest) {
129
+ const site = extremeByBarSite(isLowest, false);
130
+ let calls = 0;
131
+ return (value, length, barIndex) => site(barIndex ?? calls++, value, length);
132
+ }
125
133
  function lowest() {
126
134
  return extremeSite(true);
127
135
  }
128
136
  function highest() {
129
137
  return extremeSite(false);
130
138
  }
131
- function extremeByBarSite(isLowest) {
132
- const better = isLowest ? (a, b) => a < b : (a, b) => a > b;
133
- let ring = [];
134
- let extreme = NaN;
135
- let extremeAt = -1;
136
- return (barIndex, value, length) => {
137
- const len = Math.floor(length);
138
- if (ring.length !== len + 1) {
139
- ring = new Array(len + 1).fill(0);
140
- extreme = NaN;
141
- }
142
- ring[barIndex % (len + 1)] = value;
143
- if (Number.isNaN(extreme) || better(value, extreme)) {
144
- extreme = value;
145
- extremeAt = barIndex;
146
- } else if (barIndex - extremeAt >= len) {
147
- extreme = NaN;
148
- for (let b = barIndex - len + 1; b <= barIndex; b++) {
149
- const v = ring[b % (len + 1)];
150
- if (!Number.isNaN(v) && (Number.isNaN(extreme) || better(v, extreme))) {
151
- extreme = v;
152
- extremeAt = b;
153
- }
154
- }
155
- }
156
- return barIndex < len - 1 ? NaN : extreme;
157
- };
158
- }
159
139
  function lowestByBar() {
160
- return extremeByBarSite(true);
140
+ return extremeByBarSite(true, false);
161
141
  }
162
142
  function highestByBar() {
163
- return extremeByBarSite(false);
143
+ return extremeByBarSite(false, false);
144
+ }
145
+ function lowestbars() {
146
+ return extremeByBarSite(true, true);
147
+ }
148
+ function highestbars() {
149
+ return extremeByBarSite(false, true);
150
+ }
151
+ function pivotSite(isLowest) {
152
+ const kept = new KeptCalls();
153
+ return (barIndex, value, leftbars, rightbars) => {
154
+ kept.add(barIndex, value);
155
+ const left = Math.trunc(leftbars);
156
+ const right = Math.trunc(rightbars);
157
+ if (!(barIndex >= left + right)) return NaN;
158
+ const best = kept.best(left + right + 1, isLowest);
159
+ return best >= 0 && kept.bars[best] === barIndex - right ? kept.values[best] : NaN;
160
+ };
161
+ }
162
+ function pivothigh() {
163
+ return pivotSite(false);
164
+ }
165
+ function pivotlow() {
166
+ return pivotSite(true);
164
167
  }
165
168
  function linreg() {
166
169
  let ring = [];
@@ -180,6 +183,7 @@ function loopSumSite(name, squares) {
180
183
  let pending = false;
181
184
  return (barIndex, value, length) => {
182
185
  const len = Math.floor(length);
186
+ (0, import_limits.checkSumLength)(name === "sum" ? "math.sum" : `ta.${name}`, len, barIndex);
183
187
  if (!(len >= 1)) throw new Error(`callsite.${name}: length must be at least 1 (got ${length})`);
184
188
  if (barIndex !== lastBar) {
185
189
  if (pending) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/callsite/index.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview Per-call history of ta.* functions called in a conditional block.\n *\n * In PineScript, every ta.* call keeps its own history of the values it receives. A call inside\n * an `if` block receives values only on the bars where the block runs, so its history skips the\n * other bars: `ta.crossover(a, b)` is false on the first bar the block runs, and `ta.sma(x, 3)`\n * averages the last 3 values it received, not the last 3 bars.\n *\n * - {@link whenCalled}: vectorized, when the bars of the calls are known in advance.\n * - {@link crossover} / {@link crossunder} / {@link cross} / {@link barssince}: one stateful call site for bar\n * loops, called only on the bars where the Pine call runs.\n * - {@link lowest} / {@link highest}: `ta.lowest` / `ta.highest` with a series length (a different length on each\n * call), which PineScript computes with a state kept between calls.\n * - {@link lowestByBar} / {@link highestByBar} / {@link linreg}: `ta.lowest` / `ta.highest` / `ta.linreg` in a\n * conditional block, whose history is kept by bar (not by call).\n * - {@link sum} / {@link sma}: `math.sum` / `ta.sma` in a `for` / `while` loop, called several times on one bar.\n *\n * Since PineScript v6, `and` / `or` are lazy: the right operand runs only when the left operand does not decide\n * the result. A ta.* call in the right operand of `a or b` runs on the bars where `a` is false, in `a and b` on the\n * bars where `a` is true, so it needs a call site too:\n *\n * ```typescript\n * // Pine: longCond = longUp or (src > sig and ta.barssince(longUp) <= lookback)\n * const since = callsite.whenCalled(longUp.map((u, i) => !u && src[i] > sig[i]), (c) => taCore.barssince(c.map(Boolean)), longUp);\n * // ta.barssince(longUp) only runs where longUp is false: it never sees true and stays na\n * ```\n *\n * ```typescript\n * // Pine: if inRange\n * // buy = ta.crossover(cumRsi, 60)\n * const buy = callsite.whenCalled(inRange, (a) => taCore.crossover(a, a.map(() => 60)), cumRsi);\n *\n * // Same call in a bar loop\n * const buyCross = callsite.crossover();\n * for (let i = 0; i < n; i++) {\n * if (inRange[i]) {\n * const buy = buyCross(cumRsi[i], 60);\n * }\n * }\n * ```\n *\n * @module callsite\n */\n\nimport type { Source } from '../types/index.js';\nimport { linreg as linregSeries } from '../ta/index.js';\nimport { RunningSum, isNa } from '../ta/running-sum.js';\nimport { seededRandom } from '../math/index.js';\n\n/**\n * Runs `fn` on the bars where `called` is true only, like a ta.* call inside an `if` block.\n * `fn` receives the values of `sources` on those bars, in order; its results are placed back on\n * the same bars. The other bars get na (NaN).\n *\n * @param called - true (or non-zero) on the bars where the call runs\n * @param fn - the calculation, for example `(x) => taCore.sma(x, 3)`\n * @param sources - the arguments of the call, one value per chart bar\n */\nexport function whenCalled<T extends number | boolean>(\n called: ArrayLike<boolean | number>,\n fn: (...values: number[][]) => ArrayLike<T>,\n ...sources: Source[]\n): Array<T | number> {\n const bars: number[] = [];\n for (let i = 0; i < called.length; i++) if (called[i]) bars.push(i);\n const result = fn(...sources.map(s => bars.map(i => s[i] ?? NaN)));\n const out = new Array<T | number>(called.length).fill(NaN);\n bars.forEach((bar, k) => {\n out[bar] = result[k]!;\n });\n return out;\n}\n\n/**\n * A call site that keeps the arguments of the last call where both were not na (na before such a call), as\n * ta.crossover / ta.crossunder / ta.cross.\n */\nfunction twoSeriesSite(test: (a: number, b: number, prevA: number, prevB: number) => boolean) {\n let prevA = NaN;\n let prevB = NaN;\n return (a: number, b: number): boolean => {\n const result = test(a, b, prevA, prevB);\n if (!Number.isNaN(a) && !Number.isNaN(b)) {\n prevA = a;\n prevB = b;\n }\n return result;\n };\n}\n\n/**\n * One `ta.crossover(a, b)` call site: compared with the last call where both arguments were not na; false before\n * such a call.\n */\nexport function crossover(): (a: number, b: number) => boolean {\n return twoSeriesSite((a, b, pa, pb) => a > b && pa <= pb);\n}\n\n/**\n * One `ta.crossunder(a, b)` call site: compared with the last call where both arguments were not na; false before\n * such a call.\n */\nexport function crossunder(): (a: number, b: number) => boolean {\n return twoSeriesSite((a, b, pa, pb) => a < b && pa >= pb);\n}\n\n/**\n * One `ta.barssince(condition)` call site: the number of calls since the condition was true on a call (0 on that\n * call), na before the first true condition. An na condition counts as false.\n */\nexport function barssince(): (condition: boolean | number) => number {\n let count = NaN;\n return (condition) => {\n if (condition && !Number.isNaN(condition)) count = 0;\n else if (!Number.isNaN(count)) count++;\n return count;\n };\n}\n\n/**\n * One `ta.cross(a, b)` call site, rules of `ta.cross`: the site keeps the side of the last call where `a` was\n * strictly above or strictly below `b` (none before such a call; equal values and na arguments do not change it),\n * and is true when the arguments are strictly on the other side. False with an na argument.\n */\nexport function cross(): (a: number, b: number) => boolean {\n let side = 0; // -1: last strictly below, 1: last strictly above, 0: none yet\n return (a, b) => {\n if (Number.isNaN(a) || Number.isNaN(b)) return false;\n const result = (side < 0 && a > b) || (side > 0 && a < b);\n if (a < b) side = -1;\n else if (a > b) side = 1;\n return result;\n };\n}\n\n/** One `ta.lowest` / `ta.highest` call site with a series length; rules in {@link lowest}. */\nfunction extremeSite(isLowest: boolean): (value: number, length: number) => number {\n const better = isLowest ? (a: number, b: number) => a < b : (a: number, b: number) => a > b;\n const values: number[] = [];\n let extreme = NaN;\n let extremeAt = -1;\n let prevLength = NaN;\n const keep = (v: number, at: number) => {\n extreme = v;\n extremeAt = at;\n };\n const rescan = (i: number, length: number) => {\n extreme = NaN;\n for (let b = i; b > i - length && b >= 0; b--) {\n const v = values[b]!;\n if (!Number.isNaN(v) && (Number.isNaN(extreme) || !better(extreme, v))) keep(v, b);\n }\n };\n return (value, length) => {\n const i = values.length;\n values.push(value);\n if (Number.isNaN(value)) {\n extreme = NaN;\n prevLength = length;\n return NaN;\n }\n if (length > prevLength) {\n const from = Math.max(0, i - length + 1);\n const to = Math.max(0, i - prevLength + 1);\n if (values.slice(from, to).some(Number.isNaN)) keep(value, i);\n else {\n for (let b = from; b < to; b++) if (Number.isNaN(extreme) || better(values[b]!, extreme)) keep(values[b]!, b);\n if (Number.isNaN(extreme) || better(value, extreme)) keep(value, i);\n }\n } else if (length < prevLength || Number.isNaN(extreme) || i - extremeAt >= length) rescan(i, length);\n else if (better(value, extreme)) keep(value, i);\n prevLength = length;\n return i < length - 1 ? NaN : extreme;\n };\n}\n\n/**\n * One `ta.lowest(source, length)` call site with a series length (a different length on each call), called with\n * `(value, length)`.\n *\n * PineScript rules (measured with a length that changes on each bar):\n * - the extreme is kept with its bar; a new value that passes it replaces it; when the kept extreme is `length`\n * calls old, the last `length` values are scanned again (na skipped, the oldest wins a tie)\n * - a length smaller than on the previous call: the last `length` values are scanned again\n * - a length larger than on the previous call: the values that enter the window at its old end are compared with the\n * extreme; when one of them is na, the extreme restarts from the current value (the values in between are not read)\n * - an na value gives na and resets the extreme; na before call `length - 1`\n *\n * @example\n * ```typescript\n * // Pine: lowPrice = ta.lowest(close[1], lookback) // lookback changes per bar\n * const lowPrice = callsite.lowest();\n * const out = closes.map((_, i) => lowPrice(i > 0 ? closes[i - 1]! : NaN, lookback[i]!));\n * ```\n */\nexport function lowest(): (value: number, length: number) => number {\n return extremeSite(true);\n}\n\n/**\n * One `ta.highest(source, length)` call site with a series length (a different length on each call), called with\n * `(value, length)`. Same rules as {@link lowest}.\n */\nexport function highest(): (value: number, length: number) => number {\n return extremeSite(false);\n}\n\n/** One `ta.lowest` / `ta.highest` call site whose history is kept by bar; rules in {@link lowestByBar}. */\nfunction extremeByBarSite(isLowest: boolean): (barIndex: number, value: number, length: number) => number {\n const better = isLowest ? (a: number, b: number) => a < b : (a: number, b: number) => a > b;\n let ring: number[] = [];\n let extreme = NaN;\n let extremeAt = -1;\n return (barIndex, value, length) => {\n const len = Math.floor(length);\n if (ring.length !== len + 1) {\n ring = new Array<number>(len + 1).fill(0);\n extreme = NaN;\n }\n ring[barIndex % (len + 1)] = value;\n if (Number.isNaN(extreme) || better(value, extreme)) {\n extreme = value;\n extremeAt = barIndex;\n } else if (barIndex - extremeAt >= len) {\n extreme = NaN;\n for (let b = barIndex - len + 1; b <= barIndex; b++) {\n const v = ring[b % (len + 1)]!;\n if (!Number.isNaN(v) && (Number.isNaN(extreme) || better(v, extreme))) {\n extreme = v;\n extremeAt = b;\n }\n }\n }\n return barIndex < len - 1 ? NaN : extreme;\n };\n}\n\n/**\n * One `ta.lowest(source, length)` call site in a conditional block whose history is kept by bar (not by call), called\n * with `(barIndex, value, length)` on the bars where the Pine call runs.\n *\n * PineScript rules (measured on a call in a ternary branch, length 6):\n * - the values are kept in a ring of `length + 1` slots indexed by the bar index, filled with 0 at the start and\n * written only on the bars where the call runs: a bar before the first call counts as 0, and a bar without a call\n * holds the value of the call `length + 1` bars earlier (0 if there was none)\n * - on a call, the value replaces the kept extreme when there is none or when it is strictly lower; only otherwise,\n * when the kept extreme is `length` bars old, the last `length` bars are read again from the ring (the oldest bar\n * wins a tie)\n * - na before bar `length - 1` (by bar, not by call)\n *\n * {@link lowest} keeps the history by call instead; both rules were measured, on different scripts.\n *\n * @example\n * ```typescript\n * // Pine: lo = cond ? ta.lowest(low, 6) : na\n * const site = callsite.lowestByBar();\n * const lo = lows.map((v, i) => (cond[i] ? site(i, v, 6) : NaN));\n * ```\n */\nexport function lowestByBar(): (barIndex: number, value: number, length: number) => number {\n return extremeByBarSite(true);\n}\n\n/**\n * One `ta.highest(source, length)` call site in a conditional block whose history is kept by bar, called with\n * `(barIndex, value, length)`. Same rules as {@link lowestByBar} (a value replaces the kept extreme when it is\n * strictly higher).\n */\nexport function highestByBar(): (barIndex: number, value: number, length: number) => number {\n return extremeByBarSite(false);\n}\n\n/**\n * One `ta.linreg(source, length, offset)` call site in a conditional block, called with\n * `(barIndex, value, length, offset)` on the bars where the Pine call runs.\n *\n * PineScript rules (measured): `ta.linreg` keeps the values it receives in a ring of `length + 1` slots indexed by the\n * bar index, filled with 0 at the start and written only on the bars where it is called. The window is read from the\n * ring for the last `length` bars: a bar before the first call counts as 0, and a bar without a call holds the value of\n * the call `length + 1` bars earlier (0 if there was none). The result is na before bar `length - 1`. Called on every\n * bar, it equals `ta.linreg`.\n *\n * @example\n * ```typescript\n * // Pine: if bar_index >= 20\n * // a := ta.linreg(close, 10, 0)\n * const site = callsite.linreg();\n * const a = closes.map((c, i) => (i >= 20 ? site(i, c, 10, 0) : NaN));\n * ```\n */\nexport function linreg(): (barIndex: number, value: number, length: number, offset?: number) => number {\n let ring: number[] = [];\n return (barIndex, value, length, offset = 0) => {\n const len = Math.floor(length);\n if (ring.length !== len + 1) ring = new Array<number>(len + 1).fill(0);\n ring[barIndex % (len + 1)] = value;\n if (barIndex < len - 1) return NaN;\n const window = Array.from({ length: len }, (_, k) => ring[(barIndex - len + 1 + k) % (len + 1)]!);\n return linregSeries(window, len, offset)[len - 1]!;\n };\n}\n\n\n/**\n * One `math.sum` call site in a loop; rules in {@link sum}. With `squares`, it also keeps the running sum of the\n * squared values (for {@link stdev}). Returns `[sum, sumOfSquares]` (NaN when not kept).\n */\nfunction loopSumSite(\n name: string,\n squares: boolean\n): (barIndex: number, value: number, length: number) => [number, number] {\n const running = new RunningSum();\n const runningSq = new RunningSum();\n let lastBar = NaN;\n let pending = false;\n return (barIndex, value, length) => {\n const len = Math.floor(length);\n if (!(len >= 1)) throw new Error(`callsite.${name}: length must be at least 1 (got ${length})`);\n if (barIndex !== lastBar) {\n if (pending) {\n running.commit();\n if (squares) runningSq.commit();\n }\n pending = false;\n lastBar = barIndex;\n }\n if (isNa(value)) {\n pending = false;\n return [running.stepNa(len), squares ? runningSq.stepNa(len) : NaN];\n }\n const x = value;\n const out: [number, number] = [running.step(x, len), squares ? runningSq.step(x * x, len) : NaN];\n pending = true;\n return out;\n };\n}\n\n/**\n * One `math.sum(source, length)` call site inside a `for` / `while` loop, called with `(barIndex, value, length)` on\n * each call.\n *\n * PineScript rules (measured on calls in loops, 1 to 3 calls per bar, and bars without a call):\n * - the call site keeps one history value per bar: the value of its last call on that bar\n * - every call on a bar starts from the state of the earlier bars, so it gives the sum of its value and the last\n * `length - 1` kept values; the last call of the bar is the one kept for the later bars\n * - the length can change from one call to the next (also on the same bar): each call first moves the kept sum to\n * its own length as `math.sum` with a series length does (Kahan steps of the raw values)\n * - a bar without a call is not in the history (as a call in an `if` block)\n * - the sum is the same compensated running sum as `math.sum` (bit for bit)\n *\n * An na value is skipped as in `math.sum` (it returns the sum of the last `length` earlier values); when it is the\n * last call of a bar, the bar is not in the history (not measured).\n *\n * @example\n * ```typescript\n * // Pine: for i = 0 to 2\n * // s = math.sum(close * (1 + 0.01 * i), 7)\n * const site = callsite.sum();\n * for (let b = 0; b < closes.length; b++) {\n * for (let i = 0; i <= 2; i++) {\n * const s = site(b, closes[b]! * (1 + 0.01 * i), 7);\n * }\n * }\n * ```\n */\nexport function sum(): (barIndex: number, value: number, length: number) => number {\n const site = loopSumSite('sum', false);\n return (barIndex, value, length) => site(barIndex, value, length)[0];\n}\n\n/**\n * One `ta.sma(source, length)` call site inside a `for` / `while` loop, called with `(barIndex, value, length)` on\n * each call: {@link sum} divided by the length (same rules).\n *\n * @example\n * ```typescript\n * // Pine: evaluate(ratio) => ta.sma(gann(ratio), n) // called once per ratio in a while loop\n * const site = callsite.sma();\n * for (let b = 0; b < closes.length; b++) {\n * for (const ratio of ratios) {\n * const avg = site(b, gann(b, ratio), n);\n * }\n * }\n * ```\n */\nexport function sma(): (barIndex: number, value: number, length: number) => number {\n const site = loopSumSite('sma', false);\n return (barIndex, value, length) => site(barIndex, value, length)[0] / Math.floor(length);\n}\n\n/**\n * One `ta.stdev(source, length, biased)` call site inside a `for` / `while` loop, called with\n * `(barIndex, value, length, biased?)` on each call: the running sums of the values and of their squares follow the\n * rules of {@link sum}; the result is computed from them as `ta.stdev` (bit for bit).\n *\n * @example\n * ```typescript\n * // Pine: for len in lengths\n * // [mid, up, lo] = ta.bb(close, len, 2)\n * const avgSite = callsite.sma();\n * const devSite = callsite.stdev();\n * for (let b = 0; b < closes.length; b++) {\n * for (const len of lengths) {\n * const mid = avgSite(b, closes[b]!, len);\n * const dev = devSite(b, closes[b]!, len);\n * }\n * }\n * ```\n */\nexport function stdev(): (barIndex: number, value: number, length: number, biased?: boolean) => number {\n const site = loopSumSite('stdev', true);\n return (barIndex, value, length, biased = true) => {\n const len = Math.floor(length);\n const [s, sq] = site(barIndex, value, length);\n const mean = s / len;\n const variance = biased ? sq / len - mean * mean : sq / (len - 1) - (mean * s) / (len - 1);\n if (!biased && len <= 1) return NaN;\n return Number.isNaN(variance) ? NaN : variance > 0 ? Math.sqrt(variance) : 0;\n };\n}\n\n/**\n * One `math.random(min, max, seed)` call site: PineScript keeps one generator per call site, so two call sites\n * with the same seed give the same sequence. Called with `(min?, max?)` once per bar.\n *\n * @example\n * ```typescript\n * // Pine: a = math.random(0, 1, 42), b = math.random(0, 1, 42) // a == b on every bar\n * const a = callsite.random(42);\n * const b = callsite.random(42);\n * ```\n */\nexport function random(seed: number): (min?: number, max?: number) => number {\n return seededRandom(seed);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @fileoverview Per-call history of ta.* functions called in a conditional block.\n *\n * In PineScript, every ta.* call keeps its own history of the values it receives. A call inside\n * an `if` block receives values only on the bars where the block runs, so its history skips the\n * other bars: `ta.crossover(a, b)` is false on the first bar the block runs, and `ta.sma(x, 3)`\n * averages the last 3 values it received, not the last 3 bars.\n *\n * - {@link whenCalled}: vectorized, when the bars of the calls are known in advance.\n * - {@link crossover} / {@link crossunder} / {@link cross} / {@link barssince}: one stateful call site for bar\n * loops, called only on the bars where the Pine call runs.\n * - {@link lowestByBar} / {@link highestByBar} / {@link lowestbars} / {@link highestbars} / {@link pivothigh} /\n * {@link pivotlow}: `ta.lowest` / `ta.highest` / `ta.lowestbars` / `ta.highestbars` / `ta.pivothigh` /\n * `ta.pivotlow` in a conditional block or a loop, also with a length that changes on each call. They keep the\n * non-na values of their calls; {@link lowest} / {@link highest} are the same sites called with `(value, length)`.\n * - {@link linreg}: `ta.linreg` in a conditional block, whose history is kept by bar (not by call).\n * - {@link sum} / {@link sma}: `math.sum` / `ta.sma` in a `for` / `while` loop, called several times on one bar.\n *\n * Since PineScript v6, `and` / `or` are lazy: the right operand runs only when the left operand does not decide\n * the result. A ta.* call in the right operand of `a or b` runs on the bars where `a` is false, in `a and b` on the\n * bars where `a` is true, so it needs a call site too:\n *\n * ```typescript\n * // Pine: longCond = longUp or (src > sig and ta.barssince(longUp) <= lookback)\n * const since = callsite.whenCalled(longUp.map((u, i) => !u && src[i] > sig[i]), (c) => taCore.barssince(c.map(Boolean)), longUp);\n * // ta.barssince(longUp) only runs where longUp is false: it never sees true and stays na\n * ```\n *\n * ```typescript\n * // Pine: if inRange\n * // buy = ta.crossover(cumRsi, 60)\n * const buy = callsite.whenCalled(inRange, (a) => taCore.crossover(a, a.map(() => 60)), cumRsi);\n *\n * // Same call in a bar loop\n * const buyCross = callsite.crossover();\n * for (let i = 0; i < n; i++) {\n * if (inRange[i]) {\n * const buy = buyCross(cumRsi[i], 60);\n * }\n * }\n * ```\n *\n * @module callsite\n */\n\nimport type { Source } from '../types/index.js';\nimport { linreg as linregSeries } from '../ta/index.js';\nimport { RunningSum, isNa } from '../ta/running-sum.js';\nimport { checkSumLength, checkWindowLength } from '../ta/limits.js';\nimport { seededRandom } from '../math/index.js';\n\n/**\n * Runs `fn` on the bars where `called` is true only, like a ta.* call inside an `if` block.\n * `fn` receives the values of `sources` on those bars, in order; its results are placed back on\n * the same bars. The other bars get na (NaN).\n *\n * @param called - true (or non-zero) on the bars where the call runs\n * @param fn - the calculation, for example `(x) => taCore.sma(x, 3)`\n * @param sources - the arguments of the call, one value per chart bar\n */\nexport function whenCalled<T extends number | boolean>(\n called: ArrayLike<boolean | number>,\n fn: (...values: number[][]) => ArrayLike<T>,\n ...sources: Source[]\n): Array<T | number> {\n const bars: number[] = [];\n for (let i = 0; i < called.length; i++) if (called[i]) bars.push(i);\n const result = fn(...sources.map(s => bars.map(i => s[i] ?? NaN)));\n const out = new Array<T | number>(called.length).fill(NaN);\n bars.forEach((bar, k) => {\n out[bar] = result[k]!;\n });\n return out;\n}\n\n/**\n * A call site that keeps the arguments of the last call where both were not na (na before such a call), as\n * ta.crossover / ta.crossunder / ta.cross.\n */\nfunction twoSeriesSite(test: (a: number, b: number, prevA: number, prevB: number) => boolean) {\n let prevA = NaN;\n let prevB = NaN;\n return (a: number, b: number): boolean => {\n const result = test(a, b, prevA, prevB);\n if (!Number.isNaN(a) && !Number.isNaN(b)) {\n prevA = a;\n prevB = b;\n }\n return result;\n };\n}\n\n/**\n * One `ta.crossover(a, b)` call site: compared with the last call where both arguments were not na; false before\n * such a call.\n */\nexport function crossover(): (a: number, b: number) => boolean {\n return twoSeriesSite((a, b, pa, pb) => a > b && pa <= pb);\n}\n\n/**\n * One `ta.crossunder(a, b)` call site: compared with the last call where both arguments were not na; false before\n * such a call.\n */\nexport function crossunder(): (a: number, b: number) => boolean {\n return twoSeriesSite((a, b, pa, pb) => a < b && pa >= pb);\n}\n\n/**\n * One `ta.barssince(condition)` call site: the number of calls since the condition was true on a call (0 on that\n * call), na before the first true condition. An na condition counts as false.\n */\nexport function barssince(): (condition: boolean | number) => number {\n let count = NaN;\n return (condition) => {\n if (condition && !Number.isNaN(condition)) count = 0;\n else if (!Number.isNaN(count)) count++;\n return count;\n };\n}\n\n/**\n * One `ta.cross(a, b)` call site, rules of `ta.cross`: the site keeps the side of the last call where `a` was\n * strictly above or strictly below `b` (none before such a call; equal values and na arguments do not change it),\n * and is true when the arguments are strictly on the other side. False with an na argument.\n */\nexport function cross(): (a: number, b: number) => boolean {\n let side = 0; // -1: last strictly below, 1: last strictly above, 0: none yet\n return (a, b) => {\n if (Number.isNaN(a) || Number.isNaN(b)) return false;\n const result = (side < 0 && a > b) || (side > 0 && a < b);\n if (a < b) side = -1;\n else if (a > b) side = 1;\n return result;\n };\n}\n\n/** The values a ta.highest / ta.lowest / ta.pivothigh call site keeps: the non-na values of its calls, one per bar. */\nclass KeptCalls {\n readonly values: number[] = [];\n readonly bars: number[] = [];\n\n /** Keeps a non-na value; a later call on the same bar (a loop) replaces the value of that bar. */\n add(barIndex: number, value: number): void {\n if (Number.isNaN(value)) return;\n const last = this.values.length - 1;\n if (last >= 0 && this.bars[last] === barIndex) this.values[last] = value;\n else {\n this.values.push(value);\n this.bars.push(barIndex);\n }\n }\n\n /** Position of the best of the last `count` kept values (the newest one on ties), -1 when there is none. */\n best(count: number, isLowest: boolean): number {\n const last = this.values.length - 1;\n if (last < 0 || !(count >= 1)) return -1;\n let best = last;\n for (let k = last - 1; k >= 0 && k > last - count; k--) {\n if (isLowest ? this.values[k]! < this.values[best]! : this.values[k]! > this.values[best]!) best = k;\n }\n return best;\n }\n}\n\n/** One `ta.lowest` / `ta.highest` / `ta.lowestbars` / `ta.highestbars` call site; rules in {@link lowestByBar}. */\nfunction extremeByBarSite(\n isLowest: boolean,\n offsets: boolean\n): (barIndex: number, value: number, length: number) => number {\n const kept = new KeptCalls();\n const name = (isLowest ? 'lowest' : 'highest') + (offsets ? 'bars' : '');\n return (barIndex, value, length) => {\n checkWindowLength(name, length, barIndex);\n kept.add(barIndex, value);\n const len = Math.trunc(length);\n if (barIndex < len - 1) return NaN;\n const best = kept.best(len, isLowest);\n if (best < 0) return NaN;\n return offsets ? -(barIndex - kept.bars[best]!) : kept.values[best]!;\n };\n}\n\n/** {@link extremeByBarSite} called with `(value, length, barIndex?)`: without a bar index, every call is a new bar. */\nfunction extremeSite(isLowest: boolean): (value: number, length: number, barIndex?: number) => number {\n const site = extremeByBarSite(isLowest, false);\n let calls = 0;\n return (value, length, barIndex) => site(barIndex ?? calls++, value, length);\n}\n\n/**\n * One `ta.lowest(source, length)` call site, called with `(value, length, barIndex?)`: the same site as\n * {@link lowestByBar} (same rules). Pass the bar index when the call does not run on every bar; without it every\n * call counts as one bar, which is right for a call on every bar (for example with a length that changes).\n *\n * @example\n * ```typescript\n * // Pine: lowPrice = ta.lowest(close[1], lookback) // lookback changes per bar\n * const lowPrice = callsite.lowest();\n * const out = closes.map((_, i) => lowPrice(i > 0 ? closes[i - 1]! : NaN, lookback[i]!));\n * ```\n */\nexport function lowest(): (value: number, length: number, barIndex?: number) => number {\n return extremeSite(true);\n}\n\n/**\n * One `ta.highest(source, length)` call site, called with `(value, length, barIndex?)`. Same rules as\n * {@link lowest}.\n */\nexport function highest(): (value: number, length: number, barIndex?: number) => number {\n return extremeSite(false);\n}\n\n/**\n * One `ta.lowest(source, length)` call site in a conditional block or a loop, called with\n * `(barIndex, value, length)` on the bars (and loop turns) where the Pine call runs. The length can change from one\n * call to the next.\n *\n * PineScript rules (measured in `if` blocks, ternaries, user functions and `for` loops, with constant lengths and\n * lengths that change, on sources with and without na):\n * - the call site keeps the non-na values it received, each with its bar; nothing is kept for a bar without a call\n * or for an na value\n * - the result is na while `barIndex < length - 1` (by bar, not by call) and while no value was received\n * - otherwise it is the lowest of the last `length` kept values, or of all of them when there are fewer: the first\n * call after bar `length - 1` gives its own value. A call with an na value also gives this result\n * - in a loop (several calls on one bar), a bar has one kept value: each call replaces the value of the earlier\n * calls of that bar, so a call gives the lowest of its value and the values of the bars before\n *\n * Called on every bar, it equals `ta.lowest`.\n *\n * @example\n * ```typescript\n * // Pine: lo = cond ? ta.lowest(low, 6) : na\n * const site = callsite.lowestByBar();\n * const lo = lows.map((v, i) => (cond[i] ? site(i, v, 6) : NaN));\n * ```\n */\nexport function lowestByBar(): (barIndex: number, value: number, length: number) => number {\n return extremeByBarSite(true, false);\n}\n\n/**\n * One `ta.highest(source, length)` call site in a conditional block or a loop, called with\n * `(barIndex, value, length)`. Same rules as {@link lowestByBar}.\n */\nexport function highestByBar(): (barIndex: number, value: number, length: number) => number {\n return extremeByBarSite(false, false);\n}\n\n/**\n * One `ta.lowestbars(source, length)` call site in a conditional block or a loop, called with\n * `(barIndex, value, length)`: the offset (0 or negative) from this bar to the bar of the lowest of the last `length`\n * kept values, the newest one on equal values. The values are kept as in {@link lowestByBar}; the offset counts\n * bars, not calls, so it can be below `-(length - 1)`.\n *\n * @example\n * ```typescript\n * // Pine: off = cond ? ta.lowestbars(low, 10) : na\n * const site = callsite.lowestbars();\n * const off = lows.map((v, i) => (cond[i] ? site(i, v, 10) : NaN));\n * ```\n */\nexport function lowestbars(): (barIndex: number, value: number, length: number) => number {\n return extremeByBarSite(true, true);\n}\n\n/**\n * One `ta.highestbars(source, length)` call site in a conditional block or a loop, called with\n * `(barIndex, value, length)`. Same rules as {@link lowestbars}.\n */\nexport function highestbars(): (barIndex: number, value: number, length: number) => number {\n return extremeByBarSite(false, true);\n}\n\n/** One `ta.pivothigh` / `ta.pivotlow` call site; rules in {@link pivothigh}. */\nfunction pivotSite(isLowest: boolean): (barIndex: number, value: number, leftbars: number, rightbars: number) => number {\n const kept = new KeptCalls();\n return (barIndex, value, leftbars, rightbars) => {\n kept.add(barIndex, value);\n const left = Math.trunc(leftbars);\n const right = Math.trunc(rightbars);\n if (!(barIndex >= left + right)) return NaN;\n const best = kept.best(left + right + 1, isLowest);\n return best >= 0 && kept.bars[best] === barIndex - right ? kept.values[best]! : NaN;\n };\n}\n\n/**\n * One `ta.pivothigh(source, leftbars, rightbars)` call site in a conditional block, called with\n * `(barIndex, value, leftbars, rightbars)` on the bars where the Pine call runs. The lengths can change from one call\n * to the next (the lengths of the current call are used).\n *\n * PineScript rules (measured in `if` blocks and ternaries, and on sources with na):\n * - the call site keeps the non-na values it received, each with its bar\n * - on a call it takes the last `leftbars + rightbars + 1` kept values (all of them when there are fewer) and finds\n * the highest, the newest one on equal values\n * - there is a pivot only when that value is on the bar `rightbars` BARS back (by bar index, not by call); the\n * result is its value, na otherwise and before bar `leftbars + rightbars`\n *\n * Called on every bar, it equals `ta.pivothigh`.\n *\n * @example\n * ```typescript\n * // Pine: ph = useFilter ? ta.pivothigh(src, 5, 5) : na\n * const site = callsite.pivothigh();\n * const ph = src.map((v, i) => (useFilter[i] ? site(i, v, 5, 5) : NaN));\n * ```\n */\nexport function pivothigh(): (barIndex: number, value: number, leftbars: number, rightbars: number) => number {\n return pivotSite(false);\n}\n\n/**\n * One `ta.pivotlow(source, leftbars, rightbars)` call site in a conditional block, called with\n * `(barIndex, value, leftbars, rightbars)`. Same rules as {@link pivothigh} (the lowest value).\n */\nexport function pivotlow(): (barIndex: number, value: number, leftbars: number, rightbars: number) => number {\n return pivotSite(true);\n}\n\n/**\n * One `ta.linreg(source, length, offset)` call site in a conditional block, called with\n * `(barIndex, value, length, offset)` on the bars where the Pine call runs.\n *\n * PineScript rules (measured): `ta.linreg` keeps the values it receives in a ring of `length + 1` slots indexed by the\n * bar index, filled with 0 at the start and written only on the bars where it is called. The window is read from the\n * ring for the last `length` bars: a bar before the first call counts as 0, and a bar without a call holds the value of\n * the call `length + 1` bars earlier (0 if there was none). The result is na before bar `length - 1`. Called on every\n * bar, it equals `ta.linreg`.\n *\n * @example\n * ```typescript\n * // Pine: if bar_index >= 20\n * // a := ta.linreg(close, 10, 0)\n * const site = callsite.linreg();\n * const a = closes.map((c, i) => (i >= 20 ? site(i, c, 10, 0) : NaN));\n * ```\n */\nexport function linreg(): (barIndex: number, value: number, length: number, offset?: number) => number {\n let ring: number[] = [];\n return (barIndex, value, length, offset = 0) => {\n const len = Math.floor(length);\n if (ring.length !== len + 1) ring = new Array<number>(len + 1).fill(0);\n ring[barIndex % (len + 1)] = value;\n if (barIndex < len - 1) return NaN;\n const window = Array.from({ length: len }, (_, k) => ring[(barIndex - len + 1 + k) % (len + 1)]!);\n return linregSeries(window, len, offset)[len - 1]!;\n };\n}\n\n\n/**\n * One `math.sum` call site in a loop; rules in {@link sum}. With `squares`, it also keeps the running sum of the\n * squared values (for {@link stdev}). Returns `[sum, sumOfSquares]` (NaN when not kept).\n */\nfunction loopSumSite(\n name: string,\n squares: boolean\n): (barIndex: number, value: number, length: number) => [number, number] {\n const running = new RunningSum();\n const runningSq = new RunningSum();\n let lastBar = NaN;\n let pending = false;\n return (barIndex, value, length) => {\n const len = Math.floor(length);\n checkSumLength(name === 'sum' ? 'math.sum' : `ta.${name}`, len, barIndex);\n if (!(len >= 1)) throw new Error(`callsite.${name}: length must be at least 1 (got ${length})`);\n if (barIndex !== lastBar) {\n if (pending) {\n running.commit();\n if (squares) runningSq.commit();\n }\n pending = false;\n lastBar = barIndex;\n }\n if (isNa(value)) {\n pending = false;\n return [running.stepNa(len), squares ? runningSq.stepNa(len) : NaN];\n }\n const x = value;\n const out: [number, number] = [running.step(x, len), squares ? runningSq.step(x * x, len) : NaN];\n pending = true;\n return out;\n };\n}\n\n/**\n * One `math.sum(source, length)` call site inside a `for` / `while` loop, called with `(barIndex, value, length)` on\n * each call.\n *\n * PineScript rules (measured on calls in loops, 1 to 3 calls per bar, and bars without a call):\n * - the call site keeps one history value per bar: the value of its last call on that bar\n * - every call on a bar starts from the state of the earlier bars, so it gives the sum of its value and the last\n * `length - 1` kept values; the last call of the bar is the one kept for the later bars\n * - the length can change from one call to the next (also on the same bar): each call first moves the kept sum to\n * its own length as `math.sum` with a series length does (Kahan steps of the raw values)\n * - a bar without a call is not in the history (as a call in an `if` block)\n * - the sum is the same compensated running sum as `math.sum` (bit for bit)\n *\n * An na value is skipped as in `math.sum` (it returns the sum of the last `length` earlier values); when it is the\n * last call of a bar, the bar is not in the history (not measured).\n *\n * @example\n * ```typescript\n * // Pine: for i = 0 to 2\n * // s = math.sum(close * (1 + 0.01 * i), 7)\n * const site = callsite.sum();\n * for (let b = 0; b < closes.length; b++) {\n * for (let i = 0; i <= 2; i++) {\n * const s = site(b, closes[b]! * (1 + 0.01 * i), 7);\n * }\n * }\n * ```\n */\nexport function sum(): (barIndex: number, value: number, length: number) => number {\n const site = loopSumSite('sum', false);\n return (barIndex, value, length) => site(barIndex, value, length)[0];\n}\n\n/**\n * One `ta.sma(source, length)` call site inside a `for` / `while` loop, called with `(barIndex, value, length)` on\n * each call: {@link sum} divided by the length (same rules).\n *\n * @example\n * ```typescript\n * // Pine: evaluate(ratio) => ta.sma(gann(ratio), n) // called once per ratio in a while loop\n * const site = callsite.sma();\n * for (let b = 0; b < closes.length; b++) {\n * for (const ratio of ratios) {\n * const avg = site(b, gann(b, ratio), n);\n * }\n * }\n * ```\n */\nexport function sma(): (barIndex: number, value: number, length: number) => number {\n const site = loopSumSite('sma', false);\n return (barIndex, value, length) => site(barIndex, value, length)[0] / Math.floor(length);\n}\n\n/**\n * One `ta.stdev(source, length, biased)` call site inside a `for` / `while` loop, called with\n * `(barIndex, value, length, biased?)` on each call: the running sums of the values and of their squares follow the\n * rules of {@link sum}; the result is computed from them as `ta.stdev` (bit for bit).\n *\n * @example\n * ```typescript\n * // Pine: for len in lengths\n * // [mid, up, lo] = ta.bb(close, len, 2)\n * const avgSite = callsite.sma();\n * const devSite = callsite.stdev();\n * for (let b = 0; b < closes.length; b++) {\n * for (const len of lengths) {\n * const mid = avgSite(b, closes[b]!, len);\n * const dev = devSite(b, closes[b]!, len);\n * }\n * }\n * ```\n */\nexport function stdev(): (barIndex: number, value: number, length: number, biased?: boolean) => number {\n const site = loopSumSite('stdev', true);\n return (barIndex, value, length, biased = true) => {\n const len = Math.floor(length);\n const [s, sq] = site(barIndex, value, length);\n const mean = s / len;\n const variance = biased ? sq / len - mean * mean : sq / (len - 1) - (mean * s) / (len - 1);\n if (!biased && len <= 1) return NaN;\n return Number.isNaN(variance) ? NaN : variance > 0 ? Math.sqrt(variance) : 0;\n };\n}\n\n/**\n * One `math.random(min, max, seed)` call site: PineScript keeps one generator per call site, so two call sites\n * with the same seed give the same sequence. Called with `(min?, max?)` once per bar.\n *\n * @example\n * ```typescript\n * // Pine: a = math.random(0, 1, 42), b = math.random(0, 1, 42) // a == b on every bar\n * const a = callsite.random(42);\n * const b = callsite.random(42);\n * ```\n */\nexport function random(seed: number): (min?: number, max?: number) => number {\n return seededRandom(seed);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["linregSeries"]
7
7
  }
@@ -8,6 +8,42 @@
8
8
  * - when a creation brings the count above `max_*_count + 5`, the oldest objects are deleted until
9
9
  * `max_*_count` remain (default 50). Copies count as creations. Linefills follow the same rule with
10
10
  * `max_lines_count`; lines deleted by this rule do not delete their linefills
11
+ * - the object that was just created is never deleted by this rule
12
+ * - an object that a `var` variable of the drawing type refers to is never deleted by this rule, and it still counts
13
+ * (measured for lines, labels and boxes: with 9 held boxes and a maximum of 50, 9 held + 46 others stay; with 8
14
+ * held lines and a maximum of 5, the 8 and the newest line stay). The protection starts on the bar after the
15
+ * assignment: 12 `var` lines created on the first bar with a maximum of 5 lose the first 6. Only
16
+ * the variable itself protects: an object in a `var` array, in a field of a user type or in a variable that got
17
+ * another object or `na` later is deleted like any other. JavaScript has no `var` declaration to observe, so the
18
+ * script says it: {@link varDrawing} (a variable), or {@link holdDrawing} / {@link releaseDrawing}
19
+ * - linefills have the limit of `max_lines_count` with another rule for the held ones (measured on one script, two
20
+ * long runs): a fill is skipped when a `var` variable holds it or released it less than 5,000 bars ago (the bar
21
+ * of {@link setDrawingBar}); when the count is still above the maximum + 5 after that, the oldest fills are
22
+ * deleted until the maximum remain, the held ones too
23
+ * - the script deletes count (`line.delete`, `label.delete`, ...): each kind has a number `P` of deleted objects. A
24
+ * delete adds 1; a creation first sets `P` to 0 when it is 5 or more (3 or more for polylines)
25
+ * - polylines use `P` on every bar: a creation cuts when the count is above `max_polylines_count + 5 + P`, down to
26
+ * the maximum + `P`, and the polylines of the cut are added to `P`. A script that deletes and creates one polyline
27
+ * per bar therefore sees the cut 0, 1 or 2 bars late
28
+ * - lines, labels and boxes use `P` on the last bar only, with its value at the start of that bar: there the cut is
29
+ * above the maximum + 5 + `P`, down to the maximum + `P` (up to 4 more objects)
30
+ * - the last bar has rules of its own (measured from the count after each creation, on a closed and on an open last
31
+ * bar): a cut deletes the objects of the bars before first, at most those (a line takes its linefills with it);
32
+ * once none is left, a cut deletes objects of the last bar as on any bar. With 10 lines and a maximum of 10, 13
33
+ * lines on the last bar leave these 13: the cut at the 16th line deletes the 10 old ones only. Lines, labels and
34
+ * boxes: equal to PineScript, count after every operation and objects alive at the end, on 72 of 72 runs checked
35
+ * after the rule was written (and 218 of 218 end states before)
36
+ * - polylines on the last bar: the `P` carried from the bar before is counted twice (the first creation adds it once
37
+ * more, unless it sets `P` to 0), later creations do not set `P` to 0, and the polylines of the bars before that a
38
+ * cut deletes are added to `P`. Once none is
39
+ * left, `P` is at least the number of polylines of the bars before deleted on the last bar (by the count or by
40
+ * the script) and a cut deletes polylines of the last bar: a script that deletes its 100 polylines and creates 200
41
+ * on the last bar keeps them all (#176). Equal to PineScript for the polylines alive at the end on 271 of
42
+ * 281 probe runs; the count inside the bar can differ when the script deletes polylines of the last bar
43
+ *
44
+ * - a bar index (`xloc.bar_index`) more than 10,000 bars before the current bar stops the script (runtime error
45
+ * RE10026) in `line.new`, `box.new`, `label.new`, `polyline.new` and the setters of x. The current bar is the one
46
+ * of `eachBar` in a script run; a port with its own bar loop gives it with {@link setDrawingBar}
11
47
  *
12
48
  * The script API (`executeScript`) resets the registry at the start of every run and applies the
13
49
  * `max_*_count` values of `indicator()`. Outside a script run the registry is global to the module.
@@ -27,6 +63,54 @@ interface DrawingTypes {
27
63
  /** Default `max_lines_count`, `max_labels_count`, `max_boxes_count`, `max_polylines_count`. */
28
64
  export declare const DEFAULT_MAX_COUNT = 50;
29
65
  export type DrawingLimits = Partial<Record<Exclude<DrawingKind, 'linefill' | 'table'>, number>>;
66
+ /**
67
+ * Marks an object as held by a `var` variable (PineScript `var line l = ...` or `l := line.new(...)` on a `var`
68
+ * variable): the maximum count never deletes it, and it still counts. Returns the object.
69
+ */
70
+ export declare function holdDrawing<T extends object>(obj: T): T;
71
+ /** The `var` variable no longer refers to the object (it got another object or `na`). */
72
+ export declare function releaseDrawing(obj: object | null | undefined): void;
73
+ /** A `var` variable of a drawing type: see {@link varDrawing}. */
74
+ export interface DrawingVariable<T extends object> {
75
+ /** The object of the variable; setting it holds the new object and releases the one before */
76
+ value: T | undefined;
77
+ }
78
+ /**
79
+ * A PineScript `var` variable of a drawing type (`var line l = na`). The object it refers to is not deleted by the
80
+ * maximum count; assigning another object (or `undefined` for `na`) releases the one before.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // Pine: var line level = na
85
+ * // level := line.new(bar_index, close, bar_index + 1, close)
86
+ * const level = varDrawing<Line>();
87
+ * level.value = line.new(i, close, i + 1, close);
88
+ * ```
89
+ */
90
+ export declare function varDrawing<T extends object>(initial?: T): DrawingVariable<T>;
91
+ /** Largest distance, in bars, of a bar index before the current bar (PineScript runtime error RE10026 above it). */
92
+ export declare const MAX_DRAWING_BARS_BACK = 10000;
93
+ /** Largest distance, in bars, of a bar index after the last bar of the data (PineScript runtime error RE10020 above it). */
94
+ export declare const MAX_DRAWING_BARS_FORWARD = 500;
95
+ /**
96
+ * Tells the drawing functions which bar is being calculated (`bar_index`), so that a bar index more than 10,000
97
+ * bars back throws as in PineScript; `null` turns the check off. `eachBar` of the script API calls it.
98
+ *
99
+ * The bar also dates the objects held by a `var` variable (protected from the next bar on). `last` says that it is
100
+ * the last bar of the data, which has rules of its own for the maximum count. `lastIndex` is the bar index of the
101
+ * last bar of the data (PineScript `last_bar_index`): with it, a bar index more than 500 bars after it throws, also
102
+ * on the bars before the last one (RE10020).
103
+ */
104
+ export declare function setDrawingBar(barIndex: number | null, last?: boolean, lastIndex?: number): void;
105
+ /**
106
+ * Throws the PineScript runtime error RE10026 when `x` is a bar index more than 10,000 bars before the current bar,
107
+ * and RE10020 when it is more than 500 bars after the last bar of the data (when {@link setDrawingBar} knows it).
108
+ * `method` and `variable` are the names of the PineScript message ("line.new", "x1").
109
+ *
110
+ * Returns `x`, truncated when it is a bar index: PineScript's x is an int (a box from 5537.94 starts on bar 5537,
111
+ * #176).
112
+ */
113
+ export declare function checkBarIndex(method: string, variable: string, x: number, xloc: string | undefined): number;
30
114
  /** Records a new object and deletes the oldest objects of its kind when the count is too high. */
31
115
  export declare function register<K extends DrawingKind>(kind: K, obj: DrawingTypes[K]): DrawingTypes[K];
32
116
  /** Deletes an object (no effect when it is already deleted). */
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/drawing/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAErF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;AAEvF,UAAU,YAAY;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,+FAA+F;AAC/F,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAIpC,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAoChG,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAS9F;AAED,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAKjF;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAED,mEAAmE;AACnE,wBAAgB,GAAG,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAE1E;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,SAAS,GAAE,aAAkB,GAAG,IAAI,CAQjE;AAED,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAE/D"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/drawing/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAErF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;AAEvF,UAAU,YAAY;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,+FAA+F;AAC/F,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAIpC,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAkChG;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAOvD;AAED,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAKnE;AAgBD,kEAAkE;AAClE,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM;IAC/C,8FAA8F;IAC9F,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAY5E;AAED,oHAAoH;AACpH,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAC3C,4HAA4H;AAC5H,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAwB5C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,GAAE,OAAe,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAetG;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAiB3G;AAuDD,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAS9F;AA8BD,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CASjF;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAED,mEAAmE;AACnE,wBAAgB,GAAG,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAE1E;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,SAAS,GAAE,aAAkB,GAAG,IAAI,CAejE;AAED,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAE/D"}