oakscriptjs 0.10.1 → 0.11.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 (177) hide show
  1. package/dist/cjs/box/index.d.ts.map +1 -1
  2. package/dist/cjs/box/index.js +7 -1
  3. package/dist/cjs/box/index.js.map +2 -2
  4. package/dist/cjs/callsite/index.d.ts +73 -32
  5. package/dist/cjs/callsite/index.d.ts.map +1 -1
  6. package/dist/cjs/callsite/index.js +69 -65
  7. package/dist/cjs/callsite/index.js.map +2 -2
  8. package/dist/cjs/drawing/registry.d.ts +75 -0
  9. package/dist/cjs/drawing/registry.d.ts.map +1 -1
  10. package/dist/cjs/drawing/registry.js +139 -6
  11. package/dist/cjs/drawing/registry.js.map +2 -2
  12. package/dist/cjs/index.d.ts +6 -1
  13. package/dist/cjs/index.d.ts.map +1 -1
  14. package/dist/cjs/index.js +28 -1
  15. package/dist/cjs/index.js.map +2 -2
  16. package/dist/cjs/label/index.d.ts.map +1 -1
  17. package/dist/cjs/label/index.js +3 -0
  18. package/dist/cjs/label/index.js.map +2 -2
  19. package/dist/cjs/line/index.d.ts.map +1 -1
  20. package/dist/cjs/line/index.js +7 -1
  21. package/dist/cjs/line/index.js.map +2 -2
  22. package/dist/cjs/math/index.d.ts.map +1 -1
  23. package/dist/cjs/math/index.js +2 -0
  24. package/dist/cjs/math/index.js.map +2 -2
  25. package/dist/cjs/polyline/index.d.ts.map +1 -1
  26. package/dist/cjs/polyline/index.js +3 -0
  27. package/dist/cjs/polyline/index.js.map +2 -2
  28. package/dist/cjs/script/index.d.ts +30 -13
  29. package/dist/cjs/script/index.d.ts.map +1 -1
  30. package/dist/cjs/script/index.js +48 -9
  31. package/dist/cjs/script/index.js.map +3 -3
  32. package/dist/cjs/session/bars.d.ts +15 -1
  33. package/dist/cjs/session/bars.d.ts.map +1 -1
  34. package/dist/cjs/session/bars.js +41 -6
  35. package/dist/cjs/session/bars.js.map +3 -3
  36. package/dist/cjs/session/calendar.d.ts +9 -1
  37. package/dist/cjs/session/calendar.d.ts.map +1 -1
  38. package/dist/cjs/session/calendar.js +28 -2
  39. package/dist/cjs/session/calendar.js.map +2 -2
  40. package/dist/cjs/session/context.d.ts +75 -0
  41. package/dist/cjs/session/context.d.ts.map +1 -0
  42. package/dist/cjs/session/context.js +113 -0
  43. package/dist/cjs/session/context.js.map +7 -0
  44. package/dist/cjs/str/index.d.ts +3 -1
  45. package/dist/cjs/str/index.d.ts.map +1 -1
  46. package/dist/cjs/str/index.js +2 -1
  47. package/dist/cjs/str/index.js.map +2 -2
  48. package/dist/cjs/str/numberformat.d.ts +4 -2
  49. package/dist/cjs/str/numberformat.d.ts.map +1 -1
  50. package/dist/cjs/str/numberformat.js +1 -1
  51. package/dist/cjs/str/numberformat.js.map +2 -2
  52. package/dist/cjs/ta/index.d.ts +33 -17
  53. package/dist/cjs/ta/index.d.ts.map +1 -1
  54. package/dist/cjs/ta/index.js +70 -29
  55. package/dist/cjs/ta/index.js.map +2 -2
  56. package/dist/cjs/ta/limits.d.ts +24 -0
  57. package/dist/cjs/ta/limits.d.ts.map +1 -0
  58. package/dist/cjs/ta/limits.js +50 -0
  59. package/dist/cjs/ta/limits.js.map +7 -0
  60. package/dist/cjs/ta/running-sum.d.ts +0 -16
  61. package/dist/cjs/ta/running-sum.d.ts.map +1 -1
  62. package/dist/cjs/ta/running-sum.js +2 -0
  63. package/dist/cjs/ta/running-sum.js.map +2 -2
  64. package/dist/cjs/ta-series.d.ts +7 -7
  65. package/dist/cjs/ta-series.d.ts.map +1 -1
  66. package/dist/cjs/ta-series.js +9 -7
  67. package/dist/cjs/ta-series.js.map +2 -2
  68. package/dist/cjs/time/index.d.ts +5 -2
  69. package/dist/cjs/time/index.d.ts.map +1 -1
  70. package/dist/cjs/time/index.js +2 -2
  71. package/dist/cjs/time/index.js.map +2 -2
  72. package/dist/cjs/time/session.d.ts +17 -1
  73. package/dist/cjs/time/session.d.ts.map +1 -1
  74. package/dist/cjs/time/session.js +61 -7
  75. package/dist/cjs/time/session.js.map +2 -2
  76. package/dist/cjs/types/metadata.d.ts +27 -3
  77. package/dist/cjs/types/metadata.d.ts.map +1 -1
  78. package/dist/cjs/types/metadata.js.map +1 -1
  79. package/dist/esm/box/index.d.ts.map +1 -1
  80. package/dist/esm/box/index.js +8 -2
  81. package/dist/esm/box/index.js.map +1 -1
  82. package/dist/esm/callsite/index.d.ts +73 -32
  83. package/dist/esm/callsite/index.d.ts.map +1 -1
  84. package/dist/esm/callsite/index.js +143 -106
  85. package/dist/esm/callsite/index.js.map +1 -1
  86. package/dist/esm/drawing/registry.d.ts +75 -0
  87. package/dist/esm/drawing/registry.d.ts.map +1 -1
  88. package/dist/esm/drawing/registry.js +237 -6
  89. package/dist/esm/drawing/registry.js.map +1 -1
  90. package/dist/esm/index.d.ts +6 -1
  91. package/dist/esm/index.d.ts.map +1 -1
  92. package/dist/esm/index.js +10 -1
  93. package/dist/esm/index.js.map +1 -1
  94. package/dist/esm/label/index.d.ts.map +1 -1
  95. package/dist/esm/label/index.js +4 -1
  96. package/dist/esm/label/index.js.map +1 -1
  97. package/dist/esm/line/index.d.ts.map +1 -1
  98. package/dist/esm/line/index.js +8 -2
  99. package/dist/esm/line/index.js.map +1 -1
  100. package/dist/esm/math/index.d.ts.map +1 -1
  101. package/dist/esm/math/index.js +3 -0
  102. package/dist/esm/math/index.js.map +1 -1
  103. package/dist/esm/polyline/index.d.ts.map +1 -1
  104. package/dist/esm/polyline/index.js +5 -1
  105. package/dist/esm/polyline/index.js.map +1 -1
  106. package/dist/esm/script/index.d.ts +30 -13
  107. package/dist/esm/script/index.d.ts.map +1 -1
  108. package/dist/esm/script/index.js +54 -11
  109. package/dist/esm/script/index.js.map +1 -1
  110. package/dist/esm/session/bars.d.ts +15 -1
  111. package/dist/esm/session/bars.d.ts.map +1 -1
  112. package/dist/esm/session/bars.js +50 -6
  113. package/dist/esm/session/bars.js.map +1 -1
  114. package/dist/esm/session/calendar.d.ts +9 -1
  115. package/dist/esm/session/calendar.d.ts.map +1 -1
  116. package/dist/esm/session/calendar.js +35 -3
  117. package/dist/esm/session/calendar.js.map +1 -1
  118. package/dist/esm/session/context.d.ts +75 -0
  119. package/dist/esm/session/context.d.ts.map +1 -0
  120. package/dist/esm/session/context.js +122 -0
  121. package/dist/esm/session/context.js.map +1 -0
  122. package/dist/esm/str/index.d.ts +3 -1
  123. package/dist/esm/str/index.d.ts.map +1 -1
  124. package/dist/esm/str/index.js +8 -2
  125. package/dist/esm/str/index.js.map +1 -1
  126. package/dist/esm/str/numberformat.d.ts +4 -2
  127. package/dist/esm/str/numberformat.d.ts.map +1 -1
  128. package/dist/esm/str/numberformat.js +4 -2
  129. package/dist/esm/str/numberformat.js.map +1 -1
  130. package/dist/esm/ta/index.d.ts +33 -17
  131. package/dist/esm/ta/index.d.ts.map +1 -1
  132. package/dist/esm/ta/index.js +130 -56
  133. package/dist/esm/ta/index.js.map +1 -1
  134. package/dist/esm/ta/limits.d.ts +24 -0
  135. package/dist/esm/ta/limits.d.ts.map +1 -0
  136. package/dist/esm/ta/limits.js +42 -0
  137. package/dist/esm/ta/limits.js.map +1 -0
  138. package/dist/esm/ta/running-sum.d.ts +0 -16
  139. package/dist/esm/ta/running-sum.d.ts.map +1 -1
  140. package/dist/esm/ta/running-sum.js +2 -0
  141. package/dist/esm/ta/running-sum.js.map +1 -1
  142. package/dist/esm/ta-series.d.ts +7 -7
  143. package/dist/esm/ta-series.d.ts.map +1 -1
  144. package/dist/esm/ta-series.js +9 -7
  145. package/dist/esm/ta-series.js.map +1 -1
  146. package/dist/esm/time/index.d.ts +5 -2
  147. package/dist/esm/time/index.d.ts.map +1 -1
  148. package/dist/esm/time/index.js +6 -3
  149. package/dist/esm/time/index.js.map +1 -1
  150. package/dist/esm/time/session.d.ts +17 -1
  151. package/dist/esm/time/session.d.ts.map +1 -1
  152. package/dist/esm/time/session.js +97 -10
  153. package/dist/esm/time/session.js.map +1 -1
  154. package/dist/esm/types/metadata.d.ts +27 -3
  155. package/dist/esm/types/metadata.d.ts.map +1 -1
  156. package/package.json +1 -1
  157. package/src/box/index.ts +8 -2
  158. package/src/callsite/index.ts +150 -100
  159. package/src/drawing/registry.ts +255 -5
  160. package/src/index.ts +34 -1
  161. package/src/label/index.ts +4 -1
  162. package/src/line/index.ts +8 -2
  163. package/src/math/index.ts +2 -0
  164. package/src/polyline/index.ts +3 -1
  165. package/src/script/index.ts +77 -18
  166. package/src/session/bars.ts +47 -6
  167. package/src/session/calendar.ts +37 -3
  168. package/src/session/context.ts +160 -0
  169. package/src/str/index.ts +7 -2
  170. package/src/str/numberformat.ts +5 -3
  171. package/src/ta/index.ts +148 -66
  172. package/src/ta/limits.ts +47 -0
  173. package/src/ta/running-sum.ts +2 -0
  174. package/src/ta-series.ts +16 -14
  175. package/src/time/index.ts +6 -3
  176. package/src/time/session.ts +89 -9
  177. package/src/types/metadata.ts +27 -3
