oakscriptjs 0.11.0 → 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 (236) 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.js +6 -6
  6. package/dist/cjs/box/index.js.map +2 -2
  7. package/dist/cjs/callsite/index.js +1 -1
  8. package/dist/cjs/callsite/index.js.map +2 -2
  9. package/dist/cjs/drawing/registry.d.ts +15 -6
  10. package/dist/cjs/drawing/registry.d.ts.map +1 -1
  11. package/dist/cjs/drawing/registry.js +16 -2
  12. package/dist/cjs/drawing/registry.js.map +2 -2
  13. package/dist/cjs/index.d.ts +3 -2
  14. package/dist/cjs/index.d.ts.map +1 -1
  15. package/dist/cjs/index.js +6 -1
  16. package/dist/cjs/index.js.map +2 -2
  17. package/dist/cjs/input.d.ts +9 -1
  18. package/dist/cjs/input.d.ts.map +1 -1
  19. package/dist/cjs/input.js +16 -0
  20. package/dist/cjs/input.js.map +2 -2
  21. package/dist/cjs/label/index.js +3 -3
  22. package/dist/cjs/label/index.js.map +2 -2
  23. package/dist/cjs/line/index.d.ts +10 -27
  24. package/dist/cjs/line/index.d.ts.map +1 -1
  25. package/dist/cjs/line/index.js +10 -27
  26. package/dist/cjs/line/index.js.map +2 -2
  27. package/dist/cjs/linefill/index.d.ts +3 -0
  28. package/dist/cjs/linefill/index.d.ts.map +1 -1
  29. package/dist/cjs/linefill/index.js +15 -1
  30. package/dist/cjs/linefill/index.js.map +3 -3
  31. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +1 -1
  32. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +2 -2
  33. package/dist/cjs/runtime/index.d.ts +1 -1
  34. package/dist/cjs/runtime/index.d.ts.map +1 -1
  35. package/dist/cjs/runtime/index.js +1 -0
  36. package/dist/cjs/runtime/index.js.map +2 -2
  37. package/dist/cjs/runtime/inputs.d.ts +9 -0
  38. package/dist/cjs/runtime/inputs.d.ts.map +1 -1
  39. package/dist/cjs/runtime/inputs.js +8 -0
  40. package/dist/cjs/runtime/inputs.js.map +2 -2
  41. package/dist/cjs/runtime/types.d.ts +1 -1
  42. package/dist/cjs/runtime/types.d.ts.map +1 -1
  43. package/dist/cjs/runtime/types.js.map +1 -1
  44. package/dist/cjs/script/index.d.ts +65 -12
  45. package/dist/cjs/script/index.d.ts.map +1 -1
  46. package/dist/cjs/script/index.js +168 -19
  47. package/dist/cjs/script/index.js.map +3 -3
  48. package/dist/cjs/security/other.d.ts +92 -0
  49. package/dist/cjs/security/other.d.ts.map +1 -0
  50. package/dist/cjs/security/other.js +164 -0
  51. package/dist/cjs/security/other.js.map +7 -0
  52. package/dist/cjs/session/bars.d.ts +10 -1
  53. package/dist/cjs/session/bars.d.ts.map +1 -1
  54. package/dist/cjs/session/bars.js +16 -2
  55. package/dist/cjs/session/bars.js.map +2 -2
  56. package/dist/cjs/session/calendar.d.ts +4 -1
  57. package/dist/cjs/session/calendar.d.ts.map +1 -1
  58. package/dist/cjs/session/calendar.js +11 -7
  59. package/dist/cjs/session/calendar.js.map +2 -2
  60. package/dist/cjs/session/context.d.ts +2 -1
  61. package/dist/cjs/session/context.d.ts.map +1 -1
  62. package/dist/cjs/session/context.js +2 -1
  63. package/dist/cjs/session/context.js.map +2 -2
  64. package/dist/cjs/str/floatingdecimal.d.ts +31 -0
  65. package/dist/cjs/str/floatingdecimal.d.ts.map +1 -0
  66. package/dist/cjs/str/floatingdecimal.js +298 -0
  67. package/dist/cjs/str/floatingdecimal.js.map +7 -0
  68. package/dist/cjs/str/index.d.ts +4 -3
  69. package/dist/cjs/str/index.d.ts.map +1 -1
  70. package/dist/cjs/str/index.js +1 -1
  71. package/dist/cjs/str/index.js.map +2 -2
  72. package/dist/cjs/str/numberformat.d.ts +6 -4
  73. package/dist/cjs/str/numberformat.d.ts.map +1 -1
  74. package/dist/cjs/str/numberformat.js +3 -2
  75. package/dist/cjs/str/numberformat.js.map +2 -2
  76. package/dist/cjs/ta/index.d.ts +34 -17
  77. package/dist/cjs/ta/index.d.ts.map +1 -1
  78. package/dist/cjs/ta/index.js +132 -116
  79. package/dist/cjs/ta/index.js.map +2 -2
  80. package/dist/cjs/ta/limits.d.ts +11 -0
  81. package/dist/cjs/ta/limits.d.ts.map +1 -1
  82. package/dist/cjs/ta/limits.js +15 -1
  83. package/dist/cjs/ta/limits.js.map +2 -2
  84. package/dist/cjs/ta/running-sum.js +1 -1
  85. package/dist/cjs/ta/running-sum.js.map +2 -2
  86. package/dist/cjs/ta-series.d.ts +1 -1
  87. package/dist/cjs/ta-series.d.ts.map +1 -1
  88. package/dist/cjs/ta-series.js +1 -1
  89. package/dist/cjs/ta-series.js.map +2 -2
  90. package/dist/cjs/table/index.d.ts +3 -1
  91. package/dist/cjs/table/index.d.ts.map +1 -1
  92. package/dist/cjs/table/index.js +1 -0
  93. package/dist/cjs/table/index.js.map +3 -3
  94. package/dist/cjs/time/session.d.ts +9 -0
  95. package/dist/cjs/time/session.d.ts.map +1 -1
  96. package/dist/cjs/time/session.js +42 -14
  97. package/dist/cjs/time/session.js.map +3 -3
  98. package/dist/cjs/time/timezone.d.ts +6 -1
  99. package/dist/cjs/time/timezone.d.ts.map +1 -1
  100. package/dist/cjs/time/timezone.js +2 -2
  101. package/dist/cjs/time/timezone.js.map +2 -2
  102. package/dist/cjs/types/metadata.d.ts +1 -1
  103. package/dist/cjs/types/metadata.d.ts.map +1 -1
  104. package/dist/cjs/types/metadata.js.map +1 -1
  105. package/dist/esm/array/index.d.ts +8 -2
  106. package/dist/esm/array/index.d.ts.map +1 -1
  107. package/dist/esm/array/index.js +12 -3
  108. package/dist/esm/array/index.js.map +1 -1
  109. package/dist/esm/box/index.js +6 -6
  110. package/dist/esm/box/index.js.map +1 -1
  111. package/dist/esm/callsite/index.js +1 -1
  112. package/dist/esm/callsite/index.js.map +1 -1
  113. package/dist/esm/drawing/registry.d.ts +15 -6
  114. package/dist/esm/drawing/registry.d.ts.map +1 -1
  115. package/dist/esm/drawing/registry.js +30 -7
  116. package/dist/esm/drawing/registry.js.map +1 -1
  117. package/dist/esm/index.d.ts +3 -2
  118. package/dist/esm/index.d.ts.map +1 -1
  119. package/dist/esm/index.js +4 -2
  120. package/dist/esm/index.js.map +1 -1
  121. package/dist/esm/input.d.ts +9 -1
  122. package/dist/esm/input.d.ts.map +1 -1
  123. package/dist/esm/input.js +16 -0
  124. package/dist/esm/input.js.map +1 -1
  125. package/dist/esm/label/index.js +3 -3
  126. package/dist/esm/label/index.js.map +1 -1
  127. package/dist/esm/line/index.d.ts +10 -27
  128. package/dist/esm/line/index.d.ts.map +1 -1
  129. package/dist/esm/line/index.js +20 -64
  130. package/dist/esm/line/index.js.map +1 -1
  131. package/dist/esm/linefill/index.d.ts +3 -0
  132. package/dist/esm/linefill/index.d.ts.map +1 -1
  133. package/dist/esm/linefill/index.js +20 -1
  134. package/dist/esm/linefill/index.js.map +1 -1
  135. package/dist/esm/runtime/adapters/SimpleInputAdapter.js +1 -1
  136. package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -1
  137. package/dist/esm/runtime/index.d.ts +1 -1
  138. package/dist/esm/runtime/index.d.ts.map +1 -1
  139. package/dist/esm/runtime/index.js +1 -1
  140. package/dist/esm/runtime/index.js.map +1 -1
  141. package/dist/esm/runtime/inputs.d.ts +9 -0
  142. package/dist/esm/runtime/inputs.d.ts.map +1 -1
  143. package/dist/esm/runtime/inputs.js +15 -0
  144. package/dist/esm/runtime/inputs.js.map +1 -1
  145. package/dist/esm/runtime/types.d.ts +1 -1
  146. package/dist/esm/runtime/types.d.ts.map +1 -1
  147. package/dist/esm/script/index.d.ts +65 -12
  148. package/dist/esm/script/index.d.ts.map +1 -1
  149. package/dist/esm/script/index.js +217 -29
  150. package/dist/esm/script/index.js.map +1 -1
  151. package/dist/esm/security/other.d.ts +92 -0
  152. package/dist/esm/security/other.d.ts.map +1 -0
  153. package/dist/esm/security/other.js +211 -0
  154. package/dist/esm/security/other.js.map +1 -0
  155. package/dist/esm/session/bars.d.ts +10 -1
  156. package/dist/esm/session/bars.d.ts.map +1 -1
  157. package/dist/esm/session/bars.js +26 -1
  158. package/dist/esm/session/bars.js.map +1 -1
  159. package/dist/esm/session/calendar.d.ts +4 -1
  160. package/dist/esm/session/calendar.d.ts.map +1 -1
  161. package/dist/esm/session/calendar.js +19 -7
  162. package/dist/esm/session/calendar.js.map +1 -1
  163. package/dist/esm/session/context.d.ts +2 -1
  164. package/dist/esm/session/context.d.ts.map +1 -1
  165. package/dist/esm/session/context.js +5 -3
  166. package/dist/esm/session/context.js.map +1 -1
  167. package/dist/esm/str/floatingdecimal.d.ts +31 -0
  168. package/dist/esm/str/floatingdecimal.d.ts.map +1 -0
  169. package/dist/esm/str/floatingdecimal.js +272 -0
  170. package/dist/esm/str/floatingdecimal.js.map +1 -0
  171. package/dist/esm/str/index.d.ts +4 -3
  172. package/dist/esm/str/index.d.ts.map +1 -1
  173. package/dist/esm/str/index.js +6 -5
  174. package/dist/esm/str/index.js.map +1 -1
  175. package/dist/esm/str/numberformat.d.ts +6 -4
  176. package/dist/esm/str/numberformat.d.ts.map +1 -1
  177. package/dist/esm/str/numberformat.js +9 -5
  178. package/dist/esm/str/numberformat.js.map +1 -1
  179. package/dist/esm/ta/index.d.ts +34 -17
  180. package/dist/esm/ta/index.d.ts.map +1 -1
  181. package/dist/esm/ta/index.js +155 -185
  182. package/dist/esm/ta/index.js.map +1 -1
  183. package/dist/esm/ta/limits.d.ts +11 -0
  184. package/dist/esm/ta/limits.d.ts.map +1 -1
  185. package/dist/esm/ta/limits.js +27 -2
  186. package/dist/esm/ta/limits.js.map +1 -1
  187. package/dist/esm/ta/running-sum.js +1 -1
  188. package/dist/esm/ta/running-sum.js.map +1 -1
  189. package/dist/esm/ta-series.d.ts +1 -1
  190. package/dist/esm/ta-series.d.ts.map +1 -1
  191. package/dist/esm/ta-series.js +2 -1
  192. package/dist/esm/ta-series.js.map +1 -1
  193. package/dist/esm/table/index.d.ts +3 -1
  194. package/dist/esm/table/index.d.ts.map +1 -1
  195. package/dist/esm/table/index.js +6 -1
  196. package/dist/esm/table/index.js.map +1 -1
  197. package/dist/esm/time/session.d.ts +9 -0
  198. package/dist/esm/time/session.d.ts.map +1 -1
  199. package/dist/esm/time/session.js +53 -15
  200. package/dist/esm/time/session.js.map +1 -1
  201. package/dist/esm/time/timezone.d.ts +6 -1
  202. package/dist/esm/time/timezone.d.ts.map +1 -1
  203. package/dist/esm/time/timezone.js +8 -2
  204. package/dist/esm/time/timezone.js.map +1 -1
  205. package/dist/esm/types/metadata.d.ts +1 -1
  206. package/dist/esm/types/metadata.d.ts.map +1 -1
  207. package/package.json +1 -1
  208. package/src/array/index.ts +11 -3
  209. package/src/box/index.ts +6 -6
  210. package/src/callsite/index.ts +1 -1
  211. package/src/drawing/registry.ts +30 -7
  212. package/src/index.ts +11 -1
  213. package/src/input.ts +18 -1
  214. package/src/label/index.ts +3 -3
  215. package/src/line/index.ts +20 -68
  216. package/src/linefill/index.ts +20 -1
  217. package/src/runtime/adapters/SimpleInputAdapter.ts +1 -1
  218. package/src/runtime/index.ts +1 -0
  219. package/src/runtime/inputs.ts +16 -0
  220. package/src/runtime/types.ts +1 -1
  221. package/src/script/index.ts +292 -30
  222. package/src/security/other.ts +269 -0
  223. package/src/session/bars.ts +24 -1
  224. package/src/session/calendar.ts +23 -7
  225. package/src/session/context.ts +5 -3
  226. package/src/str/floatingdecimal.ts +268 -0
  227. package/src/str/index.ts +6 -5
  228. package/src/str/numberformat.ts +11 -6
  229. package/src/ta/index.ts +157 -183
  230. package/src/ta/limits.ts +28 -1
  231. package/src/ta/running-sum.ts +1 -1
  232. package/src/ta-series.ts +3 -2
  233. package/src/table/index.ts +4 -1
  234. package/src/time/session.ts +58 -16
  235. package/src/time/timezone.ts +9 -2
  236. package/src/types/metadata.ts +1 -1
