oakscriptjs 0.11.0 → 0.11.2

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 (238) 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.d.ts.map +1 -1
  8. package/dist/cjs/callsite/index.js +6 -3
  9. package/dist/cjs/callsite/index.js.map +2 -2
  10. package/dist/cjs/drawing/registry.d.ts +15 -6
  11. package/dist/cjs/drawing/registry.d.ts.map +1 -1
  12. package/dist/cjs/drawing/registry.js +16 -2
  13. package/dist/cjs/drawing/registry.js.map +2 -2
  14. package/dist/cjs/index.d.ts +4 -3
  15. package/dist/cjs/index.d.ts.map +1 -1
  16. package/dist/cjs/index.js +7 -1
  17. package/dist/cjs/index.js.map +2 -2
  18. package/dist/cjs/input.d.ts +9 -1
  19. package/dist/cjs/input.d.ts.map +1 -1
  20. package/dist/cjs/input.js +16 -0
  21. package/dist/cjs/input.js.map +2 -2
  22. package/dist/cjs/label/index.js +3 -3
  23. package/dist/cjs/label/index.js.map +2 -2
  24. package/dist/cjs/line/index.d.ts +10 -27
  25. package/dist/cjs/line/index.d.ts.map +1 -1
  26. package/dist/cjs/line/index.js +10 -27
  27. package/dist/cjs/line/index.js.map +2 -2
  28. package/dist/cjs/linefill/index.d.ts +3 -0
  29. package/dist/cjs/linefill/index.d.ts.map +1 -1
  30. package/dist/cjs/linefill/index.js +15 -1
  31. package/dist/cjs/linefill/index.js.map +3 -3
  32. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +1 -1
  33. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +2 -2
  34. package/dist/cjs/runtime/index.d.ts +1 -1
  35. package/dist/cjs/runtime/index.d.ts.map +1 -1
  36. package/dist/cjs/runtime/index.js +1 -0
  37. package/dist/cjs/runtime/index.js.map +2 -2
  38. package/dist/cjs/runtime/inputs.d.ts +9 -0
  39. package/dist/cjs/runtime/inputs.d.ts.map +1 -1
  40. package/dist/cjs/runtime/inputs.js +8 -0
  41. package/dist/cjs/runtime/inputs.js.map +2 -2
  42. package/dist/cjs/runtime/types.d.ts +1 -1
  43. package/dist/cjs/runtime/types.d.ts.map +1 -1
  44. package/dist/cjs/runtime/types.js.map +1 -1
  45. package/dist/cjs/script/index.d.ts +66 -13
  46. package/dist/cjs/script/index.d.ts.map +1 -1
  47. package/dist/cjs/script/index.js +139 -35
  48. package/dist/cjs/script/index.js.map +3 -3
  49. package/dist/cjs/security/other.d.ts +92 -0
  50. package/dist/cjs/security/other.d.ts.map +1 -0
  51. package/dist/cjs/security/other.js +164 -0
  52. package/dist/cjs/security/other.js.map +7 -0
  53. package/dist/cjs/session/bars.d.ts +10 -1
  54. package/dist/cjs/session/bars.d.ts.map +1 -1
  55. package/dist/cjs/session/bars.js +16 -2
  56. package/dist/cjs/session/bars.js.map +2 -2
  57. package/dist/cjs/session/calendar.d.ts +4 -1
  58. package/dist/cjs/session/calendar.d.ts.map +1 -1
  59. package/dist/cjs/session/calendar.js +12 -7
  60. package/dist/cjs/session/calendar.js.map +2 -2
  61. package/dist/cjs/session/context.d.ts +22 -5
  62. package/dist/cjs/session/context.d.ts.map +1 -1
  63. package/dist/cjs/session/context.js +67 -6
  64. package/dist/cjs/session/context.js.map +2 -2
  65. package/dist/cjs/str/floatingdecimal.d.ts +31 -0
  66. package/dist/cjs/str/floatingdecimal.d.ts.map +1 -0
  67. package/dist/cjs/str/floatingdecimal.js +298 -0
  68. package/dist/cjs/str/floatingdecimal.js.map +7 -0
  69. package/dist/cjs/str/index.d.ts +4 -3
  70. package/dist/cjs/str/index.d.ts.map +1 -1
  71. package/dist/cjs/str/index.js +1 -1
  72. package/dist/cjs/str/index.js.map +2 -2
  73. package/dist/cjs/str/numberformat.d.ts +6 -4
  74. package/dist/cjs/str/numberformat.d.ts.map +1 -1
  75. package/dist/cjs/str/numberformat.js +3 -2
  76. package/dist/cjs/str/numberformat.js.map +2 -2
  77. package/dist/cjs/ta/index.d.ts +64 -45
  78. package/dist/cjs/ta/index.d.ts.map +1 -1
  79. package/dist/cjs/ta/index.js +140 -126
  80. package/dist/cjs/ta/index.js.map +3 -3
  81. package/dist/cjs/ta/limits.d.ts +11 -0
  82. package/dist/cjs/ta/limits.d.ts.map +1 -1
  83. package/dist/cjs/ta/limits.js +15 -1
  84. package/dist/cjs/ta/limits.js.map +2 -2
  85. package/dist/cjs/ta/running-sum.js +1 -1
  86. package/dist/cjs/ta/running-sum.js.map +2 -2
  87. package/dist/cjs/ta-series.d.ts +1 -1
  88. package/dist/cjs/ta-series.d.ts.map +1 -1
  89. package/dist/cjs/ta-series.js +1 -1
  90. package/dist/cjs/ta-series.js.map +2 -2
  91. package/dist/cjs/table/index.d.ts +10 -3
  92. package/dist/cjs/table/index.d.ts.map +1 -1
  93. package/dist/cjs/table/index.js +11 -1
  94. package/dist/cjs/table/index.js.map +3 -3
  95. package/dist/cjs/time/session.d.ts +9 -0
  96. package/dist/cjs/time/session.d.ts.map +1 -1
  97. package/dist/cjs/time/session.js +42 -14
  98. package/dist/cjs/time/session.js.map +3 -3
  99. package/dist/cjs/time/timezone.d.ts +6 -1
  100. package/dist/cjs/time/timezone.d.ts.map +1 -1
  101. package/dist/cjs/time/timezone.js +2 -2
  102. package/dist/cjs/time/timezone.js.map +2 -2
  103. package/dist/cjs/types/metadata.d.ts +1 -1
  104. package/dist/cjs/types/metadata.d.ts.map +1 -1
  105. package/dist/cjs/types/metadata.js.map +1 -1
  106. package/dist/esm/array/index.d.ts +8 -2
  107. package/dist/esm/array/index.d.ts.map +1 -1
  108. package/dist/esm/array/index.js +12 -3
  109. package/dist/esm/array/index.js.map +1 -1
  110. package/dist/esm/box/index.js +6 -6
  111. package/dist/esm/box/index.js.map +1 -1
  112. package/dist/esm/callsite/index.d.ts.map +1 -1
  113. package/dist/esm/callsite/index.js +6 -3
  114. package/dist/esm/callsite/index.js.map +1 -1
  115. package/dist/esm/drawing/registry.d.ts +15 -6
  116. package/dist/esm/drawing/registry.d.ts.map +1 -1
  117. package/dist/esm/drawing/registry.js +30 -7
  118. package/dist/esm/drawing/registry.js.map +1 -1
  119. package/dist/esm/index.d.ts +4 -3
  120. package/dist/esm/index.d.ts.map +1 -1
  121. package/dist/esm/index.js +8 -5
  122. package/dist/esm/index.js.map +1 -1
  123. package/dist/esm/input.d.ts +9 -1
  124. package/dist/esm/input.d.ts.map +1 -1
  125. package/dist/esm/input.js +16 -0
  126. package/dist/esm/input.js.map +1 -1
  127. package/dist/esm/label/index.js +3 -3
  128. package/dist/esm/label/index.js.map +1 -1
  129. package/dist/esm/line/index.d.ts +10 -27
  130. package/dist/esm/line/index.d.ts.map +1 -1
  131. package/dist/esm/line/index.js +20 -64
  132. package/dist/esm/line/index.js.map +1 -1
  133. package/dist/esm/linefill/index.d.ts +3 -0
  134. package/dist/esm/linefill/index.d.ts.map +1 -1
  135. package/dist/esm/linefill/index.js +20 -1
  136. package/dist/esm/linefill/index.js.map +1 -1
  137. package/dist/esm/runtime/adapters/SimpleInputAdapter.js +1 -1
  138. package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -1
  139. package/dist/esm/runtime/index.d.ts +1 -1
  140. package/dist/esm/runtime/index.d.ts.map +1 -1
  141. package/dist/esm/runtime/index.js +1 -1
  142. package/dist/esm/runtime/index.js.map +1 -1
  143. package/dist/esm/runtime/inputs.d.ts +9 -0
  144. package/dist/esm/runtime/inputs.d.ts.map +1 -1
  145. package/dist/esm/runtime/inputs.js +15 -0
  146. package/dist/esm/runtime/inputs.js.map +1 -1
  147. package/dist/esm/runtime/types.d.ts +1 -1
  148. package/dist/esm/runtime/types.d.ts.map +1 -1
  149. package/dist/esm/script/index.d.ts +66 -13
  150. package/dist/esm/script/index.d.ts.map +1 -1
  151. package/dist/esm/script/index.js +187 -54
  152. package/dist/esm/script/index.js.map +1 -1
  153. package/dist/esm/security/other.d.ts +92 -0
  154. package/dist/esm/security/other.d.ts.map +1 -0
  155. package/dist/esm/security/other.js +211 -0
  156. package/dist/esm/security/other.js.map +1 -0
  157. package/dist/esm/session/bars.d.ts +10 -1
  158. package/dist/esm/session/bars.d.ts.map +1 -1
  159. package/dist/esm/session/bars.js +26 -1
  160. package/dist/esm/session/bars.js.map +1 -1
  161. package/dist/esm/session/calendar.d.ts +4 -1
  162. package/dist/esm/session/calendar.d.ts.map +1 -1
  163. package/dist/esm/session/calendar.js +23 -7
  164. package/dist/esm/session/calendar.js.map +1 -1
  165. package/dist/esm/session/context.d.ts +22 -5
  166. package/dist/esm/session/context.d.ts.map +1 -1
  167. package/dist/esm/session/context.js +86 -10
  168. package/dist/esm/session/context.js.map +1 -1
  169. package/dist/esm/str/floatingdecimal.d.ts +31 -0
  170. package/dist/esm/str/floatingdecimal.d.ts.map +1 -0
  171. package/dist/esm/str/floatingdecimal.js +272 -0
  172. package/dist/esm/str/floatingdecimal.js.map +1 -0
  173. package/dist/esm/str/index.d.ts +4 -3
  174. package/dist/esm/str/index.d.ts.map +1 -1
  175. package/dist/esm/str/index.js +6 -5
  176. package/dist/esm/str/index.js.map +1 -1
  177. package/dist/esm/str/numberformat.d.ts +6 -4
  178. package/dist/esm/str/numberformat.d.ts.map +1 -1
  179. package/dist/esm/str/numberformat.js +9 -5
  180. package/dist/esm/str/numberformat.js.map +1 -1
  181. package/dist/esm/ta/index.d.ts +64 -45
  182. package/dist/esm/ta/index.d.ts.map +1 -1
  183. package/dist/esm/ta/index.js +198 -228
  184. package/dist/esm/ta/index.js.map +1 -1
  185. package/dist/esm/ta/limits.d.ts +11 -0
  186. package/dist/esm/ta/limits.d.ts.map +1 -1
  187. package/dist/esm/ta/limits.js +27 -2
  188. package/dist/esm/ta/limits.js.map +1 -1
  189. package/dist/esm/ta/running-sum.js +1 -1
  190. package/dist/esm/ta/running-sum.js.map +1 -1
  191. package/dist/esm/ta-series.d.ts +1 -1
  192. package/dist/esm/ta-series.d.ts.map +1 -1
  193. package/dist/esm/ta-series.js +2 -1
  194. package/dist/esm/ta-series.js.map +1 -1
  195. package/dist/esm/table/index.d.ts +10 -3
  196. package/dist/esm/table/index.d.ts.map +1 -1
  197. package/dist/esm/table/index.js +23 -3
  198. package/dist/esm/table/index.js.map +1 -1
  199. package/dist/esm/time/session.d.ts +9 -0
  200. package/dist/esm/time/session.d.ts.map +1 -1
  201. package/dist/esm/time/session.js +53 -15
  202. package/dist/esm/time/session.js.map +1 -1
  203. package/dist/esm/time/timezone.d.ts +6 -1
  204. package/dist/esm/time/timezone.d.ts.map +1 -1
  205. package/dist/esm/time/timezone.js +8 -2
  206. package/dist/esm/time/timezone.js.map +1 -1
  207. package/dist/esm/types/metadata.d.ts +1 -1
  208. package/dist/esm/types/metadata.d.ts.map +1 -1
  209. package/package.json +1 -1
  210. package/src/array/index.ts +11 -3
  211. package/src/box/index.ts +6 -6
  212. package/src/callsite/index.ts +6 -3
  213. package/src/drawing/registry.ts +30 -7
  214. package/src/index.ts +16 -3
  215. package/src/input.ts +18 -1
  216. package/src/label/index.ts +3 -3
  217. package/src/line/index.ts +20 -68
  218. package/src/linefill/index.ts +20 -1
  219. package/src/runtime/adapters/SimpleInputAdapter.ts +1 -1
  220. package/src/runtime/index.ts +1 -0
  221. package/src/runtime/inputs.ts +16 -0
  222. package/src/runtime/types.ts +1 -1
  223. package/src/script/index.ts +262 -58
  224. package/src/security/other.ts +269 -0
  225. package/src/session/bars.ts +24 -1
  226. package/src/session/calendar.ts +26 -7
  227. package/src/session/context.ts +104 -10
  228. package/src/str/floatingdecimal.ts +268 -0
  229. package/src/str/index.ts +6 -5
  230. package/src/str/numberformat.ts +11 -6
  231. package/src/ta/index.ts +200 -225
  232. package/src/ta/limits.ts +28 -1
  233. package/src/ta/running-sum.ts +1 -1
  234. package/src/ta-series.ts +3 -2
  235. package/src/table/index.ts +22 -3
  236. package/src/time/session.ts +58 -16
  237. package/src/time/timezone.ts +9 -2
  238. 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,9 +127,10 @@ 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
