sqlite-hub 0.12.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +118 -23
  2. package/bin/sqlite-hub.js +1041 -224
  3. package/frontend/index.html +1 -0
  4. package/frontend/js/api.js +32 -2
  5. package/frontend/js/app.js +989 -13
  6. package/frontend/js/components/modal.js +644 -15
  7. package/frontend/js/components/pageHeader.js +14 -16
  8. package/frontend/js/components/queryEditor.js +9 -1
  9. package/frontend/js/components/queryHistoryPanel.js +126 -131
  10. package/frontend/js/components/queryResults.js +79 -17
  11. package/frontend/js/components/rowEditorPanel.js +204 -10
  12. package/frontend/js/components/sidebar.js +102 -18
  13. package/frontend/js/components/tableDesignerEditor.js +69 -11
  14. package/frontend/js/router.js +8 -0
  15. package/frontend/js/store.js +868 -9
  16. package/frontend/js/utils/copyColumnExport.js +117 -0
  17. package/frontend/js/utils/exportFilenames.js +32 -0
  18. package/frontend/js/utils/filePathPreview.js +315 -0
  19. package/frontend/js/utils/format.js +1 -1
  20. package/frontend/js/utils/markdownDocuments.js +248 -0
  21. package/frontend/js/utils/rowEditorJson.js +65 -0
  22. package/frontend/js/utils/sqlFormatter.js +691 -0
  23. package/frontend/js/utils/tableDesigner.js +178 -6
  24. package/frontend/js/utils/textCellStats.js +20 -0
  25. package/frontend/js/utils/timestampPreview.js +264 -0
  26. package/frontend/js/views/charts.js +3 -1
  27. package/frontend/js/views/data.js +34 -2
  28. package/frontend/js/views/documents.js +300 -0
  29. package/frontend/js/views/editor.js +48 -1
  30. package/frontend/js/views/settings.js +39 -6
  31. package/frontend/js/views/structure.js +154 -212
  32. package/frontend/styles/base.css +6 -0
  33. package/frontend/styles/components.css +476 -2
  34. package/frontend/styles/structure-graph.css +0 -3
  35. package/frontend/styles/tailwind.generated.css +1 -1
  36. package/frontend/styles/tokens.css +1 -1
  37. package/frontend/styles/views.css +422 -0
  38. package/package.json +3 -3
  39. package/server/routes/documents.js +163 -0
  40. package/server/routes/settings.js +22 -6
  41. package/server/server.js +6 -0
  42. package/server/services/sqlite/introspection.js +10 -0
  43. package/server/services/sqlite/sqlExecutor.js +29 -0
  44. package/server/services/sqlite/tableDesigner/changeAnalysis.js +25 -1
  45. package/server/services/sqlite/tableDesigner/schemaMapping.js +105 -10
  46. package/server/services/sqlite/tableDesigner/validation.js +60 -2
  47. package/server/services/sqlite/tableDesignerService.js +1 -1
  48. package/server/services/storage/appStateStore.js +313 -0
  49. package/tests/check-constraint-options.test.js +14 -0
  50. package/tests/cli-args.test.js +100 -0
  51. package/tests/copy-column-modal.test.js +83 -0
  52. package/tests/database-documents.test.js +85 -0
  53. package/tests/export-filenames.test.js +34 -0
  54. package/tests/file-path-preview.test.js +165 -0
  55. package/tests/markdown-documents.test.js +79 -0
  56. package/tests/row-editor-json.test.js +82 -0
  57. package/tests/row-editor-timestamp-preview.test.js +192 -0
  58. package/tests/settings-metadata.test.js +16 -0
  59. package/tests/settings-view.test.js +32 -0
  60. package/tests/sql-formatter.test.js +173 -0
  61. package/tests/sql-highlight.test.js +38 -0
  62. package/tests/table-designer-v2-unique-constraints.test.js +78 -0
  63. package/tests/text-cell-stats.test.js +38 -0
  64. package/fill.js +0 -526
