@iccandle/news 0.0.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/README.md ADDED
@@ -0,0 +1,340 @@
1
+ # @iccandle/news
2
+
3
+ React component that wraps an existing [TradingView Charting Library](https://www.tradingview.com/charting-library-docs/) widget and adds ICCandle's **economic calendar analysis UI**: an interactive panel that displays news events as timescale marks on the chart, draws pip-range visualizations (high/low rectangles, trend lines, pip annotations) around selected events, and lets users compare historical price reactions across similar news releases.
4
+
5
+ Published as ESM and CommonJS; component styles are bundled and injected at runtime (no separate CSS import).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @iccandle/news
11
+ ```
12
+
13
+ ### Prerequisites
14
+
15
+ - **React 18+** — `react` and `react-dom` are **peer dependencies** (install them in your app).
16
+ - **TradingView Charting Library** — obtain it under your own license from TradingView, host the static assets (e.g. under `/charting_library/` in your public folder), and load the library at runtime. **This package does not ship the charting library.**
17
+ - **ICCandle API key** — issued by ICCandle for theme, chart data, news events, and scanner validation.
18
+
19
+ ## Quick start
20
+
21
+ ```tsx
22
+ import { useState } from "react";
23
+ import type { IChartingLibraryWidget } from "charting_library/charting_library";
24
+ import { NewsWidget } from "@iccandle/news-widget";
25
+
26
+ function App() {
27
+ const [chartWidget, setChartWidget] = useState<IChartingLibraryWidget | null>(
28
+ null,
29
+ );
30
+ const widgetKey = "your-iccandle-api-key";
31
+
32
+ return (
33
+ <NewsWidget
34
+ chartWidget={chartWidget}
35
+ widgetKey={widgetKey}
36
+ defaultSymbol="XAU_USD"
37
+ chartInterval="15"
38
+ theme="system"
39
+ >
40
+ {/* Your chart container + TradingView bootstrap; call setChartWidget when ready */}
41
+ <div id="tv_chart_container" style={{ height: "100%" }} />
42
+ </NewsWidget>
43
+ );
44
+ }
45
+ ```
46
+
47
+ Replace the chart placeholder with your TradingView initialization and pass the `IChartingLibraryWidget` instance when `onChartReady` (or equivalent) fires.
48
+
49
+ ## Usage guide
50
+
51
+ ### Step 1 — Install the package
52
+
53
+ ```bash
54
+ npm install @iccandle/news
55
+ ```
56
+
57
+ Ensure `react` and `react-dom` are installed and meet the peer version range.
58
+
59
+ ### Step 2 — Host the Charting Library
60
+
61
+ 1. Copy the TradingView Charting Library build into a path your app can serve as static files (e.g. `public/charting_library/` in Vite or Create React App).
62
+ 2. Import the library constructor from that path in your bundler setup (see TradingView's integration docs for your framework). The library is **not** bundled inside `@iccandle/news-widget`; it loads at runtime via `library_path` (or equivalent) on the widget options.
63
+
64
+ ### Step 3 — Bootstrap TradingView and capture the widget instance
65
+
66
+ Create a ref for the chart DOM node, instantiate the widget in `useEffect`, store the instance in React state, and remove it on cleanup:
67
+
68
+ ```tsx
69
+ import { useEffect, useRef, useState } from "react";
70
+ import type {
71
+ ChartingLibraryWidgetOptions,
72
+ IChartingLibraryWidget,
73
+ ResolutionString,
74
+ } from "charting_library/charting_library";
75
+ import { widget } from "charting_library/charting_library";
76
+
77
+ const LIBRARY_PATH = "/charting_library/"; // must match your hosted assets
78
+
79
+ // Inside your component:
80
+ const containerRef = useRef<HTMLDivElement>(null);
81
+ const [chartWidget, setChartWidget] = useState<IChartingLibraryWidget | null>(
82
+ null,
83
+ );
84
+
85
+ useEffect(
86
+ () => {
87
+ const el = containerRef.current;
88
+ if (!el) return;
89
+
90
+ const options: ChartingLibraryWidgetOptions = {
91
+ container: el,
92
+ library_path: LIBRARY_PATH,
93
+ symbol: "XAU_USD",
94
+ interval: "15" as ResolutionString,
95
+ datafeed: yourDatafeed,
96
+ locale: "en",
97
+ autosize: true,
98
+ };
99
+
100
+ const tv = new widget(options);
101
+ setChartWidget(tv);
102
+
103
+ return () => {
104
+ try {
105
+ tv.remove();
106
+ } catch {
107
+ /* no-op */
108
+ }
109
+ setChartWidget(null);
110
+ };
111
+ },
112
+ [
113
+ /* library_path, datafeed identity, or other inputs that should recreate the chart */
114
+ ],
115
+ );
116
+ ```
117
+
118
+ You must supply a valid `datafeed`, `symbol`, `interval`, `locale`, and any other options required by your TradingView license and app. Import paths for `widget` and types differ by setup (`charting_library/charting_library`, `./public/charting_library`, etc.—follow TradingView's docs for your bundler). If your integration only exposes the instance after `onChartReady`, call `setChartWidget` inside that callback instead of immediately after `new widget(...)`.
119
+
120
+ ### Step 4 — Wrap the chart with `NewsWidget`
121
+
122
+ `NewsWidget` must wrap the same subtree that contains the chart container so the event panel and chart visualizations position correctly. Pass the live widget instance (or `null` while mounting):
123
+
124
+ ```tsx
125
+ import { NewsWidget } from "@iccandle/news-widget";
126
+
127
+ const widgetKey = "your-iccandle-api-key";
128
+
129
+ <NewsWidget
130
+ chartWidget={chartWidget}
131
+ widgetKey={widgetKey}
132
+ defaultSymbol="XAU_USD"
133
+ chartInterval="15"
134
+ theme="system"
135
+ >
136
+ <div ref={containerRef} style={{ height: "100%", minHeight: 400 }} />
137
+ </NewsWidget>;
138
+ ```
139
+
140
+ When a news event is selected, the widget switches to a 50/50 split layout: the event analysis panel on the left and the chart (with pip-range overlays) on the right. On mobile (<1024px) the panels stack vertically.
141
+
142
+ ### Step 5 — Interact with news events
143
+
144
+ Once the widget is mounted:
145
+
146
+ 1. **Economic calendar events** appear as timescale marks on the chart's time axis.
147
+ 2. **Clicking an event** opens the detail panel showing event metadata (actual, forecast, previous values), impact status, and a list of similar historical events.
148
+ 3. **Pip-range visualization** draws automatically on the chart: green rectangles for upside range, red rectangles for downside range, dotted trend lines at highs/lows, and pip annotations at extremes.
149
+ 4. **Candle window** is configurable (10–50 candles) to control how far after the event the range analysis extends.
150
+
151
+ **TypeScript:** import `NewsWidgetProps` if you wrap `NewsWidget` in your own component and want explicit prop typing. Import `IChartingLibraryWidget` from **your** Charting Library typings path (`charting_library/charting_library` or the path your project uses)—this package does not re-export TradingView types.
152
+
153
+ ### Theme and remote branding
154
+
155
+ - **`theme="light"` / `"dark"`** — forces that palette for the widget chrome and chart overlays.
156
+ - **`theme="system"`** (recommended when you don't control parent theme) — follows `prefers-color-scheme` for light/dark resolution.
157
+ - On mount, the widget fetches your org's tokens from ICCandle (see [Widget key and remote theming](#widget-key-and-remote-theming)) and sets CSS custom properties on the widget root, e.g. `--iccandle-primary`, `--iccandle-border`, so the event panel and chart overlays match your configured light/dark branding.
158
+
159
+ ### Full working example
160
+
161
+ Minimal end-to-end pattern: chart container ref, widget lifecycle, `NewsWidget` with event analysis. Replace `yourDatafeed` and widget options with your real datafeed and TradingView settings.
162
+
163
+ ```tsx
164
+ import { useEffect, useRef, useState } from "react";
165
+ import type {
166
+ ChartingLibraryWidgetOptions,
167
+ IChartingLibraryWidget,
168
+ ResolutionString,
169
+ } from "charting_library/charting_library";
170
+ import { widget } from "charting_library/charting_library";
171
+ import { NewsWidget } from "@iccandle/news-widget";
172
+
173
+ const LIBRARY_PATH = "/charting_library/";
174
+ const WIDGET_KEY = "your-iccandle-api-key";
175
+
176
+ export function ChartWithNewsWidget() {
177
+ const containerRef = useRef<HTMLDivElement>(null);
178
+ const [chartWidget, setChartWidget] = useState<IChartingLibraryWidget | null>(
179
+ null,
180
+ );
181
+
182
+ useEffect(() => {
183
+ const el = containerRef.current;
184
+ if (!el) return;
185
+
186
+ const options: ChartingLibraryWidgetOptions = {
187
+ container: el,
188
+ library_path: LIBRARY_PATH,
189
+ symbol: "XAU_USD",
190
+ interval: "15" as ResolutionString,
191
+ datafeed: yourDatafeed,
192
+ locale: "en",
193
+ autosize: true,
194
+ fullscreen: false,
195
+ };
196
+
197
+ const tv = new widget(options);
198
+ setChartWidget(tv);
199
+
200
+ return () => {
201
+ try {
202
+ tv.remove();
203
+ } catch {
204
+ /* no-op */
205
+ }
206
+ setChartWidget(null);
207
+ };
208
+ }, []);
209
+
210
+ return (
211
+ <div style={{ height: 600, width: "100%" }}>
212
+ <NewsWidget
213
+ chartWidget={chartWidget}
214
+ widgetKey={WIDGET_KEY}
215
+ defaultSymbol="XAU_USD"
216
+ chartInterval="15"
217
+ theme="system"
218
+ >
219
+ <div ref={containerRef} style={{ height: "100%", width: "100%" }} />
220
+ </NewsWidget>
221
+ </div>
222
+ );
223
+ }
224
+ ```
225
+
226
+ For a concrete in-repo reference (custom datafeed, timezone, visibility handling), see [`src/tradingview/TradingviewChart.tsx`](src/tradingview/TradingviewChart.tsx) in this repository's dev app.
227
+
228
+ ### Common patterns
229
+
230
+ | Pattern | Approach |
231
+ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
232
+ | **Full-page chart** | Set the parent container to `height: 100vh` and let `NewsWidget` fill the space with `autosize: true`. |
233
+ | **Dashboard embed** | Give the parent a fixed height (e.g. 600px) and `NewsWidget` handles the split layout internally. |
234
+ | **News / events on the time axis** | If your datafeed implements `getTimescaleMarks`, you can sync marks with `localStorage` — see [Optional: timescale marks (news/events)](#optional-timescale-marks-newsevents). |
235
+ | **Custom symbol list** | Pass any supported symbol as `defaultSymbol`; the widget supports 100+ forex, metals, indices, crypto, and commodity symbols. |
236
+
237
+ ### Troubleshooting
238
+
239
+ | Issue | What to check |
240
+ | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
241
+ | Chart area stays blank | `library_path` must point to the folder URL where TradingView static files are served; container ref must be mounted before `new widget(...)`. |
242
+ | `chartWidget` is always `null` | Ensure you call `setChartWidget` after the widget is created (or inside `onChartReady` if your integration requires it). |
243
+ | Event panel or theme looks wrong | Confirm `widgetKey` is valid; theme fetch uses `api-key: <widgetKey>`. Network or auth failures may leave defaults. |
244
+ | CORS / network errors on APIs | In local dev, browser calls to ICCandle APIs may be blocked by CORS unless you proxy; the widget should still function with fallback styling—verify in production or behind your proxy. |
245
+ | No events showing on chart | The widget falls back to `XAU_USD` if `defaultSymbol` is unrecognized, but ensure `chartInterval` is one of the accepted values (`"1"`, `"5"`, `"15"`, `"30"`, `"60"`). |
246
+
247
+ ## API
248
+
249
+ ### Exports
250
+
251
+ | Name | Kind | Description |
252
+ | ----------------- | --------- | ------------------------------------------------- |
253
+ | `NewsWidget` | Component | Economic calendar analysis overlay for your chart |
254
+ | `NewsWidgetProps` | Type | Props for `NewsWidget` |
255
+
256
+ ### `NewsWidget` props
257
+
258
+ | Prop | Type | Required | Description |
259
+ | --------------- | ------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------- |
260
+ | `chartWidget` | `IChartingLibraryWidget \| null` | Yes | Live TradingView widget instance (`null` until ready). |
261
+ | `children` | `ReactNode` | Yes | Your chart UI (e.g. container + library bootstrap). |
262
+ | `widgetKey` | `string` | Yes | ICCandle API key. Used for theme fetch, chart data, news events, and scanner validation. |
263
+ | `defaultSymbol` | `string` | Yes | Default trading symbol (e.g. `"XAU_USD"`, `"EURUSD"`, `"BTCUSDT"`). Falls back to `"XAU_USD"` if the symbol is unrecognized or unavailable. |
264
+ | `chartInterval` | `"1" \| "5" \| "15" \| "30" \| "60"` | Yes | Chart candle interval in minutes. Defaults to `"15"`. |
265
+ | `theme` | `"light" \| "dark" \| "system"` | No | Defaults to sensible behavior; `"system"` follows `prefers-color-scheme`. Affects resolved theme tokens and chart overlays. |
266
+
267
+ ### Widget key and remote theming
268
+
269
+ On mount, the component loads branding colors from ICCandle:
270
+
271
+ - **URL:** `https://api.iccandle.ai/corporate-client/v1/widgetStyle/search/user/?service_type=search`
272
+ - **Header:** `api-key: <widgetKey>`
273
+
274
+ CSS custom properties (`--iccandle-primary`, `--iccandle-border`, `--iccandle-background`, `--iccandle-text`, etc.) are applied on the widget root so the event panel and chart overlays match your configured light/dark tokens.
275
+
276
+ **Theme prop vs. API tokens:** The `theme` prop (`"light"` | `"dark"` | `"system"`) chooses which variant of those tokens to apply. `"system"` tracks `prefers-color-scheme` so the widget stays aligned with the user's OS preference when you don't pass an explicit light/dark mode from your app shell.
277
+
278
+ ### Behavior summary
279
+
280
+ - Subscribes to chart readiness, resolution, symbol changes, and drawing events.
281
+ - Displays economic calendar events as interactive timescale marks on the chart.
282
+ - On event selection, switches to a split layout with an event detail panel and pip-range chart visualization.
283
+ - Draws pip-range rectangles (green for upside, red for downside), dotted trend lines, and pip annotations on the chart.
284
+ - Fetches similar historical events for comparison and shows event metadata (actual, forecast, previous values).
285
+ - Supports configurable candle windows (10–50 candles) for range analysis.
286
+ - Stores selected events in `localStorage` (key `iccandle:current-news-event`) for timescale mark sync.
287
+ - Listens for `window` `message` events for chart/news integration.
288
+
289
+ ## Optional: timescale marks (news/events)
290
+
291
+ If your data feed implements `getTimescaleMarks`, you can surface stored events (e.g. from `localStorage` under `tv:current-news-event`) as marks on the time axis. Example shape:
292
+
293
+ ```ts
294
+ getTimescaleMarks: async (
295
+ symbolInfo: LibrarySymbolInfo,
296
+ from: number,
297
+ to: number,
298
+ onResult: GetMarksCallback<TimescaleMark>,
299
+ ) => {
300
+ const marks: TimescaleMark[] = [];
301
+
302
+ //...your code here
303
+
304
+ try {
305
+ const currentNewsEvent = JSON.parse(
306
+ localStorage.getItem("iccandle:current-news-event") || "{}",
307
+ ) as NewsEventType;
308
+
309
+ const { id, timestamp, event_name, currency, forecast, previous, actual } =
310
+ currentNewsEvent;
311
+
312
+ if (!id || !Number.isFinite(timestamp) || timestamp <= 0) return;
313
+ const hasAlready = marks.some((m) => String(m.id) === String(id));
314
+ if (hasAlready) return;
315
+
316
+ marks.push({
317
+ id: id,
318
+ time: timestamp / 1000,
319
+ color: "green",
320
+ label: event_name.slice(0, 1),
321
+ tooltip: [
322
+ event_name,
323
+ `Current Forecast: ${forecast || "-"}`,
324
+ `Previous Forecast: ${previous || "-"}`,
325
+ `Previous Actual: ${actual || "-"}`,
326
+ ],
327
+ ...(currency ? { imageUrl: `/images/symbols/${currency}.svg` } : {}),
328
+ });
329
+ } catch {
330
+ // no-op
331
+ }
332
+ onResult(marks);
333
+ };
334
+ ```
335
+
336
+ Adjust paths and types to match your app and TradingView typings.
337
+
338
+ ## License
339
+
340
+ MIT. TradingView Charting Library is subject to its own license from TradingView.