- var import_session = require("../time/session.js");
133
+ var import_context = require("../session/context.js");
132
134
  var import_strategy2 = require("../strategy/index.js");
133
135
  var compare = __toESM(require("../compare/index.js"), 1);
134
136
  var import_input_active = require("../runtime/input-active.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,23 +1134,6 @@ function sessionBars() {
1108
1134
  }
1109
1135
  return sessionCache;
1110
1136
  }
1111
- function calendarFor(session2, timezone) {
1112
- const { bars: bars2 } = sessionBars();
1113
- if (!session2 && !timezone) return { bars: bars2, test: false };
1114
- const tz = timezone ?? exchangeTimezone();
1115
- if (session2 !== void 0 && (0, import_session.parsePineSession)(session2) === null) {
1116
- const name = session2.trim();
1117
- const symbol = name === "regular" && chartCtx.regularSession ? chartCtx.regularSession : chartCtx.session;
1118
- return { bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, { session: toSpec(symbol).session }, "symbol"), bars2.chart.period), test: true };
1119
- }
1120
- const spec = session2 ? { session: session2 } : { session: toSpec(chartCtx.session).session };
1121
- return {
1122
- bars: new import_bars.SessionBars(new import_calendar.TradingCalendar(tz, spec, session2 ? "pine" : "symbol"), bars2.chart.period),
1123
- test: true,
1124
- // a PineScript session string: the rules of time.inSession (runs ending at 0000, days around a clock change)
1125
- inside: session2 ? (time2) => timeCore.inSession(time2, session2, tz, timeframeCore.in_seconds(bars2.chart.period) * 1e3) : void 0
1126
- };
1127
- }
1128
1137
  function perBar(fn) {
1129
1138
  const times = ctxBars.bars.map(barTime);
1130
1139
  return import_series.Series.fromArray(ctxBars, times.map((t, i) => fn(t, i, times)));
@@ -1134,17 +1143,19 @@ function callableSeries(series, fn) {
1134
1143
  Object.assign(fn, series);
1135
1144
  return fn;
1136
1145
  }
1146
+ function chartSessionPeriods(timeframeString, session2, timezone) {
1147
+ const { bars: bars2 } = sessionBars();
1148
+ return (0, import_context.sessionPeriods)(bars2, { ...chartCtx, timezone: exchangeTimezone() }, timeframeString, session2, timezone);
1149
+ }
1137
1150
  function timeFunction(tf, session2, timezone) {
1138
1151
  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));
