oakscriptjs 0.8.1 → 0.9.0

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 (544) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +31 -9
  3. package/dist/cjs/array/index.d.ts +701 -0
  4. package/dist/cjs/array/index.d.ts.map +1 -0
  5. package/dist/cjs/array/index.js +392 -0
  6. package/dist/cjs/array/index.js.map +7 -0
  7. package/dist/cjs/box/index.d.ts +444 -0
  8. package/dist/cjs/box/index.d.ts.map +1 -0
  9. package/dist/cjs/box/index.js +246 -0
  10. package/dist/cjs/box/index.js.map +7 -0
  11. package/dist/cjs/callsite/index.d.ts +61 -0
  12. package/dist/cjs/callsite/index.d.ts.map +1 -0
  13. package/dist/cjs/callsite/index.js +65 -0
  14. package/dist/cjs/callsite/index.js.map +7 -0
  15. package/dist/cjs/chartpoint/index.d.ts +90 -0
  16. package/dist/cjs/chartpoint/index.d.ts.map +1 -0
  17. package/dist/cjs/chartpoint/index.js +56 -0
  18. package/dist/cjs/chartpoint/index.js.map +7 -0
  19. package/dist/cjs/color/index.d.ts +285 -0
  20. package/dist/cjs/color/index.d.ts.map +1 -0
  21. package/dist/cjs/color/index.js +143 -0
  22. package/dist/cjs/color/index.js.map +7 -0
  23. package/dist/cjs/compare/index.d.ts +26 -0
  24. package/dist/cjs/compare/index.d.ts.map +1 -0
  25. package/dist/cjs/compare/index.js +50 -0
  26. package/dist/cjs/compare/index.js.map +7 -0
  27. package/dist/cjs/drawing/registry.d.ts +42 -0
  28. package/dist/cjs/drawing/registry.d.ts.map +1 -0
  29. package/dist/cjs/drawing/registry.js +87 -0
  30. package/dist/cjs/drawing/registry.js.map +7 -0
  31. package/dist/cjs/index.d.ts +85 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +184 -0
  34. package/dist/cjs/index.js.map +7 -0
  35. package/dist/cjs/indicator.d.ts +117 -0
  36. package/dist/cjs/indicator.d.ts.map +1 -0
  37. package/dist/cjs/indicator.js +74 -0
  38. package/dist/cjs/indicator.js.map +7 -0
  39. package/dist/cjs/input.d.ts +196 -0
  40. package/dist/cjs/input.d.ts.map +1 -0
  41. package/dist/cjs/input.js +197 -0
  42. package/dist/cjs/input.js.map +7 -0
  43. package/dist/cjs/label/index.d.ts +303 -0
  44. package/dist/cjs/label/index.d.ts.map +1 -0
  45. package/dist/cjs/label/index.js +190 -0
  46. package/dist/cjs/label/index.js.map +7 -0
  47. package/dist/cjs/lib/index.d.ts +8 -0
  48. package/dist/cjs/lib/index.d.ts.map +1 -0
  49. package/dist/cjs/lib/index.js +19 -0
  50. package/dist/cjs/lib/index.js.map +7 -0
  51. package/dist/{lib → cjs/lib}/zigzag/index.d.ts +4 -1
  52. package/dist/cjs/lib/zigzag/index.d.ts.map +1 -0
  53. package/dist/cjs/lib/zigzag/index.js +27 -0
  54. package/dist/cjs/lib/zigzag/index.js.map +7 -0
  55. package/dist/cjs/lib/zigzag/zigzag.d.ts +100 -0
  56. package/dist/cjs/lib/zigzag/zigzag.d.ts.map +1 -0
  57. package/dist/cjs/lib/zigzag/zigzag.js +207 -0
  58. package/dist/cjs/lib/zigzag/zigzag.js.map +7 -0
  59. package/dist/cjs/line/index.d.ts +342 -0
  60. package/dist/cjs/line/index.d.ts.map +1 -0
  61. package/dist/cjs/line/index.js +193 -0
  62. package/dist/cjs/line/index.js.map +7 -0
  63. package/dist/cjs/linefill/index.d.ts +124 -0
  64. package/dist/cjs/linefill/index.d.ts.map +1 -0
  65. package/dist/cjs/linefill/index.js +56 -0
  66. package/dist/cjs/linefill/index.js.map +7 -0
  67. package/dist/cjs/map/index.d.ts +69 -0
  68. package/dist/cjs/map/index.d.ts.map +1 -0
  69. package/dist/cjs/map/index.js +80 -0
  70. package/dist/cjs/map/index.js.map +7 -0
  71. package/dist/cjs/math/index.d.ts +560 -0
  72. package/dist/cjs/math/index.d.ts.map +1 -0
  73. package/dist/cjs/math/index.js +441 -0
  74. package/dist/cjs/math/index.js.map +7 -0
  75. package/dist/cjs/matrix/index.d.ts +1231 -0
  76. package/dist/cjs/matrix/index.d.ts.map +1 -0
  77. package/dist/cjs/matrix/index.js +1200 -0
  78. package/dist/cjs/matrix/index.js.map +7 -0
  79. package/dist/cjs/package.json +1 -0
  80. package/dist/cjs/plot.d.ts +76 -0
  81. package/dist/cjs/plot.d.ts.map +1 -0
  82. package/dist/cjs/plot.js +51 -0
  83. package/dist/cjs/plot.js.map +7 -0
  84. package/dist/cjs/polyline/index.d.ts +115 -0
  85. package/dist/cjs/polyline/index.d.ts.map +1 -0
  86. package/dist/cjs/polyline/index.js +76 -0
  87. package/dist/cjs/polyline/index.js.map +7 -0
  88. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.d.ts +86 -0
  89. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.d.ts.map +1 -0
  90. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.js +141 -0
  91. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.js.map +7 -0
  92. package/dist/cjs/runtime/adapters/SimpleInputAdapter.d.ts +59 -0
  93. package/dist/cjs/runtime/adapters/SimpleInputAdapter.d.ts.map +1 -0
  94. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +117 -0
  95. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +7 -0
  96. package/dist/{runtime → cjs/runtime}/index.d.ts +12 -5
  97. package/dist/cjs/runtime/index.d.ts.map +1 -0
  98. package/dist/cjs/runtime/index.js +49 -0
  99. package/dist/cjs/runtime/index.js.map +7 -0
  100. package/dist/cjs/runtime/inputs.d.ts +91 -0
  101. package/dist/cjs/runtime/inputs.d.ts.map +1 -0
  102. package/dist/cjs/runtime/inputs.js +262 -0
  103. package/dist/cjs/runtime/inputs.js.map +7 -0
  104. package/dist/cjs/runtime/runtime.d.ts +70 -0
  105. package/dist/cjs/runtime/runtime.d.ts.map +1 -0
  106. package/dist/cjs/runtime/runtime.js +148 -0
  107. package/dist/cjs/runtime/runtime.js.map +7 -0
  108. package/dist/cjs/runtime/series.d.ts +362 -0
  109. package/dist/cjs/runtime/series.d.ts.map +1 -0
  110. package/dist/cjs/runtime/series.js +560 -0
  111. package/dist/cjs/runtime/series.js.map +7 -0
  112. package/dist/cjs/runtime/types.d.ts +282 -0
  113. package/dist/cjs/runtime/types.d.ts.map +1 -0
  114. package/dist/cjs/runtime/types.js +17 -0
  115. package/dist/cjs/runtime/types.js.map +7 -0
  116. package/dist/cjs/script/index.d.ts +987 -0
  117. package/dist/cjs/script/index.d.ts.map +1 -0
  118. package/dist/cjs/script/index.js +1169 -0
  119. package/dist/cjs/script/index.js.map +7 -0
  120. package/dist/cjs/security/resample.d.ts +63 -0
  121. package/dist/cjs/security/resample.d.ts.map +1 -0
  122. package/dist/cjs/security/resample.js +84 -0
  123. package/dist/cjs/security/resample.js.map +7 -0
  124. package/dist/cjs/session/bars.d.ts +80 -0
  125. package/dist/cjs/session/bars.d.ts.map +1 -0
  126. package/dist/cjs/session/bars.js +219 -0
  127. package/dist/cjs/session/bars.js.map +7 -0
  128. package/dist/cjs/session/calendar.d.ts +70 -0
  129. package/dist/cjs/session/calendar.d.ts.map +1 -0
  130. package/dist/cjs/session/calendar.js +164 -0
  131. package/dist/cjs/session/calendar.js.map +7 -0
  132. package/dist/cjs/str/dateformat.d.ts +15 -0
  133. package/dist/cjs/str/dateformat.d.ts.map +1 -0
  134. package/dist/cjs/str/dateformat.js +149 -0
  135. package/dist/cjs/str/dateformat.js.map +7 -0
  136. package/dist/cjs/str/index.d.ts +459 -0
  137. package/dist/cjs/str/index.d.ts.map +1 -0
  138. package/dist/cjs/str/index.js +143 -0
  139. package/dist/cjs/str/index.js.map +7 -0
  140. package/dist/cjs/str/messageformat.d.ts +14 -0
  141. package/dist/cjs/str/messageformat.d.ts.map +1 -0
  142. package/dist/cjs/str/messageformat.js +114 -0
  143. package/dist/cjs/str/messageformat.js.map +7 -0
  144. package/dist/cjs/str/numberformat.d.ts +19 -0
  145. package/dist/cjs/str/numberformat.d.ts.map +1 -0
  146. package/dist/cjs/str/numberformat.js +170 -0
  147. package/dist/cjs/str/numberformat.js.map +7 -0
  148. package/dist/{strategy → cjs/strategy}/index.d.ts +50 -0
  149. package/dist/cjs/strategy/index.d.ts.map +1 -0
  150. package/dist/cjs/strategy/index.js +92 -0
  151. package/dist/cjs/strategy/index.js.map +7 -0
  152. package/dist/cjs/ta/index.d.ts +1397 -0
  153. package/dist/cjs/ta/index.d.ts.map +1 -0
  154. package/dist/cjs/ta/index.js +1715 -0
  155. package/dist/cjs/ta/index.js.map +7 -0
  156. package/dist/cjs/ta/running-sum.d.ts +30 -0
  157. package/dist/cjs/ta/running-sum.d.ts.map +1 -0
  158. package/dist/cjs/ta/running-sum.js +99 -0
  159. package/dist/cjs/ta/running-sum.js.map +7 -0
  160. package/dist/cjs/ta-series.d.ts +558 -0
  161. package/dist/cjs/ta-series.d.ts.map +1 -0
  162. package/dist/cjs/ta-series.js +606 -0
  163. package/dist/cjs/ta-series.js.map +7 -0
  164. package/dist/cjs/text/index.d.ts +14 -0
  165. package/dist/cjs/text/index.d.ts.map +1 -0
  166. package/dist/cjs/text/index.js +29 -0
  167. package/dist/cjs/text/index.js.map +7 -0
  168. package/dist/cjs/time/datestring.d.ts +23 -0
  169. package/dist/cjs/time/datestring.d.ts.map +1 -0
  170. package/dist/cjs/time/datestring.js +106 -0
  171. package/dist/cjs/time/datestring.js.map +7 -0
  172. package/dist/cjs/time/index.d.ts +89 -0
  173. package/dist/cjs/time/index.d.ts.map +1 -0
  174. package/dist/cjs/time/index.js +85 -0
  175. package/dist/cjs/time/index.js.map +7 -0
  176. package/dist/cjs/time/session.d.ts +17 -0
  177. package/dist/cjs/time/session.d.ts.map +1 -0
  178. package/dist/cjs/time/session.js +65 -0
  179. package/dist/cjs/time/session.js.map +7 -0
  180. package/dist/cjs/time/timezone.d.ts +40 -0
  181. package/dist/cjs/time/timezone.d.ts.map +1 -0
  182. package/dist/cjs/time/timezone.js +125 -0
  183. package/dist/cjs/time/timezone.js.map +7 -0
  184. package/dist/cjs/timeframe/index.d.ts +73 -0
  185. package/dist/cjs/timeframe/index.d.ts.map +1 -0
  186. package/dist/cjs/timeframe/index.js +85 -0
  187. package/dist/cjs/timeframe/index.js.map +7 -0
  188. package/dist/cjs/types/index.d.ts +343 -0
  189. package/dist/cjs/types/index.d.ts.map +1 -0
  190. package/dist/cjs/types/index.js +32 -0
  191. package/dist/cjs/types/index.js.map +7 -0
  192. package/dist/cjs/types/metadata.d.ts +300 -0
  193. package/dist/cjs/types/metadata.d.ts.map +1 -0
  194. package/dist/cjs/types/metadata.js +17 -0
  195. package/dist/cjs/types/metadata.js.map +7 -0
  196. package/dist/cjs/utils/index.d.ts +167 -0
  197. package/dist/cjs/utils/index.d.ts.map +1 -0
  198. package/dist/cjs/utils/index.js +209 -0
  199. package/dist/cjs/utils/index.js.map +7 -0
  200. package/dist/esm/array/index.d.ts +701 -0
  201. package/dist/esm/array/index.d.ts.map +1 -0
  202. package/dist/esm/array/index.js +983 -0
  203. package/dist/esm/array/index.js.map +1 -0
  204. package/dist/esm/box/index.d.ts +444 -0
  205. package/dist/esm/box/index.d.ts.map +1 -0
  206. package/dist/esm/box/index.js +602 -0
  207. package/dist/esm/box/index.js.map +1 -0
  208. package/dist/esm/callsite/index.d.ts +61 -0
  209. package/dist/esm/callsite/index.d.ts.map +1 -0
  210. package/dist/esm/callsite/index.js +97 -0
  211. package/dist/esm/callsite/index.js.map +1 -0
  212. package/dist/esm/chartpoint/index.d.ts +90 -0
  213. package/dist/esm/chartpoint/index.d.ts.map +1 -0
  214. package/dist/esm/chartpoint/index.js +113 -0
  215. package/dist/esm/chartpoint/index.js.map +1 -0
  216. package/dist/esm/color/index.d.ts +285 -0
  217. package/dist/esm/color/index.d.ts.map +1 -0
  218. package/dist/esm/color/index.js +373 -0
  219. package/dist/esm/color/index.js.map +1 -0
  220. package/dist/esm/compare/index.d.ts +26 -0
  221. package/dist/esm/compare/index.d.ts.map +1 -0
  222. package/dist/esm/compare/index.js +39 -0
  223. package/dist/esm/compare/index.js.map +1 -0
  224. package/dist/esm/drawing/registry.d.ts +42 -0
  225. package/dist/esm/drawing/registry.d.ts.map +1 -0
  226. package/dist/esm/drawing/registry.js +89 -0
  227. package/dist/esm/drawing/registry.js.map +1 -0
  228. package/dist/esm/index.d.ts +85 -0
  229. package/dist/esm/index.d.ts.map +1 -0
  230. package/dist/esm/index.js +96 -0
  231. package/dist/esm/index.js.map +1 -0
  232. package/dist/esm/indicator.d.ts +117 -0
  233. package/dist/esm/indicator.d.ts.map +1 -0
  234. package/dist/esm/indicator.js +84 -0
  235. package/dist/esm/indicator.js.map +1 -0
  236. package/dist/esm/input.d.ts +196 -0
  237. package/dist/esm/input.d.ts.map +1 -0
  238. package/dist/esm/input.js +183 -0
  239. package/dist/esm/input.js.map +1 -0
  240. package/dist/esm/label/index.d.ts +303 -0
  241. package/dist/esm/label/index.d.ts.map +1 -0
  242. package/dist/esm/label/index.js +417 -0
  243. package/dist/esm/label/index.js.map +1 -0
  244. package/dist/esm/lib/index.d.ts +8 -0
  245. package/dist/esm/lib/index.d.ts.map +1 -0
  246. package/dist/esm/lib/index.js +8 -0
  247. package/dist/esm/lib/index.js.map +1 -0
  248. package/dist/esm/lib/zigzag/index.d.ts +5 -0
  249. package/dist/esm/lib/zigzag/index.d.ts.map +1 -0
  250. package/dist/esm/lib/zigzag/index.js +5 -0
  251. package/dist/esm/lib/zigzag/index.js.map +1 -0
  252. package/dist/esm/lib/zigzag/zigzag.d.ts +100 -0
  253. package/dist/esm/lib/zigzag/zigzag.d.ts.map +1 -0
  254. package/dist/esm/lib/zigzag/zigzag.js +229 -0
  255. package/dist/esm/lib/zigzag/zigzag.js.map +1 -0
  256. package/dist/esm/line/index.d.ts +342 -0
  257. package/dist/esm/line/index.d.ts.map +1 -0
  258. package/dist/esm/line/index.js +470 -0
  259. package/dist/esm/line/index.js.map +1 -0
  260. package/dist/esm/linefill/index.d.ts +124 -0
  261. package/dist/esm/linefill/index.d.ts.map +1 -0
  262. package/dist/esm/linefill/index.js +144 -0
  263. package/dist/esm/linefill/index.js.map +1 -0
  264. package/dist/esm/map/index.d.ts +69 -0
  265. package/dist/esm/map/index.d.ts.map +1 -0
  266. package/dist/esm/map/index.js +106 -0
  267. package/dist/esm/map/index.js.map +1 -0
  268. package/dist/esm/math/index.d.ts +560 -0
  269. package/dist/esm/math/index.d.ts.map +1 -0
  270. package/dist/esm/math/index.js +495 -0
  271. package/dist/esm/math/index.js.map +1 -0
  272. package/dist/esm/matrix/index.d.ts +1231 -0
  273. package/dist/esm/matrix/index.d.ts.map +1 -0
  274. package/dist/esm/matrix/index.js +2450 -0
  275. package/dist/esm/matrix/index.js.map +1 -0
  276. package/dist/esm/plot.d.ts +76 -0
  277. package/dist/esm/plot.d.ts.map +1 -0
  278. package/dist/esm/plot.js +63 -0
  279. package/dist/esm/plot.js.map +1 -0
  280. package/dist/esm/polyline/index.d.ts +115 -0
  281. package/dist/esm/polyline/index.d.ts.map +1 -0
  282. package/dist/esm/polyline/index.js +157 -0
  283. package/dist/esm/polyline/index.js.map +1 -0
  284. package/dist/esm/runtime/adapters/LightweightChartsAdapter.d.ts +86 -0
  285. package/dist/esm/runtime/adapters/LightweightChartsAdapter.d.ts.map +1 -0
  286. package/dist/esm/runtime/adapters/LightweightChartsAdapter.js +140 -0
  287. package/dist/esm/runtime/adapters/LightweightChartsAdapter.js.map +1 -0
  288. package/dist/esm/runtime/adapters/SimpleInputAdapter.d.ts +59 -0
  289. package/dist/esm/runtime/adapters/SimpleInputAdapter.d.ts.map +1 -0
  290. package/dist/esm/runtime/adapters/SimpleInputAdapter.js +115 -0
  291. package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -0
  292. package/dist/esm/runtime/index.d.ts +13 -0
  293. package/dist/esm/runtime/index.d.ts.map +1 -0
  294. package/dist/esm/runtime/index.js +14 -0
  295. package/dist/esm/runtime/index.js.map +1 -0
  296. package/dist/esm/runtime/inputs.d.ts +91 -0
  297. package/dist/esm/runtime/inputs.d.ts.map +1 -0
  298. package/dist/esm/runtime/inputs.js +334 -0
  299. package/dist/esm/runtime/inputs.js.map +1 -0
  300. package/dist/esm/runtime/runtime.d.ts +70 -0
  301. package/dist/esm/runtime/runtime.d.ts.map +1 -0
  302. package/dist/esm/runtime/runtime.js +193 -0
  303. package/dist/esm/runtime/runtime.js.map +1 -0
  304. package/dist/esm/runtime/series.d.ts +362 -0
  305. package/dist/esm/runtime/series.d.ts.map +1 -0
  306. package/dist/esm/runtime/series.js +583 -0
  307. package/dist/esm/runtime/series.js.map +1 -0
  308. package/dist/esm/runtime/types.d.ts +282 -0
  309. package/dist/esm/runtime/types.d.ts.map +1 -0
  310. package/dist/esm/runtime/types.js +7 -0
  311. package/dist/esm/runtime/types.js.map +1 -0
  312. package/dist/esm/script/index.d.ts +987 -0
  313. package/dist/esm/script/index.d.ts.map +1 -0
  314. package/dist/esm/script/index.js +1289 -0
  315. package/dist/esm/script/index.js.map +1 -0
  316. package/dist/esm/security/resample.d.ts +63 -0
  317. package/dist/esm/security/resample.d.ts.map +1 -0
  318. package/dist/esm/security/resample.js +110 -0
  319. package/dist/esm/security/resample.js.map +1 -0
  320. package/dist/esm/session/bars.d.ts +80 -0
  321. package/dist/esm/session/bars.d.ts.map +1 -0
  322. package/dist/esm/session/bars.js +232 -0
  323. package/dist/esm/session/bars.js.map +1 -0
  324. package/dist/esm/session/calendar.d.ts +70 -0
  325. package/dist/esm/session/calendar.d.ts.map +1 -0
  326. package/dist/esm/session/calendar.js +172 -0
  327. package/dist/esm/session/calendar.js.map +1 -0
  328. package/dist/esm/str/dateformat.d.ts +15 -0
  329. package/dist/esm/str/dateformat.d.ts.map +1 -0
  330. package/dist/esm/str/dateformat.js +136 -0
  331. package/dist/esm/str/dateformat.js.map +1 -0
  332. package/dist/esm/str/index.d.ts +459 -0
  333. package/dist/esm/str/index.d.ts.map +1 -0
  334. package/dist/esm/str/index.js +540 -0
  335. package/dist/esm/str/index.js.map +1 -0
  336. package/dist/esm/str/messageformat.d.ts +14 -0
  337. package/dist/esm/str/messageformat.d.ts.map +1 -0
  338. package/dist/esm/str/messageformat.js +111 -0
  339. package/dist/esm/str/messageformat.js.map +1 -0
  340. package/dist/esm/str/numberformat.d.ts +19 -0
  341. package/dist/esm/str/numberformat.d.ts.map +1 -0
  342. package/dist/esm/str/numberformat.js +189 -0
  343. package/dist/esm/str/numberformat.js.map +1 -0
  344. package/dist/esm/strategy/index.d.ts +245 -0
  345. package/dist/esm/strategy/index.d.ts.map +1 -0
  346. package/dist/esm/strategy/index.js +84 -0
  347. package/dist/esm/strategy/index.js.map +1 -0
  348. package/dist/esm/ta/index.d.ts +1397 -0
  349. package/dist/esm/ta/index.d.ts.map +1 -0
  350. package/dist/esm/ta/index.js +3227 -0
  351. package/dist/esm/ta/index.js.map +1 -0
  352. package/dist/esm/ta/running-sum.d.ts +30 -0
  353. package/dist/esm/ta/running-sum.d.ts.map +1 -0
  354. package/dist/esm/ta/running-sum.js +113 -0
  355. package/dist/esm/ta/running-sum.js.map +1 -0
  356. package/dist/esm/ta-series.d.ts +558 -0
  357. package/dist/esm/ta-series.d.ts.map +1 -0
  358. package/dist/esm/ta-series.js +910 -0
  359. package/dist/esm/ta-series.js.map +1 -0
  360. package/dist/esm/text/index.d.ts +14 -0
  361. package/dist/esm/text/index.d.ts.map +1 -0
  362. package/dist/esm/text/index.js +14 -0
  363. package/dist/esm/text/index.js.map +1 -0
  364. package/dist/esm/time/datestring.d.ts +23 -0
  365. package/dist/esm/time/datestring.d.ts.map +1 -0
  366. package/dist/esm/time/datestring.js +94 -0
  367. package/dist/esm/time/datestring.js.map +1 -0
  368. package/dist/esm/time/index.d.ts +89 -0
  369. package/dist/esm/time/index.d.ts.map +1 -0
  370. package/dist/esm/time/index.js +108 -0
  371. package/dist/esm/time/index.js.map +1 -0
  372. package/dist/esm/time/session.d.ts +17 -0
  373. package/dist/esm/time/session.d.ts.map +1 -0
  374. package/dist/esm/time/session.js +69 -0
  375. package/dist/esm/time/session.js.map +1 -0
  376. package/dist/esm/time/timezone.d.ts +40 -0
  377. package/dist/esm/time/timezone.d.ts.map +1 -0
  378. package/dist/esm/time/timezone.js +144 -0
  379. package/dist/esm/time/timezone.js.map +1 -0
  380. package/dist/esm/timeframe/index.d.ts +73 -0
  381. package/dist/esm/timeframe/index.d.ts.map +1 -0
  382. package/dist/esm/timeframe/index.js +131 -0
  383. package/dist/esm/timeframe/index.js.map +1 -0
  384. package/dist/esm/types/index.d.ts +343 -0
  385. package/dist/esm/types/index.d.ts.map +1 -0
  386. package/dist/esm/types/index.js +17 -0
  387. package/dist/esm/types/index.js.map +1 -0
  388. package/dist/esm/types/metadata.d.ts +300 -0
  389. package/dist/esm/types/metadata.d.ts.map +1 -0
  390. package/dist/esm/types/metadata.js +7 -0
  391. package/dist/esm/types/metadata.js.map +1 -0
  392. package/dist/esm/utils/index.d.ts +167 -0
  393. package/dist/esm/utils/index.d.ts.map +1 -0
  394. package/dist/esm/utils/index.js +295 -0
  395. package/dist/esm/utils/index.js.map +1 -0
  396. package/package.json +53 -23
  397. package/src/array/index.ts +1056 -0
  398. package/src/box/index.ts +680 -0
  399. package/src/callsite/index.ts +104 -0
  400. package/src/chartpoint/index.ts +126 -0
  401. package/src/color/index.ts +411 -0
  402. package/src/compare/index.ts +46 -0
  403. package/src/drawing/registry.ts +106 -0
  404. package/src/index.ts +201 -0
  405. package/src/indicator.ts +185 -0
  406. package/src/input.ts +280 -0
  407. package/src/label/index.ts +490 -0
  408. package/src/lib/index.ts +8 -0
  409. package/src/lib/zigzag/index.ts +13 -0
  410. package/src/lib/zigzag/zigzag.ts +318 -0
  411. package/src/line/index.ts +530 -0
  412. package/src/linefill/index.ts +152 -0
  413. package/src/map/index.ts +115 -0
  414. package/src/math/index.ts +1071 -0
  415. package/src/matrix/index.ts +2697 -0
  416. package/src/plot.ts +121 -0
  417. package/src/polyline/index.ts +184 -0
  418. package/src/runtime/adapters/LightweightChartsAdapter.ts +201 -0
  419. package/src/runtime/adapters/SimpleInputAdapter.ts +132 -0
  420. package/src/runtime/index.ts +52 -0
  421. package/src/runtime/inputs.ts +377 -0
  422. package/src/runtime/runtime.ts +241 -0
  423. package/src/runtime/series.ts +644 -0
  424. package/src/runtime/types.ts +292 -0
  425. package/src/script/index.ts +1865 -0
  426. package/src/security/resample.ts +119 -0
  427. package/src/session/bars.ts +262 -0
  428. package/src/session/calendar.ts +199 -0
  429. package/src/str/dateformat.ts +104 -0
  430. package/src/str/index.ts +557 -0
  431. package/src/str/messageformat.ts +109 -0
  432. package/src/str/numberformat.ts +197 -0
  433. package/src/strategy/index.ts +281 -0
  434. package/src/ta/index.ts +3580 -0
  435. package/src/ta/running-sum.ts +117 -0
  436. package/src/ta-series.ts +1036 -0
  437. package/src/text/index.ts +14 -0
  438. package/src/time/datestring.ts +96 -0
  439. package/src/time/index.ts +161 -0
  440. package/src/time/session.ts +79 -0
  441. package/src/time/timezone.ts +180 -0
  442. package/src/timeframe/index.ts +144 -0
  443. package/src/types/index.ts +398 -0
  444. package/src/types/metadata.ts +334 -0
  445. package/src/utils/index.ts +334 -0
  446. package/dist/array/index.d.ts +0 -57
  447. package/dist/array/index.d.ts.map +0 -1
  448. package/dist/box/index.d.ts +0 -37
  449. package/dist/box/index.d.ts.map +0 -1
  450. package/dist/callsite/index.d.ts +0 -7
  451. package/dist/callsite/index.d.ts.map +0 -1
  452. package/dist/chartpoint/index.d.ts +0 -8
  453. package/dist/chartpoint/index.d.ts.map +0 -1
  454. package/dist/color/index.d.ts +0 -28
  455. package/dist/color/index.d.ts.map +0 -1
  456. package/dist/compare/index.d.ts +0 -8
  457. package/dist/compare/index.d.ts.map +0 -1
  458. package/dist/drawing/registry.d.ts +0 -19
  459. package/dist/drawing/registry.d.ts.map +0 -1
  460. package/dist/index.cjs +0 -7979
  461. package/dist/index.d.ts +0 -64
  462. package/dist/index.d.ts.map +0 -1
  463. package/dist/index.mjs +0 -7962
  464. package/dist/indicator.d.ts +0 -42
  465. package/dist/indicator.d.ts.map +0 -1
  466. package/dist/input.d.ts +0 -47
  467. package/dist/input.d.ts.map +0 -1
  468. package/dist/label/index.d.ts +0 -30
  469. package/dist/label/index.d.ts.map +0 -1
  470. package/dist/lib/index.d.ts +0 -2
  471. package/dist/lib/index.d.ts.map +0 -1
  472. package/dist/lib/zigzag/index.d.ts.map +0 -1
  473. package/dist/lib/zigzag/zigzag.d.ts +0 -47
  474. package/dist/lib/zigzag/zigzag.d.ts.map +0 -1
  475. package/dist/line/index.d.ts +0 -30
  476. package/dist/line/index.d.ts.map +0 -1
  477. package/dist/linefill/index.d.ts +0 -10
  478. package/dist/linefill/index.d.ts.map +0 -1
  479. package/dist/map/index.d.ts +0 -14
  480. package/dist/map/index.d.ts.map +0 -1
  481. package/dist/math/index.d.ts +0 -53
  482. package/dist/math/index.d.ts.map +0 -1
  483. package/dist/matrix/index.d.ts +0 -52
  484. package/dist/matrix/index.d.ts.map +0 -1
  485. package/dist/plot.d.ts +0 -20
  486. package/dist/plot.d.ts.map +0 -1
  487. package/dist/polyline/index.d.ts +0 -11
  488. package/dist/polyline/index.d.ts.map +0 -1
  489. package/dist/runtime/adapters/LightweightChartsAdapter.d.ts +0 -15
  490. package/dist/runtime/adapters/LightweightChartsAdapter.d.ts.map +0 -1
  491. package/dist/runtime/adapters/SimpleInputAdapter.d.ts +0 -16
  492. package/dist/runtime/adapters/SimpleInputAdapter.d.ts.map +0 -1
  493. package/dist/runtime/index.cjs +0 -600
  494. package/dist/runtime/index.d.ts.map +0 -1
  495. package/dist/runtime/index.mjs +0 -577
  496. package/dist/runtime/inputs.d.ts +0 -13
  497. package/dist/runtime/inputs.d.ts.map +0 -1
  498. package/dist/runtime/runtime.d.ts +0 -16
  499. package/dist/runtime/runtime.d.ts.map +0 -1
  500. package/dist/runtime/series.d.ts +0 -60
  501. package/dist/runtime/series.d.ts.map +0 -1
  502. package/dist/runtime/types.d.ts +0 -122
  503. package/dist/runtime/types.d.ts.map +0 -1
  504. package/dist/script/index.cjs +0 -6372
  505. package/dist/script/index.d.ts +0 -709
  506. package/dist/script/index.d.ts.map +0 -1
  507. package/dist/script/index.mjs +0 -6355
  508. package/dist/security/resample.d.ts +0 -13
  509. package/dist/security/resample.d.ts.map +0 -1
  510. package/dist/session/bars.d.ts +0 -34
  511. package/dist/session/bars.d.ts.map +0 -1
  512. package/dist/session/calendar.d.ts +0 -31
  513. package/dist/session/calendar.d.ts.map +0 -1
  514. package/dist/str/dateformat.d.ts +0 -2
  515. package/dist/str/dateformat.d.ts.map +0 -1
  516. package/dist/str/index.d.ts +0 -24
  517. package/dist/str/index.d.ts.map +0 -1
  518. package/dist/str/messageformat.d.ts +0 -2
  519. package/dist/str/messageformat.d.ts.map +0 -1
  520. package/dist/str/numberformat.d.ts +0 -3
  521. package/dist/str/numberformat.d.ts.map +0 -1
  522. package/dist/strategy/index.d.ts.map +0 -1
  523. package/dist/ta/index.d.ts +0 -72
  524. package/dist/ta/index.d.ts.map +0 -1
  525. package/dist/ta-series.d.ts +0 -143
  526. package/dist/ta-series.d.ts.map +0 -1
  527. package/dist/text/index.d.ts +0 -4
  528. package/dist/text/index.d.ts.map +0 -1
  529. package/dist/time/datestring.d.ts +0 -2
  530. package/dist/time/datestring.d.ts.map +0 -1
  531. package/dist/time/index.d.ts +0 -15
  532. package/dist/time/index.d.ts.map +0 -1
  533. package/dist/time/session.d.ts +0 -2
  534. package/dist/time/session.d.ts.map +0 -1
  535. package/dist/time/timezone.d.ts +0 -13
  536. package/dist/time/timezone.d.ts.map +0 -1
  537. package/dist/timeframe/index.d.ts +0 -17
  538. package/dist/timeframe/index.d.ts.map +0 -1
  539. package/dist/types/index.d.ts +0 -181
  540. package/dist/types/index.d.ts.map +0 -1
  541. package/dist/types/metadata.d.ts +0 -131
  542. package/dist/types/metadata.d.ts.map +0 -1
  543. package/dist/utils/index.d.ts +0 -26
  544. package/dist/utils/index.d.ts.map +0 -1
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Same-symbol `request.security` by resampling the chart bars (issue #101).
3
+ * PineScript rules:
4
+ *
5
+ * - `lookahead_off` (default): the value of a higher-timeframe period appears on the chart bar that
6
+ * completes the period; before that, the chart bars show the previous period's value
7
+ * - `lookahead_on`: every chart bar of a period shows the value of that period
8
+ * - `gaps_on`: only the bar where the value appears has it (the completing bar with lookahead off, the
9
+ * first bar of the period with lookahead on); the other bars are `na`
10
+ * - a bar completes its period only if it closes at or after the end of the period (a period still
11
+ * trading keeps showing the previous completed value); when the bars at the end of a period are missing
12
+ * (data gap, a day off not in the calendar), the period completes on the first bar of the next period
13
+ * - D / W / M periods follow the regular hours: on extended-hours charts the premarket bars still show
14
+ * the previous period, which completes on the last bar of its trading day
15
+ * - a higher-timeframe bar only holds the chart bars up to the bar that completes it: the premarket bars
16
+ * that still show the previous period are not part of its bar (no value from after the completion)
17
+ */
18
+
19
+ import type { Bar } from '../types/index.js';
20
+
21
+ /** Higher-timeframe bars and the period index of each chart bar. */
22
+ export interface Resampled {
23
+ bars: Bar[];
24
+ /** Index in `bars` of the period of each chart bar */
25
+ group: number[];
26
+ }
27
+
28
+ /**
29
+ * Groups consecutive chart bars with the same period start into higher-timeframe bars.
30
+ * @param bars - Chart bars (in order)
31
+ * @param periodStart - Period start of each chart bar, in the unit of `Bar.time`
32
+ */
33
+ export function resample(bars: Bar[], periodStart: number[]): Resampled {
34
+ const out: Bar[] = [];
35
+ const group: number[] = [];
36
+ bars.forEach((b, i) => {
37
+ const start = periodStart[i]!;
38
+ const last = out[out.length - 1];
39
+ if (!last || last.time !== start) {
40
+ out.push({ time: start, open: b.open, high: b.high, low: b.low, close: b.close, volume: b.volume ?? NaN });
41
+ } else {
42
+ last.high = Math.max(last.high, b.high);
43
+ last.low = Math.min(last.low, b.low);
44
+ last.close = b.close;
45
+ last.volume = (last.volume ?? 0) + (b.volume ?? NaN);
46
+ }
47
+ group.push(out.length - 1);
48
+ });
49
+ return { bars: out, group };
50
+ }
51
+
52
+ /**
53
+ * Period index of each chart bar, and the latest completed period at each chart bar.
54
+ * @param starts - Period start of each chart bar (the higher-timeframe bar it belongs to)
55
+ * @param dayPeriods - Period of the trading day of each chart bar in the loaded session: on extended-hours
56
+ * charts the premarket bars still belong to the previous daily period, but a new trading day completes it
57
+ * @param reaches - True when the chart bar closes at or after the end of its period
58
+ */
59
+ export function periodsOf(starts: number[], dayPeriods: number[], reaches: boolean[]): { group: number[]; latest: number[] } {
60
+ const n = starts.length;
61
+ const group: number[] = [];
62
+ starts.forEach((s, i) => group.push(i === 0 ? 0 : group[i - 1]! + (s !== starts[i - 1] ? 1 : 0)));
63
+ const latest: number[] = [];
64
+ starts.forEach((s, i) => {
65
+ let done = i === 0 ? -1 : latest[i - 1]!;
66
+ // a new period completes all the earlier ones (their last bars may be missing)
67
+ if (i > 0 && group[i] !== group[i - 1]) done = Math.max(done, group[i]! - 1);
68
+ // the last bar of its period in the loaded session (the premarket bars after it do not complete it again)
69
+ const ends = i < n - 1 ? starts[i + 1] !== s || dayPeriods[i + 1] !== dayPeriods[i] : true;
70
+ if (ends && reaches[i]) done = Math.max(done, group[i]!);
71
+ latest.push(done);
72
+ });
73
+ return { group, latest };
74
+ }
75
+
76
+ /**
77
+ * True for the chart bars that come after the bar that completed their period: on extended-hours charts
78
+ * the premarket bars of the next trading day still show the previous D / W / M period, but they are not
79
+ * part of its higher-timeframe bar. A period's first bar is never after its completion.
80
+ * @param group - Period index of each chart bar
81
+ * @param latest - Latest completed period at each chart bar
82
+ */
83
+ export function afterCompletion(group: number[], latest: number[]): boolean[] {
84
+ return group.map((g, i) => i > 0 && group[i - 1] === g && latest[i - 1]! >= g);
85
+ }
86
+
87
+ /**
88
+ * Maps values computed on the higher-timeframe bars to the chart bars.
89
+ * @param values - One value per higher-timeframe bar
90
+ * @param group - Period index of each chart bar
91
+ * @param latest - Latest completed period at each chart bar (-1: none yet)
92
+ */
93
+ export function mapToChart(values: number[], group: number[], latest: number[], lookahead: boolean, gaps: boolean): number[] {
94
+ return group.map((g, i) => {
95
+ if (lookahead) {
96
+ const first = i === 0 || group[i - 1] !== g;
97
+ return gaps && !first ? NaN : (values[g] ?? NaN);
98
+ }
99
+ const done = latest[i]!;
100
+ if (done < 0 || (gaps && i > 0 && latest[i - 1] === done)) return NaN;
101
+ return values[done] ?? NaN;
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Heikin Ashi bars (PineScript `ticker.heikinashi`): close = (open + high + low + close) / 4, open = the
107
+ * average of the previous Heikin Ashi open and close ((open + close) / 2 on the first bar),
108
+ * high / low = the extremes of high / low and the Heikin Ashi open and close.
109
+ */
110
+ export function heikinAshi(bars: Bar[]): Bar[] {
111
+ const out: Bar[] = [];
112
+ bars.forEach((b, i) => {
113
+ const close = (b.open + b.high + b.low + b.close) / 4;
114
+ const prev = out[i - 1];
115
+ const open = prev ? (prev.open + prev.close) / 2 : (b.open + b.close) / 2;
116
+ out.push({ time: b.time, open, high: Math.max(b.high, open, close), low: Math.min(b.low, open, close), close, volume: b.volume });
117
+ });
118
+ return out;
119
+ }
@@ -0,0 +1,262 @@
1
+ /**
2
+ * PineScript values that depend on the chart timeframe and the symbol session (issue #100):
3
+ * `time(tf)`, `time_close(tf)`, `timeframe.change(tf)`, `time_tradingday`, `session.*`.
4
+ * PineScript rules:
5
+ *
6
+ * - intraday periods are aligned on the start of the session period of the trading day: 240 minutes from
7
+ * 09:30 gives 09:30, 13:30; `time(tf)` is the start of the period that contains the bar open
8
+ * - "D" is the session start of the trading day; "W" / "M" the session start of the first trading day
9
+ * of the week (Monday to Sunday) / month
10
+ * - intraday closes are cut at the end of the session period; the "D" close is the session end
11
+ * - on intraday charts the "W" / "M" (and "nD") close is the session start of the next period's first
12
+ * trading day; on D / W / M charts it is the session end of the last trading day of the week / month
13
+ * - on D / W / M charts, intraday timeframes give the chart bar's time, and the end of the session
14
+ * period that contains the bar open as close
15
+ * - `time_tradingday` is 00:00 UTC of the trading day (on W / M charts, of the last trading day)
16
+ *
17
+ * Multipliers above one day (issue #100 follow-up): periods restart each
18
+ * calendar year. "nD" groups n trading days from the first trading day of the year; "nW" groups n weeks from
19
+ * the first week whose Monday is in the year; "nM" groups n months from January. The last group of a year
20
+ * can be shorter.
21
+ */
22
+
23
+ import { info, in_seconds, type TimeframeInfo } from '../timeframe/index.js';
24
+ import {
25
+ TradingCalendar,
26
+ addDays,
27
+ dateUtcMs,
28
+ monthEnd,
29
+ monthStart,
30
+ weekStart,
31
+ type DateNum,
32
+ } from './calendar.js';
33
+
34
+ type Unit = 'D' | 'W' | 'M';
35
+
36
+ function unitOf(tf: TimeframeInfo): { unit: Unit; n: number } {
37
+ return { unit: tf.isdaily ? 'D' : tf.isweekly ? 'W' : 'M', n: tf.multiplier };
38
+ }
39
+
40
+ const yearOf = (date: DateNum): number => Math.floor(date / 10000);
41
+
42
+ /** Monday of the first week of `year` (the first Monday on or after 1 January). */
43
+ const firstMonday = (year: number): DateNum => {
44
+ const jan1 = year * 10000 + 101;
45
+ const monday = weekStart(jan1);
46
+ return monday === jan1 ? jan1 : addDays(monday, 7);
47
+ };
48
+
49
+ /** Values of the bars of one chart, for a trading calendar. */
50
+ export class SessionBars {
51
+ readonly chart: TimeframeInfo;
52
+
53
+ private readonly yearDays = new Map<number, DateNum[]>();
54
+
55
+ constructor(
56
+ readonly calendar: TradingCalendar,
57
+ chartTimeframe: string
58
+ ) {
59
+ this.chart = info(chartTimeframe);
60
+ }
61
+
62
+ /** Trading days of a calendar year, in order. */
63
+ private tradingDaysOf(year: number): DateNum[] {
64
+ let days = this.yearDays.get(year);
65
+ if (!days) {
66
+ days = [];
67
+ for (let date = year * 10000 + 101; yearOf(date) === year; date = addDays(date, 1)) {
68
+ if (this.calendar.isTradingDay(date)) days.push(date);
69
+ }
70
+ this.yearDays.set(year, days);
71
+ }
72
+ return days;
73
+ }
74
+
75
+ /**
76
+ * Dates [from, to] of the `n`-`unit` period that contains `date` (for "D": its first and last trading days).
77
+ * Periods restart each calendar year.
78
+ */
79
+ private periodRange(date: DateNum, unit: Unit, n: number): [DateNum, DateNum] {
80
+ if (unit === 'D') {
81
+ if (n === 1) return [date, date];
82
+ const days = this.tradingDaysOf(yearOf(date));
83
+ let k = days.findIndex((d) => d >= date);
84
+ if (k === -1) return this.periodRange(yearOf(date) * 10000 + 10000 + 101, unit, n);
85
+ k -= k % n;
86
+ return [days[k]!, days[Math.min(k + n, days.length) - 1]!];
87
+ }
88
+ if (unit === 'W') {
89
+ const monday = weekStart(date);
90
+ const year = yearOf(monday);
91
+ const first = firstMonday(year);
92
+ const next = firstMonday(year + 1);
93
+ const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 86_400_000));
94
+ const from = addDays(first, (k - (k % n)) * 7);
95
+ const to = addDays(from, n * 7 - 1);
96
+ return [from, to < next ? to : addDays(next, -1)];
97
+ }
98
+ const year = yearOf(date);
99
+ const month = Math.floor(date / 100) % 100;
100
+ const firstMonth = month - ((month - 1) % n);
101
+ const lastMonth = Math.min(firstMonth + n - 1, 12);
102
+ return [monthStart(year * 10000 + firstMonth * 100 + 1), monthEnd(year * 10000 + lastMonth * 100 + 1)];
103
+ }
104
+
105
+ private dayStart(date: DateNum): number {
106
+ return this.calendar.periods(date)[0]![0];
107
+ }
108
+
109
+ private dayEnd(date: DateNum): number {
110
+ const p = this.calendar.periods(date);
111
+ return p[p.length - 1]![1];
112
+ }
113
+
114
+ /** PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. */
115
+ timeOf(time: number, timeframe: string): number {
116
+ const tf = info(timeframe);
117
+ const at = this.calendar.locate(time);
118
+ if (!at) return NaN;
119
+ if (tf.isintraday) {
120
+ if (this.chart.isdwm) return time;
121
+ const [start] = this.calendar.periods(at.date)[at.index]!;
122
+ const ms = in_seconds(tf.period) * 1000;
123
+ return start + Math.floor((time - start) / ms) * ms;
124
+ }
125
+ const { unit, n } = unitOf(tf);
126
+ const [from, to] = this.periodRange(at.date, unit, n);
127
+ const first = this.calendar.firstTradingDay(from, to);
128
+ return first === null ? NaN : this.dayStart(first);
129
+ }
130
+
131
+ /** PineScript `time_close(tf)` for a bar that opens at `time`. */
132
+ closeOf(time: number, timeframe: string): number {
133
+ const tf = info(timeframe);
134
+ const at = this.calendar.locate(time);
135
+ if (!at) return NaN;
136
+ if (tf.isintraday) {
137
+ const [, end] = this.calendar.periods(at.date)[at.index]!;
138
+ // on D / W / M charts: the end of the session period that contains the bar open
139
+ if (this.chart.isdwm) return end;
140
+ return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);
141
+ }
142
+ const { unit, n } = unitOf(tf);
143
+ const [from, to] = this.periodRange(at.date, unit, n);
144
+ // intraday charts: the start of the next period, except "1D" (the session end)
145
+ if (this.chart.isintraday && (unit !== 'D' || n > 1)) {
146
+ const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);
147
+ const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));
148
+ return first === null ? NaN : this.dayStart(first);
149
+ }
150
+ const last = this.calendar.lastTradingDay(from, to);
151
+ return last === null ? NaN : this.dayEnd(last);
152
+ }
153
+
154
+ /** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
155
+ tradingDay(time: number): DateNum | null {
156
+ const at = this.calendar.locate(time);
157
+ if (!at) return null;
158
+ if (this.chart.isdwm) {
159
+ const { unit, n } = unitOf(this.chart);
160
+ const [from, to] = this.periodRange(at.date, unit, n);
161
+ return this.calendar.lastTradingDay(from, to);
162
+ }
163
+ return at.date;
164
+ }
165
+
166
+ /**
167
+ * End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,
168
+ * or the session end of the last trading day of the period. Used to know whether the last loaded
169
+ * bar completes a higher-timeframe period (request.security).
170
+ */
171
+ periodEnd(time: number, timeframe: string): number {
172
+ const tf = info(timeframe);
173
+ const at = this.calendar.locate(time);
174
+ if (!at) return NaN;
175
+ if (tf.isintraday) {
176
+ const [, end] = this.calendar.periods(at.date)[at.index]!;
177
+ return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);
178
+ }
179
+ const { unit, n } = unitOf(tf);
180
+ const [from, to] = this.periodRange(at.date, unit, n);
181
+ const last = this.calendar.lastTradingDay(from, to);
182
+ return last === null ? NaN : this.dayEnd(last);
183
+ }
184
+
185
+ /** PineScript `time_tradingday`: 00:00 UTC of the trading day. */
186
+ tradingDayTime(time: number): number {
187
+ const day = this.tradingDay(time);
188
+ return day === null ? NaN : dateUtcMs(day);
189
+ }
190
+
191
+ /** True when the bar at `time` is inside the session. */
192
+ inside(time: number): boolean {
193
+ return this.calendar.locate(time)?.inside ?? false;
194
+ }
195
+
196
+ /** Session start and end of the trading day of `time`, or null. */
197
+ dayBounds(time: number): { date: DateNum; start: number; end: number } | null {
198
+ const at = this.calendar.locate(time);
199
+ return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
200
+ }
201
+ }
202
+
203
+ /** PineScript `session.*` flags of each bar. */
204
+ export interface SessionFlags {
205
+ isfirstbar: boolean[];
206
+ islastbar: boolean[];
207
+ ismarket: boolean[];
208
+ ispremarket: boolean[];
209
+ ispostmarket: boolean[];
210
+ isfirstbar_regular: boolean[];
211
+ islastbar_regular: boolean[];
212
+ }
213
+
214
+ /**
215
+ * `session.*` flags for bars that open at `times` (in order). `regular` gives the regular trading
216
+ * hours when the bars include extended hours. PineScript rules: flags use the bar open
217
+ * time; first and last bars are per session period (a trading day can have two periods, e.g. after a
218
+ * futures holiday); pre / post market compare with the regular hours of the same trading day; on
219
+ * D / W / M charts every bar is its own session (first, last, market, first and last regular).
220
+ */
221
+ export function sessionFlags(times: number[], bars: SessionBars, regular: SessionBars): SessionFlags {
222
+ const n = times.length;
223
+ const flag = () => new Array<boolean>(n).fill(false);
224
+ const out: SessionFlags = {
225
+ isfirstbar: flag(), islastbar: flag(), ismarket: flag(), ispremarket: flag(), ispostmarket: flag(),
226
+ isfirstbar_regular: flag(), islastbar_regular: flag(),
227
+ };
228
+ const chart = bars.chart;
229
+ let previousPeriod = '';
230
+ let previousRegular = '';
231
+ for (let i = 0; i < n; i++) {
232
+ const t = times[i]!;
233
+ if (chart.isdwm) {
234
+ for (const k of ['isfirstbar', 'islastbar', 'ismarket', 'isfirstbar_regular', 'islastbar_regular'] as const) out[k][i] = true;
235
+ continue;
236
+ }
237
+ const at = bars.calendar.locate(t);
238
+ if (!at) {
239
+ previousPeriod = previousRegular = '';
240
+ continue;
241
+ }
242
+ const close = bars.closeOf(t, chart.period);
243
+ const [, end] = bars.calendar.periods(at.date)[at.index]!;
244
+ const period = `${at.date}/${at.index}`;
245
+ out.isfirstbar[i] = period !== previousPeriod;
246
+ out.islastbar[i] = close >= end;
247
+ const regularPeriods = regular.calendar.periods(at.date);
248
+ const r = regularPeriods.findIndex(([s, e]) => s <= t && t < e);
249
+ const market = r !== -1;
250
+ out.ismarket[i] = market;
251
+ if (!market && regularPeriods.length) {
252
+ out.ispremarket[i] = t < regularPeriods[0]![0];
253
+ out.ispostmarket[i] = t >= regularPeriods[regularPeriods.length - 1]![1];
254
+ }
255
+ const regularPeriod = market ? `${at.date}/${r}` : '';
256
+ out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
257
+ out.islastbar_regular[i] = market && close >= regularPeriods[r]![1];
258
+ previousPeriod = period;
259
+ previousRegular = regularPeriod;
260
+ }
261
+ return out;
262
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Trading calendar: the session periods of each trading day of a symbol, from the symbol session
3
+ * information (issue #100).
4
+ *
5
+ * Session format (symbol session information, also PineScript session strings):
6
+ * - periods "HHMM-HHMM", several separated by commas; "24x7" is the whole day, every day
7
+ * - a period whose end is not after its start ("1700-1600", "1700-1700") starts the day before the
8
+ * trading day: the session that opens Sunday 17:00 is Monday's
9
+ * - "HHMMF<n>" moves a time <n> days before the trading day ("1700F2-1200F1")
10
+ * - optional days after ":" (1 = Sunday ... 7 = Saturday); without days a symbol session trades Monday to
11
+ * Friday ("24x7": every day), and a PineScript session string follows PineScript's rules (one period:
12
+ * every day; several periods: Monday to Friday)
13
+ * - "#YYYYMMDD/<session>" changes the session from that date ("0900-1746#20251201/0800-2200")
14
+ * - corrections ("session-correction"): "<session>:<dates>;dayoff:<dates>" replace the session of these
15
+ * dates (early closes, days off); holidays ("session_holidays") are dates without session
16
+ */
17
+
18
+ import { zonedFields, zonedToUnix } from '../time/timezone.js';
19
+
20
+ /** Session information of a symbol (hours, corrections, holidays). */
21
+ export interface SessionSpec {
22
+ /** Session hours: "0930-1600", "1700-1600", "24x7", "0400-2000" ... */
23
+ session: string;
24
+ /** Exceptions by date (symbol info "session-correction"): "0930-1300:20251128,20251224;dayoff:20250109" */
25
+ corrections?: string;
26
+ /** Exchange holidays as "YYYYMMDD" (symbol info "session_holidays"), comma-separated or as an array */
27
+ holidays?: string | string[];
28
+ }
29
+
30
+ /** Date as YYYYMMDD. */
31
+ export type DateNum = number;
32
+
33
+ interface Period {
34
+ /** Minutes after midnight */
35
+ start: number;
36
+ end: number;
37
+ /** Days before the trading day */
38
+ startOffset: number;
39
+ endOffset: number;
40
+ }
41
+
42
+ interface Version {
43
+ from: DateNum;
44
+ periods: Period[];
45
+ /** Index 1 (Sunday) to 7 (Saturday) */
46
+ days: boolean[];
47
+ }
48
+
49
+ export const toDateNum = (y: number, m: number, d: number): DateNum => y * 10000 + m * 100 + d;
50
+ const utcOf = (date: DateNum): number => Date.UTC(Math.floor(date / 10000), Math.floor(date / 100) % 100 - 1, date % 100);
51
+ const fromUtc = (ms: number): DateNum => {
52
+ const d = new Date(ms);
53
+ return toDateNum(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
54
+ };
55
+ export const addDays = (date: DateNum, n: number): DateNum => fromUtc(utcOf(date) + n * 86_400_000);
56
+ /** 1 = Sunday ... 7 = Saturday */
57
+ export const weekdayOf = (date: DateNum): number => new Date(utcOf(date)).getUTCDay() + 1;
58
+ /** 00:00 UTC of the date, in ms (PineScript `time_tradingday`). */
59
+ export const dateUtcMs = utcOf;
60
+
61
+ function parseTime(token: string, spec: string): { minutes: number; offset?: number } {
62
+ const m = /^(\d{2})(\d{2})(?:F(\d+))?$/.exec(token.trim());
63
+ if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
64
+ return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === undefined ? undefined : Number(m[3]) };
65
+ }
66
+
67
+ function parsePeriods(text: string, spec: string): Period[] {
68
+ if (text.trim() === '24x7') return [{ start: 0, end: 1440, startOffset: 0, endOffset: 0 }];
69
+ return text.split(',').map((p) => {
70
+ const [a = '', b = ''] = p.split('-');
71
+ const s = parseTime(a, spec);
72
+ const e = parseTime(b, spec);
73
+ if (s.minutes === 0 && e.minutes === 0 && s.offset === undefined && e.offset === undefined) {
74
+ return { start: 0, end: 1440, startOffset: 0, endOffset: 0 };
75
+ }
76
+ return {
77
+ start: s.minutes,
78
+ end: e.minutes,
79
+ startOffset: s.offset ?? (e.minutes <= s.minutes ? 1 : 0),
80
+ endOffset: e.offset ?? 0,
81
+ };
82
+ });
83
+ }
84
+
85
+ function parseVersion(text: string, from: DateNum, spec: string, rule: 'symbol' | 'pine'): Version {
86
+ const [periodText = '', dayText] = text.trim().split(':');
87
+ const periods = parsePeriods(periodText, spec);
88
+ const allDays = periodText.trim() === '24x7' || (rule === 'pine' && periods.length === 1);
89
+ const digits = dayText ?? (allDays ? '1234567' : '23456');
90
+ if (!/^[1-7]+$/.test(digits)) throw new SyntaxError(`Invalid session days in "${spec}"`);
91
+ const days = new Array<boolean>(8).fill(false);
92
+ for (const d of digits) days[Number(d)] = true;
93
+ return { from, periods, days };
94
+ }
95
+
96
+ /** Session periods of every trading day of a symbol, as UNIX times (ms). */
97
+ export class TradingCalendar {
98
+ private readonly versions: Version[];
99
+ private readonly corrections = new Map<DateNum, Period[] | null>();
100
+ private readonly holidays: Set<DateNum>;
101
+ private readonly cache = new Map<DateNum, Array<[number, number]>>();
102
+
103
+ /**
104
+ * @param timezone - Time zone of the session hours (the exchange time zone)
105
+ * @param spec - Session information (hours, corrections, holidays)
106
+ * @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
107
+ */
108
+ constructor(
109
+ readonly timezone: string,
110
+ spec: SessionSpec,
111
+ rule: 'symbol' | 'pine' = 'symbol'
112
+ ) {
113
+ const [first = '', ...changes] = spec.session.split('#');
114
+ this.versions = [parseVersion(first, 0, spec.session, rule)];
115
+ for (const change of changes) {
116
+ const m = /^(\d{8})\/(.+)$/.exec(change.trim());
117
+ if (!m) throw new SyntaxError(`Invalid session change in "${spec.session}"`);
118
+ this.versions.push(parseVersion(m[2]!, Number(m[1]), spec.session, rule));
119
+ }
120
+ for (const part of (spec.corrections ?? '').split(';').filter((p) => p.trim())) {
121
+ const i = part.lastIndexOf(':');
122
+ const text = part.slice(0, i).trim();
123
+ const periods = text === 'dayoff' ? null : parsePeriods(text, part);
124
+ for (const date of part.slice(i + 1).split(',')) this.corrections.set(Number(date), periods);
125
+ }
126
+ const holidays = Array.isArray(spec.holidays) ? spec.holidays : (spec.holidays ?? '').split(',');
127
+ this.holidays = new Set(holidays.filter((h) => h.trim()).map(Number));
128
+ }
129
+
130
+ /** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
131
+ periods(date: DateNum): Array<[number, number]> {
132
+ let out = this.cache.get(date);
133
+ if (out) return out;
134
+ let periods: Period[] = [];
135
+ const correction = this.corrections.get(date);
136
+ if (correction !== undefined) {
137
+ periods = correction ?? [];
138
+ } else if (!this.holidays.has(date)) {
139
+ const version = [...this.versions].reverse().find((v) => v.from <= date)!;
140
+ if (version.days[weekdayOf(date)]) periods = version.periods;
141
+ }
142
+ const y = Math.floor(date / 10000);
143
+ const m = Math.floor(date / 100) % 100;
144
+ const d = date % 100;
145
+ out = periods.map((p) => [
146
+ zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60),
147
+ zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60),
148
+ ]);
149
+ this.cache.set(date, out);
150
+ return out;
151
+ }
152
+
153
+ isTradingDay(date: DateNum): boolean {
154
+ return this.periods(date).length > 0;
155
+ }
156
+
157
+ /**
158
+ * Trading day and period of a time: the period that contains it, else the last period that started
159
+ * before it. Null when no trading day is found near the time.
160
+ */
161
+ locate(time: number): { date: DateNum; index: number; inside: boolean } | null {
162
+ const f = zonedFields(time, this.timezone);
163
+ const local = toDateNum(f.year, f.month, f.day);
164
+ for (let k = 0; k <= 5; k++) {
165
+ const date = addDays(local, k);
166
+ const index = this.periods(date).findIndex(([s, e]) => s <= time && time < e);
167
+ if (index !== -1) return { date, index, inside: true };
168
+ }
169
+ for (let k = 5; k >= -7; k--) {
170
+ const date = addDays(local, k);
171
+ const periods = this.periods(date);
172
+ let index = -1;
173
+ periods.forEach(([s], i) => {
174
+ if (s <= time) index = i;
175
+ });
176
+ if (index !== -1) return { date, index, inside: false };
177
+ }
178
+ return null;
179
+ }
180
+
181
+ /** First trading day in [from, to] (dates), or null. */
182
+ firstTradingDay(from: DateNum, to: DateNum): DateNum | null {
183
+ for (let date = from; date <= to; date = addDays(date, 1)) if (this.isTradingDay(date)) return date;
184
+ return null;
185
+ }
186
+
187
+ /** Last trading day in [from, to] (dates), or null. */
188
+ lastTradingDay(from: DateNum, to: DateNum): DateNum | null {
189
+ for (let date = to; date >= from; date = addDays(date, -1)) if (this.isTradingDay(date)) return date;
190
+ return null;
191
+ }
192
+ }
193
+
194
+ /** Monday of the week of `date` (weeks run Monday to Sunday). */
195
+ export const weekStart = (date: DateNum): DateNum => addDays(date, -((weekdayOf(date) + 5) % 7));
196
+ /** First day of the month of `date`. */
197
+ export const monthStart = (date: DateNum): DateNum => Math.floor(date / 100) * 100 + 1;
198
+ /** Last day of the month of `date`. */
199
+ export const monthEnd = (date: DateNum): DateNum => addDays(monthStart(addDays(monthStart(date), 32)), -1);
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Date patterns of `str.format_time` and `str.format("{0,date,...}")`, as PineScript formats them
3
+ * (Java SimpleDateFormat letters, English names):
4
+ *
5
+ * y year, M month (M, MM, MMM, MMMM), d day, E weekday (EEE, EEEE), u weekday number (1 = Monday),
6
+ * D day of year, w week of year (weeks start on Sunday, week 1 contains 1 January), H hour 0-23,
7
+ * k hour 1-24, K hour 0-11, h hour 1-12, a AM/PM, m minute, s second, S millisecond,
8
+ * Z offset (+0530), z time zone name, 'text' literal text ('' is a quote).
9
+ *
10
+ * `z` gives "UTC" for Etc/UTC, "GMT" for "UTC"/"GMT", "GMT+05:00" for other offsets, and the
11
+ * host's short English name for IANA zones (PineScript's names can differ, e.g. "IST" for Asia/Kolkata).
12
+ */
13
+
14
+ import { zonedFields, zoneOffset } from '../time/timezone.js';
15
+
16
+ const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
17
+ 'October', 'November', 'December'];
18
+ const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
19
+
20
+ const pad = (n: number, width: number): string => String(n).padStart(width, '0');
21
+
22
+ function zoneName(time: number, timezone: string, offsetMs: number): string {
23
+ if (timezone === 'Etc/UTC') return 'UTC';
24
+ if (/^(UTC|GMT)/.test(timezone)) {
25
+ if (offsetMs === 0) return 'GMT';
26
+ const minutes = Math.abs(offsetMs) / 60000;
27
+ return `GMT${offsetMs < 0 ? '-' : '+'}${pad(Math.floor(minutes / 60), 2)}:${pad(minutes % 60, 2)}`;
28
+ }
29
+ const part = new Intl.DateTimeFormat('en-US', { timeZone: timezone, timeZoneName: 'short' })
30
+ .formatToParts(time)
31
+ .find((p) => p.type === 'timeZoneName');
32
+ return part?.value ?? timezone;
33
+ }
34
+
35
+ /** Week of year: weeks start on Sunday and week 1 is the week that contains 1 January. */
36
+ function weekOfYear(year: number, month: number, day: number): number {
37
+ const date = Date.UTC(year, month - 1, day);
38
+ const dow = new Date(date).getUTCDay();
39
+ const weekStart = date - dow * 86_400_000;
40
+ // the week that contains 1 January of the next year is week 1
41
+ if (weekStart + 6 * 86_400_000 >= Date.UTC(year + 1, 0, 1)) return 1;
42
+ const jan1 = Date.UTC(year, 0, 1);
43
+ const jan1Dow = new Date(jan1).getUTCDay();
44
+ return Math.floor((date - jan1 + jan1Dow * 86_400_000) / (7 * 86_400_000)) + 1;
45
+ }
46
+
47
+ /** Formats a UNIX time (ms) with a SimpleDateFormat pattern in `timezone`. */
48
+ export function formatDate(time: number, pattern: string, timezone: string): string {
49
+ if (Number.isNaN(time)) return 'NaN';
50
+ const f = zonedFields(time, timezone);
51
+ const offset = zoneOffset(time, timezone);
52
+ const ms = ((time % 1000) + 1000) % 1000;
53
+ const dayOfYear = (Date.UTC(f.year, f.month - 1, f.day) - Date.UTC(f.year, 0, 1)) / 86_400_000 + 1;
54
+
55
+ let out = '';
56
+ for (let i = 0; i < pattern.length; ) {
57
+ const ch = pattern[i]!;
58
+ if (ch === "'") {
59
+ const end = pattern.indexOf("'", i + 1);
60
+ if (end === i + 1) {
61
+ out += "'";
62
+ i += 2;
63
+ } else {
64
+ out += pattern.slice(i + 1, end === -1 ? undefined : end);
65
+ i = end === -1 ? pattern.length : end + 1;
66
+ }
67
+ continue;
68
+ }
69
+ if (!/[A-Za-z]/.test(ch)) {
70
+ out += ch;
71
+ i++;
72
+ continue;
73
+ }
74
+ let n = 1;
75
+ while (pattern[i + n] === ch) n++;
76
+ i += n;
77
+ const hour12 = f.hour % 12;
78
+ switch (ch) {
79
+ case 'y': out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n); break;
80
+ case 'M': out += n >= 4 ? MONTHS[f.month - 1] : n === 3 ? MONTHS[f.month - 1]!.slice(0, 3) : pad(f.month, n); break;
81
+ case 'd': out += pad(f.day, n); break;
82
+ case 'E': out += n >= 4 ? DAYS[f.dayOfWeek - 1] : DAYS[f.dayOfWeek - 1]!.slice(0, 3); break;
83
+ case 'u': out += pad(f.dayOfWeek === 1 ? 7 : f.dayOfWeek - 1, n); break;
84
+ case 'D': out += pad(dayOfYear, n); break;
85
+ case 'w': out += pad(weekOfYear(f.year, f.month, f.day), n); break;
86
+ case 'H': out += pad(f.hour, n); break;
87
+ case 'k': out += pad(f.hour === 0 ? 24 : f.hour, n); break;
88
+ case 'K': out += pad(hour12, n); break;
89
+ case 'h': out += pad(hour12 === 0 ? 12 : hour12, n); break;
90
+ case 'a': out += f.hour < 12 ? 'AM' : 'PM'; break;
91
+ case 'm': out += pad(f.minute, n); break;
92
+ case 's': out += pad(f.second, n); break;
93
+ case 'S': out += pad(ms, n); break;
94
+ case 'Z': {
95
+ const minutes = Math.abs(offset) / 60000;
96
+ out += (offset < 0 ? '-' : '+') + pad(Math.floor(minutes / 60), 2) + pad(minutes % 60, 2);
97
+ break;
98
+ }
99
+ case 'z': out += zoneName(time, timezone, offset); break;
100
+ default: throw new SyntaxError(`Unsupported date pattern letter "${ch}" in "${pattern}"`);
101
+ }
102
+ }
103
+ return out;
104
+ }