wickchart 1.0.0 → 1.2.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/types/core.d.ts CHANGED
@@ -585,6 +585,28 @@ export declare function checkAlertCross(alert: {
585
585
  price: number;
586
586
  direction?: 'above' | 'below' | 'cross';
587
587
  }, prevPrice: number, price: number): boolean;
588
+ /**
589
+ * Boolean truth series for a WickScript predicate: any numeric expression
590
+ * where nonzero & finite counts as true (NaN / 0 / ±Infinity → false).
591
+ * Powers scripted alerts — `addAlert({ when: 'crossup(close, sma(close,50))' })`.
592
+ * @param {object|string} compiled compiled predicate (or raw source)
593
+ * @param {Bar[]} bars
594
+ * @returns {boolean[]}
595
+ */
596
+ export declare function predicateTrueSeries(compiled: object | string, bars: Bar[]): boolean[];
597
+ /**
598
+ * Edge-triggered step for a scripted alert. `armed` starts true; a rising
599
+ * edge (false → true) fires once and disarms; a true → false transition
600
+ * re-arms, so `once: false` alerts can fire again on the next edge while
601
+ * `once: true` alerts are removed after their first fire.
602
+ * @param {boolean} armed
603
+ * @param {boolean} curTrue
604
+ * @returns {{ fire: boolean, armed: boolean }}
605
+ */
606
+ export declare function scriptAlertStep(armed: boolean, curTrue: boolean): {
607
+ fire: boolean;
608
+ armed: boolean;
609
+ };
588
610
  /**
589
611
  * Statistics over a visible slice of bars.
590
612
  * @param {Bar[]} bars
@@ -648,6 +670,83 @@ export declare function parseVolShading(val: string | null | undefined): {
648
670
  p2: number;
649
671
  period: number;
650
672
  };
673
+ /**
674
+ * Index of the last bar whose time is <= `t` (binary search). Clamps to
675
+ * [0, n-1]: a time before the first bar → 0, past the last bar → n-1.
676
+ * Empty bars or a non-numeric time → null.
677
+ * @param {object[]} bars normalized bar objects
678
+ * @param {number} t timestamp in ms or s
679
+ * @returns {number|null}
680
+ */
681
+ export declare function barIndexForTime(bars: object[], t: number): number | null;
682
+ /**
683
+ * Validate & normalize server-side overlay definitions. Overlays are data
684
+ * from an API, so invalid entries are silently dropped — never thrown.
685
+ *
686
+ * zone: { type:'zone', from?: time|null, to?: time|null, priceFrom, priceTo,
687
+ * color?, alpha?, border?, label?, id? } — a time×price rectangle.
688
+ * `from`/`to` omitted (or null) anchor to the left/right chart edge;
689
+ * a zone with no `to` extends into future space past the last bar.
690
+ * level: { type:'level', price, from?, to?, color?, width?, dash?, label?, id? }
691
+ * — a horizontal price line, full width by default.
692
+ *
693
+ * Colors go through safeColor(); `alpha` clamps to [0.02, 0.8] (default 0.22).
694
+ * @param {any} list
695
+ * @returns {object[]} normalized overlays (possibly empty)
696
+ */
697
+ export declare function normalizeOverlays(list: any): object[];
698
+ /**
699
+ * Resolve an overlay color against the active palette: 'up'/'down'/'accent'
700
+ * map to theme colors, anything else passes through safeColor(), and invalid
701
+ * or missing values fall back to the accent color.
702
+ * @param {any} raw
703
+ * @param {object} pal active theme palette
704
+ * @returns {string} a concrete CSS color
705
+ */
706
+ export declare function resolveOverlayColor(raw: any, pal: object): string;
707
+ /**
708
+ * σ-cone projection from realized per-bar volatility: price bands widening
709
+ * with √h (GBM-style, exp(±z·σ·√h)) over `horizon` future bars.
710
+ * @param {number} lastClose anchor price (bar 0)
711
+ * @param {number} volPerBar per-bar stddev of log returns (from calcRealizedVol)
712
+ * @param {number} horizon future bars (clamped 1–500, default 48)
713
+ * @param {number[]} [levels] σ multipliers, e.g. [1, 2] (each clamped to 0–5)
714
+ * @returns {{horizon: number, levels: number[], bands: Record<string, {up: number[], down: number[]}>}}
715
+ * bands[z].up/.down are arrays indexed by h = 0…horizon ([0] === lastClose)
716
+ */
717
+ export declare function calcVolCone(lastClose: number, volPerBar: number, horizon: number, levels?: number[]): {
718
+ horizon: number;
719
+ levels: number[];
720
+ bands: Record<string, {
721
+ up: number[];
722
+ down: number[];
723
+ }>;
724
+ };
725
+ /**
726
+ * Validate a scenario spec: a ghost path of future prices (bars or API data)
727
+ * plus optional cone settings. Invalid entries are dropped, never thrown.
728
+ *
729
+ * { path: [64000, 65500, {price: 68000}], // future bars 1..N
730
+ * horizon: 48, // alternative/additional: cone-only projection
731
+ * cone: true, // σ-bands from realized vol (default true)
732
+ * levels: [1, 2], // σ multipliers (default [1, 2])
733
+ * color?, label? } // palette keys up|down|accent or safe CSS colors
734
+ *
735
+ * @param {any} spec
736
+ * @returns {null|{path: {h:number, price:number}[], horizon: number,
737
+ * cone: boolean, levels: number[], color: string|null, label: string}}
738
+ */
739
+ export declare function normalizeScenario(spec: any): null | {
740
+ path: {
741
+ h: number;
742
+ price: number;
743
+ }[];
744
+ horizon: number;
745
+ cone: boolean;
746
+ levels: number[];
747
+ color: string | null;
748
+ label: string;
749
+ };
651
750
  export declare const tfLabelOf: (dtMs: any) => string;
