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
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var script_exports = {};
30
30
  __export(script_exports, {
31
31
  BarData: () => import_series.BarData,
32
+ MissingSymbolDataError: () => MissingSymbolDataError,
32
33
  STRATEGY_DEFAULTS: () => import_strategy2.STRATEGY_DEFAULTS,
33
34
  Series: () => import_series.Series,
34
35
  alertcondition: () => alertcondition,
@@ -52,6 +53,7 @@ __export(script_exports, {
52
53
  hlc3: () => hlc3,
53
54
  hlcc4: () => hlcc4,
54
55
  hline: () => hline,
56
+ holdDrawing: () => import_registry2.holdDrawing,
55
57
  hour: () => hour,
56
58
  inSession: () => inSession,
57
59
  indicator: () => indicator,
@@ -76,6 +78,7 @@ __export(script_exports, {
76
78
  plotshape: () => plotshape,
77
79
  polyline: () => polyline,
78
80
  position: () => import_types.position,
81
+ releaseDrawing: () => import_registry2.releaseDrawing,
79
82
  request: () => request,
80
83
  second: () => second,
81
84
  seriesOf: () => seriesOf,
@@ -91,7 +94,9 @@ __export(script_exports, {
91
94
  time_close: () => time_close,
92
95
  time_tradingday: () => time_tradingday,
93
96
  timeframe: () => timeframe,
97
+ timenow: () => timenow,
94
98
  timestamp: () => timestamp,
99
+ varDrawing: () => import_registry2.varDrawing,
95
100
  volume: () => volume,
96
101
  weekofyear: () => weekofyear,
97
102
  year: () => year
@@ -112,6 +117,7 @@ var chartPointCore = __toESM(require("../chartpoint/index.js"), 1);
112
117
  var textCore = __toESM(require("../text/index.js"), 1);
113
118
  var mathCore = __toESM(require("../math/index.js"), 1);
114
119
  var import_registry = require("../drawing/registry.js");
120
+ var import_registry2 = require("../drawing/registry.js");
115
121
  var import_output = require("../drawing/output.js");
116
122
  var timeframeCore = __toESM(require("../timeframe/index.js"), 1);
117
123
  var timeCore = __toESM(require("../time/index.js"), 1);
@@ -121,6 +127,7 @@ var import_numberformat = require("../str/numberformat.js");
121
127
  var import_calendar = require("../session/calendar.js");
122
128
  var import_bars = require("../session/bars.js");
123
129
  var import_resample = require("../security/resample.js");
130
+ var import_other = require("../security/other.js");
124
131
  var import_types = require("../types/index.js");
125
132
  var import_strategy = require("../strategy/index.js");
126
133
  var import_session = require("../time/session.js");
@@ -175,12 +182,15 @@ let scriptOptions = {};
175
182
  function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {}) {
176
183
  ctxBars.setAll(barsInput);
177
184
  chartCtx = { ...chart2 };
185
+ runNow = chart2.now ?? Date.now();
178
186
  scriptOptions = options;
179
187
  ctx = freshCollector(inputs);
180
188
  (0, import_registry.resetDrawings)();
181
189
  mathCore.resetRandom();
190
+ missingSymbols = [];
182
191
  try {
183
192
  body();
193
+ if (missingSymbols.length) throw new MissingSymbolDataError(missingSymbols);
184
194
  const c = ctx;
185
195
  return {
186
196
  metadata: {
@@ -304,6 +314,10 @@ const input = {
304
314
  "input_session"
305
315
  );
306
316
  },
317
+ /** Ticker id ("NASDAQ:MSFT"), for `request.security` of another symbol (#180). */
318
+ symbol(defval, title, opts = {}) {
319
+ return registerInput({ type: "symbol", defval, title, options: opts.options, ...common(opts) }, "input_symbol");
320
+ },
307
321
  /** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
308
322
  time(defval, title, opts = {}) {
309
323
  const v = registerInput({ type: "time", defval, title, ...common(opts) }, "input_time");
@@ -355,10 +369,12 @@ const ta = {
355
369
  highestbars: (sourceOrLength, length) => typeof sourceOrLength === "number" ? taSeries.highestbars(high, sourceOrLength) : taSeries.highestbars(sourceOrLength, length),
356
370
  /** `ta.lowestbars(source, length)` or `ta.lowestbars(length)` (source = low); offsets are 0 or negative. */
357
371
  lowestbars: (sourceOrLength, length) => typeof sourceOrLength === "number" ? taSeries.lowestbars(low, sourceOrLength) : taSeries.lowestbars(sourceOrLength, length),
358
- /** `ta.vwap(source, anchor?, stdev_mult?)` with the chart volume; the default anchor is a new trading
359
- * day (`timeframe.change("1D")`), which needs the chart context (timeframe, time zone, session). */
372
+ /** `ta.vwap(source, anchor?, stdev_mult?)` with the chart volume; the default anchor is a new trading day
373
+ * and the first bar: as in PineScript, the first loaded bars (a day in progress) have a value. On D / W / M
374
+ * charts every bar is a new day (no time zone or session needed); on intraday charts it needs the chart context
375
+ * (timeframe, time zone, session). */
360
376
  vwap: ((source, anchor, stdev_mult) => {
361
- const a = anchor ?? changeOf("1D");
377
+ const a = anchor ?? vwapAnchor();
362
378
  return stdev_mult === void 0 ? taSeries.vwap(source, volume, a) : taSeries.vwapBands(source, volume, a, stdev_mult);
363
379
  }),
364
380
  /** `ta.mfi(source, length)` with the chart volume (PineScript takes 2 arguments). */
@@ -758,6 +774,7 @@ function eachBar(fn) {
758
774
  for (idx = 0; idx < b.length; idx++) {
759
775
  if (pendingError && pendingError.bar === idx) throw new Error((0, import_series.historyError)(idx, pendingError.barsBack));
760
776
  currentBar = idx;
777
+ (0, import_registry.setDrawingBar)(idx, idx === b.length - 1, b.length - 1);
761
778
  const r = fn(ctx2);
762
779
  out[idx] = typeof r === "number" ? r : typeof r === "boolean" ? r ? 1 : 0 : NaN;
763
780
  for (const buffer of buffers.values()) {
@@ -773,6 +790,7 @@ function eachBar(fn) {
773
790
  }
774
791
  } finally {
775
792
  currentBar = -1;
793
+ (0, import_registry.setDrawingBar)(null);
776
794
  }
777
795
  return import_series.Series.fromArray(ctxBars, out);
778
796
  }
@@ -918,6 +936,17 @@ const strategy = Object.defineProperties(
918
936
  Object.assign((title, options) => declareStrategy(title, options), strategyMembers),
919
937
  variableGetters
920
938
  );
939
+ class MissingSymbolDataError extends Error {
940
+ constructor(requests) {
941
+ super(
942
+ `request.security needs the bars of ${requests.map((r) => `${r.symbol} (${r.timeframe})`).join(", ")}: pass them with ChartContext.bars.`
943
+ );
944
+ this.requests = requests;
945
+ this.name = "MissingSymbolDataError";
946
+ }
947
+ requests;
948
+ }
949
+ let missingSymbols = [];
921
950
  let chartCtx = {};
922
951
  function chartTimeframe() {
923
952
  collector();
@@ -988,6 +1017,14 @@ function symbolProperty(key) {
988
1017
  }
989
1018
  return value;
990
1019
  }
1020
+ function chartText(key, name) {
1021
+ collector();
1022
+ const value = chartCtx[key];
1023
+ if (value === void 0) {
1024
+ throw new Error(`${name} is not known: pass it as executeScript(body, bars, inputs, { ${key} }).`);
1025
+ }
1026
+ return value;
1027
+ }
991
1028
  function symbolScale() {
992
1029
  collector();
993
1030
  const { minmove, pricescale } = chartCtx;
@@ -1024,6 +1061,18 @@ const syminfo = {
1024
1061
  get session() {
1025
1062
  collector();
1026
1063
  return chartCtx.sessionType ?? "regular";
1064
+ },
1065
+ get type() {
1066
+ return chartText("symbolType", "syminfo.type");
1067
+ },
1068
+ get currency() {
1069
+ return chartText("currency", "syminfo.currency");
1070
+ },
1071
+ get basecurrency() {
1072
+ return chartText("basecurrency", "syminfo.basecurrency");
1073
+ },
1074
+ get root() {
1075
+ return chartText("root", "syminfo.root");
1027
1076
  }
1028
1077
  };
1029
1078
  function calendar(fn) {
@@ -1085,7 +1134,7 @@ function sessionBars() {
1085
1134
  }
1086
1135
  return sessionCache;
1087
1136
  }
1088
- function calendarFor(session2, timezone) {
1137
+ function calendarFor(session2, timezone, dayPlacement = false) {
1089
1138
  const { bars: bars2 } = sessionBars();
1090
1139
  if (!session2 && !timezone) return { bars: bars2, test: false };
1091
1140
  const tz = timezone ?? exchangeTimezone();
@@ -1095,7 +1144,12 @@ function calendarFor(session2, timezone) {
1095
1144
  return { bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, { session: toSpec(symbol).session }, "symbol"), bars2.chart.period), test: true };
1096
1145
  }
1097
1146
  const spec = session2 ? { session: session2 } : { session: toSpec(chartCtx.session).session };
1098
- return { bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, spec, session2 ? "pine" : "symbol"), bars2.chart.period), test: true };
1147
+ return {
1148
+ bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, spec, session2 ? "pine" : "symbol", dayPlacement), bars2.chart.period),
1149
+ test: true,
1150
+ // a PineScript session string: the rules of time.inSession (runs ending at 0000, days around a clock change)
1151
+ inside: session2 ? (time2) => timeCore.inSession(time2, session2, tz, timeframeCore.in_seconds(bars2.chart.period) * 1e3) : void 0
1152
+ };
1099
1153
  }
1100
1154
  function perBar(fn) {
1101
1155
  const times = ctxBars.bars.map(barTime);
@@ -1106,27 +1160,73 @@ function callableSeries(series, fn) {
1106
1160
  Object.assign(fn, series);
1107
1161
  return fn;
1108
1162
  }
1163
+ function sessionPeriods(timeframeString, session2, timezone) {
1164
+ const tf = timeframeCore.info(timeframeString);
1165
+ const { bars: bars2, test, inside } = calendarFor(session2, timezone, !tf.isintraday);
1166
+ const open2 = (t) => bars2.timeOf(t, timeframeString);
1167
+ const close2 = (t) => bars2.closeOf(t, timeframeString);
1168
+ if (!test) return { open: open2, close: close2 };
1169
+ if (tf.isintraday) {
1170
+ if (session2 !== void 0 && (0, import_session.parsePineSession)(session2) !== null && !bars2.chart.isdwm) {
1171
+ const tz = timezone ?? exchangeTimezone();
1172
+ const barMs = timeframeCore.in_seconds(bars2.chart.period) * 1e3;
1173
+ const ms = timeframeCore.in_seconds(tf.period) * 1e3;
1174
+ const run = (t) => (0, import_session.sessionRun)(t, session2, tz, barMs);
1175
+ const start = (t, r) => r[0] + Math.floor((t - r[0]) / ms) * ms;
1176
+ return {
1177
+ open: (t) => {
1178
+ const r = run(t);
1179
+ return r ? start(t, r) : NaN;
1180
+ },
1181
+ close: (t) => {
1182
+ const r = run(t);
1183
+ return r ? Math.min(start(t, r) + ms, r[1]) : NaN;
1184
+ }
1185
+ };
1186
+ }
1187
+ const isIn = (t) => inside ? inside(t) : bars2.inside(t);
1188
+ return { open: (t) => isIn(t) ? open2(t) : NaN, close: (t) => isIn(t) ? close2(t) : NaN };
1189
+ }
1190
+ if (tf.isdaily && tf.multiplier === 1) {
1191
+ return { open: (t) => bars2.inside(t) ? open2(t) : NaN, close: (t) => bars2.inside(t) ? close2(t) : NaN };
1192
+ }
1193
+ return { open: open2, close: close2 };
1194
+ }
1109
1195
  function timeFunction(tf, session2, timezone) {
1110
1196
  collector();
1111
- const { bars: bars2, test } = calendarFor(session2, timezone);
1112
- const timeframeString = tf || chartTimeframe().period;
1113
- return perBar((t) => test && !bars2.inside(t) ? NaN : bars2.timeOf(t, timeframeString));
1197
+ const { open: open2 } = sessionPeriods(tf || chartTimeframe().period, session2, timezone);
1198
+ return perBar((t) => open2(t));
1114
1199
  }
1115
1200
  function timeCloseFunction(tf, session2, timezone) {
1116
1201
  collector();
1117
- const { bars: bars2, test } = calendarFor(session2, timezone);
1118
- const timeframeString = tf || chartTimeframe().period;
1119
- return perBar((t) => test && !bars2.inside(t) ? NaN : bars2.closeOf(t, timeframeString));
1202
+ const { close: close2 } = sessionPeriods(tf || chartTimeframe().period, session2, timezone);
1203
+ return perBar((t) => close2(t));
1120
1204
  }
1205
+ let runNow = NaN;
1206
+ const timenow = new import_series.Series(ctxBars, () => runNow);
1121
1207
  const time = callableSeries(new import_series.Series(ctxBars, (b) => barTime(b)), timeFunction);
1122
1208
  const time_close = callableSeries(
1123
1209
  new import_series.Series(ctxBars, (_b, i) => sessionBars().bars.closeOf(barTime(ctxBars.bars[i]), chartTimeframe().period)),
1124
1210
  timeCloseFunction
1125
1211
  );
1126
1212
  const time_tradingday = new import_series.Series(ctxBars, (b) => sessionBars().bars.tradingDayTime(barTime(b)));
1127
- function changeOf(tf) {
1213
+ function changeOf(tf, firstBar = false) {
1214
+ const { bars: bars2 } = sessionBars();
1215
+ const changed = (a, b) => !Number.isNaN(a) && !Number.isNaN(b) && a !== b;
1216
+ return perBar((t, i, times) => (i > 0 ? changed(bars2.timeOf(t, tf), bars2.timeOf(times[i - 1], tf)) : firstBar) ? 1 : 0);
1217
+ }
1218
+ function vwapAnchor() {
1219
+ if (chartTimeframe().isdwm) return barFlag(() => true);
1128
1220
  const { bars: bars2 } = sessionBars();
1129
- return perBar((t, i, times) => i > 0 && bars2.timeOf(t, tf) !== bars2.timeOf(times[i - 1], tf) ? 1 : 0);
1221
+ let last = NaN;
1222
+ let previous = NaN;
1223
+ return perBar((t, i) => {
1224
+ const day = bars2.timeOf(t, "1D");
1225
+ const isNew = i === 0 || (Number.isNaN(day) ? Number.isNaN(previous) : day !== last);
1226
+ if (!Number.isNaN(day)) last = day;
1227
+ previous = day;
1228
+ return isNew ? 1 : 0;
1229
+ });
1130
1230
  }
1131
1231
  function flag(key) {
1132
1232
  const { bars: bars2, regular } = sessionBars();
@@ -1213,17 +1313,17 @@ function valuesOf(value, length) {
1213
1313
  }
1214
1314
  return value.toArray().slice();
1215
1315
  }
1216
- function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off) {
1316
+ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off, ignore_invalid_symbol = false) {
1217
1317
  collector();
1218
1318
  const heikin = symbol.startsWith(HEIKIN_ASHI);
1219
1319
  const base = heikin ? symbol.slice(HEIKIN_ASHI.length) : symbol;
1220
- if (base !== "" && base !== chartCtx.tickerid) {
1221
- throw new Error(`request.security: "${symbol}" is not the chart symbol; other symbols need external data.`);
1222
- }
1223
1320
  const chart2 = chartTimeframe();
1224
1321
  const tf = timeframeCore.info(timeframe2 || chart2.period).period;
1322
+ if (base !== "" && base !== chartCtx.tickerid) {
1323
+ return externalSecurity(base, heikin, tf, expression, gaps, lookahead, ignore_invalid_symbol, false);
1324
+ }
1225
1325
  if (timeframeCore.in_seconds(tf) < timeframeCore.in_seconds(chart2.period)) {
1226
- throw new Error(`request.security: timeframe "${tf}" is lower than the chart timeframe "${chart2.period}".`);
1326
+ return externalSecurity(chartCtx.tickerid ?? "", heikin, tf, expression, gaps, lookahead, ignore_invalid_symbol, true);
1227
1327
  }
1228
1328
  const chartBars = ctxBars.bars;
1229
1329
  const times = chartBars.map(barTime);
@@ -1243,6 +1343,8 @@ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, look
1243
1343
  const periods = at ? calendar2.calendar.periods(at.date) : [];
1244
1344
  return periods.length ? calendar2.timeOf(periods[0][0], tf) : starts[i];
1245
1345
  });
1346
+ const tfInfo = timeframeCore.info(tf);
1347
+ (0, import_bars.strayPeriods)(starts, dayPeriods, times, loaded, tfInfo.isdwm ? null : timeframeCore.in_seconds(tf) * 1e3);
1246
1348
  const reaches = times.map((t) => loaded.closeOf(t, chart2.period) >= calendar2.periodEnd(t, tf));
1247
1349
  ({ group, latest } = (0, import_resample.periodsOf)(starts, dayPeriods, reaches));
1248
1350
  const unit = chartCtx.timeUnit === "ms" ? 1 : 1e3;
@@ -1269,7 +1371,85 @@ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, look
1269
1371
  );
1270
1372
  return Array.isArray(result) ? mapped : mapped[0];
1271
1373
  }
1272
- const request = { security };
1374
+ function runExternal(symbol, heikin, tf, expression, ignoreInvalid, own) {
1375
+ let bars2 = chartCtx.bars?.(symbol, tf);
1376
+ if (bars2 === void 0 && !missingSymbols.some((r) => r.symbol === symbol && r.timeframe === tf)) {
1377
+ missingSymbols.push({ symbol, timeframe: tf });
1378
+ }
1379
+ if (bars2 !== void 0 && bars2.length === 0 && !ignoreInvalid) throw new Error(`Invalid symbol: ${symbol}`);
1380
+ bars2 ??= [];
1381
+ if (heikin) bars2 = (0, import_resample.heikinAshi)(bars2);
1382
+ const given2 = chartCtx.symbolInfo?.(symbol);
1383
+ const info = own ? { ...chartCtx, ...given2 } : given2 ?? {};
1384
+ const chartBars = ctxBars.bars;
1385
+ const savedCtx = chartCtx;
1386
+ let result;
1387
+ let values;
1388
+ ctxBars.setAll(bars2);
1389
+ chartCtx = {
1390
+ ...chartCtx,
1391
+ tickerid: symbol,
1392
+ timeframe: tf,
1393
+ timezone: info.timezone,
1394
+ session: info.session,
1395
+ regularSession: info.regularSession,
1396
+ mintick: info.mintick,
1397
+ minmove: info.minmove,
1398
+ pricescale: info.pricescale,
1399
+ pointvalue: info.pointvalue,
1400
+ mincontract: info.mincontract,
1401
+ symbolType: info.symbolType,
1402
+ currency: info.currency,
1403
+ basecurrency: info.basecurrency,
1404
+ root: info.root
1405
+ };
1406
+ try {
1407
+ result = expression();
1408
+ const parts = Array.isArray(result) ? result : [result];
1409
+ values = parts.map((p) => valuesOf(p, bars2.length));
1410
+ } finally {
1411
+ ctxBars.setAll(chartBars);
1412
+ chartCtx = savedCtx;
1413
+ }
1414
+ return { bars: bars2, info, result, values };
1415
+ }
1416
+ function mergeChart() {
1417
+ return {
1418
+ timeframe: chartTimeframe().period,
1419
+ timezone: chartCtx.timezone,
1420
+ session: chartCtx.session,
1421
+ timeUnit: chartCtx.timeUnit,
1422
+ // the realtime rule applies to a last bar that receives live updates
1423
+ lastBarConfirmed: chartCtx.realtime !== true
1424
+ };
1425
+ }
1426
+ function externalSecurity(symbol, heikin, tf, expression, gaps, lookahead, ignoreInvalid, own) {
1427
+ const { bars: bars2, info, result, values } = runExternal(symbol, heikin, tf, expression, ignoreInvalid, own);
1428
+ const index = (0, import_other.securityOther)(ctxBars.bars, bars2, tf, mergeChart(), {
1429
+ gaps: gaps === barmerge.gaps_on,
1430
+ lookahead: lookahead === barmerge.lookahead_on,
1431
+ other: info
1432
+ });
1433
+ const mapped = values.map((v) => import_series.Series.fromArray(ctxBars, index.map((j) => j < 0 ? NaN : v[j] ?? NaN)));
1434
+ return Array.isArray(result) ? mapped : mapped[0];
1435
+ }
1436
+ function security_lower_tf(symbol, timeframe2, expression, ignore_invalid_symbol = false) {
1437
+ collector();
1438
+ const heikin = symbol.startsWith(HEIKIN_ASHI);
1439
+ const base = heikin ? symbol.slice(HEIKIN_ASHI.length) : symbol;
1440
+ const chart2 = chartTimeframe();
1441
+ const tf = timeframeCore.info(timeframe2 || chart2.period).period;
1442
+ if (timeframeCore.in_seconds(tf) > timeframeCore.in_seconds(chart2.period)) {
1443
+ throw new Error(`request.security_lower_tf: timeframe "${tf}" is higher than the chart timeframe "${chart2.period}".`);
1444
+ }
1445
+ const own = base === "" || base === chartCtx.tickerid;
1446
+ const ticker2 = own ? chartCtx.tickerid ?? "" : base;
1447
+ const { bars: bars2, info, result, values } = runExternal(ticker2, heikin, tf, expression, ignore_invalid_symbol, own);
1448
+ const ranges = (0, import_other.securityLowerTf)(ctxBars.bars, bars2, tf, mergeChart(), { other: info });
1449
+ const mapped = values.map((v) => ranges.map(([from, to]) => v.slice(from, to)));
1450
+ return Array.isArray(result) ? mapped : mapped[0];
1451
+ }
1452
+ const request = { security, security_lower_tf };
1273
1453
  const line = {
1274
1454
  ...lineCore,
1275
1455
  get all() {
@@ -1308,6 +1488,14 @@ const table = {
1308
1488
  };
1309
1489
  const text = { ...textCore };
1310
1490
  const chart = {
1491
+ /** Chart foreground colour (PineScript `chart.fg_color`), from the chart context. */
1492
+ get fg_color() {
1493
+ return chartText("foregroundColor", "chart.fg_color");
1494
+ },
1495
+ /** Chart background colour (PineScript `chart.bg_color`), from the chart context. */
1496
+ get bg_color() {
1497
+ return chartText("backgroundColor", "chart.bg_color");
1498
+ },
1311
1499
  point: {
1312
1500
  ...chartPointCore,
1313
1501
  now(price) {