1152
+ const { open: open2 } = chartSessionPeriods(tf || chartTimeframe().period, session2, timezone);
1153
+ return perBar((t) => open2(t));
1142
1154
  }
1143
1155
  function timeCloseFunction(tf, session2, timezone) {
1144
1156
  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));
1157
+ const { close: close2 } = chartSessionPeriods(tf || chartTimeframe().period, session2, timezone);
1158
+ return perBar((t) => close2(t));
1148
1159
  }
1149
1160
  let runNow = NaN;
1150
1161
  const timenow = new import_series.Series(ctxBars, () => runNow);
@@ -1159,6 +1170,19 @@ function changeOf(tf, firstBar = false) {
1159
1170
  const changed = (a, b) => !Number.isNaN(a) && !Number.isNaN(b) && a !== b;
1160
1171
  return perBar((t, i, times) => (i > 0 ? changed(bars2.timeOf(t, tf), bars2.timeOf(times[i - 1], tf)) : firstBar) ? 1 : 0);
1161
1172
  }
1173
+ function vwapAnchor() {
1174
+ if (chartTimeframe().isdwm) return barFlag(() => true);
1175
+ const { bars: bars2 } = sessionBars();
1176
+ let last = NaN;
1177
+ let previous = NaN;
1178
+ return perBar((t, i) => {
1179
+ const day = bars2.timeOf(t, "1D");
1180
+ const isNew = i === 0 || (Number.isNaN(day) ? Number.isNaN(previous) : day !== last);
1181
+ if (!Number.isNaN(day)) last = day;
1182
+ previous = day;
1183
+ return isNew ? 1 : 0;
1184
+ });
1185
+ }
1162
1186
  function flag(key) {
1163
1187
  const { bars: bars2, regular } = sessionBars();
1164
1188
  const values = (0, import_bars.sessionFlags)(ctxBars.bars.map(barTime), bars2, regular)[key];
@@ -1244,17 +1268,17 @@ function valuesOf(value, length) {
1244
1268
  }
1245
1269
  return value.toArray().slice();
1246
1270
  }