@@ -12,11 +12,13 @@
12
12
  * - a trailing ",", ":" or "|" ends its list ("1100-1400," is "1100-1400" Monday to Friday)
13
13
  * - an end before the start is an overnight run that belongs to the day it ends; equal ends are 24 hours;
14
14
  * "0000-0000" and "24x7" are the whole day, every day
15
+ * - a run that ends at 0000 ("2000-0000") ends at 24:00 of the day it starts and belongs to that day
16
+ * ("2000-0000:6" is Friday 20:00 to midnight)
15
17
  * - a string that is empty or does not start with a digit ("regular", "extended") is the symbol's own session
16
18
  * - a malformed string ("1100 -1400", "0930-16", ":8") is an error, as the PineScript runtime error
17
19
  */
18
20
 
19
- import { zonedFields } from './timezone.js';
21
+ import { zoneOffset, zonedFields } from './timezone.js';
20
22
 
21
23
  const MINUTES_PER_DAY = 1440;
22
24
  const WEEKDAYS = [2, 3, 4, 5, 6];
@@ -103,26 +105,104 @@ export function parsePineSession(session: string): SessionRange[] | null {
103
105
  return out;
104
106
  }
105
107
 
108
+ const MS_PER_MINUTE = 60_000;
109
+ const MS_PER_HOUR = 3_600_000;
110
+ const MS_PER_DAY = 86_400_000;
111
+ /** A clock change is looked for this far on each side of the tested time. */
112
+ const CHANGE_WINDOW = 36 * MS_PER_HOUR;
113
+
114
+ /** The clock change of `timezone` within 36 hours of `time`: its UNIX time and the offsets (ms) around it. */
115
+ function clockChangeNear(time: number, timezone: string): { at: number; before: number; after: number } | null {
116
+ let lo = time - CHANGE_WINDOW;
117
+ let hi = time + CHANGE_WINDOW;
118
+ const before = zoneOffset(lo, timezone);
119
+ const after = zoneOffset(hi, timezone);
120
+ if (before === after) return null;
121
+ while (hi - lo > MS_PER_MINUTE) {
122
+ const mid = Math.floor((lo + hi) / 2 / MS_PER_MINUTE) * MS_PER_MINUTE;
123
+ if (zoneOffset(mid, timezone) === before) lo = mid;
124
+ else hi = mid;
125
+ }
126
+ return { at: hi, before, after };
127
+ }
128
+
106
129
  /**
107
130
  * True when `time` falls inside `session`, with the session hours read in `timezone`.
108
131
  * A run includes its start minute and excludes its end minute.
132
+ *
133
+ * On the days around a clock change PineScript does not read the wall clock of each bar; it places each run of
134
+ * each local day (measured on 15- and 5-minute bars, clocks going forward and back, four time zones):
135
+ * - a wall time of the day is placed with the offset before the change when it is before the wall time of the
136
+ * change (02:00 for 02:00 -> 03:00, 03:00 for 03:00 -> 02:00), with the offset after it otherwise. Forward
137
+ * change: "0100-0300" lasts one hour and "0130-0230" is empty; back change: "0230-0330" lasts two hours
138
+ * - a run that ends exactly on the wall time of the change is placed with the offset after the change at both ends
139
+ * (forward change: "0100-0200" is one hour earlier than the wall clock says)
140
+ * - clocks going back: a run that ends inside the repeated hour also covers its second pass
141
+ * - clocks going back, the day BEFORE the change: a run with a start or an end on the wall time of the change is
142
+ * also true one hour (the amount of the change) later, from one bar after its usual end. This needs the bar
143
+ * duration `barMs`; without it the rule is not applied
144
+ *
145
+ * @param barMs - Duration of the bars in ms (the chart timeframe); only used by the last rule
109
146
  * @throws Error for the symbol's own session ("regular", "extended", ""), which this function does not know: use
110
147
  * `time(timeframe, session)` in a script with the chart session
111
148
  */
