oakscriptjs 0.10.0 → 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.
- package/dist/cjs/box/index.d.ts.map +1 -1
- package/dist/cjs/box/index.js +7 -1
- package/dist/cjs/box/index.js.map +2 -2
- package/dist/cjs/callsite/index.d.ts +73 -32
- package/dist/cjs/callsite/index.d.ts.map +1 -1
- package/dist/cjs/callsite/index.js +69 -65
- package/dist/cjs/callsite/index.js.map +2 -2
- package/dist/cjs/drawing/registry.d.ts +75 -0
- package/dist/cjs/drawing/registry.d.ts.map +1 -1
- package/dist/cjs/drawing/registry.js +139 -6
- package/dist/cjs/drawing/registry.js.map +2 -2
- package/dist/cjs/index.d.ts +8 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +30 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/label/index.d.ts.map +1 -1
- package/dist/cjs/label/index.js +3 -0
- package/dist/cjs/label/index.js.map +2 -2
- package/dist/cjs/line/index.d.ts.map +1 -1
- package/dist/cjs/line/index.js +7 -1
- package/dist/cjs/line/index.js.map +2 -2
- package/dist/cjs/math/index.d.ts.map +1 -1
- package/dist/cjs/math/index.js +2 -0
- package/dist/cjs/math/index.js.map +2 -2
- package/dist/cjs/polyline/index.d.ts.map +1 -1
- package/dist/cjs/polyline/index.js +3 -0
- package/dist/cjs/polyline/index.js.map +2 -2
- package/dist/cjs/runtime/index.d.ts +2 -1
- package/dist/cjs/runtime/index.d.ts.map +1 -1
- package/dist/cjs/runtime/index.js +2 -0
- package/dist/cjs/runtime/index.js.map +2 -2
- package/dist/cjs/runtime/input-active.d.ts +27 -0
- package/dist/cjs/runtime/input-active.d.ts.map +1 -0
- package/dist/cjs/runtime/input-active.js +44 -0
- package/dist/cjs/runtime/input-active.js.map +7 -0
- package/dist/cjs/runtime/types.d.ts +29 -2
- 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 +53 -17
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +70 -11
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/cjs/session/bars.d.ts +15 -1
- package/dist/cjs/session/bars.d.ts.map +1 -1
- package/dist/cjs/session/bars.js +41 -6
- package/dist/cjs/session/bars.js.map +3 -3
- package/dist/cjs/session/calendar.d.ts +9 -1
- package/dist/cjs/session/calendar.d.ts.map +1 -1
- package/dist/cjs/session/calendar.js +28 -2
- package/dist/cjs/session/calendar.js.map +2 -2
- package/dist/cjs/session/context.d.ts +75 -0
- package/dist/cjs/session/context.d.ts.map +1 -0
- package/dist/cjs/session/context.js +113 -0
- package/dist/cjs/session/context.js.map +7 -0
- package/dist/cjs/str/index.d.ts +12 -4
- package/dist/cjs/str/index.d.ts.map +1 -1
- package/dist/cjs/str/index.js +13 -7
- package/dist/cjs/str/index.js.map +2 -2
- package/dist/cjs/str/numberformat.d.ts +10 -2
- package/dist/cjs/str/numberformat.d.ts.map +1 -1
- package/dist/cjs/str/numberformat.js +10 -2
- package/dist/cjs/str/numberformat.js.map +2 -2
- package/dist/cjs/ta/index.d.ts +33 -17
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +70 -29
- package/dist/cjs/ta/index.js.map +2 -2
- package/dist/cjs/ta/limits.d.ts +24 -0
- package/dist/cjs/ta/limits.d.ts.map +1 -0
- package/dist/cjs/ta/limits.js +50 -0
- package/dist/cjs/ta/limits.js.map +7 -0
- package/dist/cjs/ta/running-sum.d.ts +0 -16
- package/dist/cjs/ta/running-sum.d.ts.map +1 -1
- package/dist/cjs/ta/running-sum.js +2 -0
- package/dist/cjs/ta/running-sum.js.map +2 -2
- package/dist/cjs/ta-series.d.ts +7 -7
- package/dist/cjs/ta-series.d.ts.map +1 -1
- package/dist/cjs/ta-series.js +9 -7
- package/dist/cjs/ta-series.js.map +2 -2
- package/dist/cjs/time/index.d.ts +5 -2
- package/dist/cjs/time/index.d.ts.map +1 -1
- package/dist/cjs/time/index.js +2 -2
- package/dist/cjs/time/index.js.map +2 -2
- package/dist/cjs/time/session.d.ts +17 -1
- package/dist/cjs/time/session.d.ts.map +1 -1
- package/dist/cjs/time/session.js +61 -7
- package/dist/cjs/time/session.js.map +2 -2
- package/dist/cjs/types/metadata.d.ts +27 -3
- package/dist/cjs/types/metadata.d.ts.map +1 -1
- package/dist/cjs/types/metadata.js.map +1 -1
- package/dist/esm/box/index.d.ts.map +1 -1
- package/dist/esm/box/index.js +8 -2
- package/dist/esm/box/index.js.map +1 -1
- package/dist/esm/callsite/index.d.ts +73 -32
- package/dist/esm/callsite/index.d.ts.map +1 -1
- package/dist/esm/callsite/index.js +143 -106
- package/dist/esm/callsite/index.js.map +1 -1
- package/dist/esm/drawing/registry.d.ts +75 -0
- package/dist/esm/drawing/registry.d.ts.map +1 -1
- package/dist/esm/drawing/registry.js +237 -6
- package/dist/esm/drawing/registry.js.map +1 -1
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +11 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/label/index.d.ts.map +1 -1
- package/dist/esm/label/index.js +4 -1
- package/dist/esm/label/index.js.map +1 -1
- package/dist/esm/line/index.d.ts.map +1 -1
- package/dist/esm/line/index.js +8 -2
- package/dist/esm/line/index.js.map +1 -1
- package/dist/esm/math/index.d.ts.map +1 -1
- package/dist/esm/math/index.js +3 -0
- package/dist/esm/math/index.js.map +1 -1
- package/dist/esm/polyline/index.d.ts.map +1 -1
- package/dist/esm/polyline/index.js +5 -1
- package/dist/esm/polyline/index.js.map +1 -1
- package/dist/esm/runtime/index.d.ts +2 -1
- package/dist/esm/runtime/index.d.ts.map +1 -1
- package/dist/esm/runtime/index.js +1 -0
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/input-active.d.ts +27 -0
- package/dist/esm/runtime/input-active.d.ts.map +1 -0
- package/dist/esm/runtime/input-active.js +54 -0
- package/dist/esm/runtime/input-active.js.map +1 -0
- package/dist/esm/runtime/types.d.ts +29 -2
- package/dist/esm/runtime/types.d.ts.map +1 -1
- package/dist/esm/script/index.d.ts +53 -17
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +80 -13
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/session/bars.d.ts +15 -1
- package/dist/esm/session/bars.d.ts.map +1 -1
- package/dist/esm/session/bars.js +50 -6
- package/dist/esm/session/bars.js.map +1 -1
- package/dist/esm/session/calendar.d.ts +9 -1
- package/dist/esm/session/calendar.d.ts.map +1 -1
- package/dist/esm/session/calendar.js +35 -3
- package/dist/esm/session/calendar.js.map +1 -1
- package/dist/esm/session/context.d.ts +75 -0
- package/dist/esm/session/context.d.ts.map +1 -0
- package/dist/esm/session/context.js +122 -0
- package/dist/esm/session/context.js.map +1 -0
- package/dist/esm/str/index.d.ts +12 -4
- package/dist/esm/str/index.d.ts.map +1 -1
- package/dist/esm/str/index.js +33 -12
- package/dist/esm/str/index.js.map +1 -1
- package/dist/esm/str/numberformat.d.ts +10 -2
- package/dist/esm/str/numberformat.d.ts.map +1 -1
- package/dist/esm/str/numberformat.js +16 -2
- package/dist/esm/str/numberformat.js.map +1 -1
- package/dist/esm/ta/index.d.ts +33 -17
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +130 -56
- package/dist/esm/ta/index.js.map +1 -1
- package/dist/esm/ta/limits.d.ts +24 -0
- package/dist/esm/ta/limits.d.ts.map +1 -0
- package/dist/esm/ta/limits.js +42 -0
- package/dist/esm/ta/limits.js.map +1 -0
- package/dist/esm/ta/running-sum.d.ts +0 -16
- package/dist/esm/ta/running-sum.d.ts.map +1 -1
- package/dist/esm/ta/running-sum.js +2 -0
- package/dist/esm/ta/running-sum.js.map +1 -1
- package/dist/esm/ta-series.d.ts +7 -7
- package/dist/esm/ta-series.d.ts.map +1 -1
- package/dist/esm/ta-series.js +9 -7
- package/dist/esm/ta-series.js.map +1 -1
- package/dist/esm/time/index.d.ts +5 -2
- package/dist/esm/time/index.d.ts.map +1 -1
- package/dist/esm/time/index.js +6 -3
- package/dist/esm/time/index.js.map +1 -1
- package/dist/esm/time/session.d.ts +17 -1
- package/dist/esm/time/session.d.ts.map +1 -1
- package/dist/esm/time/session.js +97 -10
- package/dist/esm/time/session.js.map +1 -1
- package/dist/esm/types/metadata.d.ts +27 -3
- package/dist/esm/types/metadata.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/box/index.ts +8 -2
- package/src/callsite/index.ts +150 -100
- package/src/drawing/registry.ts +255 -5
- package/src/index.ts +36 -1
- package/src/label/index.ts +4 -1
- package/src/line/index.ts +8 -2
- package/src/math/index.ts +2 -0
- package/src/polyline/index.ts +3 -1
- package/src/runtime/index.ts +3 -0
- package/src/runtime/input-active.ts +50 -0
- package/src/runtime/types.ts +25 -2
- package/src/script/index.ts +123 -23
- package/src/session/bars.ts +47 -6
- package/src/session/calendar.ts +37 -3
- package/src/session/context.ts +160 -0
- package/src/str/index.ts +30 -12
- package/src/str/numberformat.ts +18 -3
- package/src/ta/index.ts +148 -66
- package/src/ta/limits.ts +47 -0
- package/src/ta/running-sum.ts +2 -0
- package/src/ta-series.ts +16 -14
- package/src/time/index.ts +6 -3
- package/src/time/session.ts +89 -9
- package/src/types/metadata.ts +27 -3
package/src/script/index.ts
CHANGED
|
@@ -69,6 +69,7 @@ import type {
|
|
|
69
69
|
FillConfig,
|
|
70
70
|
HLineConfig,
|
|
71
71
|
InputConfig,
|
|
72
|
+
InputCondition,
|
|
72
73
|
PlotConfig,
|
|
73
74
|
ShapeConfig,
|
|
74
75
|
} from '../runtime/types.js';
|
|
@@ -86,12 +87,14 @@ import * as tableCore from '../table/index.js';
|
|
|
86
87
|
import * as chartPointCore from '../chartpoint/index.js';
|
|
87
88
|
import * as textCore from '../text/index.js';
|
|
88
89
|
import * as mathCore from '../math/index.js';
|
|
89
|
-
import { resetDrawings, setDrawingLimits } from '../drawing/registry.js';
|
|
90
|
+
import { resetDrawings, setDrawingBar, setDrawingLimits } from '../drawing/registry.js';
|
|
91
|
+
export { holdDrawing, releaseDrawing, varDrawing, type DrawingVariable } from '../drawing/registry.js';
|
|
90
92
|
import { drawingOutputs } from '../drawing/output.js';
|
|
91
93
|
import * as timeframeCore from '../timeframe/index.js';
|
|
92
94
|
import * as timeCore from '../time/index.js';
|
|
93
95
|
import * as strCore from '../str/index.js';
|
|
94
96
|
import { formatMessage } from '../str/messageformat.js';
|
|
97
|
+
import { tickScale } from '../str/numberformat.js';
|
|
95
98
|
import { TradingCalendar, type SessionSpec } from '../session/calendar.js';
|
|
96
99
|
import { SessionBars, sessionFlags, type SessionFlags } from '../session/bars.js';
|
|
97
100
|
import { afterCompletion, heikinAshi, mapToChart, periodsOf, resample } from '../security/resample.js';
|
|
@@ -294,6 +297,7 @@ export function executeScript(
|
|
|
294
297
|
): ScriptRunResult {
|
|
295
298
|
ctxBars.setAll(barsInput);
|
|
296
299
|
chartCtx = { ...chart };
|
|
300
|
+
runNow = chart.now ?? Date.now();
|
|
297
301
|
scriptOptions = options;
|
|
298
302
|
ctx = freshCollector(inputs);
|
|
299
303
|
resetDrawings();
|
|
@@ -380,13 +384,19 @@ function declare(c: Collector, kind: 'indicator' | 'strategy'): void {
|
|
|
380
384
|
c.declaration = kind;
|
|
381
385
|
}
|
|
382
386
|
|
|
383
|
-
/** Options of every `input.*` kind (PineScript `group`, `inline`, `tooltip`, `confirm`, `display`). */
|
|
387
|
+
/** Options of every `input.*` kind (PineScript `group`, `inline`, `tooltip`, `confirm`, `display`, `active`). */
|
|
384
388
|
export interface InputOptions {
|
|
385
389
|
group?: string;
|
|
386
390
|
inline?: string;
|
|
387
391
|
tooltip?: string;
|
|
388
392
|
confirm?: boolean;
|
|
389
393
|
display?: InputConfig['display'];
|
|
394
|
+
/**
|
|
395
|
+
* PineScript `active`: false greys the input out in the settings (it keeps its value). A boolean as in
|
|
396
|
+
* PineScript (`active: showMa`), or a condition on input ids that a host can apply without running the script
|
|
397
|
+
* (`active: 'ma_1'`, `active: { input: 'type', ne: 'None' }`)
|
|
398
|
+
*/
|
|
399
|
+
active?: boolean | InputCondition;
|
|
390
400
|
}
|
|
391
401
|
|
|
392
402
|
export interface NumericInputOptions extends InputOptions {
|
|
@@ -407,6 +417,7 @@ function common(opts: InputOptions): Partial<InputConfig> {
|
|
|
407
417
|
if (opts.tooltip !== undefined) out.tooltip = opts.tooltip;
|
|
408
418
|
if (opts.confirm !== undefined) out.confirm = opts.confirm;
|
|
409
419
|
if (opts.display !== undefined) out.display = opts.display;
|
|
420
|
+
if (opts.active !== undefined) out.active = opts.active;
|
|
410
421
|
return out;
|
|
411
422
|
}
|
|
412
423
|
|
|
@@ -538,25 +549,27 @@ export const ta = {
|
|
|
538
549
|
): [Series, Series, Series, Series, Series] =>
|
|
539
550
|
taSeries.ichimoku(bars(), conversionPeriods, basePeriods, laggingSpan2Periods, displacement),
|
|
540
551
|
/** `ta.highest(source, length)` or `ta.highest(length)` (source = high). */
|
|
541
|
-
highest: (sourceOrLength: Series | number, length?: number): Series =>
|
|
552
|
+
highest: (sourceOrLength: Series | number, length?: number | Series): Series =>
|
|
542
553
|
typeof sourceOrLength === 'number' ? taSeries.highest(high, sourceOrLength) : taSeries.highest(sourceOrLength, length!),
|
|
543
554
|
/** `ta.lowest(source, length)` or `ta.lowest(length)` (source = low). */
|
|
544
|
-
lowest: (sourceOrLength: Series | number, length?: number): Series =>
|
|
555
|
+
lowest: (sourceOrLength: Series | number, length?: number | Series): Series =>
|
|
545
556
|
typeof sourceOrLength === 'number' ? taSeries.lowest(low, sourceOrLength) : taSeries.lowest(sourceOrLength, length!),
|
|
546
557
|
/** `ta.highestbars(source, length)` or `ta.highestbars(length)` (source = high); offsets are 0 or negative. */
|
|
547
|
-
highestbars: (sourceOrLength: Series | number, length?: number): Series =>
|
|
558
|
+
highestbars: (sourceOrLength: Series | number, length?: number | Series): Series =>
|
|
548
559
|
typeof sourceOrLength === 'number'
|
|
549
560
|
? taSeries.highestbars(high, sourceOrLength)
|
|
550
561
|
: taSeries.highestbars(sourceOrLength, length!),
|
|
551
562
|
/** `ta.lowestbars(source, length)` or `ta.lowestbars(length)` (source = low); offsets are 0 or negative. */
|
|
552
|
-
lowestbars: (sourceOrLength: Series | number, length?: number): Series =>
|
|
563
|
+
lowestbars: (sourceOrLength: Series | number, length?: number | Series): Series =>
|
|
553
564
|
typeof sourceOrLength === 'number'
|
|
554
565
|
? taSeries.lowestbars(low, sourceOrLength)
|
|
555
566
|
: taSeries.lowestbars(sourceOrLength, length!),
|
|
556
567
|
/** `ta.vwap(source, anchor?, stdev_mult?)` with the chart volume; the default anchor is a new trading
|
|
557
|
-
* day (`timeframe.change("1D")`), which needs the chart context (timeframe, time zone, session)
|
|
568
|
+
* day (`timeframe.change("1D")`), which needs the chart context (timeframe, time zone, session), and the
|
|
569
|
+
* first bar: as in PineScript, the first loaded bars (a day in progress) have a value. */
|
|
558
570
|
vwap: ((source: Series, anchor?: Series, stdev_mult?: number): Series | [Series, Series, Series] => {
|
|
559
|
-
|
|
571
|
+
// PineScript default: timeframe.change("1D"); the sums also start on the first bar (a day in progress)
|
|
572
|
+
const a = anchor ?? changeOf('1D', true);
|
|
560
573
|
return stdev_mult === undefined ? taSeries.vwap(source, volume, a) : taSeries.vwapBands(source, volume, a, stdev_mult);
|
|
561
574
|
}) as {
|
|
562
575
|
(source: Series, anchor?: Series): Series;
|
|
@@ -566,12 +579,12 @@ export const ta = {
|
|
|
566
579
|
mfi: (source: Series, length: number): Series => taSeries.mfi(source, length, volume),
|
|
567
580
|
/** `ta.pivothigh(source, leftbars, rightbars)` or `ta.pivothigh(leftbars, rightbars)` (source = high).
|
|
568
581
|
* The value appears `rightbars` bars after the pivot bar, as in PineScript. */
|
|
569
|
-
pivothigh: (sourceOrLeft: Series | number, leftOrRight: number, rightbars?: number): Series =>
|
|
582
|
+
pivothigh: (sourceOrLeft: Series | number, leftOrRight: number | Series, rightbars?: number | Series): Series =>
|
|
570
583
|
typeof sourceOrLeft === 'number'
|
|
571
584
|
? taSeries.pivothigh(high, sourceOrLeft, leftOrRight)
|
|
572
585
|
: taSeries.pivothigh(sourceOrLeft, leftOrRight, rightbars!),
|
|
573
586
|
/** `ta.pivotlow(source, leftbars, rightbars)` or `ta.pivotlow(leftbars, rightbars)` (source = low). */
|
|
574
|
-
pivotlow: (sourceOrLeft: Series | number, leftOrRight: number, rightbars?: number): Series =>
|
|
587
|
+
pivotlow: (sourceOrLeft: Series | number, leftOrRight: number | Series, rightbars?: number | Series): Series =>
|
|
575
588
|
typeof sourceOrLeft === 'number'
|
|
576
589
|
? taSeries.pivotlow(low, sourceOrLeft, leftOrRight)
|
|
577
590
|
: taSeries.pivotlow(sourceOrLeft, leftOrRight, rightbars!),
|
|
@@ -1253,6 +1266,7 @@ export function eachBar(fn: (c: BarContext) => number | boolean | void): Series
|
|
|
1253
1266
|
for (idx = 0; idx < b.length; idx++) {
|
|
1254
1267
|
if (pendingError && pendingError.bar === idx) throw new Error(historyError(idx, pendingError.barsBack));
|
|
1255
1268
|
currentBar = idx;
|
|
1269
|
+
setDrawingBar(idx, idx === b.length - 1);
|
|
1256
1270
|
const r = fn(ctx);
|
|
1257
1271
|
out[idx] = typeof r === 'number' ? r : typeof r === 'boolean' ? (r ? 1 : 0) : NaN;
|
|
1258
1272
|
// grow the history buffers from the largest reference of this bar
|
|
@@ -1269,6 +1283,7 @@ export function eachBar(fn: (c: BarContext) => number | boolean | void): Series
|
|
|
1269
1283
|
}
|
|
1270
1284
|
} finally {
|
|
1271
1285
|
currentBar = -1;
|
|
1286
|
+
setDrawingBar(null);
|
|
1272
1287
|
}
|
|
1273
1288
|
return Series.fromArray(ctxBars, out);
|
|
1274
1289
|
}
|
|
@@ -1522,12 +1537,32 @@ export interface ChartContext {
|
|
|
1522
1537
|
tickerid?: string;
|
|
1523
1538
|
/** Unit of `Bar.time`: 's' (default, as lightweight-charts) or 'ms'. PineScript times are in ms. */
|
|
1524
1539
|
timeUnit?: 's' | 'ms';
|
|
1525
|
-
/**
|
|
1540
|
+
/**
|
|
1541
|
+
* Minimum price move of the symbol (PineScript `syminfo.mintick`), e.g. 0.01; used by `math.round_to_mintick` and
|
|
1542
|
+
* `format.mintick`. Default: `minmove / pricescale` when both are given
|
|
1543
|
+
*/
|
|
1526
1544
|
mintick?: number;
|
|
1545
|
+
/**
|
|
1546
|
+
* PineScript `syminfo.minmove` and `syminfo.pricescale` (mintick = minmove / pricescale). Default: from `mintick`,
|
|
1547
|
+
* with pricescale 10^(its decimals) (0.25 is 25 / 100). Pass them for a symbol priced in fractions (1 / 32):
|
|
1548
|
+
* `format.mintick` shows floor(log10(pricescale)) decimals
|
|
1549
|
+
*/
|
|
1550
|
+
minmove?: number;
|
|
1551
|
+
pricescale?: number;
|
|
1527
1552
|
/** Currency value of one point of price move for one contract (PineScript `syminfo.pointvalue`); 1 for stocks */
|
|
1528
1553
|
pointvalue?: number;
|
|
1529
1554
|
/** Smallest tradable quantity (PineScript `syminfo.mincontract`); 1 for whole shares */
|
|
1530
1555
|
mincontract?: number;
|
|
1556
|
+
/** Symbol type (PineScript `syminfo.type`): "stock", "crypto", "forex", "futures", "index", "fund"... */
|
|
1557
|
+
symbolType?: string;
|
|
1558
|
+
/** Currency of the symbol (PineScript `syminfo.currency`), e.g. "USD" */
|
|
1559
|
+
currency?: string;
|
|
1560
|
+
/** Chart foreground colour (PineScript `chart.fg_color`), e.g. "#DBDBDB" on a dark chart */
|
|
1561
|
+
foregroundColor?: string;
|
|
1562
|
+
/** Chart background colour (PineScript `chart.bg_color`), e.g. "#0F0F0F" on a dark chart */
|
|
1563
|
+
backgroundColor?: string;
|
|
1564
|
+
/** Current time in ms (PineScript `timenow`); default: the clock of the computer at the start of the run */
|
|
1565
|
+
now?: number;
|
|
1531
1566
|
/**
|
|
1532
1567
|
* The last bar is closed (`barstate.isconfirmed` on the last bar). Default false: PineScript treats the last bar
|
|
1533
1568
|
* of the data as not confirmed until the data feed closes it.
|
|
@@ -1611,19 +1646,48 @@ function symbolProperty(key: 'mintick' | 'pointvalue' | 'mincontract'): number {
|
|
|
1611
1646
|
collector();
|
|
1612
1647
|
const value = chartCtx[key];
|
|
1613
1648
|
if (value === undefined) {
|
|
1649
|
+
if (key === 'mintick' && chartCtx.minmove !== undefined && chartCtx.pricescale !== undefined) {
|
|
1650
|
+
return chartCtx.minmove / chartCtx.pricescale;
|
|
1651
|
+
}
|
|
1614
1652
|
throw new Error(`syminfo.${key} is not known: pass it as executeScript(body, bars, inputs, { ${key} }).`);
|
|
1615
1653
|
}
|
|
1616
1654
|
return value;
|
|
1617
1655
|
}
|
|
1618
1656
|
|
|
1657
|
+
/** A text value of the chart or the symbol that the host passes in the chart context. */
|
|
1658
|
+
function chartText(key: 'symbolType' | 'currency' | 'foregroundColor' | 'backgroundColor', name: string): string {
|
|
1659
|
+
collector();
|
|
1660
|
+
const value = chartCtx[key];
|
|
1661
|
+
if (value === undefined) {
|
|
1662
|
+
throw new Error(`${name} is not known: pass it as executeScript(body, bars, inputs, { ${key} }).`);
|
|
1663
|
+
}
|
|
1664
|
+
return value;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
/** `[minmove, pricescale]` of the chart symbol: from the chart context, else from its mintick. */
|
|
1668
|
+
function symbolScale(): [number, number] {
|
|
1669
|
+
collector();
|
|
1670
|
+
const { minmove, pricescale } = chartCtx;
|
|
1671
|
+
if (minmove !== undefined && pricescale !== undefined) return [minmove, pricescale];
|
|
1672
|
+
const [move, scale] = tickScale(symbolProperty('mintick'), pricescale);
|
|
1673
|
+
return [minmove ?? move, scale];
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1619
1676
|
/**
|
|
1620
1677
|
* PineScript `syminfo.timezone`, `syminfo.tickerid`, `syminfo.session` (session type), `syminfo.mintick`,
|
|
1621
|
-
* `syminfo.
|
|
1678
|
+
* `syminfo.minmove`, `syminfo.pricescale`, `syminfo.pointvalue`, `syminfo.mincontract`, `syminfo.type` and
|
|
1679
|
+
* `syminfo.currency`, from the chart context.
|
|
1622
1680
|
*/
|
|
1623
1681
|
export const syminfo = {
|
|
1624
1682
|
get mintick(): number {
|
|
1625
1683
|
return symbolProperty('mintick');
|
|
1626
1684
|
},
|
|
1685
|
+
get minmove(): number {
|
|
1686
|
+
return symbolScale()[0];
|
|
1687
|
+
},
|
|
1688
|
+
get pricescale(): number {
|
|
1689
|
+
return symbolScale()[1];
|
|
1690
|
+
},
|
|
1627
1691
|
get pointvalue(): number {
|
|
1628
1692
|
return symbolProperty('pointvalue');
|
|
1629
1693
|
},
|
|
@@ -1644,6 +1708,12 @@ export const syminfo = {
|
|
|
1644
1708
|
collector();
|
|
1645
1709
|
return chartCtx.sessionType ?? 'regular';
|
|
1646
1710
|
},
|
|
1711
|
+
get type(): string {
|
|
1712
|
+
return chartText('symbolType', 'syminfo.type');
|
|
1713
|
+
},
|
|
1714
|
+
get currency(): string {
|
|
1715
|
+
return chartText('currency', 'syminfo.currency');
|
|
1716
|
+
},
|
|
1647
1717
|
};
|
|
1648
1718
|
|
|
1649
1719
|
/** A calendar function: `(time, timezone?)` on a UNIX time or on a Series of times. */
|
|
@@ -1709,9 +1779,11 @@ export function inSession(time: number, session: string, timezone?: string): boo
|
|
|
1709
1779
|
/** PineScript `str.*`; `format_time` and the dates of `format` use the exchange time zone by default. */
|
|
1710
1780
|
export const str = {
|
|
1711
1781
|
...strCore,
|
|
1712
|
-
// format.mintick
|
|
1713
|
-
tostring: ((value: unknown, format?: string, mintick?: number) =>
|
|
1714
|
-
|
|
1782
|
+
// format.mintick uses the chart symbol's tick and price scale (syminfo.mintick, syminfo.pricescale)
|
|
1783
|
+
tostring: ((value: unknown, format?: string, mintick?: number, pricescale?: number) =>
|
|
1784
|
+
format === 'mintick' && mintick === undefined
|
|
1785
|
+
? strCore.tostring(value as never, format, syminfo.mintick, pricescale ?? syminfo.pricescale)
|
|
1786
|
+
: strCore.tostring(value as never, format, mintick, pricescale)) as typeof strCore.tostring,
|
|
1715
1787
|
format_time(time: number, format: string = "yyyy-MM-dd'T'HH:mm:ssZ", timezone?: string): string {
|
|
1716
1788
|
return strCore.format_time(time, format, timezone ?? exchangeTimezone());
|
|
1717
1789
|
},
|
|
@@ -1755,7 +1827,10 @@ function sessionBars(): { bars: SessionBars; regular: SessionBars } {
|
|
|
1755
1827
|
* session. As in PineScript, an explicit time zone reads the symbol session hours in that zone without
|
|
1756
1828
|
* corrections and holidays, and an explicit session follows PineScript's session string rules.
|
|
1757
1829
|
*/
|
|
1758
|
-
function calendarFor(
|
|
1830
|
+
function calendarFor(
|
|
1831
|
+
session?: string,
|
|
1832
|
+
timezone?: string
|
|
1833
|
+
): { bars: SessionBars; test: boolean; inside?: (time: number) => boolean } {
|
|
1759
1834
|
const { bars } = sessionBars();
|
|
1760
1835
|
if (!session && !timezone) return { bars, test: false };
|
|
1761
1836
|
const tz = timezone ?? exchangeTimezone();
|
|
@@ -1767,7 +1842,14 @@ function calendarFor(session?: string, timezone?: string): { bars: SessionBars;
|
|
|
1767
1842
|
return { bars: new SessionBars(new TradingCalendar(tz, { session: toSpec(symbol).session }, 'symbol'), bars.chart.period), test: true };
|
|
1768
1843
|
}
|
|
1769
1844
|
const spec = session ? { session } : { session: toSpec(chartCtx.session!).session };
|
|
1770
|
-
return {
|
|
1845
|
+
return {
|
|
1846
|
+
bars: new SessionBars(new TradingCalendar(tz, spec, session ? 'pine' : 'symbol'), bars.chart.period),
|
|
1847
|
+
test: true,
|
|
1848
|
+
// a PineScript session string: the rules of time.inSession (runs ending at 0000, days around a clock change)
|
|
1849
|
+
inside: session
|
|
1850
|
+
? (time) => timeCore.inSession(time, session, tz, timeframeCore.in_seconds(bars.chart.period) * 1000)
|
|
1851
|
+
: undefined,
|
|
1852
|
+
};
|
|
1771
1853
|
}
|
|
1772
1854
|
|
|
1773
1855
|
function perBar(fn: (t: number, i: number, times: number[]) => number): Series {
|
|
@@ -1784,22 +1866,28 @@ function callableSeries<F extends (...args: never[]) => Series>(series: Series,
|
|
|
1784
1866
|
|
|
1785
1867
|
function timeFunction(tf?: string, session?: string, timezone?: string): Series {
|
|
1786
1868
|
collector();
|
|
1787
|
-
const { bars, test } = calendarFor(session, timezone);
|
|
1869
|
+
const { bars, test, inside } = calendarFor(session, timezone);
|
|
1788
1870
|
const timeframeString = tf || chartTimeframe().period;
|
|
1789
|
-
return perBar((t) => (test && !bars.inside(t) ? NaN : bars.timeOf(t, timeframeString)));
|
|
1871
|
+
return perBar((t) => (test && !(inside ? inside(t) : bars.inside(t)) ? NaN : bars.timeOf(t, timeframeString)));
|
|
1790
1872
|
}
|
|
1791
1873
|
|
|
1792
1874
|
function timeCloseFunction(tf?: string, session?: string, timezone?: string): Series {
|
|
1793
1875
|
collector();
|
|
1794
|
-
const { bars, test } = calendarFor(session, timezone);
|
|
1876
|
+
const { bars, test, inside } = calendarFor(session, timezone);
|
|
1795
1877
|
const timeframeString = tf || chartTimeframe().period;
|
|
1796
|
-
return perBar((t) => (test && !bars.inside(t) ? NaN : bars.closeOf(t, timeframeString)));
|
|
1878
|
+
return perBar((t) => (test && !(inside ? inside(t) : bars.inside(t)) ? NaN : bars.closeOf(t, timeframeString)));
|
|
1797
1879
|
}
|
|
1798
1880
|
|
|
1799
1881
|
/**
|
|
1800
1882
|
* PineScript `time`: the bar open time in ms (a Series), and `time(timeframe?, session?, timezone?)`:
|
|
1801
1883
|
* the open time of the `timeframe` period that contains the bar, `na` outside `session`.
|
|
1802
1884
|
*/
|
|
1885
|
+
/** Current time of the run in ms, see `ChartContext.now`. */
|
|
1886
|
+
let runNow = NaN;
|
|
1887
|
+
|
|
1888
|
+
/** PineScript `timenow`: the current time in ms, the same on every bar of a run (`ChartContext.now`). */
|
|
1889
|
+
export const timenow = new Series(ctxBars, () => runNow);
|
|
1890
|
+
|
|
1803
1891
|
export const time = callableSeries(new Series(ctxBars, (b) => barTime(b)), timeFunction);
|
|
1804
1892
|
|
|
1805
1893
|
/**
|
|
@@ -1814,9 +1902,11 @@ export const time_close = callableSeries(
|
|
|
1814
1902
|
/** PineScript `time_tradingday`: 00:00 UTC of the trading day of each bar, in ms. */
|
|
1815
1903
|
export const time_tradingday = new Series(ctxBars, (b) => sessionBars().bars.tradingDayTime(barTime(b)));
|
|
1816
1904
|
|
|
1817
|
-
function changeOf(tf: string): Series {
|
|
1905
|
+
function changeOf(tf: string, firstBar = false): Series {
|
|
1818
1906
|
const { bars } = sessionBars();
|
|
1819
|
-
|
|
1907
|
+
// a bar without a period (after an early close) is no change, and neither is the bar after it
|
|
1908
|
+
const changed = (a: number, b: number): boolean => !Number.isNaN(a) && !Number.isNaN(b) && a !== b;
|
|
1909
|
+
return perBar((t, i, times) => ((i > 0 ? changed(bars.timeOf(t, tf), bars.timeOf(times[i - 1]!, tf)) : firstBar) ? 1 : 0));
|
|
1820
1910
|
}
|
|
1821
1911
|
|
|
1822
1912
|
function flag(key: keyof SessionFlags): Series {
|
|
@@ -2052,6 +2142,14 @@ export const text = { ...textCore };
|
|
|
2052
2142
|
* (index, time, and `price`, default the close), so it runs inside eachBar().
|
|
2053
2143
|
*/
|
|
2054
2144
|
export const chart = {
|
|
2145
|
+
/** Chart foreground colour (PineScript `chart.fg_color`), from the chart context. */
|
|
2146
|
+
get fg_color(): string {
|
|
2147
|
+
return chartText('foregroundColor', 'chart.fg_color');
|
|
2148
|
+
},
|
|
2149
|
+
/** Chart background colour (PineScript `chart.bg_color`), from the chart context. */
|
|
2150
|
+
get bg_color(): string {
|
|
2151
|
+
return chartText('backgroundColor', 'chart.bg_color');
|
|
2152
|
+
},
|
|
2055
2153
|
point: {
|
|
2056
2154
|
...chartPointCore,
|
|
2057
2155
|
now(price?: number): ChartPoint {
|
|
@@ -2115,11 +2213,13 @@ export const math = {
|
|
|
2115
2213
|
}) as typeof mathCore.round_to_mintick,
|
|
2116
2214
|
};
|
|
2117
2215
|
export * as compare from '../compare/index.js';
|
|
2216
|
+
export { isInputActive } from '../runtime/input-active.js';
|
|
2118
2217
|
export type {
|
|
2119
2218
|
Bar,
|
|
2120
2219
|
IndicatorResult,
|
|
2121
2220
|
TimeValue,
|
|
2122
2221
|
InputConfig,
|
|
2222
|
+
InputCondition,
|
|
2123
2223
|
PlotConfig,
|
|
2124
2224
|
HLineConfig,
|
|
2125
2225
|
FillConfig,
|
package/src/session/bars.ts
CHANGED
|
@@ -111,7 +111,10 @@ export class SessionBars {
|
|
|
111
111
|
return p[p.length - 1]![1];
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. An intraday bar that
|
|
116
|
+
* opens after an early close has no day: `time("D")` is NaN on it (measured; `time("W")` keeps its value).
|
|
117
|
+
*/
|
|
115
118
|
timeOf(time: number, timeframe: string): number {
|
|
116
119
|
const tf = info(timeframe);
|
|
117
120
|
const at = this.calendar.locate(time);
|
|
@@ -123,6 +126,7 @@ export class SessionBars {
|
|
|
123
126
|
return start + Math.floor((time - start) / ms) * ms;
|
|
124
127
|
}
|
|
125
128
|
const { unit, n } = unitOf(tf);
|
|
129
|
+
if (unit === 'D' && n === 1 && this.stray(time)) return NaN;
|
|
126
130
|
const [from, to] = this.periodRange(at.date, unit, n);
|
|
127
131
|
const first = this.calendar.firstTradingDay(from, to);
|
|
128
132
|
return first === null ? NaN : this.dayStart(first);
|
|
@@ -140,6 +144,7 @@ export class SessionBars {
|
|
|
140
144
|
return Math.min(this.timeOf(time, timeframe) + in_seconds(tf.period) * 1000, end);
|
|
141
145
|
}
|
|
142
146
|
const { unit, n } = unitOf(tf);
|
|
147
|
+
if (unit === 'D' && n === 1 && this.stray(time)) return NaN;
|
|
143
148
|
const [from, to] = this.periodRange(at.date, unit, n);
|
|
144
149
|
// intraday charts: the start of the next period, except "1D" (the session end)
|
|
145
150
|
if (this.chart.isintraday && (unit !== 'D' || n > 1)) {
|
|
@@ -154,7 +159,7 @@ export class SessionBars {
|
|
|
154
159
|
/** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
|
|
155
160
|
tradingDay(time: number): DateNum | null {
|
|
156
161
|
const at = this.calendar.locate(time);
|
|
157
|
-
if (!at) return null;
|
|
162
|
+
if (!at || this.stray(time)) return null;
|
|
158
163
|
if (this.chart.isdwm) {
|
|
159
164
|
const { unit, n } = unitOf(this.chart);
|
|
160
165
|
const [from, to] = this.periodRange(at.date, unit, n);
|
|
@@ -188,6 +193,35 @@ export class SessionBars {
|
|
|
188
193
|
return day === null ? NaN : dateUtcMs(day);
|
|
189
194
|
}
|
|
190
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Open time of the bar after the bar that opens at `time`, on the trading calendar: the next bar of the session
|
|
198
|
+
* period, else the start of the next period or trading day; on D / W / M charts the session start of the first
|
|
199
|
+
* trading day of the next chart period. NaN when none is found within 400 days.
|
|
200
|
+
*/
|
|
201
|
+
nextBarTime(time: number): number {
|
|
202
|
+
const at = this.calendar.locate(time);
|
|
203
|
+
if (!at) return NaN;
|
|
204
|
+
if (!this.chart.isdwm) {
|
|
205
|
+
const periods = this.calendar.periods(at.date);
|
|
206
|
+
const [start, end] = periods[at.index]!;
|
|
207
|
+
const ms = in_seconds(this.chart.period) * 1000;
|
|
208
|
+
const next = start + (Math.floor((time - start) / ms) + 1) * ms;
|
|
209
|
+
if (at.inside && next < end) return next;
|
|
210
|
+
if (at.index + 1 < periods.length) return periods[at.index + 1]![0];
|
|
211
|
+
const day = this.calendar.firstTradingDay(addDays(at.date, 1), addDays(at.date, 400));
|
|
212
|
+
return day === null ? NaN : this.dayStart(day);
|
|
213
|
+
}
|
|
214
|
+
const { unit, n } = unitOf(this.chart);
|
|
215
|
+
const [, to] = this.periodRange(at.date, unit, n);
|
|
216
|
+
const day = this.calendar.firstTradingDay(addDays(to, 1), addDays(to, 400));
|
|
217
|
+
return day === null ? NaN : this.dayStart(day);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** An intraday bar that opens after an early close of its day (see TradingCalendar.afterEarlyClose). */
|
|
221
|
+
stray(time: number): boolean {
|
|
222
|
+
return !this.chart.isdwm && this.calendar.afterEarlyClose(time);
|
|
223
|
+
}
|
|
224
|
+
|
|
191
225
|
/** True when the bar at `time` is inside the session. */
|
|
192
226
|
inside(time: number): boolean {
|
|
193
227
|
return this.calendar.locate(time)?.inside ?? false;
|
|
@@ -217,6 +251,9 @@ export interface SessionFlags {
|
|
|
217
251
|
* time; first and last bars are per session period (a trading day can have two periods, e.g. after a
|
|
218
252
|
* futures holiday); pre / post market compare with the regular hours of the same trading day; on
|
|
219
253
|
* D / W / M charts every bar is its own session (first, last, market, first and last regular).
|
|
254
|
+
* The first loaded bar is a first bar only when no earlier bar of its period can exist (it opens less than one chart
|
|
255
|
+
* period after the period start). A bar that opens after an early close is in the market hours (the usual hours of
|
|
256
|
+
* its day) but is no last bar.
|
|
220
257
|
*/
|
|
221
258
|
export function sessionFlags(times: number[], bars: SessionBars, regular: SessionBars): SessionFlags {
|
|
222
259
|
const n = times.length;
|
|
@@ -242,18 +279,22 @@ export function sessionFlags(times: number[], bars: SessionBars, regular: Sessio
|
|
|
242
279
|
const close = bars.closeOf(t, chart.period);
|
|
243
280
|
const [, end] = bars.calendar.periods(at.date)[at.index]!;
|
|
244
281
|
const period = `${at.date}/${at.index}`;
|
|
245
|
-
|
|
246
|
-
|
|
282
|
+
const [start] = bars.calendar.periods(at.date)[at.index]!;
|
|
283
|
+
const barMs = in_seconds(chart.period) * 1000;
|
|
284
|
+
// the first loaded bar: a first bar only when no earlier bar of the period can exist
|
|
285
|
+
out.isfirstbar[i] = i === 0 ? t - start < barMs : period !== previousPeriod;
|
|
286
|
+
const stray = bars.stray(t);
|
|
287
|
+
out.islastbar[i] = !stray && close >= end;
|
|
247
288
|
const regularPeriods = regular.calendar.periods(at.date);
|
|
248
289
|
const r = regularPeriods.findIndex(([s, e]) => s <= t && t < e);
|
|
249
290
|
const market = r !== -1;
|
|
250
|
-
out.ismarket[i] = market;
|
|
291
|
+
out.ismarket[i] = market || regular.stray(t);
|
|
251
292
|
if (!market && regularPeriods.length) {
|
|
252
293
|
out.ispremarket[i] = t < regularPeriods[0]![0];
|
|
253
294
|
out.ispostmarket[i] = t >= regularPeriods[regularPeriods.length - 1]![1];
|
|
254
295
|
}
|
|
255
296
|
const regularPeriod = market ? `${at.date}/${r}` : '';
|
|
256
|
-
out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
|
|
297
|
+
out.isfirstbar_regular[i] = market && (i === 0 ? t - regularPeriods[r]![0] < barMs : regularPeriod !== previousRegular);
|
|
257
298
|
out.islastbar_regular[i] = market && close >= regularPeriods[r]![1];
|
|
258
299
|
previousPeriod = period;
|
|
259
300
|
previousRegular = regularPeriod;
|
package/src/session/calendar.ts
CHANGED
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* - periods "HHMM-HHMM", several separated by commas; "24x7" is the whole day, every day
|
|
7
7
|
* - a period whose end is not after its start ("1700-1600", "1700-1700") starts the day before the
|
|
8
8
|
* trading day: the session that opens Sunday 17:00 is Monday's
|
|
9
|
-
* - "HHMMF<n>" moves a time <n> days before the trading day ("1700F2-1200F1")
|
|
9
|
+
* - "HHMMF<n>" moves a time <n> days before the trading day ("1700F2-1200F1"); "F" alone is one day ("1700F-1900":
|
|
10
|
+
* 17:00 of the day before to 19:00)
|
|
11
|
+
* - several sections joined by "|", each with its own days ("1900-1900:3456|1700F-1900:2": Monday opens on Sunday
|
|
12
|
+
* 17:00, the other days at 19:00 of the day before)
|
|
10
13
|
* - optional days after ":" (1 = Sunday ... 7 = Saturday); without days a symbol session trades Monday to
|
|
11
14
|
* Friday ("24x7": every day), and a PineScript session string follows PineScript's rules (one period:
|
|
12
15
|
* every day; several periods: Monday to Friday)
|
|
@@ -62,9 +65,10 @@ export const weekdayOf = (date: DateNum): number => new Date(utcOf(date)).getUTC
|
|
|
62
65
|
export const dateUtcMs = utcOf;
|
|
63
66
|
|
|
64
67
|
function parseTime(token: string, spec: string): { minutes: number; offset?: number } {
|
|
65
|
-
const m = /^(\d{2})(\d{2})(?:F(\d
|
|
68
|
+
const m = /^(\d{2})(\d{2})(?:F(\d*))?$/.exec(token.trim());
|
|
66
69
|
if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
|
|
67
|
-
|
|
70
|
+
// "F" without a number is one day before the trading day
|
|
71
|
+
return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === undefined ? undefined : Number(m[3] || 1) };
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
function parsePeriods(text: string, spec: string): Period[] {
|
|
@@ -102,6 +106,17 @@ function pineVersion(text: string, from: DateNum): Version {
|
|
|
102
106
|
|
|
103
107
|
function parseVersion(text: string, from: DateNum, spec: string, rule: 'symbol' | 'pine'): Version {
|
|
104
108
|
if (rule === 'pine') return pineVersion(text, from);
|
|
109
|
+
if (text.includes('|')) {
|
|
110
|
+
// sections with their own days
|
|
111
|
+
const byDay: Period[][] = Array.from({ length: 8 }, () => []);
|
|
112
|
+
for (const section of text.split('|').filter((part) => part.trim())) {
|
|
113
|
+
const one = parseVersion(section, from, spec, rule);
|
|
114
|
+
one.days.forEach((on, d) => {
|
|
115
|
+
if (on) byDay[d] = one.periods;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return { from, periods: [], days: byDay.map((p) => p.length > 0), byDay };
|
|
119
|
+
}
|
|
105
120
|
const [periodText = '', dayText] = text.trim().split(':');
|
|
106
121
|
const periods = parsePeriods(periodText, spec);
|
|
107
122
|
const allDays = periodText.trim() === '24x7';
|
|
@@ -174,6 +189,25 @@ export class TradingCalendar {
|
|
|
174
189
|
return this.periods(date).length > 0;
|
|
175
190
|
}
|
|
176
191
|
|
|
192
|
+
/**
|
|
193
|
+
* True for a bar that opens after the session of its day was cut by a correction (an early close) but inside the
|
|
194
|
+
* usual hours of that day: PineScript has no period for such a bar (`time("D")` is na on it).
|
|
195
|
+
*/
|
|
196
|
+
afterEarlyClose(time: number): boolean {
|
|
197
|
+
const at = this.locate(time);
|
|
198
|
+
if (!at || at.inside || !this.corrections.get(at.date)) return false;
|
|
199
|
+
const version = [...this.versions].reverse().find((v) => v.from <= at.date)!;
|
|
200
|
+
const usual = version.byDay ? version.byDay[weekdayOf(at.date)]! : version.days[weekdayOf(at.date)] ? version.periods : [];
|
|
201
|
+
const y = Math.floor(at.date / 10000);
|
|
202
|
+
const m = Math.floor(at.date / 100) % 100;
|
|
203
|
+
const d = at.date % 100;
|
|
204
|
+
return usual.some(
|
|
205
|
+
(p) =>
|
|
206
|
+
zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60) <= time &&
|
|
207
|
+
time < zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
177
211
|
/**
|
|
178
212
|
* Trading day and period of a time: the period that contains it, else the last period that started
|
|
179
213
|
* before it. Null when no trading day is found near the time.
|