1247
- function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off) {
1271
+ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off, ignore_invalid_symbol = false) {
1248
1272
  collector();
1249
1273
  const heikin = symbol.startsWith(HEIKIN_ASHI);
1250
1274
  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
1275
  const chart2 = chartTimeframe();
1255
1276
  const tf = timeframeCore.info(timeframe2 || chart2.period).period;
1277
+ if (base !== "" && base !== chartCtx.tickerid) {
1278
+ return externalSecurity(base, heikin, tf, expression, gaps, lookahead, ignore_invalid_symbol, false);
1279
+ }
1256
1280
  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}".`);
1281
+ return externalSecurity(chartCtx.tickerid ?? "", heikin, tf, expression, gaps, lookahead, ignore_invalid_symbol, true);
1258
1282
  }
1259
1283
  const chartBars = ctxBars.bars;
1260
1284
  const times = chartBars.map(barTime);
@@ -1274,6 +1298,8 @@ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, look
1274
1298
  const periods = at ? calendar2.calendar.periods(at.date) : [];
1275
1299
  return periods.length ? calendar2.timeOf(periods[0][0], tf) : starts[i];
1276
1300
  });
1301
+ const tfInfo = timeframeCore.info(tf);
1302
+ (0, import_bars.strayPeriods)(starts, dayPeriods, times, loaded, tfInfo.isdwm ? null : timeframeCore.in_seconds(tf) * 1e3);
1277
1303
  const reaches = times.map((t) => loaded.closeOf(t, chart2.period) >= calendar2.periodEnd(t, tf));