112
- export function inSession(time: number, session: string, timezone: string): boolean {
149
+ export function inSession(time: number, session: string, timezone: string, barMs?: number): boolean {
113
150
  if (Number.isNaN(time)) return false;
114
151
  const ranges = parsePineSession(session);
115
152
  if (ranges === null) throw new Error(`Session "${session}" is the symbol session: it needs the chart session (time(timeframe, session) in a script)`);
153
+ const change = clockChangeNear(time, timezone);
116
154
  const f = zonedFields(time, timezone);
117
155
  const minute = f.hour * 60 + f.minute;
118
156
  const nextDay = (f.dayOfWeek % 7) + 1;
119
- for (const { start, end, days } of ranges) {
120
- if (start < end || (start === 0 && end === 0)) {
121
- if (minute >= start && (minute < end || end === 0) && days.has(f.dayOfWeek)) return true;
122
- } else {
123
- // Overnight (24 hours when start === end): the part from `start` belongs to the next day.
124
- if (minute >= start && days.has(nextDay)) return true;
125
- if (minute < end && days.has(f.dayOfWeek)) return true;
157
+ for (const { start, end: rawEnd, days } of ranges) {
158
+ if (start === rawEnd) {
159
+ // 24 hours: the run belongs to the day it ends ("0000-0000": the day itself)
160
+ if (days.has(start === 0 || minute < start ? f.dayOfWeek : nextDay)) return true;
161
+ continue;
162
+ }
163
+ // a run that ends at 0000 ends at 24:00 of the day it starts
164
+ const end = rawEnd === 0 ? MINUTES_PER_DAY : rawEnd;
165
+ const overnight = start > end;
166
+ if (!change) {
167
+ if (!overnight) {
168
+ if (minute >= start && minute < end && days.has(f.dayOfWeek)) return true;
169
+ } else {
170
+ // the part from `start` belongs to the next day
171
+ if (minute >= start && days.has(nextDay)) return true;
172
+ if (minute < end && days.has(f.dayOfWeek)) return true;
173
+ }
174
+ continue;
175
+ }
176
+ // local days as naive instants (wall clock read as UTC)
177
+ const changeWall = change.at + change.before;
178
+ const place = (naive: number): number => (naive < changeWall ? naive - change.before : naive - change.after);
179
+ const today = Math.floor((time + change.before) / MS_PER_DAY);
180
+ for (let day = today - 1; day <= today + 1; day++) {
181
+ if (!days.has(((day + 4) % 7) + 1)) continue; // 01/01/1970 is a Thursday (5)
182
+ const from = day * MS_PER_DAY + (overnight ? start - MINUTES_PER_DAY : start) * MS_PER_MINUTE;
183
+ const to = day * MS_PER_DAY + end * MS_PER_MINUTE;
184
+ if (to === changeWall) {
185
+ if (time >= from - change.after && time < to - change.after) return true;
186
+ continue;
187
+ }
188
+ if (time >= place(from) && time < place(to)) return true;
189
+ // clocks going back: the second pass of the repeated hour
190
+ const repeated = change.at + change.after;
191
+ if (change.after < change.before && to < changeWall && to > repeated) {
192
+ if (time >= Math.max(from, repeated) - change.after && time < to - change.after) return true;
193
+ }
194
+ }
195
+ // clocks going back, the day before: a run with an end on the wall time of the change is also true one change
196
+ // later, from one bar after its usual end
197
+ if (barMs !== undefined && change.after < change.before) {
198
+ const day = Math.floor(changeWall / MS_PER_DAY) - 1;
199
+ const wallMinute = (changeWall - (day + 1) * MS_PER_DAY) / MS_PER_MINUTE;
200
+ if ((start === wallMinute || end === wallMinute) && days.has(((day + 4) % 7) + 1)) {
201
+ const from = day * MS_PER_DAY + (overnight ? start - MINUTES_PER_DAY : start) * MS_PER_MINUTE - change.before;
202
+ const to = day * MS_PER_DAY + end * MS_PER_MINUTE - change.before;
203
+ const shift = change.before - change.after;
204
+ if (time >= from + shift && time < to + shift && time >= to + barMs) return true;
205
+ }
126
206
  }
127
207
  }
128
208
  return false;
@@ -431,17 +431,20 @@ export interface LabelData {
431
431
  /** Price; not used with yloc 'abovebar' / 'belowbar' */
432
432
  price: number;
433
433
  text: string;
434
- /** Background, border and arrow colour */
434
+ /** Background, border and arrow colour. Omitted: #2962FF (color.blue; #2196F3 in a v4 script) */
435
435
  color?: string;
436
+ /** Omitted: #FFFFFF in a v6 script, #363A45 in v4 and v5 (the result does not carry the version) */
436
437
  textColor?: string;
437
- /** 'none': text only, no background (PineScript label.style_none) */
438
+ /** 'none': text only, no background (PineScript label.style_none). Omitted: 'label_down' */
438
439
  style?: LabelStyle;
440
+ /** Omitted: 'normal' */
439
441
  size?: PineSize | number;
440
442
  /**
441
443
  * PineScript yloc: 'price' (default) places the label at `price`; 'abovebar' / 'belowbar' place it above the bar
442
444
  * high / below the bar low and ignore `price` (the renderer reads the bar at `time`).
443
445
  */
444
446
  yloc?: 'price' | 'abovebar' | 'belowbar';
447
+ /** Omitted: 'center' */
445
448
  textAlign?: 'left' | 'center' | 'right';
446
449
  tooltip?: string;
447
450
  fontFamily?: 'default' | 'monospace';
@@ -459,8 +462,11 @@ export interface LineDrawingData {
459
462
  price1: number;
460
463
  time2: number;
461
464
  price2: number;
465
+ /** Omitted: #2962FF (color.blue; #2196F3 in a v4 script) */
462
466
  color?: string;
467
+ /** Omitted: 1. A width of 0 is kept (PineScript `width = 0`) */
463
468
  width?: number;
469
+ /** Omitted: 'solid' */
464
470
  style?: 'solid' | 'dashed' | 'dotted' | 'arrow_left' | 'arrow_right' | 'arrow_both';
465
471
  extend?: 'none' | 'left' | 'right' | 'both';
466
472
  /** PineScript force_overlay = true: the line of a non-overlay indicator is drawn on the price pane */
@@ -475,14 +481,22 @@ export interface BoxData {
475
481
  price1: number;
476
482
  time2: number;
477
483
  price2: number;
484
+ /** Omitted: #2962FF (color.blue; #2196F3 in a v4 script) */
478
485
  bgColor?: string;
486
+ /** Omitted: #2962FF (color.blue; #2196F3 in a v4 script) */
479
487
  borderColor?: string;
488
+ /** Omitted: 1. A width of 0 is no border (PineScript `border_width = 0`) */
480
489
  borderWidth?: number;
490
+ /** Omitted: 'solid' */
481
491
  borderStyle?: 'solid' | 'dashed' | 'dotted';
482
492
  text?: string;
493
+ /** Omitted: #FFFFFF in a v6 script, #363A45 in v5 (the result does not carry the version) */
483
494
  textColor?: string;
495
+ /** Omitted: 'auto' */
484
496
  textSize?: PineSize | number;
497
+ /** Omitted: 'center' */
485
498
  textHAlign?: 'left' | 'center' | 'right';
499
+ /** Omitted: 'center' */
486
500
  textVAlign?: 'top' | 'center' | 'bottom';
487
501
  textWrap?: 'none' | 'auto';
488
502
  fontFamily?: 'default' | 'monospace';
@@ -512,10 +526,12 @@ export interface PolylineData {
512
526
  curved?: boolean;
513
527
  /** The last point is connected to the first */
514
528
  closed?: boolean;
529
+ /** Omitted: #2962FF (color.blue) */
515
530
  lineColor?: string;
516
- /** Fill of the area inside the polyline */
531
+ /** Fill of the area inside the polyline. Omitted: no fill */
517
532
  fillColor?: string;
518
533
  lineStyle?: 'solid' | 'dotted' | 'dashed' | 'arrow_left' | 'arrow_right' | 'arrow_both';
534
+ /** Omitted: 1 */
519
535
  lineWidth?: number;
520
536
  /** PineScript force_overlay = true: the polyline of a non-overlay indicator is drawn on the price pane */
521
537
  forceOverlay?: boolean;
@@ -540,8 +556,11 @@ export interface TableCellData {
540
556
  row: number;
541
557
  column: number;
542
558
  text: string;
559
+ /** Omitted: no background */
543
560
  bgColor?: string;
561
+ /** Omitted: #363A45 (in v4, v5 and v6 scripts) */
544
562
  textColor?: string;
563
+ /** Omitted: 'auto' */
545
564
  textSize?: PineSize | number;
546
565
  /** Width in % of the chart width; 0 fits the text */
547
566
  width?: number;
@@ -575,10 +594,15 @@ export interface TableData {
575
594
  rows: number;
576
595
  cells: TableCellData[];
577
596
  merges?: TableMergeData[];
597
+ /** Omitted: no background */
578
598
  bgColor?: string;
599
+ /** Omitted: no frame */
579
600
  frameColor?: string;
601
+ /** Omitted: 0 */
580
602
  frameWidth?: number;
603
+ /** Omitted: no cell borders */
581
604
  borderColor?: string;
605
+ /** Omitted: 0 */
582
606
  borderWidth?: number;
583
607
  /** PineScript force_overlay = true: the table of a non-overlay indicator is drawn on the price pane */
584
608
  forceOverlay?: boolean;