652
751
  /**
653
752
  * Compact, LLM-friendly summary of a bar window: structured fields plus a
@@ -677,3 +776,110 @@ export declare function encodeStateQuery(state: ChartState | null): string;
677
776
  * @returns {ChartState}
678
777
  */
679
778
  export declare function decodeStateQuery(str: string): ChartState;
779
+ /**
780
+ * Tool manifest for LLM/agent control of a chart. Tools map 1:1 onto the
781
+ * public element API; every op through applyChartOps is validated before it
782
+ * touches the chart (LLM output is untrusted input).
783
+ */
784
+ export declare const AI_TOOLS: ({
785
+ tool: string;
786
+ description: string;
787
+ args: {
788
+ indicators?: undefined;
789
+ overlays?: undefined;
790
+ from?: undefined;
791
+ to?: undefined;
792
+ type?: undefined;
793
+ enabled?: undefined;
794
+ low?: undefined;
795
+ high?: undefined;
796
+ };
797
+ } | {
798
+ tool: string;
799
+ description: string;
800
+ args: {
801
+ indicators: string;
802
+ overlays?: undefined;
803
+ from?: undefined;
804
+ to?: undefined;
805
+ type?: undefined;
806
+ enabled?: undefined;
807
+ low?: undefined;
808
+ high?: undefined;
809
+ };
810
+ } | {
811
+ tool: string;
812
+ description: string;
813
+ args: {
814
+ indicators?: undefined;
815
+ overlays: string;
816
+ from?: undefined;
817
+ to?: undefined;
818
+ type?: undefined;
819
+ enabled?: undefined;
820
+ low?: undefined;
821
+ high?: undefined;
822
+ };
823
+ } | {
824
+ tool: string;
825
+ description: string;
826
+ args: {
827
+ indicators?: undefined;
828
+ overlays?: undefined;
829
+ from: string;
830
+ to: string;
831
+ type?: undefined;
832
+ enabled?: undefined;
833
+ low?: undefined;
834
+ high?: undefined;
835
+ };
836
+ } | {
837
+ tool: string;
838
+ description: string;
839
+ args: {
840
+ indicators?: undefined;
841
+ overlays?: undefined;
842
+ from?: undefined;
843
+ to?: undefined;
844
+ type: string;
845
+ enabled?: undefined;
846
+ low?: undefined;
847
+ high?: undefined;
848
+ };
849
+ } | {
850
+ tool: string;
851
+ description: string;
852
+ args: {
853
+ indicators?: undefined;
854
+ overlays?: undefined;
855
+ from?: undefined;
856
+ to?: undefined;
857
+ type?: undefined;
858
+ enabled: string;
859
+ low: string;
860
+ high: string;
861
+ };
862
+ })[];
863
+ /**
864
+ * Compact system prompt for agent control: paste into any LLM alongside the
865
+ * tool manifest. The model answers with a JSON array of {tool, args} ops.
866
+ * @returns {string}
867
+ */
868
+ export declare function aiPromptText(): string;
869
+ /**
870
+ * Validate + apply a list of {tool, args} ops (typically LLM output) to a
871
+ * chart-like target. Ops are whitelisted and their args validated — an op
872
+ * never throws; it returns {ok: false, error} instead so the agent can
873
+ * self-correct. Target contract: getDataWindow(), setAttribute(k, v),
874
+ * setOverlays(list), clearOverlays(), addAlert(a), setVisibleRange(r),
875
+ * fit(), and (static) _registry() for indicator name checks.
876
+ * @param {object} target chart element (or test double)
877
+ * @param {any} ops
878
+ * @returns {Array<{ok: boolean, tool?: string, result?: any, error?: string}>}
879
+ */
880
+ export declare function applyChartOps(target: object, ops: any): Array<{
881
+ ok: boolean;
882
+ tool?: string;
883
+ result?: any;
884
+ error?: string;
885
+ }>;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Map an event shorthand to the dispatched event name.
3
+ * "range" / "wick:range" → "wick:range" (the 0.x "hab:" prefix is no longer emitted).
4
+ * @param {string} name
5
+ * @returns {string}
6
+ */
7
+ export declare const toWickEventName: (name: string) => string;
8
+ /**
9
+ * camelCase prop name → kebab-case attribute name ("volShading" → "vol-shading").
10
+ * @param {string} key
11
+ * @returns {string}
12
+ */
13
+ export declare const toAttrName: (key: string) => string;
14
+ /**
15
+ * Split React props into chart attrs / event handlers / DOM passthrough /
16
+ * the data array / the overlays array.
17
+ * @param {object} props
18
+ * @returns {{ attrs: object, events: Record<string, Function>, dom: object, data: any, overlays: any }}
19
+ */
20
+ export declare function splitChartProps(props: object): {
21
+ attrs: object;
22
+ events: Record<string, Function>;
23
+ dom: object;
24
+ data: any;
25
+ overlays: any;
26
+ };
27
+ /**
28
+ * Apply split props to a chart element. Every write is guarded so re-running
29
+ * with identical values is a no-op (attributes compared as strings, `data`
30
+ * and `overlays` compared by identity — passing a fresh array is what
31
+ * triggers a redraw).
32
+ * @param {HTMLElement} el
33
+ * @param {{ attrs?: object, data?: any, overlays?: any }} split
34
+ */
35
+ export declare function applyChartProps(el: HTMLElement, split: {
36
+ attrs?: object;
37
+ data?: any;
38
+ overlays?: any;
39
+ }): void;
40
+ /**
41
+ * Full control hook: renders nothing — attach the returned ref to your own
42
+ * <wick-chart> element and pass the same options you would give the component.
43
+ *
44
+ * const { ref, chart } = useWickChart({ data: bars, indicators: 'sma:20', onRange });
45
+ * return <wick-chart ref={ref} style={{ height: 420 }} />;
46
+ * // chart.getDataWindow() etc. once mounted
47
+ *
48
+ * @param {object} [options] any <wick-chart> attribute, plus `data`, `events`
49
+ * and `onXxx`-style handlers (see splitChartProps).
50
+ * @returns {{ ref: (node: any) => void, chart: any }} `chart` is the element
51
+ * instance (or null before mount) for the imperative API.
52
+ */
53
+ export declare function useWickChart(options?: object): {
54
+ ref: (node: any) => void;
55
+ chart: any;
56
+ };
57
+ /**
58
+ * Drop-in React component for <wick-chart>. Attributes ride through
59
+ * createElement (so they exist at first paint and in SSR output) while the
60
+ * hook keeps them in sync on updates; `data` and event handlers never touch
61
+ * React's prop pipeline. Works the same on React 16.8 → 19.
62
+ */
63
+ export declare const WickChart: import("react").ForwardRefExoticComponent<import("react").RefAttributes<any>>;
64
+ export default WickChart;
@@ -0,0 +1,3 @@
1
+ import './wick-chart.js';
2
+ export { WickChart, useWickChart, splitChartProps, applyChartProps, toWickEventName, toAttrName, } from './react-core.js';
3
+ export { default } from './react-core.js';
@@ -142,6 +142,18 @@ declare class WickChart extends HTMLElementBase {
142
142
  _positions: any[];
143
143
  _alerts: any[];
144
144
  _seq: number;
145
+ _overlays: any[];
146
+ _scenario: {
147
+ path: {
148
+ h: number;
149
+ price: number;
150
+ }[];
151
+ horizon: number;
152
+ cone: boolean;
153
+ levels: number[];
154
+ color: string | null;
155
+ label: string;
156
+ };
145
157
  _onResize: () => void;
146
158
  _onPointerDown: (e: any) => void;
147
159
  _onPointerMove: (e: any) => void;
@@ -349,23 +361,128 @@ declare class WickChart extends HTMLElementBase {
349
361
  removePosition(id: any): void;
350
362
  clearPositions(): void;
351
363
  /**
352
- * Price alert. Fires `wick:alert` ({id, price, bar}) on an edge crossing
353
- * (plus the deprecated `hab:alert` alias)
354
- * during streaming updates.
355
- * @param {{id?: string, price: number, direction?: 'above'|'below'|'cross',
356
- * once?: boolean}} alert
357
- * @returns {string|null} the alert id
364
+ * Price or scripted alert. Price alerts fire `wick:alert`
365
+ * ({id, price, bar}) on an edge crossing; scripted alerts evaluate a
366
+ * WickScript predicate (`when`) on every streamed bar and fire on its
367
+ * false→true edge e.g. `when: 'crossup(rsi(close,14), 30)'` or
368
+ * `when: 'volume > sma(volume,20) * 3'`. Scripted events carry the
369
+ * triggering close as `price` plus the `when` source (deprecated
370
+ * `hab:alert` alias still dispatched).
371
+ * @param {{id?: string, price?: number, direction?: 'above'|'below'|'cross',
372
+ * when?: string, once?: boolean}} alert
373
+ * @returns {string|null} the alert id (null when no valid price/when,
374
+ * or the predicate fails to compile)
358
375
  */
359
376
  addAlert(alert: {
360
377
  id?: string;
361
- price: number;
378
+ price?: number;
362
379
  direction?: 'above' | 'below' | 'cross';
380
+ when?: string;
363
381
  once?: boolean;
364
382
  }): string | null;
365
383
  removeAlert(id: any): void;
366
384
  clearAlerts(): void;
367
- /** Check alerts against an incoming bar (prev close → new close). */
385
+ /**
386
+ * Server-side overlays: zones & levels anchored in time × price — e.g.
387
+ * supply/demand zones from an analysis API. Zones with no `to` extend
388
+ * into future space past the last bar, like TradingView drawings.
389
+ *
390
+ * zone: { type:'zone', from?:ms, to?:ms|null, priceFrom, priceTo,
391
+ * color?, alpha?, border?, label?, id? }
392
+ * level: { type:'level', price, from?, to?, color?, width?, dash?,
393
+ * label?, id? }
394
+ *
395
+ * Invalid entries are dropped, never thrown. Colors accept hex/rgb()/CSS
396
+ * names plus the palette keys 'up' | 'down' | 'accent'.
397
+ * @param {object[]} list
398
+ * @returns {string[]} applied overlay ids
399
+ */
400
+ setOverlays(list: object[]): string[];
401
+ /** @returns {object[]} a copy of the current overlays */
402
+ get overlays(): object[];
403
+ /**
404
+ * Add or replace (upsert, by id) a single overlay.
405
+ * @returns {string|null} the overlay id, or null if invalid
406
+ */
407
+ addOverlay(ov: any): string | null;
408
+ removeOverlay(id: any): void;
409
+ clearOverlays(): void;
410
+ /**
411
+ * Scenario projection into future space: a ghost path of future prices
412
+ * plus optional σ-bands (vol cone) from realized volatility.
413
+ *
414
+ * chart.setScenario({ path: [64000, 65500, 68000], label: 'bull case' });
415
+ * chart.setScenario({ horizon: 48, cone: true }); // cone-only
416
+ *
417
+ * The path is an array of prices (or {price} objects) for future bars
418
+ * 1..N; horizon defaults to the path length (1–500). `cone` (default
419
+ * true) draws ±levels·σ bands widening with √h from the current realized
420
+ * vol; `color` accepts up|down|accent or safe CSS colors. Setting a
421
+ * scenario reserves future space on the right; analysis data — excluded
422
+ * from getState/setState.
423
+ * @param {object} spec
424
+ * @returns {object|null} the normalized scenario, or null when invalid
425
+ */
426
+ setScenario(spec: object): object | null;
427
+ clearScenario(): void;
428
+ /** @returns {object|null} a copy of the active scenario */
429
+ get scenario(): object | null;
430
+ /** σ-cone for the active scenario, cached per data version. */
431
+ _scenarioConeCache(): any;
432
+ /** Tool manifest for LLM control — JSON-safe copy of AI_TOOLS. */
433
+ aiTools(): any;
434
+ /** System prompt for agent control — paste into any LLM alongside aiTools(). */
435
+ aiPrompt(): string;
436
+ /** Grounding context for a model: current state + visible-window summary. */
437
+ aiContext(): {
438
+ state: import("./core.js").ChartState;
439
+ window: object;
440
+ };
441
+ /**
442
+ * Apply a list of {tool, args} ops (typically LLM output) through the
443
+ * validated dispatcher in core. Never throws — each op resolves
444
+ * {ok, tool, result} or {ok: false, tool, error} so an agent can
445
+ * self-correct.
446
+ * @param {any} ops
447
+ * @returns {Array<object>}
448
+ */
449
+ applyAI(ops: any): Array<object>;
450
+ /**
451
+ * Ask an AI to operate the chart. Builds the payload {system,
452
+ * instruction, chart, tools}; with a `run` async function (your model
453
+ * call — the chart itself never touches the network), applies the
454
+ * returned ops and resolves {payload, ops, results}. Without `run`,
455
+ * returns the payload for manual wiring — send it anywhere, then call
456
+ * chart.applyAI(ops) with the model's answer.
457
+ *
458
+ * const { results } = await chart.ask('add RSI and mark the demand zone', {
459
+ * run: async (payload) => (await callMyLLM(payload)).ops,
460
+ * });
461
+ *
462
+ * @param {string} instruction natural-language request
463
+ * @param {{run?: (payload: object) => Promise<any>}} [opts]
464
+ */
465
+ ask(instruction: string, opts?: {
466
+ run?: (payload: object) => Promise<any>;
467
+ }): Promise<{
468
+ payload: {
469
+ system: string;
470
+ instruction: string;
471
+ chart: {
472
+ state: import("./core.js").ChartState;
473
+ window: object;
474
+ };
475
+ tools: any;
476
+ };
477
+ ops: any;
478
+ results: object[];
479
+ }>;
480
+ /** Check alerts against an incoming bar (prev close → new close).
481
+ * Scripted (`when`) alerts evaluate their predicate series, cached per
482
+ * data version, and fire on the false→true edge. */
368
483
  _checkAlerts(prevClose: any, bar: any): void;
484
+ /** Cached boolean series for a scripted alert's predicate (per data version). */
485
+ _predicateCache(alert: any): any;
369
486
  get theme(): string;
370
487
  set theme(v: string);
371
488
  get type(): string;