oakscriptjs 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/array/index.d.ts +8 -2
- package/dist/cjs/array/index.d.ts.map +1 -1
- package/dist/cjs/array/index.js +2 -1
- package/dist/cjs/array/index.js.map +2 -2
- package/dist/cjs/box/index.js +6 -6
- package/dist/cjs/box/index.js.map +2 -2
- package/dist/cjs/callsite/index.js +1 -1
- package/dist/cjs/callsite/index.js.map +2 -2
- package/dist/cjs/drawing/registry.d.ts +15 -6
- package/dist/cjs/drawing/registry.d.ts.map +1 -1
- package/dist/cjs/drawing/registry.js +16 -2
- package/dist/cjs/drawing/registry.js.map +2 -2
- package/dist/cjs/index.d.ts +3 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +6 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/input.d.ts +9 -1
- package/dist/cjs/input.d.ts.map +1 -1
- package/dist/cjs/input.js +16 -0
- package/dist/cjs/input.js.map +2 -2
- package/dist/cjs/label/index.js +3 -3
- package/dist/cjs/label/index.js.map +2 -2
- package/dist/cjs/line/index.d.ts +10 -27
- package/dist/cjs/line/index.d.ts.map +1 -1
- package/dist/cjs/line/index.js +10 -27
- package/dist/cjs/line/index.js.map +2 -2
- package/dist/cjs/linefill/index.d.ts +3 -0
- package/dist/cjs/linefill/index.d.ts.map +1 -1
- package/dist/cjs/linefill/index.js +15 -1
- package/dist/cjs/linefill/index.js.map +3 -3
- package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +1 -1
- package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +2 -2
- package/dist/cjs/runtime/index.d.ts +1 -1
- package/dist/cjs/runtime/index.d.ts.map +1 -1
- package/dist/cjs/runtime/index.js +1 -0
- package/dist/cjs/runtime/index.js.map +2 -2
- package/dist/cjs/runtime/inputs.d.ts +9 -0
- package/dist/cjs/runtime/inputs.d.ts.map +1 -1
- package/dist/cjs/runtime/inputs.js +8 -0
- package/dist/cjs/runtime/inputs.js.map +2 -2
- package/dist/cjs/runtime/types.d.ts +1 -1
- package/dist/cjs/runtime/types.d.ts.map +1 -1
- package/dist/cjs/runtime/types.js.map +1 -1
- package/dist/cjs/script/index.d.ts +65 -12
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +168 -19
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/cjs/security/other.d.ts +92 -0
- package/dist/cjs/security/other.d.ts.map +1 -0
- package/dist/cjs/security/other.js +164 -0
- package/dist/cjs/security/other.js.map +7 -0
- package/dist/cjs/session/bars.d.ts +10 -1
- package/dist/cjs/session/bars.d.ts.map +1 -1
- package/dist/cjs/session/bars.js +16 -2
- package/dist/cjs/session/bars.js.map +2 -2
- package/dist/cjs/session/calendar.d.ts +4 -1
- package/dist/cjs/session/calendar.d.ts.map +1 -1
- package/dist/cjs/session/calendar.js +11 -7
- package/dist/cjs/session/calendar.js.map +2 -2
- package/dist/cjs/session/context.d.ts +2 -1
- package/dist/cjs/session/context.d.ts.map +1 -1
- package/dist/cjs/session/context.js +2 -1
- package/dist/cjs/session/context.js.map +2 -2
- package/dist/cjs/str/floatingdecimal.d.ts +31 -0
- package/dist/cjs/str/floatingdecimal.d.ts.map +1 -0
- package/dist/cjs/str/floatingdecimal.js +298 -0
- package/dist/cjs/str/floatingdecimal.js.map +7 -0
- package/dist/cjs/str/index.d.ts +4 -3
- package/dist/cjs/str/index.d.ts.map +1 -1
- package/dist/cjs/str/index.js +1 -1
- package/dist/cjs/str/index.js.map +2 -2
- package/dist/cjs/str/numberformat.d.ts +6 -4
- package/dist/cjs/str/numberformat.d.ts.map +1 -1
- package/dist/cjs/str/numberformat.js +3 -2
- package/dist/cjs/str/numberformat.js.map +2 -2
- package/dist/cjs/ta/index.d.ts +34 -17
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +132 -116
- package/dist/cjs/ta/index.js.map +2 -2
- package/dist/cjs/ta/limits.d.ts +11 -0
- package/dist/cjs/ta/limits.d.ts.map +1 -1
- package/dist/cjs/ta/limits.js +15 -1
- package/dist/cjs/ta/limits.js.map +2 -2
- package/dist/cjs/ta/running-sum.js +1 -1
- package/dist/cjs/ta/running-sum.js.map +2 -2
- package/dist/cjs/ta-series.d.ts +1 -1
- package/dist/cjs/ta-series.d.ts.map +1 -1
- package/dist/cjs/ta-series.js +1 -1
- package/dist/cjs/ta-series.js.map +2 -2
- package/dist/cjs/table/index.d.ts +3 -1
- package/dist/cjs/table/index.d.ts.map +1 -1
- package/dist/cjs/table/index.js +1 -0
- package/dist/cjs/table/index.js.map +3 -3
- package/dist/cjs/time/session.d.ts +9 -0
- package/dist/cjs/time/session.d.ts.map +1 -1
- package/dist/cjs/time/session.js +42 -14
- package/dist/cjs/time/session.js.map +3 -3
- package/dist/cjs/time/timezone.d.ts +6 -1
- package/dist/cjs/time/timezone.d.ts.map +1 -1
- package/dist/cjs/time/timezone.js +2 -2
- package/dist/cjs/time/timezone.js.map +2 -2
- package/dist/cjs/types/metadata.d.ts +1 -1
- package/dist/cjs/types/metadata.d.ts.map +1 -1
- package/dist/cjs/types/metadata.js.map +1 -1
- package/dist/esm/array/index.d.ts +8 -2
- package/dist/esm/array/index.d.ts.map +1 -1
- package/dist/esm/array/index.js +12 -3
- package/dist/esm/array/index.js.map +1 -1
- package/dist/esm/box/index.js +6 -6
- package/dist/esm/box/index.js.map +1 -1
- package/dist/esm/callsite/index.js +1 -1
- package/dist/esm/callsite/index.js.map +1 -1
- package/dist/esm/drawing/registry.d.ts +15 -6
- package/dist/esm/drawing/registry.d.ts.map +1 -1
- package/dist/esm/drawing/registry.js +30 -7
- package/dist/esm/drawing/registry.js.map +1 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input.d.ts +9 -1
- package/dist/esm/input.d.ts.map +1 -1
- package/dist/esm/input.js +16 -0
- package/dist/esm/input.js.map +1 -1
- package/dist/esm/label/index.js +3 -3
- package/dist/esm/label/index.js.map +1 -1
- package/dist/esm/line/index.d.ts +10 -27
- package/dist/esm/line/index.d.ts.map +1 -1
- package/dist/esm/line/index.js +20 -64
- package/dist/esm/line/index.js.map +1 -1
- package/dist/esm/linefill/index.d.ts +3 -0
- package/dist/esm/linefill/index.d.ts.map +1 -1
- package/dist/esm/linefill/index.js +20 -1
- package/dist/esm/linefill/index.js.map +1 -1
- package/dist/esm/runtime/adapters/SimpleInputAdapter.js +1 -1
- package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -1
- package/dist/esm/runtime/index.d.ts +1 -1
- package/dist/esm/runtime/index.d.ts.map +1 -1
- package/dist/esm/runtime/index.js +1 -1
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/inputs.d.ts +9 -0
- package/dist/esm/runtime/inputs.d.ts.map +1 -1
- package/dist/esm/runtime/inputs.js +15 -0
- package/dist/esm/runtime/inputs.js.map +1 -1
- package/dist/esm/runtime/types.d.ts +1 -1
- package/dist/esm/runtime/types.d.ts.map +1 -1
- package/dist/esm/script/index.d.ts +65 -12
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +217 -29
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/security/other.d.ts +92 -0
- package/dist/esm/security/other.d.ts.map +1 -0
- package/dist/esm/security/other.js +211 -0
- package/dist/esm/security/other.js.map +1 -0
- package/dist/esm/session/bars.d.ts +10 -1
- package/dist/esm/session/bars.d.ts.map +1 -1
- package/dist/esm/session/bars.js +26 -1
- package/dist/esm/session/bars.js.map +1 -1
- package/dist/esm/session/calendar.d.ts +4 -1
- package/dist/esm/session/calendar.d.ts.map +1 -1
- package/dist/esm/session/calendar.js +19 -7
- package/dist/esm/session/calendar.js.map +1 -1
- package/dist/esm/session/context.d.ts +2 -1
- package/dist/esm/session/context.d.ts.map +1 -1
- package/dist/esm/session/context.js +5 -3
- package/dist/esm/session/context.js.map +1 -1
- package/dist/esm/str/floatingdecimal.d.ts +31 -0
- package/dist/esm/str/floatingdecimal.d.ts.map +1 -0
- package/dist/esm/str/floatingdecimal.js +272 -0
- package/dist/esm/str/floatingdecimal.js.map +1 -0
- package/dist/esm/str/index.d.ts +4 -3
- package/dist/esm/str/index.d.ts.map +1 -1
- package/dist/esm/str/index.js +6 -5
- package/dist/esm/str/index.js.map +1 -1
- package/dist/esm/str/numberformat.d.ts +6 -4
- package/dist/esm/str/numberformat.d.ts.map +1 -1
- package/dist/esm/str/numberformat.js +9 -5
- package/dist/esm/str/numberformat.js.map +1 -1
- package/dist/esm/ta/index.d.ts +34 -17
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +155 -185
- package/dist/esm/ta/index.js.map +1 -1
- package/dist/esm/ta/limits.d.ts +11 -0
- package/dist/esm/ta/limits.d.ts.map +1 -1
- package/dist/esm/ta/limits.js +27 -2
- package/dist/esm/ta/limits.js.map +1 -1
- package/dist/esm/ta/running-sum.js +1 -1
- package/dist/esm/ta/running-sum.js.map +1 -1
- package/dist/esm/ta-series.d.ts +1 -1
- package/dist/esm/ta-series.d.ts.map +1 -1
- package/dist/esm/ta-series.js +2 -1
- package/dist/esm/ta-series.js.map +1 -1
- package/dist/esm/table/index.d.ts +3 -1
- package/dist/esm/table/index.d.ts.map +1 -1
- package/dist/esm/table/index.js +6 -1
- package/dist/esm/table/index.js.map +1 -1
- package/dist/esm/time/session.d.ts +9 -0
- package/dist/esm/time/session.d.ts.map +1 -1
- package/dist/esm/time/session.js +53 -15
- package/dist/esm/time/session.js.map +1 -1
- package/dist/esm/time/timezone.d.ts +6 -1
- package/dist/esm/time/timezone.d.ts.map +1 -1
- package/dist/esm/time/timezone.js +8 -2
- package/dist/esm/time/timezone.js.map +1 -1
- package/dist/esm/types/metadata.d.ts +1 -1
- package/dist/esm/types/metadata.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/array/index.ts +11 -3
- package/src/box/index.ts +6 -6
- package/src/callsite/index.ts +1 -1
- package/src/drawing/registry.ts +30 -7
- package/src/index.ts +11 -1
- package/src/input.ts +18 -1
- package/src/label/index.ts +3 -3
- package/src/line/index.ts +20 -68
- package/src/linefill/index.ts +20 -1
- package/src/runtime/adapters/SimpleInputAdapter.ts +1 -1
- package/src/runtime/index.ts +1 -0
- package/src/runtime/inputs.ts +16 -0
- package/src/runtime/types.ts +1 -1
- package/src/script/index.ts +292 -30
- package/src/security/other.ts +269 -0
- package/src/session/bars.ts +24 -1
- package/src/session/calendar.ts +23 -7
- package/src/session/context.ts +5 -3
- package/src/str/floatingdecimal.ts +268 -0
- package/src/str/index.ts +6 -5
- package/src/str/numberformat.ts +11 -6
- package/src/ta/index.ts +157 -183
- package/src/ta/limits.ts +28 -1
- package/src/ta/running-sum.ts +1 -1
- package/src/ta-series.ts +3 -2
- package/src/table/index.ts +4 -1
- package/src/time/session.ts +58 -16
- package/src/time/timezone.ts +9 -2
- package/src/types/metadata.ts +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PineScript `request.security(symbol, timeframe, expression, gaps, lookahead)` of another symbol: which bar of the
|
|
3
|
+
* other symbol each chart bar shows (#179). The bars of the other symbol are given by the caller, already on the
|
|
4
|
+
* requested timeframe; the expression is computed on them and its values are mapped to the chart bars with the index
|
|
5
|
+
* given here. The script API does this with the `bars` accessor of its chart context.
|
|
6
|
+
*
|
|
7
|
+
* PineScript rules (measured on stocks, crypto and an exchange whose trading day starts on the previous UTC day; the
|
|
8
|
+
* chart timeframe, D, W and M on intraday and daily charts; the four gaps / lookahead combinations):
|
|
9
|
+
* - lookahead off: the last bar of the other symbol whose close time is at or before the close time of the chart bar
|
|
10
|
+
* (a daily stock bar closes at the session end, a crypto daily bar at 00:00 UTC: a stock chart shows the crypto
|
|
11
|
+
* bar of the day before, a crypto chart the stock bar of the same day)
|
|
12
|
+
* - lookahead on, intraday chart or intraday request: the last bar of the other symbol that opened at or before the
|
|
13
|
+
* open of the chart bar
|
|
14
|
+
* - lookahead on, D / W / M chart and request: the last bar of the other symbol whose period starts at or before the trading day
|
|
15
|
+
* of the chart bar: the trading day of a D bar, the Monday of a W bar, the first day of the month of an M bar, each
|
|
16
|
+
* in the exchange time zone of its symbol (a week that opens on a Tuesday after a holiday still starts on Monday)
|
|
17
|
+
* - before the first bar of the other symbol: na; on chart bars where the other symbol has no bar (weekends,
|
|
18
|
+
* holidays, closed hours), gaps off repeats the last value
|
|
19
|
+
* - gaps on: a value only on the chart bar where the shown bar changes (and on the first chart bar), na on the others
|
|
20
|
+
* - the last bar while it is open (`lastBarConfirmed` false) with gaps off: the realtime update shows the bar given by
|
|
21
|
+
* lookahead on (the open bar of a higher timeframe), with lookahead off as well
|
|
22
|
+
*
|
|
23
|
+
* Close times, trading days and time zones come from the exchange calendars of the chart and of the other symbol
|
|
24
|
+
* (time zone and session, read by the session functions). Without them:
|
|
25
|
+
* - a symbol that trades every day (bars on Saturdays or Sundays; W bars at Monday 00:00 UTC; M bars on the first day
|
|
26
|
+
* at 00:00 UTC) is on the "24x7" UTC calendar
|
|
27
|
+
* - another symbol whose bars open where the chart calendar starts its periods is on the calendar of the chart
|
|
28
|
+
* - else the UTC rule: an intraday bar closes one bar interval after its open (or at the next bar), a D / W / M bar at
|
|
29
|
+
* the end of the last weekday (UTC) of its day / week / month; the trading day is the UTC date of the bar
|
|
30
|
+
* The fallback is exact between symbols of the same calendar and with 24x7 symbols; between a stock and a 24x7 symbol,
|
|
31
|
+
* or an exchange whose trading day starts on the previous UTC day, it needs the session of the stock.
|
|
32
|
+
*
|
|
33
|
+
* @module security/other
|
|
34
|
+
*/
|
|
35
|
+
import type { SessionSpec } from '../session/calendar.js';
|
|
36
|
+
/** Exchange calendar of a symbol: time zone and session (hours, corrections, holidays). */
|
|
37
|
+
export interface SymbolCalendar {
|
|
38
|
+
timezone?: string;
|
|
39
|
+
session?: SessionSpec | string;
|
|
40
|
+
}
|
|
41
|
+
/** Options of {@link securityOther}. */
|
|
42
|
+
export interface OtherSymbolOptions {
|
|
43
|
+
/** PineScript `barmerge.lookahead_on`; default false */
|
|
44
|
+
lookahead?: boolean;
|
|
45
|
+
/** PineScript `barmerge.gaps_on`; default false */
|
|
46
|
+
gaps?: boolean;
|
|
47
|
+
/** Calendar of the other symbol; see the module notes for the fallback */
|
|
48
|
+
other?: SymbolCalendar;
|
|
49
|
+
}
|
|
50
|
+
/** The chart: its timeframe, calendar, time unit and whether its last bar is closed. */
|
|
51
|
+
export interface OtherSymbolChart extends SymbolCalendar {
|
|
52
|
+
/** Chart timeframe ("60", "1D"...) */
|
|
53
|
+
timeframe: string;
|
|
54
|
+
/** Unit of the bar times: 's' (default) or 'ms' */
|
|
55
|
+
timeUnit?: 's' | 'ms';
|
|
56
|
+
/** false: the last chart bar is still open (realtime rule) */
|
|
57
|
+
lastBarConfirmed?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* PineScript `request.security` of another symbol: the index in `otherBars` of the bar shown on each chart bar, -1
|
|
61
|
+
* for na (#179). `otherBars` are the bars of the other symbol on `tf` ("" for the chart timeframe, or a higher
|
|
62
|
+
* or a lower one), with times in the unit of the chart bars. Rules in the module notes; the same rules hold for a
|
|
63
|
+
* lower timeframe (#181): lookahead off shows the last lower bar that closes by the close of the chart bar, lookahead
|
|
64
|
+
* on the last one that opened by its open. It also serves the chart symbol on a lower timeframe.
|
|
65
|
+
* @throws RangeError for a tick timeframe
|
|
66
|
+
*/
|
|
67
|
+
export declare function securityOther(chartBars: ReadonlyArray<{
|
|
68
|
+
time: number;
|
|
69
|
+
}>, otherBars: ReadonlyArray<{
|
|
70
|
+
time: number;
|
|
71
|
+
}>, tf: string, chart: OtherSymbolChart, options?: OtherSymbolOptions): number[];
|
|
72
|
+
/**
|
|
73
|
+
* PineScript `request.security_lower_tf` (#181): for each chart bar, the range `[from, to)` of the bars of
|
|
74
|
+
* `otherBars` (a lower timeframe, the chart symbol or another one) that it contains: the bars whose close time is
|
|
75
|
+
* after the open of the chart bar and at or before its close (a 13:00 hourly bar of a 24x7 symbol is in a 13:30 stock
|
|
76
|
+
* day, which closes at 20:00). An empty range for a chart bar without such bars.
|
|
77
|
+
*/
|
|
78
|
+
export declare function securityLowerTf(chartBars: ReadonlyArray<{
|
|
79
|
+
time: number;
|
|
80
|
+
}>, otherBars: ReadonlyArray<{
|
|
81
|
+
time: number;
|
|
82
|
+
}>, tf: string, chart: OtherSymbolChart, options?: Pick<OtherSymbolOptions, 'other'>): Array<[number, number]>;
|
|
83
|
+
/**
|
|
84
|
+
* {@link securityOther} with the values of an expression: `values` has one value per bar of the other symbol; the
|
|
85
|
+
* result has one value per chart bar, NaN for na.
|
|
86
|
+
*/
|
|
87
|
+
export declare function securityOtherValues(chartBars: ReadonlyArray<{
|
|
88
|
+
time: number;
|
|
89
|
+
}>, otherBars: ReadonlyArray<{
|
|
90
|
+
time: number;
|
|
91
|
+
}>, tf: string, values: ArrayLike<number>, chart: OtherSymbolChart, options?: OtherSymbolOptions): number[];
|
|
92
|
+
//# sourceMappingURL=other.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"other.d.ts","sourceRoot":"","sources":["../../../src/security/other.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1D,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;CAChC;AAED,wCAAwC;AACxC,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0EAA0E;IAC1E,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,wFAAwF;AACxF,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IACtB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA4HD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,SAAS,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,gBAAgB,EACvB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,EAAE,CA2BV;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,SAAS,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,gBAAgB,EACvB,OAAO,GAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAM,GAC9C,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASzB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,SAAS,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,EACzB,KAAK,EAAE,gBAAgB,EACvB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,EAAE,CAEV"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var other_exports = {};
|
|
30
|
+
__export(other_exports, {
|
|
31
|
+
securityLowerTf: () => securityLowerTf,
|
|
32
|
+
securityOther: () => securityOther,
|
|
33
|
+
securityOtherValues: () => securityOtherValues
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(other_exports);
|
|
36
|
+
var timeframe = __toESM(require("../timeframe/index.js"), 1);
|
|
37
|
+
var import_context = require("../session/context.js");
|
|
38
|
+
const DAY = 864e5;
|
|
39
|
+
const calendars = /* @__PURE__ */ new Map();
|
|
40
|
+
function calendarOf(zone, tf) {
|
|
41
|
+
if (!zone) return null;
|
|
42
|
+
const key = `${zone.timezone}|${typeof zone.session === "string" ? zone.session : JSON.stringify(zone.session)}|${tf}`;
|
|
43
|
+
let context = calendars.get(key);
|
|
44
|
+
if (context === void 0) {
|
|
45
|
+
context = { timeframe: tf, timezone: zone.timezone, session: zone.session, timeUnit: "ms" };
|
|
46
|
+
try {
|
|
47
|
+
(0, import_context.chartSessions)(context);
|
|
48
|
+
} catch {
|
|
49
|
+
context = null;
|
|
50
|
+
}
|
|
51
|
+
if (calendars.size > 64) calendars.clear();
|
|
52
|
+
calendars.set(key, context);
|
|
53
|
+
}
|
|
54
|
+
return context;
|
|
55
|
+
}
|
|
56
|
+
const UTC_24X7 = { timezone: "Etc/UTC", session: "24x7" };
|
|
57
|
+
function tradesEveryDay(times, tf) {
|
|
58
|
+
if (times.length === 0) return false;
|
|
59
|
+
const info = timeframe.info(tf);
|
|
60
|
+
if (info.isweekly) return times.every((t) => t % DAY === 0 && new Date(t).getUTCDay() === 1);
|
|
61
|
+
if (info.ismonthly) return times.every((t) => t % DAY === 0 && new Date(t).getUTCDate() === 1);
|
|
62
|
+
return times.some((t) => {
|
|
63
|
+
const wd = new Date(t).getUTCDay();
|
|
64
|
+
return wd === 0 || wd === 6;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function onCalendar(times, tf, zone) {
|
|
68
|
+
const calendar = calendarOf(zone, tf);
|
|
69
|
+
if (!calendar || times.length === 0) return false;
|
|
70
|
+
const last = times.slice(-50);
|
|
71
|
+
return last.filter((t) => (0, import_context.periodTime)(t, tf, calendar) === t).length >= 0.9 * last.length;
|
|
72
|
+
}
|
|
73
|
+
const utcDay = (t) => Math.floor(t / DAY) * DAY;
|
|
74
|
+
const weekStart = (day) => day - (new Date(day).getUTCDay() + 6) % 7 * DAY;
|
|
75
|
+
const monthStart = (day) => {
|
|
76
|
+
const d = new Date(day);
|
|
77
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
|
|
78
|
+
};
|
|
79
|
+
function afterLastWeekday(end) {
|
|
80
|
+
let day = end - DAY;
|
|
81
|
+
while (new Date(day).getUTCDay() % 6 === 0) day -= DAY;
|
|
82
|
+
return day + DAY;
|
|
83
|
+
}
|
|
84
|
+
function closeTimes(times, tf, zone) {
|
|
85
|
+
const calendar = calendarOf(zone, tf);
|
|
86
|
+
const info = timeframe.info(tf);
|
|
87
|
+
const len = timeframe.in_seconds(tf) * 1e3;
|
|
88
|
+
return times.map((t, i) => {
|
|
89
|
+
if (calendar) {
|
|
90
|
+
const c = (0, import_context.periodClose)(t, tf, calendar);
|
|
91
|
+
if (!Number.isNaN(c)) return c;
|
|
92
|
+
}
|
|
93
|
+
if (info.isintraday) return i + 1 < times.length ? Math.min(t + len, times[i + 1]) : t + len;
|
|
94
|
+
const day = utcDay(t);
|
|
95
|
+
if (info.isweekly) return afterLastWeekday(weekStart(day) + 7 * DAY * info.multiplier);
|
|
96
|
+
if (info.ismonthly) {
|
|
97
|
+
const d = new Date(day);
|
|
98
|
+
return afterLastWeekday(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + info.multiplier, 1));
|
|
99
|
+
}
|
|
100
|
+
return day + DAY * info.multiplier;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function tradingDays(times, zone) {
|
|
104
|
+
const calendar = calendarOf(zone, "1D");
|
|
105
|
+
return times.map((t) => {
|
|
106
|
+
const d = calendar ? (0, import_context.tradingDayTime)(t, calendar) : NaN;
|
|
107
|
+
return Number.isNaN(d) ? utcDay(t) : d;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function latestAtOrBefore(keys, at) {
|
|
111
|
+
let j = -1;
|
|
112
|
+
return at.map((x) => {
|
|
113
|
+
while (j + 1 < keys.length && keys[j + 1] <= x) j++;
|
|
114
|
+
return j;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const zoneOf = (c) => c?.timezone && c.session ? { timezone: c.timezone, session: c.session } : null;
|
|
118
|
+
function setup(ct, ot, tf, chart, options) {
|
|
119
|
+
const chartTf = timeframe.info(chart.timeframe).period;
|
|
120
|
+
const otherTf = tf.trim() === "" ? chartTf : timeframe.info(tf).period;
|
|
121
|
+
if (timeframe.info(otherTf).isticks) throw new RangeError(`request.security: tick timeframe "${tf}" is not supported.`);
|
|
122
|
+
const chartZone = zoneOf(chart) ?? (tradesEveryDay(ct, chartTf) ? UTC_24X7 : null);
|
|
123
|
+
const otherZone = zoneOf(options.other) ?? (tradesEveryDay(ot, otherTf) ? UTC_24X7 : chartZone && onCalendar(ot, otherTf, chartZone) ? chartZone : null);
|
|
124
|
+
return { chartTf, otherTf, chartZone, otherZone };
|
|
125
|
+
}
|
|
126
|
+
function securityOther(chartBars, otherBars, tf, chart, options = {}) {
|
|
127
|
+
const n = chartBars.length;
|
|
128
|
+
if (n === 0) return [];
|
|
129
|
+
const unit = chart.timeUnit === "ms" ? 1 : 1e3;
|
|
130
|
+
const ct = chartBars.map((b) => b.time * unit);
|
|
131
|
+
const ot = otherBars.map((b) => b.time * unit);
|
|
132
|
+
const { chartTf, otherTf, chartZone, otherZone } = setup(ct, ot, tf, chart, options);
|
|
133
|
+
if (ot.length === 0) return new Array(n).fill(-1);
|
|
134
|
+
const daily = timeframe.info(chartTf).isdwm && timeframe.info(otherTf).isdwm;
|
|
135
|
+
const realtime = chart.lastBarConfirmed === false && !options.gaps;
|
|
136
|
+
let on = [];
|
|
137
|
+
if (options.lookahead || realtime) {
|
|
138
|
+
if (daily) {
|
|
139
|
+
const info = timeframe.info(otherTf);
|
|
140
|
+
const starts = tradingDays(ot, otherZone).map((d) => info.isweekly ? weekStart(d) : info.ismonthly ? monthStart(d) : d);
|
|
141
|
+
on = latestAtOrBefore(starts, tradingDays(ct, chartZone));
|
|
142
|
+
} else {
|
|
143
|
+
on = latestAtOrBefore(ot, ct);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const index = options.lookahead ? on : latestAtOrBefore(closeTimes(ot, otherTf, otherZone), closeTimes(ct, chartTf, chartZone));
|
|
147
|
+
if (realtime) index[n - 1] = on[n - 1];
|
|
148
|
+
if (!options.gaps) return index;
|
|
149
|
+
return index.map((j, i) => i === 0 || j !== index[i - 1] ? j : -1);
|
|
150
|
+
}
|
|
151
|
+
function securityLowerTf(chartBars, otherBars, tf, chart, options = {}) {
|
|
152
|
+
const unit = chart.timeUnit === "ms" ? 1 : 1e3;
|
|
153
|
+
const ct = chartBars.map((b) => b.time * unit);
|
|
154
|
+
const ot = otherBars.map((b) => b.time * unit);
|
|
155
|
+
const { chartTf, otherTf, chartZone, otherZone } = setup(ct, ot, tf, chart, options);
|
|
156
|
+
const oc = closeTimes(ot, otherTf, otherZone);
|
|
157
|
+
const from = latestAtOrBefore(oc, ct);
|
|
158
|
+
const to = latestAtOrBefore(oc, closeTimes(ct, chartTf, chartZone));
|
|
159
|
+
return ct.map((_, i) => [from[i] + 1, Math.max(from[i] + 1, to[i] + 1)]);
|
|
160
|
+
}
|
|
161
|
+
function securityOtherValues(chartBars, otherBars, tf, values, chart, options = {}) {
|
|
162
|
+
return securityOther(chartBars, otherBars, tf, chart, options).map((j) => j < 0 ? NaN : values[j] ?? NaN);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=other.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/security/other.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * PineScript `request.security(symbol, timeframe, expression, gaps, lookahead)` of another symbol: which bar of the\n * other symbol each chart bar shows (#179). The bars of the other symbol are given by the caller, already on the\n * requested timeframe; the expression is computed on them and its values are mapped to the chart bars with the index\n * given here. The script API does this with the `bars` accessor of its chart context.\n *\n * PineScript rules (measured on stocks, crypto and an exchange whose trading day starts on the previous UTC day; the\n * chart timeframe, D, W and M on intraday and daily charts; the four gaps / lookahead combinations):\n * - lookahead off: the last bar of the other symbol whose close time is at or before the close time of the chart bar\n * (a daily stock bar closes at the session end, a crypto daily bar at 00:00 UTC: a stock chart shows the crypto\n * bar of the day before, a crypto chart the stock bar of the same day)\n * - lookahead on, intraday chart or intraday request: the last bar of the other symbol that opened at or before the\n * open of the chart bar\n * - lookahead on, D / W / M chart and request: the last bar of the other symbol whose period starts at or before the trading day\n * of the chart bar: the trading day of a D bar, the Monday of a W bar, the first day of the month of an M bar, each\n * in the exchange time zone of its symbol (a week that opens on a Tuesday after a holiday still starts on Monday)\n * - before the first bar of the other symbol: na; on chart bars where the other symbol has no bar (weekends,\n * holidays, closed hours), gaps off repeats the last value\n * - gaps on: a value only on the chart bar where the shown bar changes (and on the first chart bar), na on the others\n * - the last bar while it is open (`lastBarConfirmed` false) with gaps off: the realtime update shows the bar given by\n * lookahead on (the open bar of a higher timeframe), with lookahead off as well\n *\n * Close times, trading days and time zones come from the exchange calendars of the chart and of the other symbol\n * (time zone and session, read by the session functions). Without them:\n * - a symbol that trades every day (bars on Saturdays or Sundays; W bars at Monday 00:00 UTC; M bars on the first day\n * at 00:00 UTC) is on the \"24x7\" UTC calendar\n * - another symbol whose bars open where the chart calendar starts its periods is on the calendar of the chart\n * - else the UTC rule: an intraday bar closes one bar interval after its open (or at the next bar), a D / W / M bar at\n * the end of the last weekday (UTC) of its day / week / month; the trading day is the UTC date of the bar\n * The fallback is exact between symbols of the same calendar and with 24x7 symbols; between a stock and a 24x7 symbol,\n * or an exchange whose trading day starts on the previous UTC day, it needs the session of the stock.\n *\n * @module security/other\n */\n\nimport * as timeframe from '../timeframe/index.js';\nimport { chartSessions, periodClose, periodTime, tradingDayTime, type SessionContext } from '../session/context.js';\nimport type { SessionSpec } from '../session/calendar.js';\n\nconst DAY = 86_400_000;\n\n/** Exchange calendar of a symbol: time zone and session (hours, corrections, holidays). */\nexport interface SymbolCalendar {\n timezone?: string;\n session?: SessionSpec | string;\n}\n\n/** Options of {@link securityOther}. */\nexport interface OtherSymbolOptions {\n /** PineScript `barmerge.lookahead_on`; default false */\n lookahead?: boolean;\n /** PineScript `barmerge.gaps_on`; default false */\n gaps?: boolean;\n /** Calendar of the other symbol; see the module notes for the fallback */\n other?: SymbolCalendar;\n}\n\n/** The chart: its timeframe, calendar, time unit and whether its last bar is closed. */\nexport interface OtherSymbolChart extends SymbolCalendar {\n /** Chart timeframe (\"60\", \"1D\"...) */\n timeframe: string;\n /** Unit of the bar times: 's' (default) or 'ms' */\n timeUnit?: 's' | 'ms';\n /** false: the last chart bar is still open (realtime rule) */\n lastBarConfirmed?: boolean;\n}\n\ninterface Zone {\n timezone: string;\n session: SessionSpec | string;\n}\n\nconst calendars = new Map<string, SessionContext | null>();\n\n/** The session context of a zone and a timeframe (bar times in ms); null when the session cannot be read. */\nfunction calendarOf(zone: Zone | null, tf: string): SessionContext | null {\n if (!zone) return null;\n const key = `${zone.timezone}|${typeof zone.session === 'string' ? zone.session : JSON.stringify(zone.session)}|${tf}`;\n let context = calendars.get(key);\n if (context === undefined) {\n context = { timeframe: tf, timezone: zone.timezone, session: zone.session, timeUnit: 'ms' };\n try {\n chartSessions(context);\n } catch {\n context = null;\n }\n if (calendars.size > 64) calendars.clear();\n calendars.set(key, context);\n }\n return context;\n}\n\nconst UTC_24X7: Zone = { timezone: 'Etc/UTC', session: '24x7' };\n\n/** True when bars of timeframe `tf` opening at `times` (ms) are those of a symbol that trades every day in UTC. */\nfunction tradesEveryDay(times: number[], tf: string): boolean {\n if (times.length === 0) return false;\n const info = timeframe.info(tf);\n if (info.isweekly) return times.every((t) => t % DAY === 0 && new Date(t).getUTCDay() === 1);\n if (info.ismonthly) return times.every((t) => t % DAY === 0 && new Date(t).getUTCDate() === 1);\n return times.some((t) => {\n const wd = new Date(t).getUTCDay();\n return wd === 0 || wd === 6;\n });\n}\n\n/** True when most of the last bars open at the start of a period of `tf` on the calendar `zone`. */\nfunction onCalendar(times: number[], tf: string, zone: Zone | null): boolean {\n const calendar = calendarOf(zone, tf);\n if (!calendar || times.length === 0) return false;\n const last = times.slice(-50);\n return last.filter((t) => periodTime(t, tf, calendar) === t).length >= 0.9 * last.length;\n}\n\nconst utcDay = (t: number): number => Math.floor(t / DAY) * DAY;\n/** Monday 00:00 UTC of the week of the day `day` (00:00 UTC, ms). */\nconst weekStart = (day: number): number => day - ((new Date(day).getUTCDay() + 6) % 7) * DAY;\nconst monthStart = (day: number): number => {\n const d = new Date(day);\n return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);\n};\n\n/** 00:00 UTC after the last weekday before `end` (00:00 UTC, ms): the end of a period of a Monday-to-Friday symbol. */\nfunction afterLastWeekday(end: number): number {\n let day = end - DAY;\n while (new Date(day).getUTCDay() % 6 === 0) day -= DAY;\n return day + DAY;\n}\n\n/** Close time (ms) of each bar of timeframe `tf` opening at `times` (ms). */\nfunction closeTimes(times: number[], tf: string, zone: Zone | null): number[] {\n const calendar = calendarOf(zone, tf);\n const info = timeframe.info(tf);\n const len = timeframe.in_seconds(tf) * 1000;\n return times.map((t, i) => {\n if (calendar) {\n const c = periodClose(t, tf, calendar);\n if (!Number.isNaN(c)) return c;\n }\n if (info.isintraday) return i + 1 < times.length ? Math.min(t + len, times[i + 1]!) : t + len;\n const day = utcDay(t);\n if (info.isweekly) return afterLastWeekday(weekStart(day) + 7 * DAY * info.multiplier);\n if (info.ismonthly) {\n const d = new Date(day);\n return afterLastWeekday(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + info.multiplier, 1));\n }\n return day + DAY * info.multiplier;\n });\n}\n\n/** Trading day (00:00 UTC, ms) of each bar opening at `times` (ms): its date in the exchange time zone. */\nfunction tradingDays(times: number[], zone: Zone | null): number[] {\n const calendar = calendarOf(zone, '1D');\n return times.map((t) => {\n const d = calendar ? tradingDayTime(t, calendar) : NaN;\n return Number.isNaN(d) ? utcDay(t) : d;\n });\n}\n\n/** For each element of `at` (non-decreasing), the index of the last element of `keys` (non-decreasing) <= it; -1: none. */\nfunction latestAtOrBefore(keys: number[], at: number[]): number[] {\n let j = -1;\n return at.map((x) => {\n while (j + 1 < keys.length && keys[j + 1]! <= x) j++;\n return j;\n });\n}\n\nconst zoneOf = (c: SymbolCalendar | undefined): Zone | null =>\n c?.timezone && c.session ? { timezone: c.timezone, session: c.session } : null;\n\n/** Timeframes and exchange calendars of a merge: given, 24x7, the chart's, else the UTC rule. */\nfunction setup(\n ct: number[],\n ot: number[],\n tf: string,\n chart: OtherSymbolChart,\n options: OtherSymbolOptions\n): { chartTf: string; otherTf: string; chartZone: Zone | null; otherZone: Zone | null } {\n const chartTf = timeframe.info(chart.timeframe).period;\n const otherTf = tf.trim() === '' ? chartTf : timeframe.info(tf).period;\n if (timeframe.info(otherTf).isticks) throw new RangeError(`request.security: tick timeframe \"${tf}\" is not supported.`);\n const chartZone = zoneOf(chart) ?? (tradesEveryDay(ct, chartTf) ? UTC_24X7 : null);\n const otherZone =\n zoneOf(options.other) ??\n (tradesEveryDay(ot, otherTf) ? UTC_24X7 : chartZone && onCalendar(ot, otherTf, chartZone) ? chartZone : null);\n return { chartTf, otherTf, chartZone, otherZone };\n}\n\n/**\n * PineScript `request.security` of another symbol: the index in `otherBars` of the bar shown on each chart bar, -1\n * for na (#179). `otherBars` are the bars of the other symbol on `tf` (\"\" for the chart timeframe, or a higher\n * or a lower one), with times in the unit of the chart bars. Rules in the module notes; the same rules hold for a\n * lower timeframe (#181): lookahead off shows the last lower bar that closes by the close of the chart bar, lookahead\n * on the last one that opened by its open. It also serves the chart symbol on a lower timeframe.\n * @throws RangeError for a tick timeframe\n */\nexport function securityOther(\n chartBars: ReadonlyArray<{ time: number }>,\n otherBars: ReadonlyArray<{ time: number }>,\n tf: string,\n chart: OtherSymbolChart,\n options: OtherSymbolOptions = {}\n): number[] {\n const n = chartBars.length;\n if (n === 0) return [];\n const unit = chart.timeUnit === 'ms' ? 1 : 1000;\n const ct = chartBars.map((b) => b.time * unit);\n const ot = otherBars.map((b) => b.time * unit);\n const { chartTf, otherTf, chartZone, otherZone } = setup(ct, ot, tf, chart, options);\n if (ot.length === 0) return new Array<number>(n).fill(-1);\n\n // by trading day when both timeframes are D / W / M; by open time with an intraday side (#181)\n const daily = timeframe.info(chartTf).isdwm && timeframe.info(otherTf).isdwm;\n const realtime = chart.lastBarConfirmed === false && !options.gaps;\n let on: number[] = [];\n if (options.lookahead || realtime) {\n if (daily) {\n const info = timeframe.info(otherTf);\n const starts = tradingDays(ot, otherZone).map((d) => (info.isweekly ? weekStart(d) : info.ismonthly ? monthStart(d) : d));\n on = latestAtOrBefore(starts, tradingDays(ct, chartZone));\n } else {\n on = latestAtOrBefore(ot, ct);\n }\n }\n const index = options.lookahead ? on : latestAtOrBefore(closeTimes(ot, otherTf, otherZone), closeTimes(ct, chartTf, chartZone));\n // realtime updates of the open last bar: lookahead off shows the bar of lookahead on\n if (realtime) index[n - 1] = on[n - 1]!;\n if (!options.gaps) return index;\n return index.map((j, i) => (i === 0 || j !== index[i - 1] ? j : -1));\n}\n\n/**\n * PineScript `request.security_lower_tf` (#181): for each chart bar, the range `[from, to)` of the bars of\n * `otherBars` (a lower timeframe, the chart symbol or another one) that it contains: the bars whose close time is\n * after the open of the chart bar and at or before its close (a 13:00 hourly bar of a 24x7 symbol is in a 13:30 stock\n * day, which closes at 20:00). An empty range for a chart bar without such bars.\n */\nexport function securityLowerTf(\n chartBars: ReadonlyArray<{ time: number }>,\n otherBars: ReadonlyArray<{ time: number }>,\n tf: string,\n chart: OtherSymbolChart,\n options: Pick<OtherSymbolOptions, 'other'> = {}\n): Array<[number, number]> {\n const unit = chart.timeUnit === 'ms' ? 1 : 1000;\n const ct = chartBars.map((b) => b.time * unit);\n const ot = otherBars.map((b) => b.time * unit);\n const { chartTf, otherTf, chartZone, otherZone } = setup(ct, ot, tf, chart, options);\n const oc = closeTimes(ot, otherTf, otherZone);\n const from = latestAtOrBefore(oc, ct);\n const to = latestAtOrBefore(oc, closeTimes(ct, chartTf, chartZone));\n return ct.map((_, i) => [from[i]! + 1, Math.max(from[i]! + 1, to[i]! + 1)]);\n}\n\n/**\n * {@link securityOther} with the values of an expression: `values` has one value per bar of the other symbol; the\n * result has one value per chart bar, NaN for na.\n */\nexport function securityOtherValues(\n chartBars: ReadonlyArray<{ time: number }>,\n otherBars: ReadonlyArray<{ time: number }>,\n tf: string,\n values: ArrayLike<number>,\n chart: OtherSymbolChart,\n options: OtherSymbolOptions = {}\n): number[] {\n return securityOther(chartBars, otherBars, tf, chart, options).map((j) => (j < 0 ? NaN : (values[j] ?? NaN)));\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -38,7 +38,8 @@ export declare class SessionBars {
|
|
|
38
38
|
private dayEnd;
|
|
39
39
|
/**
|
|
40
40
|
* PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. An intraday bar that
|
|
41
|
-
* opens after an early close has no day: `time("D")`
|
|
41
|
+
* opens after an early close has no day and no intraday period: `time("D")`, `time("240")` and `time("60")` are
|
|
42
|
+
* NaN on it (measured; `time("W")` keeps its value).
|
|
42
43
|
*/
|
|
43
44
|
timeOf(time: number, timeframe: string): number;
|
|
44
45
|
/** PineScript `time_close(tf)` for a bar that opens at `time`. */
|
|
@@ -70,6 +71,14 @@ export declare class SessionBars {
|
|
|
70
71
|
end: number;
|
|
71
72
|
} | null;
|
|
72
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Periods of the chart bars that open after an early close, for `request.security` (#173): such a bar has no period
|
|
76
|
+
* (`time("D")` and `time("240")` are na on it), but PineScript resamples it into the D / W / M bar of the bar before
|
|
77
|
+
* it, and into an intraday bar of its own (opening at the bar's time). The bar before it still completes its period
|
|
78
|
+
* (its day period is cut there). `intradayMs` is the duration of an intraday timeframe, null for D / W / M.
|
|
79
|
+
* Changes `starts` and `dayPeriods` in place.
|
|
80
|
+
*/
|
|
81
|
+
export declare function strayPeriods(starts: number[], dayPeriods: number[], times: number[], bars: SessionBars, intradayMs: number | null): void;
|
|
73
82
|
/** PineScript `session.*` flags of each bar. */
|
|
74
83
|
export interface SessionFlags {
|
|
75
84
|
isfirstbar: boolean[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bars.d.ts","sourceRoot":"","sources":["../../../src/session/bars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,eAAe,EAMf,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AAiBvB,+DAA+D;AAC/D,qBAAa,WAAW;IAMpB,QAAQ,CAAC,QAAQ,EAAE,eAAe;IALpC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;gBAG9C,QAAQ,EAAE,eAAe,EAClC,cAAc,EAAE,MAAM;IAKxB,iDAAiD;IACjD,OAAO,CAAC,aAAa;IAYrB;;;OAGG;IACH,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;IAKd
|
|
1
|
+
{"version":3,"file":"bars.d.ts","sourceRoot":"","sources":["../../../src/session/bars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,eAAe,EAMf,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AAiBvB,+DAA+D;AAC/D,qBAAa,WAAW;IAMpB,QAAQ,CAAC,QAAQ,EAAE,eAAe;IALpC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;gBAG9C,QAAQ,EAAE,eAAe,EAClC,cAAc,EAAE,MAAM;IAKxB,iDAAiD;IACjD,OAAO,CAAC,aAAa;IAYrB;;;OAGG;IACH,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;IAKd;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAmB/C,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAwBhD,0FAA0F;IAC1F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAWxC;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAclD,kEAAkE;IAClE,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKpC;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAmBjC,wGAAwG;IACxG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI5B,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B,mEAAmE;IACnE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAI9E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAUxI;AAED,gDAAgD;AAChD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,SAAS,EAAE,OAAO,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,YAAY,EAAE,OAAO,EAAE,CAAC;IACxB,kBAAkB,EAAE,OAAO,EAAE,CAAC;IAC9B,iBAAiB,EAAE,OAAO,EAAE,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,YAAY,CA6CnG"}
|
package/dist/cjs/session/bars.js
CHANGED
|
@@ -19,7 +19,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var bars_exports = {};
|
|
20
20
|
__export(bars_exports, {
|
|
21
21
|
SessionBars: () => SessionBars,
|
|
22
|
-
sessionFlags: () => sessionFlags
|
|
22
|
+
sessionFlags: () => sessionFlags,
|
|
23
|
+
strayPeriods: () => strayPeriods
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(bars_exports);
|
|
25
26
|
var import_timeframe = require("../timeframe/index.js");
|
|
@@ -91,7 +92,8 @@ class SessionBars {
|
|
|
91
92
|
}
|
|
92
93
|
/**
|
|
93
94
|
* PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. An intraday bar that
|
|
94
|
-
* opens after an early close has no day: `time("D")`
|
|
95
|
+
* opens after an early close has no day and no intraday period: `time("D")`, `time("240")` and `time("60")` are
|
|
96
|
+
* NaN on it (measured; `time("W")` keeps its value).
|
|
95
97
|
*/
|
|
96
98
|
timeOf(time, timeframe) {
|
|
97
99
|
const tf = (0, import_timeframe.info)(timeframe);
|
|
@@ -99,6 +101,7 @@ class SessionBars {
|
|
|
99
101
|
if (!at) return NaN;
|
|
100
102
|
if (tf.isintraday) {
|
|
101
103
|
if (this.chart.isdwm) return time;
|
|
104
|
+
if (this.stray(time)) return NaN;
|
|
102
105
|
const [start] = this.calendar.periods(at.date)[at.index];
|
|
103
106
|
const ms = (0, import_timeframe.in_seconds)(tf.period) * 1e3;
|
|
104
107
|
return start + Math.floor((time - start) / ms) * ms;
|
|
@@ -117,6 +120,7 @@ class SessionBars {
|
|
|
117
120
|
if (tf.isintraday) {
|
|
118
121
|
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
119
122
|
if (this.chart.isdwm) return end;
|
|
123
|
+
if (this.stray(time)) return NaN;
|
|
120
124
|
return Math.min(this.timeOf(time, timeframe) + (0, import_timeframe.in_seconds)(tf.period) * 1e3, end);
|
|
121
125
|
}
|
|
122
126
|
const { unit, n } = unitOf(tf);
|
|
@@ -201,6 +205,16 @@ class SessionBars {
|
|
|
201
205
|
return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
|
|
202
206
|
}
|
|
203
207
|
}
|
|
208
|
+
function strayPeriods(starts, dayPeriods, times, bars, intradayMs) {
|
|
209
|
+
for (let i = 1; i < starts.length; i++) {
|
|
210
|
+
if (!bars.stray(times[i])) continue;
|
|
211
|
+
if (Number.isNaN(starts[i])) {
|
|
212
|
+
const run = Number.isNaN(dayPeriods[i - 1]) && times[i] < starts[i - 1] + (intradayMs ?? 0);
|
|
213
|
+
starts[i] = intradayMs === null || run ? starts[i - 1] : times[i];
|
|
214
|
+
}
|
|
215
|
+
dayPeriods[i] = NaN;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
204
218
|
function sessionFlags(times, bars, regular) {
|
|
205
219
|
const n = times.length;
|
|
206
220
|
const flag = () => new Array(n).fill(false);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/session/bars.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * PineScript values that depend on the chart timeframe and the symbol session (issue #100):\n * `time(tf)`, `time_close(tf)`, `timeframe.change(tf)`, `time_tradingday`, `session.*`.\n * PineScript rules:\n *\n * - intraday periods are aligned on the start of the session period of the trading day: 240 minutes from\n * 09:30 gives 09:30, 13:30; `time(tf)` is the start of the period that contains the bar open\n * - \"D\" is the session start of the trading day; \"W\" / \"M\" the session start of the first trading day\n * of the week (Monday to Sunday) / month\n * - intraday closes are cut at the end of the session period; the \"D\" close is the session end\n * - on intraday charts the \"W\" / \"M\" (and \"nD\") close is the session start of the next period's first\n * trading day; on D / W / M charts it is the session end of the last trading day of the week / month\n * - on D / W / M charts, intraday timeframes give the chart bar's time, and the end of the session\n * period that contains the bar open as close\n * - `time_tradingday` is 00:00 UTC of the trading day (on W / M charts, of the last trading day)\n *\n * Multipliers above one day (issue #100 follow-up): periods restart each\n * calendar year. \"nD\" groups n trading days from the first trading day of the year; \"nW\" groups n weeks from\n * the first week whose Monday is in the year; \"nM\" groups n months from January. The last group of a year\n * can be shorter.\n */\n\nimport { info, in_seconds, type TimeframeInfo } from '../timeframe/index.js';\nimport {\n TradingCalendar,\n addDays,\n dateUtcMs,\n monthEnd,\n monthStart,\n weekStart,\n type DateNum,\n} from './calendar.js';\n\ntype Unit = 'D' | 'W' | 'M';\n\nfunction unitOf(tf: TimeframeInfo): { unit: Unit; n: number } {\n return { unit: tf.isdaily ? 'D' : tf.isweekly ? 'W' : 'M', n: tf.multiplier };\n}\n\nconst yearOf = (date: DateNum): number => Math.floor(date / 10000);\n\n/** Monday of the first week of `year` (the first Monday on or after 1 January). */\nconst firstMonday = (year: number): DateNum => {\n const jan1 = year * 10000 + 101;\n const monday = weekStart(jan1);\n return monday === jan1 ? jan1 : addDays(monday, 7);\n};\n\n/** Values of the bars of one chart, for a trading calendar. */\nexport class SessionBars {\n readonly chart: TimeframeInfo;\n\n private readonly yearDays = new Map<number, DateNum[]>();\n\n constructor(\n readonly calendar: TradingCalendar,\n chartTimeframe: string\n ) {\n this.chart = info(chartTimeframe);\n }\n\n /** Trading days of a calendar year, in order. */\n private tradingDaysOf(year: number): DateNum[] {\n let days = this.yearDays.get(year);\n if (!days) {\n days = [];\n for (let date = year * 10000 + 101; yearOf(date) === year; date = addDays(date, 1)) {\n if (this.calendar.isTradingDay(date)) days.push(date);\n }\n this.yearDays.set(year, days);\n }\n return days;\n }\n\n /**\n * Dates [from, to] of the `n`-`unit` period that contains `date` (for \"D\": its first and last trading days).\n * Periods restart each calendar year.\n */\n private periodRange(date: DateNum, unit: Unit, n: number): [DateNum, DateNum] {\n if (unit === 'D') {\n if (n === 1) return [date, date];\n const days = this.tradingDaysOf(yearOf(date));\n let k = days.findIndex((d) => d >= date);\n if (k === -1) return this.periodRange(yearOf(date) * 10000 + 10000 + 101, unit, n);\n k -= k % n;\n return [days[k]!, days[Math.min(k + n, days.length) - 1]!];\n }\n if (unit === 'W') {\n const monday = weekStart(date);\n const year = yearOf(monday);\n const first = firstMonday(year);\n const next = firstMonday(year + 1);\n const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 86_400_000));\n const from = addDays(first, (k - (k % n)) * 7);\n const to = addDays(from, n * 7 - 1);\n return [from, to < next ? to : addDays(next, -1)];\n }\n const year = yearOf(date);\n const month = Math.floor(date / 100) % 100;\n const firstMonth = month - ((month - 1) % n);\n const lastMonth = Math.min(firstMonth + n - 1, 12);\n return [monthStart(year * 10000 + firstMonth * 100 + 1), monthEnd(year * 10000 + lastMonth * 100 + 1)];\n }\n\n private dayStart(date: DateNum): number {\n return this.calendar.periods(date)[0]![0];\n }\n\n private dayEnd(date: DateNum): number {\n const p = this.calendar.periods(date);\n return p[p.length - 1]![1];\n }\n\n /**\n * PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. An intraday bar that\n * opens after an early close has no day: `time(\"D\")` is NaN on it (measured; `time(\"W\")` keeps its value).\n */\n timeOf(time: number, timeframe: string): number {\n const tf = info(timeframe);\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (tf.isintraday) {\n if (this.chart.isdwm) return time;\n const [start] = this.calendar.periods(at.date)[at.index]!;\n const ms = in_seconds(tf.period) * 1000;\n return start + Math.floor((time - start) / ms) * ms;\n }\n const { unit, n } = unitOf(tf);\n if (unit === 'D' && n === 1 && this.stray(time)) return NaN;\n const [from, to] = this.periodRange(at.date, unit, n);\n const first = this.calendar.firstTradingDay(from, to);\n return first === null ? NaN : this.dayStart(first);\n }\n\n /** PineScript `time_close(tf)` for a bar that opens at `time`. */\n closeOf(time: number, timeframe: string): number {\n const tf = info(timeframe);\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (tf.isintraday) {\n const [, end] = this.calendar.periods(at.date)[at.index]!;\n // on D / W / M charts: the end of the session period that contains the bar open\n if (this.chart.isdwm) return end;\n return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);\n }\n const { unit, n } = unitOf(tf);\n if (unit === 'D' && n === 1 && this.stray(time)) return NaN;\n const [from, to] = this.periodRange(at.date, unit, n);\n // intraday charts: the start of the next period, except \"1D\" (the session end)\n if (this.chart.isintraday && (unit !== 'D' || n > 1)) {\n const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);\n const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));\n return first === null ? NaN : this.dayStart(first);\n }\n const last = this.calendar.lastTradingDay(from, to);\n return last === null ? NaN : this.dayEnd(last);\n }\n\n /** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */\n tradingDay(time: number): DateNum | null {\n const at = this.calendar.locate(time);\n if (!at || this.stray(time)) return null;\n if (this.chart.isdwm) {\n const { unit, n } = unitOf(this.chart);\n const [from, to] = this.periodRange(at.date, unit, n);\n return this.calendar.lastTradingDay(from, to);\n }\n return at.date;\n }\n\n /**\n * End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,\n * or the session end of the last trading day of the period. Used to know whether the last loaded\n * bar completes a higher-timeframe period (request.security).\n */\n periodEnd(time: number, timeframe: string): number {\n const tf = info(timeframe);\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (tf.isintraday) {\n const [, end] = this.calendar.periods(at.date)[at.index]!;\n return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);\n }\n const { unit, n } = unitOf(tf);\n const [from, to] = this.periodRange(at.date, unit, n);\n const last = this.calendar.lastTradingDay(from, to);\n return last === null ? NaN : this.dayEnd(last);\n }\n\n /** PineScript `time_tradingday`: 00:00 UTC of the trading day. */\n tradingDayTime(time: number): number {\n const day = this.tradingDay(time);\n return day === null ? NaN : dateUtcMs(day);\n }\n\n /**\n * Open time of the bar after the bar that opens at `time`, on the trading calendar: the next bar of the session\n * period, else the start of the next period or trading day; on D / W / M charts the session start of the first\n * trading day of the next chart period. NaN when none is found within 400 days.\n */\n nextBarTime(time: number): number {\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (!this.chart.isdwm) {\n const periods = this.calendar.periods(at.date);\n const [start, end] = periods[at.index]!;\n const ms = in_seconds(this.chart.period) * 1000;\n const next = start + (Math.floor((time - start) / ms) + 1) * ms;\n if (at.inside && next < end) return next;\n if (at.index + 1 < periods.length) return periods[at.index + 1]![0];\n const day = this.calendar.firstTradingDay(addDays(at.date, 1), addDays(at.date, 400));\n return day === null ? NaN : this.dayStart(day);\n }\n const { unit, n } = unitOf(this.chart);\n const [, to] = this.periodRange(at.date, unit, n);\n const day = this.calendar.firstTradingDay(addDays(to, 1), addDays(to, 400));\n return day === null ? NaN : this.dayStart(day);\n }\n\n /** An intraday bar that opens after an early close of its day (see TradingCalendar.afterEarlyClose). */\n stray(time: number): boolean {\n return !this.chart.isdwm && this.calendar.afterEarlyClose(time);\n }\n\n /** True when the bar at `time` is inside the session. */\n inside(time: number): boolean {\n return this.calendar.locate(time)?.inside ?? false;\n }\n\n /** Session start and end of the trading day of `time`, or null. */\n dayBounds(time: number): { date: DateNum; start: number; end: number } | null {\n const at = this.calendar.locate(time);\n return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;\n }\n}\n\n/** PineScript `session.*` flags of each bar. */\nexport interface SessionFlags {\n isfirstbar: boolean[];\n islastbar: boolean[];\n ismarket: boolean[];\n ispremarket: boolean[];\n ispostmarket: boolean[];\n isfirstbar_regular: boolean[];\n islastbar_regular: boolean[];\n}\n\n/**\n * `session.*` flags for bars that open at `times` (in order). `regular` gives the regular trading\n * hours when the bars include extended hours. PineScript rules: flags use the bar open\n * time; first and last bars are per session period (a trading day can have two periods, e.g. after a\n * futures holiday); pre / post market compare with the regular hours of the same trading day; on\n * D / W / M charts every bar is its own session (first, last, market, first and last regular).\n * The first loaded bar is a first bar only when no earlier bar of its period can exist (it opens less than one chart\n * period after the period start). A bar that opens after an early close is in the market hours (the usual hours of\n * its day) but is no last bar.\n */\nexport function sessionFlags(times: number[], bars: SessionBars, regular: SessionBars): SessionFlags {\n const n = times.length;\n const flag = () => new Array<boolean>(n).fill(false);\n const out: SessionFlags = {\n isfirstbar: flag(), islastbar: flag(), ismarket: flag(), ispremarket: flag(), ispostmarket: flag(),\n isfirstbar_regular: flag(), islastbar_regular: flag(),\n };\n const chart = bars.chart;\n let previousPeriod = '';\n let previousRegular = '';\n for (let i = 0; i < n; i++) {\n const t = times[i]!;\n if (chart.isdwm) {\n for (const k of ['isfirstbar', 'islastbar', 'ismarket', 'isfirstbar_regular', 'islastbar_regular'] as const) out[k][i] = true;\n continue;\n }\n const at = bars.calendar.locate(t);\n if (!at) {\n previousPeriod = previousRegular = '';\n continue;\n }\n const close = bars.closeOf(t, chart.period);\n const [, end] = bars.calendar.periods(at.date)[at.index]!;\n const period = `${at.date}/${at.index}`;\n const [start] = bars.calendar.periods(at.date)[at.index]!;\n const barMs = in_seconds(chart.period) * 1000;\n // the first loaded bar: a first bar only when no earlier bar of the period can exist\n out.isfirstbar[i] = i === 0 ? t - start < barMs : period !== previousPeriod;\n const stray = bars.stray(t);\n out.islastbar[i] = !stray && close >= end;\n const regularPeriods = regular.calendar.periods(at.date);\n const r = regularPeriods.findIndex(([s, e]) => s <= t && t < e);\n const market = r !== -1;\n out.ismarket[i] = market || regular.stray(t);\n if (!market && regularPeriods.length) {\n out.ispremarket[i] = t < regularPeriods[0]![0];\n out.ispostmarket[i] = t >= regularPeriods[regularPeriods.length - 1]![1];\n }\n const regularPeriod = market ? `${at.date}/${r}` : '';\n out.isfirstbar_regular[i] = market && (i === 0 ? t - regularPeriods[r]![0] < barMs : regularPeriod !== previousRegular);\n out.islastbar_regular[i] = market && close >= regularPeriods[r]![1];\n previousPeriod = period;\n previousRegular = regularPeriod;\n }\n return out;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,uBAAqD;AACrD,sBAQO;AAIP,SAAS,OAAO,IAA8C;AAC5D,SAAO,EAAE,MAAM,GAAG,UAAU,MAAM,GAAG,WAAW,MAAM,KAAK,GAAG,GAAG,WAAW;AAC9E;AAEA,MAAM,SAAS,CAAC,SAA0B,KAAK,MAAM,OAAO,GAAK;AAGjE,MAAM,cAAc,CAAC,SAA0B;AAC7C,QAAM,OAAO,OAAO,MAAQ;AAC5B,QAAM,aAAS,2BAAU,IAAI;AAC7B,SAAO,WAAW,OAAO,WAAO,yBAAQ,QAAQ,CAAC;AACnD;AAGO,MAAM,YAAY;AAAA,EAKvB,YACW,UACT,gBACA;AAFS;AAGT,SAAK,YAAQ,uBAAK,cAAc;AAAA,EAClC;AAAA,EAJW;AAAA,EALF;AAAA,EAEQ,WAAW,oBAAI,IAAuB;AAAA;AAAA,EAU/C,cAAc,MAAyB;AAC7C,QAAI,OAAO,KAAK,SAAS,IAAI,IAAI;AACjC,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AACR,eAAS,OAAO,OAAO,MAAQ,KAAK,OAAO,IAAI,MAAM,MAAM,WAAO,yBAAQ,MAAM,CAAC,GAAG;AAClF,YAAI,KAAK,SAAS,aAAa,IAAI,EAAG,MAAK,KAAK,IAAI;AAAA,MACtD;AACA,WAAK,SAAS,IAAI,MAAM,IAAI;AAAA,IAC9B;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,MAAe,MAAY,GAA+B;AAC5E,QAAI,SAAS,KAAK;AAChB,UAAI,MAAM,EAAG,QAAO,CAAC,MAAM,IAAI;AAC/B,YAAM,OAAO,KAAK,cAAc,OAAO,IAAI,CAAC;AAC5C,UAAI,IAAI,KAAK,UAAU,CAAC,MAAM,KAAK,IAAI;AACvC,UAAI,MAAM,GAAI,QAAO,KAAK,YAAY,OAAO,IAAI,IAAI,MAAQ,MAAQ,KAAK,MAAM,CAAC;AACjF,WAAK,IAAI;AACT,aAAO,CAAC,KAAK,CAAC,GAAI,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,CAAE;AAAA,IAC3D;AACA,QAAI,SAAS,KAAK;AAChB,YAAM,aAAS,2BAAU,IAAI;AAC7B,YAAMA,QAAO,OAAO,MAAM;AAC1B,YAAM,QAAQ,YAAYA,KAAI;AAC9B,YAAM,OAAO,YAAYA,QAAO,CAAC;AACjC,YAAM,IAAI,KAAK,WAAO,2BAAU,MAAM,QAAI,2BAAU,KAAK,MAAM,IAAI,MAAW;AAC9E,YAAM,WAAO,yBAAQ,QAAQ,IAAK,IAAI,KAAM,CAAC;AAC7C,YAAM,SAAK,yBAAQ,MAAM,IAAI,IAAI,CAAC;AAClC,aAAO,CAAC,MAAM,KAAK,OAAO,SAAK,yBAAQ,MAAM,EAAE,CAAC;AAAA,IAClD;AACA,UAAM,OAAO,OAAO,IAAI;AACxB,UAAM,QAAQ,KAAK,MAAM,OAAO,GAAG,IAAI;AACvC,UAAM,aAAa,SAAU,QAAQ,KAAK;AAC1C,UAAM,YAAY,KAAK,IAAI,aAAa,IAAI,GAAG,EAAE;AACjD,WAAO,KAAC,4BAAW,OAAO,MAAQ,aAAa,MAAM,CAAC,OAAG,0BAAS,OAAO,MAAQ,YAAY,MAAM,CAAC,CAAC;AAAA,EACvG;AAAA,EAEQ,SAAS,MAAuB;AACtC,WAAO,KAAK,SAAS,QAAQ,IAAI,EAAE,CAAC,EAAG,CAAC;AAAA,EAC1C;AAAA,EAEQ,OAAO,MAAuB;AACpC,UAAM,IAAI,KAAK,SAAS,QAAQ,IAAI;AACpC,WAAO,EAAE,EAAE,SAAS,CAAC,EAAG,CAAC;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * PineScript values that depend on the chart timeframe and the symbol session (issue #100):\n * `time(tf)`, `time_close(tf)`, `timeframe.change(tf)`, `time_tradingday`, `session.*`.\n * PineScript rules:\n *\n * - intraday periods are aligned on the start of the session period of the trading day: 240 minutes from\n * 09:30 gives 09:30, 13:30; `time(tf)` is the start of the period that contains the bar open\n * - \"D\" is the session start of the trading day; \"W\" / \"M\" the session start of the first trading day\n * of the week (Monday to Sunday) / month\n * - intraday closes are cut at the end of the session period; the \"D\" close is the session end\n * - on intraday charts the \"W\" / \"M\" (and \"nD\") close is the session start of the next period's first\n * trading day; on D / W / M charts it is the session end of the last trading day of the week / month\n * - on D / W / M charts, intraday timeframes give the chart bar's time, and the end of the session\n * period that contains the bar open as close\n * - `time_tradingday` is 00:00 UTC of the trading day (on W / M charts, of the last trading day)\n *\n * Multipliers above one day (issue #100 follow-up): periods restart each\n * calendar year. \"nD\" groups n trading days from the first trading day of the year; \"nW\" groups n weeks from\n * the first week whose Monday is in the year; \"nM\" groups n months from January. The last group of a year\n * can be shorter.\n */\n\nimport { info, in_seconds, type TimeframeInfo } from '../timeframe/index.js';\nimport {\n TradingCalendar,\n addDays,\n dateUtcMs,\n monthEnd,\n monthStart,\n weekStart,\n type DateNum,\n} from './calendar.js';\n\ntype Unit = 'D' | 'W' | 'M';\n\nfunction unitOf(tf: TimeframeInfo): { unit: Unit; n: number } {\n return { unit: tf.isdaily ? 'D' : tf.isweekly ? 'W' : 'M', n: tf.multiplier };\n}\n\nconst yearOf = (date: DateNum): number => Math.floor(date / 10000);\n\n/** Monday of the first week of `year` (the first Monday on or after 1 January). */\nconst firstMonday = (year: number): DateNum => {\n const jan1 = year * 10000 + 101;\n const monday = weekStart(jan1);\n return monday === jan1 ? jan1 : addDays(monday, 7);\n};\n\n/** Values of the bars of one chart, for a trading calendar. */\nexport class SessionBars {\n readonly chart: TimeframeInfo;\n\n private readonly yearDays = new Map<number, DateNum[]>();\n\n constructor(\n readonly calendar: TradingCalendar,\n chartTimeframe: string\n ) {\n this.chart = info(chartTimeframe);\n }\n\n /** Trading days of a calendar year, in order. */\n private tradingDaysOf(year: number): DateNum[] {\n let days = this.yearDays.get(year);\n if (!days) {\n days = [];\n for (let date = year * 10000 + 101; yearOf(date) === year; date = addDays(date, 1)) {\n if (this.calendar.isTradingDay(date)) days.push(date);\n }\n this.yearDays.set(year, days);\n }\n return days;\n }\n\n /**\n * Dates [from, to] of the `n`-`unit` period that contains `date` (for \"D\": its first and last trading days).\n * Periods restart each calendar year.\n */\n private periodRange(date: DateNum, unit: Unit, n: number): [DateNum, DateNum] {\n if (unit === 'D') {\n if (n === 1) return [date, date];\n const days = this.tradingDaysOf(yearOf(date));\n let k = days.findIndex((d) => d >= date);\n if (k === -1) return this.periodRange(yearOf(date) * 10000 + 10000 + 101, unit, n);\n k -= k % n;\n return [days[k]!, days[Math.min(k + n, days.length) - 1]!];\n }\n if (unit === 'W') {\n const monday = weekStart(date);\n const year = yearOf(monday);\n const first = firstMonday(year);\n const next = firstMonday(year + 1);\n const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 86_400_000));\n const from = addDays(first, (k - (k % n)) * 7);\n const to = addDays(from, n * 7 - 1);\n return [from, to < next ? to : addDays(next, -1)];\n }\n const year = yearOf(date);\n const month = Math.floor(date / 100) % 100;\n const firstMonth = month - ((month - 1) % n);\n const lastMonth = Math.min(firstMonth + n - 1, 12);\n return [monthStart(year * 10000 + firstMonth * 100 + 1), monthEnd(year * 10000 + lastMonth * 100 + 1)];\n }\n\n private dayStart(date: DateNum): number {\n return this.calendar.periods(date)[0]![0];\n }\n\n private dayEnd(date: DateNum): number {\n const p = this.calendar.periods(date);\n return p[p.length - 1]![1];\n }\n\n /**\n * PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. An intraday bar that\n * opens after an early close has no day and no intraday period: `time(\"D\")`, `time(\"240\")` and `time(\"60\")` are\n * NaN on it (measured; `time(\"W\")` keeps its value).\n */\n timeOf(time: number, timeframe: string): number {\n const tf = info(timeframe);\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (tf.isintraday) {\n if (this.chart.isdwm) return time;\n // a bar after an early close has no intraday period either (#173)\n if (this.stray(time)) return NaN;\n const [start] = this.calendar.periods(at.date)[at.index]!;\n const ms = in_seconds(tf.period) * 1000;\n return start + Math.floor((time - start) / ms) * ms;\n }\n const { unit, n } = unitOf(tf);\n if (unit === 'D' && n === 1 && this.stray(time)) return NaN;\n const [from, to] = this.periodRange(at.date, unit, n);\n const first = this.calendar.firstTradingDay(from, to);\n return first === null ? NaN : this.dayStart(first);\n }\n\n /** PineScript `time_close(tf)` for a bar that opens at `time`. */\n closeOf(time: number, timeframe: string): number {\n const tf = info(timeframe);\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (tf.isintraday) {\n const [, end] = this.calendar.periods(at.date)[at.index]!;\n // on D / W / M charts: the end of the session period that contains the bar open\n if (this.chart.isdwm) return end;\n if (this.stray(time)) return NaN;\n return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);\n }\n const { unit, n } = unitOf(tf);\n if (unit === 'D' && n === 1 && this.stray(time)) return NaN;\n const [from, to] = this.periodRange(at.date, unit, n);\n // intraday charts: the start of the next period, except \"1D\" (the session end)\n if (this.chart.isintraday && (unit !== 'D' || n > 1)) {\n const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);\n const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));\n return first === null ? NaN : this.dayStart(first);\n }\n const last = this.calendar.lastTradingDay(from, to);\n return last === null ? NaN : this.dayEnd(last);\n }\n\n /** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */\n tradingDay(time: number): DateNum | null {\n const at = this.calendar.locate(time);\n if (!at || this.stray(time)) return null;\n if (this.chart.isdwm) {\n const { unit, n } = unitOf(this.chart);\n const [from, to] = this.periodRange(at.date, unit, n);\n return this.calendar.lastTradingDay(from, to);\n }\n return at.date;\n }\n\n /**\n * End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,\n * or the session end of the last trading day of the period. Used to know whether the last loaded\n * bar completes a higher-timeframe period (request.security).\n */\n periodEnd(time: number, timeframe: string): number {\n const tf = info(timeframe);\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (tf.isintraday) {\n const [, end] = this.calendar.periods(at.date)[at.index]!;\n return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);\n }\n const { unit, n } = unitOf(tf);\n const [from, to] = this.periodRange(at.date, unit, n);\n const last = this.calendar.lastTradingDay(from, to);\n return last === null ? NaN : this.dayEnd(last);\n }\n\n /** PineScript `time_tradingday`: 00:00 UTC of the trading day. */\n tradingDayTime(time: number): number {\n const day = this.tradingDay(time);\n return day === null ? NaN : dateUtcMs(day);\n }\n\n /**\n * Open time of the bar after the bar that opens at `time`, on the trading calendar: the next bar of the session\n * period, else the start of the next period or trading day; on D / W / M charts the session start of the first\n * trading day of the next chart period. NaN when none is found within 400 days.\n */\n nextBarTime(time: number): number {\n const at = this.calendar.locate(time);\n if (!at) return NaN;\n if (!this.chart.isdwm) {\n const periods = this.calendar.periods(at.date);\n const [start, end] = periods[at.index]!;\n const ms = in_seconds(this.chart.period) * 1000;\n const next = start + (Math.floor((time - start) / ms) + 1) * ms;\n if (at.inside && next < end) return next;\n if (at.index + 1 < periods.length) return periods[at.index + 1]![0];\n const day = this.calendar.firstTradingDay(addDays(at.date, 1), addDays(at.date, 400));\n return day === null ? NaN : this.dayStart(day);\n }\n const { unit, n } = unitOf(this.chart);\n const [, to] = this.periodRange(at.date, unit, n);\n const day = this.calendar.firstTradingDay(addDays(to, 1), addDays(to, 400));\n return day === null ? NaN : this.dayStart(day);\n }\n\n /** An intraday bar that opens after an early close of its day (see TradingCalendar.afterEarlyClose). */\n stray(time: number): boolean {\n return !this.chart.isdwm && this.calendar.afterEarlyClose(time);\n }\n\n /** True when the bar at `time` is inside the session. */\n inside(time: number): boolean {\n return this.calendar.locate(time)?.inside ?? false;\n }\n\n /** Session start and end of the trading day of `time`, or null. */\n dayBounds(time: number): { date: DateNum; start: number; end: number } | null {\n const at = this.calendar.locate(time);\n return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;\n }\n}\n\n/**\n * Periods of the chart bars that open after an early close, for `request.security` (#173): such a bar has no period\n * (`time(\"D\")` and `time(\"240\")` are na on it), but PineScript resamples it into the D / W / M bar of the bar before\n * it, and into an intraday bar of its own (opening at the bar's time). The bar before it still completes its period\n * (its day period is cut there). `intradayMs` is the duration of an intraday timeframe, null for D / W / M.\n * Changes `starts` and `dayPeriods` in place.\n */\nexport function strayPeriods(starts: number[], dayPeriods: number[], times: number[], bars: SessionBars, intradayMs: number | null): void {\n for (let i = 1; i < starts.length; i++) {\n if (!bars.stray(times[i]!)) continue;\n if (Number.isNaN(starts[i]!)) {\n // intraday: periods of `intradayMs` from the first such bar (\"240\": 18:30 and 20:30 are one bar)\n const run = Number.isNaN(dayPeriods[i - 1]!) && times[i]! < starts[i - 1]! + (intradayMs ?? 0);\n starts[i] = intradayMs === null || run ? starts[i - 1]! : times[i]!;\n }\n dayPeriods[i] = NaN;\n }\n}\n\n/** PineScript `session.*` flags of each bar. */\nexport interface SessionFlags {\n isfirstbar: boolean[];\n islastbar: boolean[];\n ismarket: boolean[];\n ispremarket: boolean[];\n ispostmarket: boolean[];\n isfirstbar_regular: boolean[];\n islastbar_regular: boolean[];\n}\n\n/**\n * `session.*` flags for bars that open at `times` (in order). `regular` gives the regular trading\n * hours when the bars include extended hours. PineScript rules: flags use the bar open\n * time; first and last bars are per session period (a trading day can have two periods, e.g. after a\n * futures holiday); pre / post market compare with the regular hours of the same trading day; on\n * D / W / M charts every bar is its own session (first, last, market, first and last regular).\n * The first loaded bar is a first bar only when no earlier bar of its period can exist (it opens less than one chart\n * period after the period start). A bar that opens after an early close is in the market hours (the usual hours of\n * its day) but is no last bar.\n */\nexport function sessionFlags(times: number[], bars: SessionBars, regular: SessionBars): SessionFlags {\n const n = times.length;\n const flag = () => new Array<boolean>(n).fill(false);\n const out: SessionFlags = {\n isfirstbar: flag(), islastbar: flag(), ismarket: flag(), ispremarket: flag(), ispostmarket: flag(),\n isfirstbar_regular: flag(), islastbar_regular: flag(),\n };\n const chart = bars.chart;\n let previousPeriod = '';\n let previousRegular = '';\n for (let i = 0; i < n; i++) {\n const t = times[i]!;\n if (chart.isdwm) {\n for (const k of ['isfirstbar', 'islastbar', 'ismarket', 'isfirstbar_regular', 'islastbar_regular'] as const) out[k][i] = true;\n continue;\n }\n const at = bars.calendar.locate(t);\n if (!at) {\n previousPeriod = previousRegular = '';\n continue;\n }\n const close = bars.closeOf(t, chart.period);\n const [, end] = bars.calendar.periods(at.date)[at.index]!;\n const period = `${at.date}/${at.index}`;\n const [start] = bars.calendar.periods(at.date)[at.index]!;\n const barMs = in_seconds(chart.period) * 1000;\n // the first loaded bar: a first bar only when no earlier bar of the period can exist\n out.isfirstbar[i] = i === 0 ? t - start < barMs : period !== previousPeriod;\n const stray = bars.stray(t);\n out.islastbar[i] = !stray && close >= end;\n const regularPeriods = regular.calendar.periods(at.date);\n const r = regularPeriods.findIndex(([s, e]) => s <= t && t < e);\n const market = r !== -1;\n out.ismarket[i] = market || regular.stray(t);\n if (!market && regularPeriods.length) {\n out.ispremarket[i] = t < regularPeriods[0]![0];\n out.ispostmarket[i] = t >= regularPeriods[regularPeriods.length - 1]![1];\n }\n const regularPeriod = market ? `${at.date}/${r}` : '';\n out.isfirstbar_regular[i] = market && (i === 0 ? t - regularPeriods[r]![0] < barMs : regularPeriod !== previousRegular);\n out.islastbar_regular[i] = market && close >= regularPeriods[r]![1];\n previousPeriod = period;\n previousRegular = regularPeriod;\n }\n return out;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["year", "day"]
|
|
7
7
|
}
|
|
@@ -41,12 +41,15 @@ export declare class TradingCalendar {
|
|
|
41
41
|
private readonly corrections;
|
|
42
42
|
private readonly holidays;
|
|
43
43
|
private readonly cache;
|
|
44
|
+
private readonly pine;
|
|
44
45
|
/**
|
|
45
46
|
* @param timezone - Time zone of the session hours (the exchange time zone)
|
|
46
47
|
* @param spec - Session information (hours, corrections, holidays)
|
|
47
48
|
* @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
|
|
49
|
+
* @param dayPlacement - PineScript session strings read for `time("D", session)`: the wall times of a clock-change
|
|
50
|
+
* day are placed as the JVM does (see `periods`); without it, as `time.inSession` places them
|
|
48
51
|
*/
|
|
49
|
-
constructor(timezone: string, spec: SessionSpec, rule?: 'symbol' | 'pine');
|
|
52
|
+
constructor(timezone: string, spec: SessionSpec, rule?: 'symbol' | 'pine', dayPlacement?: boolean);
|
|
50
53
|
/** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
|
|
51
54
|
periods(date: DateNum): Array<[number, number]>;
|
|
52
55
|
isTradingDay(date: DateNum): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/session/calendar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,2GAA2G;IAC3G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAwB;AACxB,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAoB7B,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAAkC,CAAC;AAM/F,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,GAAG,MAAM,KAAG,OAAgD,CAAC;AACpG,kCAAkC;AAClC,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,KAAG,MAA+C,CAAC;AAC1F,mEAAmE;AACnE,eAAO,MAAM,SAAS,SATD,OAAO,KAAG,MASD,CAAC;
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/session/calendar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,2GAA2G;IAC3G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAwB;AACxB,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAoB7B,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAAkC,CAAC;AAM/F,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,GAAG,MAAM,KAAG,OAAgD,CAAC;AACpG,kCAAkC;AAClC,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,KAAG,MAA+C,CAAC;AAC1F,mEAAmE;AACnE,eAAO,MAAM,SAAS,SATD,OAAO,KAAG,MASD,CAAC;AAsE/B,4EAA4E;AAC5E,qBAAa,eAAe;IAexB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAd3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuC;IACnE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+C;IACrE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAU;IAE/B;;;;;;OAMG;gBAEQ,QAAQ,EAAE,MAAM,EACzB,IAAI,EAAE,WAAW,EACjB,IAAI,GAAE,QAAQ,GAAG,MAAiB,EAClC,YAAY,UAAQ;IAoBtB,iGAAiG;IACjG,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IA6B/C,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAIpC;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAetC;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAoB9E,wDAAwD;IACxD,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI;IAK3D,uDAAuD;IACvD,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI;CAI3D;AAED,iEAAiE;AACjE,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,KAAG,OAAsD,CAAC;AACjG,wCAAwC;AACxC,eAAO,MAAM,UAAU,GAAI,MAAM,OAAO,KAAG,OAA2C,CAAC;AACvF,uCAAuC;AACvC,eAAO,MAAM,QAAQ,GAAI,MAAM,OAAO,KAAG,OAAiE,CAAC"}
|
|
@@ -65,8 +65,8 @@ function pineVersion(text, from) {
|
|
|
65
65
|
const ranges = (0, import_session.parsePineSession)(text);
|
|
66
66
|
if (ranges === null) throw new SyntaxError(`Session "${text}" is the symbol session`);
|
|
67
67
|
const byDay = Array.from({ length: 8 }, () => []);
|
|
68
|
-
for (const { start, end, days } of ranges) {
|
|
69
|
-
const period = start === 0 && end === 0 ? { start: 0, end: 1440, startOffset: 0, endOffset: 0 } : { start, end, startOffset: end <= start ? 1 : 0, endOffset: 0 };
|
|
68
|
+
for (const { start, end, days, startDays } of ranges) {
|
|
69
|
+
const period = start === 0 && end === 0 ? { start: 0, end: 1440, startOffset: 0, endOffset: 0 } : startDays !== void 0 ? { start, end, startOffset: startDays, endOffset: 0 } : end === 0 ? { start, end: 1440, startOffset: 0, endOffset: 0 } : { start, end, startOffset: end <= start ? 1 : 0, endOffset: 0 };
|
|
70
70
|
for (const d of days) byDay[d].push(period);
|
|
71
71
|
}
|
|
72
72
|
return { from, periods: [], days: byDay.map((p) => p.length > 0), byDay };
|
|
@@ -97,9 +97,12 @@ class TradingCalendar {
|
|
|
97
97
|
* @param timezone - Time zone of the session hours (the exchange time zone)
|
|
98
98
|
* @param spec - Session information (hours, corrections, holidays)
|
|
99
99
|
* @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
|
|
100
|
+
* @param dayPlacement - PineScript session strings read for `time("D", session)`: the wall times of a clock-change
|
|
101
|
+
* day are placed as the JVM does (see `periods`); without it, as `time.inSession` places them
|
|
100
102
|
*/
|
|
101
|
-
constructor(timezone, spec, rule = "symbol") {
|
|
103
|
+
constructor(timezone, spec, rule = "symbol", dayPlacement = false) {
|
|
102
104
|
this.timezone = timezone;
|
|
105
|
+
this.pine = rule === "pine" && dayPlacement;
|
|
103
106
|
const [first = "", ...changes] = spec.session.split("#");
|
|
104
107
|
this.versions = [parseVersion(first, 0, spec.session, rule)];
|
|
105
108
|
for (const change of changes) {
|
|
@@ -121,6 +124,7 @@ class TradingCalendar {
|
|
|
121
124
|
corrections = /* @__PURE__ */ new Map();
|
|
122
125
|
holidays;
|
|
123
126
|
cache = /* @__PURE__ */ new Map();
|
|
127
|
+
pine;
|
|
124
128
|
/** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
|
|
125
129
|
periods(date) {
|
|
126
130
|
let out = this.cache.get(date);
|
|
@@ -137,10 +141,10 @@ class TradingCalendar {
|
|
|
137
141
|
const y = Math.floor(date / 1e4);
|
|
138
142
|
const m = Math.floor(date / 100) % 100;
|
|
139
143
|
const d = date % 100;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
(
|
|
143
|
-
|
|
144
|
+
const at = (dd, minutes, earlier = false) => (0, import_timezone.zonedToUnix)(this.timezone, y, m, dd, Math.floor(minutes / 60), minutes % 60, 0, earlier);
|
|
145
|
+
out = periods.map(
|
|
146
|
+
(p) => this.pine ? [at(d - p.startOffset, p.start, true), at(d - p.endOffset, p.end - 1, true) + 6e4] : [at(d - p.startOffset, p.start), at(d - p.endOffset, p.end)]
|
|
147
|
+
);
|
|
144
148
|
this.cache.set(date, out);
|
|
145
149
|
return out;
|
|
146
150
|
}
|