1278
1304
  ({ group, latest } = (0, import_resample.periodsOf)(starts, dayPeriods, reaches));
1279
1305
  const unit = chartCtx.timeUnit === "ms" ? 1 : 1e3;
@@ -1300,7 +1326,85 @@ function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, look
1300
1326
  );
1301
1327
  return Array.isArray(result) ? mapped : mapped[0];
1302
1328
  }
1303
- const request = { security };
1329
+ function runExternal(symbol, heikin, tf, expression, ignoreInvalid, own) {
1330
+ let bars2 = chartCtx.bars?.(symbol, tf);
1331
+ if (bars2 === void 0 && !missingSymbols.some((r) => r.symbol === symbol && r.timeframe === tf)) {
1332
+ missingSymbols.push({ symbol, timeframe: tf });
1333
+ }
1334
+ if (bars2 !== void 0 && bars2.length === 0 && !ignoreInvalid) throw new Error(`Invalid symbol: ${symbol}`);
1335
+ bars2 ??= [];
1336
+ if (heikin) bars2 = (0, import_resample.heikinAshi)(bars2);
1337
+ const given2 = chartCtx.symbolInfo?.(symbol);
1338
+ const info = own ? { ...chartCtx, ...given2 } : given2 ?? {};
1339
+ const chartBars = ctxBars.bars;
1340
+ const savedCtx = chartCtx;
1341
+ let result;
1342
+ let values;
1343
+ ctxBars.setAll(bars2);
1344
+ chartCtx = {
1345
+ ...chartCtx,
1346
+ tickerid: symbol,
1347
+ timeframe: tf,
1348
+ timezone: info.timezone,
1349
+ session: info.session,
1350
+ regularSession: info.regularSession,
1351
+ mintick: info.mintick,
1352
+ minmove: info.minmove,
1353
+ pricescale: info.pricescale,
1354
+ pointvalue: info.pointvalue,
1355
+ mincontract: info.mincontract,
1356
+ symbolType: info.symbolType,
1357
+ currency: info.currency,
1358
+ basecurrency: info.basecurrency,
1359
+ root: info.root
1360
+ };
1361
+ try {
1362
+ result = expression();
1363
+ const parts = Array.isArray(result) ? result : [result];
1364
+ values = parts.map((p) => valuesOf(p, bars2.length));
1365
+ } finally {
1366
+ ctxBars.setAll(chartBars);
1367
+ chartCtx = savedCtx;
1368
+ }
1369
+ return { bars: bars2, info, result, values };
1370
+ }
1371
+ function mergeChart() {
1372
+ return {
1373
+ timeframe: chartTimeframe().period,
1374
+ timezone: chartCtx.timezone,
1375
+ session: chartCtx.session,
1376
+ timeUnit: chartCtx.timeUnit,
1377
+ // the realtime rule applies to a last bar that receives live updates
1378
+ lastBarConfirmed: chartCtx.realtime !== true
1379
+ };
1380
+ }
1381
+ function externalSecurity(symbol, heikin, tf, expression, gaps, lookahead, ignoreInvalid, own) {
1382
+ const { bars: bars2, info, result, values } = runExternal(symbol, heikin, tf, expression, ignoreInvalid, own);
1383
+ const index = (0, import_other.securityOther)(ctxBars.bars, bars2, tf, mergeChart(), {
1384
+ gaps: gaps === barmerge.gaps_on,
1385
+ lookahead: lookahead === barmerge.lookahead_on,
1386
+ other: info
1387
+ });
1388
+ const mapped = values.map((v) => import_series.Series.fromArray(ctxBars, index.map((j) => j < 0 ? NaN : v[j] ?? NaN)));
1389
+ return Array.isArray(result) ? mapped : mapped[0];
1390
+ }
1391
+ function security_lower_tf(symbol, timeframe2, expression, ignore_invalid_symbol = false) {
1392
+ collector();
1393
+ const heikin = symbol.startsWith(HEIKIN_ASHI);
1394
+ const base = heikin ? symbol.slice(HEIKIN_ASHI.length) : symbol;
1395
+ const chart2 = chartTimeframe();
1396
+ const tf = timeframeCore.info(timeframe2 || chart2.period).period;
1397
+ if (timeframeCore.in_seconds(tf) > timeframeCore.in_seconds(chart2.period)) {
1398
+ throw new Error(`request.security_lower_tf: timeframe "${tf}" is higher than the chart timeframe "${chart2.period}".`);
1399
+ }
1400
+ const own = base === "" || base === chartCtx.tickerid;
1401
+ const ticker2 = own ? chartCtx.tickerid ?? "" : base;
1402
+ const { bars: bars2, info, result, values } = runExternal(ticker2, heikin, tf, expression, ignore_invalid_symbol, own);
1403
+ const ranges = (0, import_other.securityLowerTf)(ctxBars.bars, bars2, tf, mergeChart(), { other: info });
1404
+ const mapped = values.map((v) => ranges.map(([from, to]) => v.slice(from, to)));
1405
+ return Array.isArray(result) ? mapped : mapped[0];
1406
+ }
1407
+ const request = { security, security_lower_tf };
1304
1408
  const line = {
1305
1409
  ...lineCore,
1306
1410
  get all() {