package/fill.js DELETED
@@ -1,526 +0,0 @@
1
- import Database from 'better-sqlite3';
2
-
3
- const DB_PATH = '/Users/oli/database/project_trump/trump.sqlite';
4
- const POLYGON_API_KEY = 'j6q5v6iWfVGettyfUxMllrfqg9E9iweT';
5
- const LIMIT = 1;
6
- const CALLS_PER_WINDOW = 5;
7
- const RATE_LIMIT_SLEEP_MS = 61_000;
8
-
9
- if (!POLYGON_API_KEY) {
10
- throw new Error(
11
- "POLYGON_API_KEY fehlt. Starte z.B. mit: POLYGON_API_KEY='dein_key' DB_PATH='./deine-db.sqlite' node fill-mention-impact-prices-all.mjs",
12
- );
13
- }
14
-
15
- const db = new Database(DB_PATH);
16
-
17
- let polygonCallCounter = 0;
18
- const polygonCache = new Map();
19
-
20
- function sleep(ms) {
21
- return new Promise(resolve => setTimeout(resolve, ms));
22
- }
23
-
24
- function normalizeUnixSeconds(value) {
25
- if (value == null) return null;
26
-
27
- const raw = String(value).trim();
28
-
29
- // Format: YYYYMMDD, z.B. 20250121
30
- // Da wir keine genaue Uhrzeit haben, nehmen wir US-Markteröffnung 09:30 New York.
31
- // Für Januar ist das 14:30 UTC. Für einen ersten Lauf reicht das.
32
- if (/^\d{8}$/.test(raw)) {
33
- const year = Number(raw.slice(0, 4));
34
- const month = Number(raw.slice(4, 6));
35
- const day = Number(raw.slice(6, 8));
36
-
37
- return Math.floor(Date.UTC(year, month - 1, day, 14, 30, 0) / 1000);
38
- }
39
-
40
- // Format: YYYY-MM-DD
41
- if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
42
- const [year, month, day] = raw.split('-').map(Number);
43
-
44
- return Math.floor(Date.UTC(year, month - 1, day, 14, 30, 0) / 1000);
45
- }
46
-
47
- const n = Number(value);
48
- if (!Number.isFinite(n)) return null;
49
-
50
- // Millisekunden-Timestamp
51
- if (n > 1_000_000_000_000) {
52
- return Math.floor(n / 1000);
53
- }
54
-
55
- // Unix-Sekunden
56
- return Math.floor(n);
57
- }
58
-
59
- function dateStringFromUnixSeconds(unixSeconds, offsetDays = 0) {
60
- const ms = unixSeconds * 1000 + offsetDays * 24 * 60 * 60 * 1000;
61
- return new Date(ms).toISOString().slice(0, 10);
62
- }
63
-
64
- function etDateKey(ms) {
65
- const parts = new Intl.DateTimeFormat('en-CA', {
66
- timeZone: 'America/New_York',
67
- year: 'numeric',
68
- month: '2-digit',
69
- day: '2-digit',
70
- }).formatToParts(new Date(ms));
71
-
72
- const map = Object.fromEntries(parts.map(p => [p.type, p.value]));
73
- return `${map.year}-${map.month}-${map.day}`;
74
- }
75
-
76
- function normalizePolygonSymbol(symbol) {
77
- if (!symbol) return null;
78
-
79
- const clean = String(symbol).trim();
80
-
81
- const map = {
82
- '^IXIC': 'I:COMP',
83
- '^GSPC': 'I:SPX',
84
- '^DJI': 'I:DJI',
85
- '^NDX': 'I:NDX',
86
- };
87
-
88
- return map[clean] || clean;
89
- }
90
-
91
- async function waitIfRateLimitWindowHit() {
92
- if (polygonCallCounter > 0 && polygonCallCounter % CALLS_PER_WINDOW === 0) {
93
- console.log(`Rate-Limit-Pause nach ${polygonCallCounter} Polygon-Calls: ${RATE_LIMIT_SLEEP_MS / 1000}s`);
94
- await sleep(RATE_LIMIT_SLEEP_MS);
95
- }
96
- }
97
-
98
- async function fetchPolygonJson(url, label) {
99
- polygonCallCounter += 1;
100
-
101
- console.log(`Polygon call #${polygonCallCounter}: ${label}`);
102
-
103
- const res = await fetch(url);
104
- const text = await res.text();
105
-
106
- await waitIfRateLimitWindowHit();
107
-
108
- if (res.status === 429) {
109
- console.warn('Polygon 429 Rate Limit. Warte 61 Sekunden und versuche es nochmal...');
110
- await sleep(RATE_LIMIT_SLEEP_MS);
111
- return fetchPolygonJson(url, `${label} retry`);
112
- }
113
-
114
- if (!res.ok) {
115
- throw new Error(`Polygon HTTP ${res.status}: ${text.slice(0, 500)}`);
116
- }
117
-
118
- let json;
119
-
120
- try {
121
- json = JSON.parse(text);
122
- } catch {
123
- throw new Error(`Polygon response ist kein JSON: ${text.slice(0, 500)}`);
124
- }
125
-
126
- if (json.status === 'ERROR') {
127
- throw new Error(`Polygon ERROR: ${json.error || JSON.stringify(json).slice(0, 500)}`);
128
- }
129
-
130
- return json;
131
- }
132
-
133
- async function polygonAggs(symbol, multiplier, timespan, from, to) {
134
- const polygonSymbol = normalizePolygonSymbol(symbol);
135
-
136
- if (!polygonSymbol) {
137
- throw new Error('Kein Symbol vorhanden.');
138
- }
139
-
140
- const cacheKey = [polygonSymbol, multiplier, timespan, from, to].join('|');
141
-
142
- if (polygonCache.has(cacheKey)) {
143
- console.log(`Cache hit: ${cacheKey}`);
144
- return polygonCache.get(cacheKey);
145
- }
146
-
147
- const url = new URL(
148
- `https://api.polygon.io/v2/aggs/ticker/${encodeURIComponent(polygonSymbol)}/range/${multiplier}/${timespan}/${from}/${to}`,
149
- );
150
-
151
- url.searchParams.set('adjusted', 'true');
152
- url.searchParams.set('sort', 'asc');
153
- url.searchParams.set('limit', '50000');
154
- url.searchParams.set('apiKey', POLYGON_API_KEY);
155
-
156
- const json = await fetchPolygonJson(url, `${polygonSymbol} ${multiplier}/${timespan} ${from} -> ${to}`);
157
-
158
- const bars = (json.results || [])
159
- .filter(row => row && Number.isFinite(row.t) && Number.isFinite(row.c))
160
- .map(row => ({
161
- t: row.t,
162
- open: row.o,
163
- high: row.h,
164
- low: row.l,
165
- close: row.c,
166
- volume: row.v,
167
- }))
168
- .sort((a, b) => a.t - b.t);
169
-
170
- polygonCache.set(cacheKey, bars);
171
-
172
- return bars;
173
- }
174
-
175
- function firstBarAtOrAfter(bars, targetMs) {
176
- return bars.find(bar => bar.t >= targetMs && Number.isFinite(bar.close)) || null;
177
- }
178
-
179
- function eodCloseForSession(intradayBars, sessionDateKey) {
180
- const sessionBars = intradayBars.filter(bar => etDateKey(bar.t) === sessionDateKey);
181
-
182
- if (sessionBars.length === 0) {
183
- return null;
184
- }
185
-
186
- return sessionBars[sessionBars.length - 1].close;
187
- }
188
-
189
- function dailyRows(dailyBars) {
190
- return dailyBars
191
- .filter(bar => Number.isFinite(bar.close))
192
- .map(bar => ({
193
- t: bar.t,
194
- dateKey: etDateKey(bar.t),
195
- close: bar.close,
196
- }))
197
- .sort((a, b) => a.t - b.t);
198
- }
199
-
200
- function pickPrices(intradayBars, dailyBars, eventUnixSeconds) {
201
- const eventMs = eventUnixSeconds * 1000;
202
-
203
- const atEventBar = firstBarAtOrAfter(intradayBars, eventMs);
204
-
205
- if (!atEventBar) {
206
- return {
207
- price_at_event: null,
208
- price_1h: null,
209
- price_eod: null,
210
- price_next_trading_day_1: null,
211
- price_next_trading_day_2: null,
212
- price_next_trading_day_3: null,
213
- price_next_trading_day_5: null,
214
- };
215
- }
216
-
217
- const oneHourBar = firstBarAtOrAfter(intradayBars, atEventBar.t + 60 * 60 * 1000);
218
-
219
- const baseSessionDateKey = etDateKey(atEventBar.t);
220
- const eod = eodCloseForSession(intradayBars, baseSessionDateKey);
221
-
222
- const days = dailyRows(dailyBars);
223
-
224
- let baseDayIndex = days.findIndex(day => day.dateKey === baseSessionDateKey);
225
-
226
- if (baseDayIndex === -1) {
227
- baseDayIndex = days.findIndex(day => day.t >= atEventBar.t);
228
- }
229
-
230
- function nextTradingDayClose(n) {
231
- if (baseDayIndex === -1) return null;
232
- const row = days[baseDayIndex + n];
233
- return row ? row.close : null;
234
- }
235
-
236
- return {
237
- price_at_event: atEventBar.close,
238
- price_1h: oneHourBar ? oneHourBar.close : null,
239
- price_eod: eod,
240
- price_next_trading_day_1: nextTradingDayClose(1),
241
- price_next_trading_day_2: nextTradingDayClose(2),
242
- price_next_trading_day_3: nextTradingDayClose(3),
243
- price_next_trading_day_5: nextTradingDayClose(5),
244
- };
245
- }
246
-
247
- function calcReturn(fromPrice, toPrice) {
248
- if (!Number.isFinite(fromPrice)) return null;
249
- if (!Number.isFinite(toPrice)) return null;
250
- if (fromPrice === 0) return null;
251
-
252
- return (toPrice - fromPrice) / fromPrice;
253
- }
254
-
255
- function calcReturns(prices) {
256
- return {
257
- return_1h: calcReturn(prices.price_at_event, prices.price_1h),
258
- return_eod: calcReturn(prices.price_at_event, prices.price_eod),
259
- return_next_trading_day_1: calcReturn(prices.price_at_event, prices.price_next_trading_day_1),
260
- return_next_trading_day_2: calcReturn(prices.price_at_event, prices.price_next_trading_day_2),
261
- return_next_trading_day_3: calcReturn(prices.price_at_event, prices.price_next_trading_day_3),
262
- return_next_trading_day_5: calcReturn(prices.price_at_event, prices.price_next_trading_day_5),
263
- };
264
- }
265
-
266
- function calcDelta(stockReturn, benchmarkReturn) {
267
- if (!Number.isFinite(stockReturn)) return null;
268
- if (!Number.isFinite(benchmarkReturn)) return null;
269
-
270
- return stockReturn - benchmarkReturn;
271
- }
272
-
273
- function completionStatus(stockPrices, benchmarkPrices) {
274
- const required = [
275
- stockPrices.price_at_event,
276
- stockPrices.price_1h,
277
- stockPrices.price_eod,
278
- stockPrices.price_next_trading_day_1,
279
- stockPrices.price_next_trading_day_2,
280
- stockPrices.price_next_trading_day_3,
281
- stockPrices.price_next_trading_day_5,
282
-
283
- benchmarkPrices.price_at_event,
284
- benchmarkPrices.price_1h,
285
- benchmarkPrices.price_eod,
286
- benchmarkPrices.price_next_trading_day_1,
287
- benchmarkPrices.price_next_trading_day_2,
288
- benchmarkPrices.price_next_trading_day_3,
289
- benchmarkPrices.price_next_trading_day_5,
290
- ];
291
-
292
- return required.every(Number.isFinite) ? 'complete' : 'partial';
293
- }
294
-
295
- const selectRows = db.prepare(`
296
- SELECT
297
- mi.id,
298
- mi.event_time,
299
- COALESCE(mi.benchmark_symbol, '^IXIC') AS benchmark_symbol,
300
- c.ticker AS stock_symbol,
301
- c.short_name AS company_name
302
- FROM mention_impact mi
303
- JOIN companies c
304
- ON c.id = mi.company_id
305
- WHERE mi.event_time IS NOT NULL
306
- AND c.ticker IS NOT NULL
307
- AND TRIM(c.ticker) != ''
308
- AND (
309
- mi.price_at_event IS NULL
310
- OR mi.benchmark_price_at_event IS NULL
311
- OR mi.status IN ('pending', 'failed')
312
- )
313
- ORDER BY mi.event_time ASC
314
- `);
315
-
316
- const updateRow = db.prepare(`
317
- UPDATE mention_impact
318
- SET
319
- price_at_event = @price_at_event,
320
- price_1h = @price_1h,
321
- price_eod = @price_eod,
322
- price_next_trading_day_1 = @price_next_trading_day_1,
323
- price_next_trading_day_2 = @price_next_trading_day_2,
324
- price_next_trading_day_3 = @price_next_trading_day_3,
325
- price_next_trading_day_5 = @price_next_trading_day_5,
326
-
327
- benchmark_price_at_event = @benchmark_price_at_event,
328
- benchmark_price_1h = @benchmark_price_1h,
329
- benchmark_price_eod = @benchmark_price_eod,
330
- benchmark_price_next_trading_day_1 = @benchmark_price_next_trading_day_1,
331
- benchmark_price_next_trading_day_2 = @benchmark_price_next_trading_day_2,
332
- benchmark_price_next_trading_day_3 = @benchmark_price_next_trading_day_3,
333
- benchmark_price_next_trading_day_5 = @benchmark_price_next_trading_day_5,
334
-
335
- stock_return_1h = @stock_return_1h,
336
- stock_return_eod = @stock_return_eod,
337
- stock_return_next_trading_day_1 = @stock_return_next_trading_day_1,
338
- stock_return_next_trading_day_2 = @stock_return_next_trading_day_2,
339
- stock_return_next_trading_day_3 = @stock_return_next_trading_day_3,
340
- stock_return_next_trading_day_5 = @stock_return_next_trading_day_5,
341
-
342
- benchmark_return_1h = @benchmark_return_1h,
343
- benchmark_return_eod = @benchmark_return_eod,
344
- benchmark_return_next_trading_day_1 = @benchmark_return_next_trading_day_1,
345
- benchmark_return_next_trading_day_2 = @benchmark_return_next_trading_day_2,
346
- benchmark_return_next_trading_day_3 = @benchmark_return_next_trading_day_3,
347
- benchmark_return_next_trading_day_5 = @benchmark_return_next_trading_day_5,
348
-
349
- delta_return_1h = @delta_return_1h,
350
- delta_return_eod = @delta_return_eod,
351
- delta_return_next_trading_day_1 = @delta_return_next_trading_day_1,
352
- delta_return_next_trading_day_2 = @delta_return_next_trading_day_2,
353
- delta_return_next_trading_day_3 = @delta_return_next_trading_day_3,
354
- delta_return_next_trading_day_5 = @delta_return_next_trading_day_5,
355
-
356
- status = @status,
357
- error_text = NULL,
358
- updated_at = unixepoch()
359
- WHERE id = @id
360
- `);
361
-
362
- const markFailed = db.prepare(`
363
- UPDATE mention_impact
364
- SET
365
- status = 'failed',
366
- error_text = @error_text,
367
- updated_at = unixepoch()
368
- WHERE id = @id
369
- `);
370
-
371
- async function fillOne(row) {
372
- const eventUnixSeconds = normalizeUnixSeconds(row.event_time);
373
-
374
- if (!eventUnixSeconds) {
375
- throw new Error('event_time ist leer oder ungültig.');
376
- }
377
-
378
- const stockSymbol = normalizePolygonSymbol(row.stock_symbol);
379
- const benchmarkSymbol = normalizePolygonSymbol(row.benchmark_symbol || '^IXIC');
380
-
381
- if (/^\d+$/.test(String(stockSymbol))) {
382
- throw new Error(
383
- `Ticker "${stockSymbol}" sieht nach einem nicht-US-Ticker aus. Polygon braucht ein handelbares Symbol wie AAPL, MSFT, TSLA oder ggf. ein ADR/OTC-Symbol.`,
384
- );
385
- }
386
-
387
- if (!stockSymbol) {
388
- throw new Error('Kein Aktien-Ticker in companies.ticker vorhanden.');
389
- }
390
-
391
- if (!benchmarkSymbol) {
392
- throw new Error('Kein Benchmark-Symbol vorhanden.');
393
- }
394
-
395
- const from = dateStringFromUnixSeconds(eventUnixSeconds, -3);
396
- const to = dateStringFromUnixSeconds(eventUnixSeconds, 14);
397
-
398
- const stockIntradayBars = await polygonAggs(stockSymbol, 5, 'minute', from, to);
399
- const stockDailyBars = await polygonAggs(stockSymbol, 1, 'day', from, to);
400
-
401
- const benchmarkIntradayBars = await polygonAggs(benchmarkSymbol, 5, 'minute', from, to);
402
- const benchmarkDailyBars = await polygonAggs(benchmarkSymbol, 1, 'day', from, to);
403
-
404
- const stockPrices = pickPrices(stockIntradayBars, stockDailyBars, eventUnixSeconds);
405
- const benchmarkPrices = pickPrices(benchmarkIntradayBars, benchmarkDailyBars, eventUnixSeconds);
406
-
407
- const stockReturns = calcReturns(stockPrices);
408
- const benchmarkReturns = calcReturns(benchmarkPrices);
409
-
410
- const payload = {
411
- id: row.id,
412
-
413
- price_at_event: stockPrices.price_at_event,
414
- price_1h: stockPrices.price_1h,
415
- price_eod: stockPrices.price_eod,
416
- price_next_trading_day_1: stockPrices.price_next_trading_day_1,
417
- price_next_trading_day_2: stockPrices.price_next_trading_day_2,
418
- price_next_trading_day_3: stockPrices.price_next_trading_day_3,
419
- price_next_trading_day_5: stockPrices.price_next_trading_day_5,
420
-
421
- benchmark_price_at_event: benchmarkPrices.price_at_event,
422
- benchmark_price_1h: benchmarkPrices.price_1h,
423
- benchmark_price_eod: benchmarkPrices.price_eod,
424
- benchmark_price_next_trading_day_1: benchmarkPrices.price_next_trading_day_1,
425
- benchmark_price_next_trading_day_2: benchmarkPrices.price_next_trading_day_2,
426
- benchmark_price_next_trading_day_3: benchmarkPrices.price_next_trading_day_3,
427
- benchmark_price_next_trading_day_5: benchmarkPrices.price_next_trading_day_5,
428
-
429
- stock_return_1h: stockReturns.return_1h,
430
- stock_return_eod: stockReturns.return_eod,
431
- stock_return_next_trading_day_1: stockReturns.return_next_trading_day_1,
432
- stock_return_next_trading_day_2: stockReturns.return_next_trading_day_2,
433
- stock_return_next_trading_day_3: stockReturns.return_next_trading_day_3,
434
- stock_return_next_trading_day_5: stockReturns.return_next_trading_day_5,
435
-
436
- benchmark_return_1h: benchmarkReturns.return_1h,
437
- benchmark_return_eod: benchmarkReturns.return_eod,
438
- benchmark_return_next_trading_day_1: benchmarkReturns.return_next_trading_day_1,
439
- benchmark_return_next_trading_day_2: benchmarkReturns.return_next_trading_day_2,
440
- benchmark_return_next_trading_day_3: benchmarkReturns.return_next_trading_day_3,
441
- benchmark_return_next_trading_day_5: benchmarkReturns.return_next_trading_day_5,
442
-
443
- delta_return_1h: calcDelta(stockReturns.return_1h, benchmarkReturns.return_1h),
444
- delta_return_eod: calcDelta(stockReturns.return_eod, benchmarkReturns.return_eod),
445
-
446
- delta_return_next_trading_day_1: calcDelta(
447
- stockReturns.return_next_trading_day_1,
448
- benchmarkReturns.return_next_trading_day_1,
449
- ),
450
-
451
- delta_return_next_trading_day_2: calcDelta(
452
- stockReturns.return_next_trading_day_2,
453
- benchmarkReturns.return_next_trading_day_2,
454
- ),
455
-
456
- delta_return_next_trading_day_3: calcDelta(
457
- stockReturns.return_next_trading_day_3,
458
- benchmarkReturns.return_next_trading_day_3,
459
- ),
460
-
461
- delta_return_next_trading_day_5: calcDelta(
462
- stockReturns.return_next_trading_day_5,
463
- benchmarkReturns.return_next_trading_day_5,
464
- ),
465
-
466
- status: completionStatus(stockPrices, benchmarkPrices),
467
- };
468
-
469
- updateRow.run(payload);
470
-
471
- return payload;
472
- }
473
-
474
- async function main() {
475
- const rows = selectRows.all();
476
-
477
- console.log(`DB: ${DB_PATH}`);
478
- console.log(`Gefundene mention_impact rows: ${rows.length}`);
479
- console.log(`Rate limit: ${CALLS_PER_WINDOW} Calls, dann ${RATE_LIMIT_SLEEP_MS / 1000}s Pause`);
480
-
481
- let processed = 0;
482
- let failed = 0;
483
-
484
- for (const row of rows) {
485
- try {
486
- processed += 1;
487
-
488
- console.log('');
489
- console.log(`Bearbeite ${processed}/${rows.length}: ${row.id}`);
490
- console.log(`Company: ${row.company_name}`);
491
- console.log(`Ticker: ${row.stock_symbol}`);
492
- console.log(`Benchmark: ${row.benchmark_symbol}`);
493
- console.log(`Event time: ${row.event_time}`);
494
-
495
- const payload = await fillOne(row);
496
-
497
- console.log(`OK: ${row.id} -> ${payload.status}`);
498
- console.log(`price_at_event: ${payload.price_at_event}`);
499
- console.log(`price_1h: ${payload.price_1h}`);
500
- console.log(`price_eod: ${payload.price_eod}`);
501
- console.log(`stock_return_1h: ${payload.stock_return_1h}`);
502
- console.log(`delta_return_1h: ${payload.delta_return_1h}`);
503
- } catch (error) {
504
- failed += 1;
505
-
506
- console.error(`FAILED: ${row.id}`);
507
- console.error(error.message);
508
-
509
- markFailed.run({
510
- id: row.id,
511
- error_text: error.message,
512
- });
513
- }
514
- }
515
-
516
- console.log('');
517
- console.log('Fertig.');
518
- console.log(`Verarbeitet: ${processed}`);
519
- console.log(`Fehlgeschlagen: ${failed}`);
520
- console.log(`Polygon-Calls insgesamt: ${polygonCallCounter}`);
521
- }
522
-
523
- main().catch(error => {
524
- console.error(error);
525
- process.exit(1);
526
- });