@@ -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,
@@ -126,6 +127,7 @@ var import_numberformat = require("../str/numberformat.js");
126
127
  var import_calendar = require("../session/calendar.js");
127
128
  var import_bars = require("../session/bars.js");
128
129
  var import_resample = require("../security/resample.js");
130
+ var import_other = require("../security/other.js");
129
131
  var import_types = require("../types/index.js");
130
132
  var import_strategy = require("../strategy/index.js");
131
133
  var import_session = require("../time/session.js");
@@ -185,8 +187,10 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {})
185
187
  ctx = freshCollector(inputs);
186
188
  (0, import_registry.resetDrawings)();
187
189
  mathCore.resetRandom();
190
+ missingSymbols = [];
188
191
  try {
189
192
  body();
193
+ if (missingSymbols.length) throw new MissingSymbolDataError(missingSymbols);
190
194
  const c = ctx;
191
195
  return {
192
196
  metadata: {
@@ -310,6 +314,10 @@ const input = {
310
314
  "input_session"
311
315
  );
312
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
+ },
313
321
  /** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
314
322
  time(defval, title, opts = {}) {
315
323
  const v = registerInput({ type: "time", defval, title, ...common(opts) }, "input_time");
@@ -361,11 +369,12 @@ const ta = {
361
369
  highestbars: (sourceOrLength, length) => typeof sourceOrLength === "number" ? taSeries.highestbars(high, sourceOrLength) : taSeries.highestbars(sourceOrLength, length),
362
370
  /** `ta.lowestbars(source, length)` or `ta.lowestbars(length)` (source = low); offsets are 0 or negative. */
363
371
  lowestbars: (sourceOrLength, length) => typeof sourceOrLength === "number" ? taSeries.lowestbars(low, sourceOrLength) : taSeries.lowestbars(sourceOrLength, length),
364
- /** `ta.vwap(source, anchor?, stdev_mult?)` with the chart volume; the default anchor is a new trading
365
- * day (`timeframe.change("1D")`), which needs the chart context (timeframe, time zone, session), and the
366
- * first bar: as in PineScript, the first loaded bars (a day in progress) have a value. */
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). */
367
376
  vwap: ((source, anchor, stdev_mult) => {
368
- const a = anchor ?? changeOf("1D", true);
377
+ const a = anchor ?? vwapAnchor();
369
378
  return stdev_mult === void 0 ? taSeries.vwap(source, volume, a) : taSeries.vwapBands(source, volume, a, stdev_mult);
370
379
  }),
371
380
  /** `ta.mfi(source, length)` with the chart volume (PineScript takes 2 arguments). */
@@ -765,7 +774,7 @@ function eachBar(fn) {
765
774
  for (idx = 0; idx < b.length; idx++) {
766
775
  if (pendingError && pendingError.bar === idx) throw new Error((0, import_series.historyError)(idx, pendingError.barsBack));
767
776
  currentBar = idx;
768
- (0, import_registry.setDrawingBar)(idx, idx === b.length - 1);
777
+ (0, import_registry.setDrawingBar)(idx, idx === b.length - 1, b.length - 1);
769
778
  const r = fn(ctx2);
770
779
  out[idx] = typeof r === "number" ? r : typeof r === "boolean" ? r ? 1 : 0 : NaN;
771
780
  for (const buffer of buffers.values()) {
@@ -927,6 +936,17 @@ const strategy = Object.defineProperties(
927
936
  Object.assign((title, options) => declareStrategy(title, options), strategyMembers),
928
937
  variableGetters
929
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 = [];
930
950
  let chartCtx = {};
931
951
  function chartTimeframe() {
932
952
  collector();
@@ -1047,6 +1067,12 @@ const syminfo = {
1047
1067
  },
1048
1068
  get currency() {
1049
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");
1050
1076
  }
1051
1077
  };
1052
1078
  function calendar(fn) {
@@ -1108,7 +1134,7 @@ function sessionBars() {
1108
1134
  }
1109
1135
  return sessionCache;
1110
1136
  }
1111
- function calendarFor(session2, timezone) {
1137
+ function calendarFor(session2, timezone, dayPlacement = false) {
1112
1138
  const { bars: bars2 } = sessionBars();
1113
1139
  if (!session2 && !timezone) return { bars: bars2, test: false };
1114
1140
  const tz = timezone ?? exchangeTimezone();
@@ -1119,7 +1145,7 @@ function calendarFor(session2, timezone) {
1119
1145
  }
1120
1146
  const spec = session2 ? { session: session2 } : { session: toSpec(chartCtx.session).session };
1121
1147
  return {
1122
- bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, spec, session2 ? "pine" : "symbol"), bars2.chart.period),
1148
+ bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, spec, session2 ? "pine" : "symbol", dayPlacement), bars2.chart.period),
1123
1149
  test: true,
1124
1150
  // a PineScript session string: the rules of time.inSession (runs ending at 0000, days around a clock change)
1125
1151
  inside: session2 ? (time2) => timeCore.inSession(time2, session2, tz, timeframeCore.in_seconds(bars2.chart.period) * 1e3) : void 0
@@ -1134,17 +1160,47 @@ function callableSeries(series, fn) {
1134
1160
  Object.assign(fn, series);
1135
1161
  return fn;
1136
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
+ }
1137
1195
  function timeFunction(tf, session2, timezone) {
1138
1196
  collector();
1139
- const { bars: bars2, test, inside } = calendarFor(session2, timezone);
1140
- const timeframeString = tf || chartTimeframe().period;
1141
- return perBar((t) => test && !(inside ? inside(t) : bars2.inside(t)) ? NaN : bars2.timeOf(t, timeframeString));
1197
+ const { open: open2 } = sessionPeriods(tf || chartTimeframe().period, session2, timezone);
1198
+ return perBar((t) => open2(t));
1142
1199
  }
1143
1200
  function timeCloseFunction(tf, session2, timezone) {
1144
1201
  collector();
1145
- const { bars: bars2, test, inside } = calendarFor(session2, timezone);
1146
- const timeframeString = tf || chartTimeframe().period;
1147
- return perBar((t) => test && !(inside ? inside(t) : bars2.inside(t)) ? NaN : bars2.closeOf(t, timeframeString));
1202
+ const { close: close2 } = sessionPeriods(tf || chartTimeframe().period, session2, timezone);
1203
+ return perBar((t) => close2(t));
1148
1204
  }
1149
1205
  let runNow = NaN;
1150
1206
  const timenow = new import_series.Series(ctxBars, () => runNow);
@@ -1159,6 +1215,19 @@ function changeOf(tf, firstBar = false) {
1159
1215
  const changed = (a, b) => !Number.isNaN(a) && !Number.isNaN(b) && a !== b;
1160
1216
  return perBar((t, i, times) => (i > 0 ? changed(bars2.timeOf(t, tf), bars2.timeOf(times[i - 1], tf)) : firstBar) ? 1 : 0);
1161
1217
  }
1218
+ function vwapAnchor() {
1219
+ if (chartTimeframe().isdwm) return barFlag(() => true);
1220
+ const { bars: bars2 } = sessionBars();
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
+ });
1230
+ }
1162
1231
  function flag(key) {
1163
1232
  const { bars: bars2, regular } = sessionBars();
1164
1233
  const values = (0, import_bars.sessionFlags)(ctxBars.bars.map(barTime), bars2, regular)[key];
@@ -1244,17 +1313,17 @@ function valuesOf(value, length) {
1244
1313
  }
1245
1314
  return value.toArray().slice();
1246
1315
  }
1247
- 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) {
1248
1317
  collector();
1249
1318
  const heikin = symbol.startsWith(HEIKIN_ASHI);
1250
1319
  const base = heikin ? symbol.slice(HEIKIN_ASHI.length) : symbol;
1251
- if (base !== "" && base !== chartCtx.tickerid) {
1252
- throw new Error(`request.security: "${symbol}" is not the chart symbol; other symbols need external data.`);
1253
- }
1254
1320
  const chart2 = chartTimeframe();
1255
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
+ }
1256
1325
  if (timeframeCore.in_seconds(tf) < timeframeCore.in_seconds(chart2.period)) {
1257
- 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);
1258
1327
  }
1259
1328
  const chartBars = ctxBars.bars;
1260
1329
  const times = chartBars.map(barTime);
@@ -1274,6 +1343,8 @@ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, look
1274
1343
  const periods = at ? calendar2.calendar.periods(at.date) : [];
1275
1344
  return periods.length ? calendar2.timeOf(periods[0][0], tf) : starts[i];
1276
1345
  });
1346
+ const tfInfo = timeframeCore.info(tf);
1347
+ (0, import_bars.strayPeriods)(starts, dayPeriods, times, loaded, tfInfo.isdwm ? null : timeframeCore.in_seconds(tf) * 1e3);
1277
1348
  const reaches = times.map((t) => loaded.closeOf(t, chart2.period) >= calendar2.periodEnd(t, tf));
1278
1349
  ({ group, latest } = (0, import_resample.periodsOf)(starts, dayPeriods, reaches));
1279
1350
  const unit = chartCtx.timeUnit === "ms" ? 1 : 1e3;
@@ -1300,7 +1371,85 @@ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, look
1300
1371
  );
1301
1372
  return Array.isArray(result) ? mapped : mapped[0];
1302
1373
  }
1303
- 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 };
1304
1453
  const line = {
1305
1454
  ...lineCore,
1306
1455
  get all() {