@fin.cx/opendata 1.7.0 → 2.1.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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.handelsregister.d.ts +2 -1
- package/dist_ts/classes.handelsregister.js +5 -5
- package/dist_ts/classes.jsonldata.d.ts +2 -1
- package/dist_ts/classes.jsonldata.js +5 -5
- package/dist_ts/classes.main.opendata.d.ts +7 -0
- package/dist_ts/classes.main.opendata.js +16 -5
- package/dist_ts/paths.d.ts +0 -3
- package/dist_ts/paths.js +1 -6
- package/dist_ts/stocks/classes.stockservice.d.ts +28 -1
- package/dist_ts/stocks/classes.stockservice.js +147 -9
- package/dist_ts/stocks/interfaces/stockprice.d.ts +51 -0
- package/dist_ts/stocks/providers/provider.marketstack.d.ts +43 -9
- package/dist_ts/stocks/providers/provider.marketstack.js +159 -22
- package/dist_ts/stocks/providers/provider.yahoo.js +7 -3
- package/package.json +1 -1
- package/readme.md +320 -22
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.handelsregister.ts +6 -4
- package/ts/classes.jsonldata.ts +6 -4
- package/ts/classes.main.opendata.ts +39 -13
- package/ts/paths.ts +1 -10
- package/ts/stocks/classes.stockservice.ts +204 -28
- package/ts/stocks/interfaces/stockprice.ts +73 -0
- package/ts/stocks/providers/provider.marketstack.ts +189 -22
- package/ts/stocks/providers/provider.yahoo.ts +6 -2
package/readme.md
CHANGED
|
@@ -4,6 +4,62 @@
|
|
|
4
4
|
|
|
5
5
|
Access live stock prices, cryptocurrencies, forex, commodities AND comprehensive German company data - all through a single, unified API.
|
|
6
6
|
|
|
7
|
+
## ⚠️ Breaking Changes
|
|
8
|
+
|
|
9
|
+
### v2.1 - Enhanced Stock Market API (Current)
|
|
10
|
+
|
|
11
|
+
**The stock market API has been significantly enhanced with a new unified request system.**
|
|
12
|
+
|
|
13
|
+
**What Changed:**
|
|
14
|
+
- New discriminated union request types (`IStockDataRequest`)
|
|
15
|
+
- Enhanced `IStockPrice` interface with OHLCV data and metadata
|
|
16
|
+
- New `getData()` method replaces legacy `getPrice()` and `getPrices()`
|
|
17
|
+
- Historical data support with date ranges
|
|
18
|
+
- Exchange filtering via MIC codes
|
|
19
|
+
- Smart caching with data-type aware TTL
|
|
20
|
+
|
|
21
|
+
**Migration:**
|
|
22
|
+
```typescript
|
|
23
|
+
// OLD (v2.0 and earlier)
|
|
24
|
+
const price = await service.getPrice({ ticker: 'AAPL' });
|
|
25
|
+
const prices = await service.getPrices({ tickers: ['AAPL', 'MSFT'] });
|
|
26
|
+
|
|
27
|
+
// NEW (v2.1+) - Unified API
|
|
28
|
+
const price = await service.getData({ type: 'current', ticker: 'AAPL' });
|
|
29
|
+
const prices = await service.getData({ type: 'batch', tickers: ['AAPL', 'MSFT'] });
|
|
30
|
+
|
|
31
|
+
// NEW - Historical data
|
|
32
|
+
const history = await service.getData({
|
|
33
|
+
type: 'historical',
|
|
34
|
+
ticker: 'AAPL',
|
|
35
|
+
from: new Date('2024-01-01'),
|
|
36
|
+
to: new Date('2024-12-31')
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// NEW - Exchange filtering
|
|
40
|
+
const price = await service.getData({
|
|
41
|
+
type: 'current',
|
|
42
|
+
ticker: 'VOD',
|
|
43
|
+
exchange: 'XLON' // London Stock Exchange
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Note:** Legacy `getPrice()` and `getPrices()` methods still work but are deprecated.
|
|
48
|
+
|
|
49
|
+
### v2.0 - Directory Configuration
|
|
50
|
+
|
|
51
|
+
**Directory paths are now MANDATORY when using German business data features.** The package no longer creates `.nogit/` directories automatically. You must explicitly configure all directory paths when instantiating `OpenData`:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const openData = new OpenData({
|
|
55
|
+
nogitDir: '/path/to/your/data',
|
|
56
|
+
downloadDir: '/path/to/your/data/downloads',
|
|
57
|
+
germanBusinessDataDir: '/path/to/your/data/germanbusinessdata'
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This change enables the package to work in read-only filesystems (like Deno compiled binaries) and gives you full control over where data is stored.
|
|
62
|
+
|
|
7
63
|
## Installation
|
|
8
64
|
|
|
9
65
|
```bash
|
|
@@ -14,17 +70,17 @@ pnpm add @fin.cx/opendata
|
|
|
14
70
|
|
|
15
71
|
## Quick Start
|
|
16
72
|
|
|
17
|
-
### 📈 Stock Market Data
|
|
73
|
+
### 📈 Stock Market Data (v2.1+ Enhanced)
|
|
18
74
|
|
|
19
|
-
Get market data with EOD
|
|
75
|
+
Get comprehensive market data with EOD, historical, and OHLCV data:
|
|
20
76
|
|
|
21
77
|
```typescript
|
|
22
78
|
import { StockPriceService, MarketstackProvider } from '@fin.cx/opendata';
|
|
23
79
|
|
|
24
|
-
// Initialize the service with caching
|
|
80
|
+
// Initialize the service with smart caching
|
|
25
81
|
const stockService = new StockPriceService({
|
|
26
|
-
ttl: 60000,
|
|
27
|
-
maxEntries:
|
|
82
|
+
ttl: 60000, // Default cache TTL (historical data cached forever)
|
|
83
|
+
maxEntries: 10000 // Increased for historical data
|
|
28
84
|
});
|
|
29
85
|
|
|
30
86
|
// Register Marketstack provider with API key
|
|
@@ -33,18 +89,38 @@ stockService.register(new MarketstackProvider('YOUR_API_KEY'), {
|
|
|
33
89
|
retryAttempts: 3
|
|
34
90
|
});
|
|
35
91
|
|
|
36
|
-
// Get
|
|
37
|
-
const apple = await stockService.
|
|
92
|
+
// Get current price (new unified API)
|
|
93
|
+
const apple = await stockService.getData({ type: 'current', ticker: 'AAPL' });
|
|
38
94
|
console.log(`Apple: $${apple.price} (${apple.changePercent.toFixed(2)}%)`);
|
|
95
|
+
console.log(`OHLCV: O=${apple.open} H=${apple.high} L=${apple.low} V=${apple.volume}`);
|
|
96
|
+
|
|
97
|
+
// Get historical data (1 year of daily prices)
|
|
98
|
+
const history = await stockService.getData({
|
|
99
|
+
type: 'historical',
|
|
100
|
+
ticker: 'AAPL',
|
|
101
|
+
from: new Date('2024-01-01'),
|
|
102
|
+
to: new Date('2024-12-31'),
|
|
103
|
+
sort: 'DESC' // Newest first
|
|
104
|
+
});
|
|
105
|
+
console.log(`Fetched ${history.length} trading days`);
|
|
39
106
|
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
107
|
+
// Exchange-specific data (London vs NYSE)
|
|
108
|
+
const vodLondon = await stockService.getData({
|
|
109
|
+
type: 'current',
|
|
110
|
+
ticker: 'VOD',
|
|
111
|
+
exchange: 'XLON' // London Stock Exchange
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const vodNYSE = await stockService.getData({
|
|
115
|
+
type: 'current',
|
|
116
|
+
ticker: 'VOD',
|
|
117
|
+
exchange: 'XNYS' // New York Stock Exchange
|
|
43
118
|
});
|
|
44
119
|
|
|
45
|
-
//
|
|
46
|
-
const
|
|
47
|
-
|
|
120
|
+
// Batch current prices
|
|
121
|
+
const prices = await stockService.getData({
|
|
122
|
+
type: 'batch',
|
|
123
|
+
tickers: ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA']
|
|
48
124
|
});
|
|
49
125
|
```
|
|
50
126
|
|
|
@@ -54,8 +130,14 @@ Access comprehensive data on German companies:
|
|
|
54
130
|
|
|
55
131
|
```typescript
|
|
56
132
|
import { OpenData } from '@fin.cx/opendata';
|
|
133
|
+
import * as path from 'path';
|
|
57
134
|
|
|
58
|
-
|
|
135
|
+
// REQUIRED: Configure directory paths
|
|
136
|
+
const openData = new OpenData({
|
|
137
|
+
nogitDir: path.join(process.cwd(), '.nogit'),
|
|
138
|
+
downloadDir: path.join(process.cwd(), '.nogit', 'downloads'),
|
|
139
|
+
germanBusinessDataDir: path.join(process.cwd(), '.nogit', 'germanbusinessdata')
|
|
140
|
+
});
|
|
59
141
|
await openData.start();
|
|
60
142
|
|
|
61
143
|
// Create a business record
|
|
@@ -80,15 +162,18 @@ await openData.buildInitialDb();
|
|
|
80
162
|
|
|
81
163
|
## Features
|
|
82
164
|
|
|
83
|
-
### 🎯 Stock Market Module
|
|
165
|
+
### 🎯 Stock Market Module (v2.1 Enhanced)
|
|
84
166
|
|
|
85
|
-
- **
|
|
86
|
-
- **
|
|
87
|
-
- **
|
|
88
|
-
- **Smart
|
|
89
|
-
- **
|
|
90
|
-
- **
|
|
91
|
-
- **
|
|
167
|
+
- **Historical Data** - Up to 15 years of daily EOD prices with automatic pagination
|
|
168
|
+
- **Exchange Filtering** - Query specific exchanges via MIC codes (XNAS, XLON, XNYS, etc.)
|
|
169
|
+
- **OHLCV Data** - Open, High, Low, Close, Volume for comprehensive analysis
|
|
170
|
+
- **Smart Caching** - Data-type aware TTL (historical cached forever, EOD 24h, live 30s)
|
|
171
|
+
- **Marketstack API** - 500,000+ tickers across 72+ exchanges worldwide
|
|
172
|
+
- **Batch Operations** - Fetch 100+ symbols in one request
|
|
173
|
+
- **Unified API** - Discriminated union types for type-safe requests
|
|
174
|
+
- **Extensible Providers** - Easy to add new data sources
|
|
175
|
+
- **Retry Logic** - Configurable attempts and delays
|
|
176
|
+
- **Type-Safe** - Full TypeScript support with detailed interfaces
|
|
92
177
|
|
|
93
178
|
### 🇩🇪 German Business Intelligence
|
|
94
179
|
|
|
@@ -100,6 +185,151 @@ await openData.buildInitialDb();
|
|
|
100
185
|
|
|
101
186
|
## Advanced Examples
|
|
102
187
|
|
|
188
|
+
### Phase 1: Historical Data Analysis
|
|
189
|
+
|
|
190
|
+
Fetch and analyze historical price data:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Get 1 year of historical data
|
|
194
|
+
const history = await stockService.getData({
|
|
195
|
+
type: 'historical',
|
|
196
|
+
ticker: 'AAPL',
|
|
197
|
+
from: new Date('2024-01-01'),
|
|
198
|
+
to: new Date('2024-12-31'),
|
|
199
|
+
sort: 'DESC' // Newest first (default)
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Calculate statistics
|
|
203
|
+
const prices = history.map(p => p.price);
|
|
204
|
+
const high52Week = Math.max(...prices);
|
|
205
|
+
const low52Week = Math.min(...prices);
|
|
206
|
+
const avgPrice = prices.reduce((a, b) => a + b) / prices.length;
|
|
207
|
+
|
|
208
|
+
console.log(`52-Week Analysis for AAPL:`);
|
|
209
|
+
console.log(`High: $${high52Week.toFixed(2)}`);
|
|
210
|
+
console.log(`Low: $${low52Week.toFixed(2)}`);
|
|
211
|
+
console.log(`Average: $${avgPrice.toFixed(2)}`);
|
|
212
|
+
console.log(`Days: ${history.length}`);
|
|
213
|
+
|
|
214
|
+
// Calculate daily returns
|
|
215
|
+
for (let i = 0; i < history.length - 1; i++) {
|
|
216
|
+
const todayPrice = history[i].price;
|
|
217
|
+
const yesterdayPrice = history[i + 1].price;
|
|
218
|
+
const dailyReturn = ((todayPrice - yesterdayPrice) / yesterdayPrice) * 100;
|
|
219
|
+
console.log(`${history[i].timestamp.toISOString().split('T')[0]}: ${dailyReturn.toFixed(2)}%`);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Phase 1: Exchange-Specific Trading
|
|
224
|
+
|
|
225
|
+
Compare prices across different exchanges:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// Vodafone trades on both London and NYSE
|
|
229
|
+
const exchanges = [
|
|
230
|
+
{ mic: 'XLON', name: 'London Stock Exchange' },
|
|
231
|
+
{ mic: 'XNYS', name: 'New York Stock Exchange' }
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
for (const exchange of exchanges) {
|
|
235
|
+
try {
|
|
236
|
+
const price = await stockService.getData({
|
|
237
|
+
type: 'current',
|
|
238
|
+
ticker: 'VOD',
|
|
239
|
+
exchange: exchange.mic
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
console.log(`${exchange.name}:`);
|
|
243
|
+
console.log(` Price: ${price.price} ${price.currency}`);
|
|
244
|
+
console.log(` Volume: ${price.volume?.toLocaleString()}`);
|
|
245
|
+
console.log(` Exchange: ${price.exchangeName}`);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.log(`${exchange.name}: Not available`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Phase 1: OHLCV Technical Analysis
|
|
253
|
+
|
|
254
|
+
Use OHLCV data for technical indicators:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
const history = await stockService.getData({
|
|
258
|
+
type: 'historical',
|
|
259
|
+
ticker: 'TSLA',
|
|
260
|
+
from: new Date('2024-11-01'),
|
|
261
|
+
to: new Date('2024-11-30')
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Calculate daily trading range
|
|
265
|
+
for (const day of history) {
|
|
266
|
+
const range = day.high - day.low;
|
|
267
|
+
const rangePercent = (range / day.low) * 100;
|
|
268
|
+
|
|
269
|
+
console.log(`${day.timestamp.toISOString().split('T')[0]}:`);
|
|
270
|
+
console.log(` Open: $${day.open}`);
|
|
271
|
+
console.log(` High: $${day.high}`);
|
|
272
|
+
console.log(` Low: $${day.low}`);
|
|
273
|
+
console.log(` Close: $${day.price}`);
|
|
274
|
+
console.log(` Volume: ${day.volume?.toLocaleString()}`);
|
|
275
|
+
console.log(` Range: $${range.toFixed(2)} (${rangePercent.toFixed(2)}%)`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Calculate Simple Moving Average (SMA)
|
|
279
|
+
const calculateSMA = (data: IStockPrice[], period: number) => {
|
|
280
|
+
const sma: number[] = [];
|
|
281
|
+
for (let i = period - 1; i < data.length; i++) {
|
|
282
|
+
const sum = data.slice(i - period + 1, i + 1)
|
|
283
|
+
.reduce((acc, p) => acc + p.price, 0);
|
|
284
|
+
sma.push(sum / period);
|
|
285
|
+
}
|
|
286
|
+
return sma;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const sma20 = calculateSMA(history, 20);
|
|
290
|
+
const sma50 = calculateSMA(history, 50);
|
|
291
|
+
|
|
292
|
+
console.log(`20-day SMA: $${sma20[0].toFixed(2)}`);
|
|
293
|
+
console.log(`50-day SMA: $${sma50[0].toFixed(2)}`);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Phase 1: Smart Caching Performance
|
|
297
|
+
|
|
298
|
+
Leverage smart caching for efficiency:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// Historical data is cached FOREVER (never changes)
|
|
302
|
+
console.time('First historical fetch');
|
|
303
|
+
const history1 = await stockService.getData({
|
|
304
|
+
type: 'historical',
|
|
305
|
+
ticker: 'AAPL',
|
|
306
|
+
from: new Date('2024-01-01'),
|
|
307
|
+
to: new Date('2024-12-31')
|
|
308
|
+
});
|
|
309
|
+
console.timeEnd('First historical fetch');
|
|
310
|
+
// Output: First historical fetch: 2341ms
|
|
311
|
+
|
|
312
|
+
console.time('Second historical fetch (cached)');
|
|
313
|
+
const history2 = await stockService.getData({
|
|
314
|
+
type: 'historical',
|
|
315
|
+
ticker: 'AAPL',
|
|
316
|
+
from: new Date('2024-01-01'),
|
|
317
|
+
to: new Date('2024-12-31')
|
|
318
|
+
});
|
|
319
|
+
console.timeEnd('Second historical fetch (cached)');
|
|
320
|
+
// Output: Second historical fetch (cached): 2ms (1000x faster!)
|
|
321
|
+
|
|
322
|
+
// EOD data cached for 24 hours
|
|
323
|
+
const currentPrice = await stockService.getData({
|
|
324
|
+
type: 'current',
|
|
325
|
+
ticker: 'MSFT'
|
|
326
|
+
});
|
|
327
|
+
// Subsequent calls within 24h served from cache
|
|
328
|
+
|
|
329
|
+
// Cache statistics
|
|
330
|
+
console.log(`Cache size: ${stockService['cache'].size} entries`);
|
|
331
|
+
```
|
|
332
|
+
|
|
103
333
|
### Market Dashboard
|
|
104
334
|
|
|
105
335
|
Create an EOD market overview:
|
|
@@ -159,6 +389,17 @@ console.log('Marketstack Stats:', {
|
|
|
159
389
|
Automate German company data retrieval:
|
|
160
390
|
|
|
161
391
|
```typescript
|
|
392
|
+
import { OpenData } from '@fin.cx/opendata';
|
|
393
|
+
import * as path from 'path';
|
|
394
|
+
|
|
395
|
+
// Configure paths first
|
|
396
|
+
const openData = new OpenData({
|
|
397
|
+
nogitDir: path.join(process.cwd(), '.nogit'),
|
|
398
|
+
downloadDir: path.join(process.cwd(), '.nogit', 'downloads'),
|
|
399
|
+
germanBusinessDataDir: path.join(process.cwd(), '.nogit', 'germanbusinessdata')
|
|
400
|
+
});
|
|
401
|
+
await openData.start();
|
|
402
|
+
|
|
162
403
|
// Search for a company
|
|
163
404
|
const results = await openData.handelsregister.searchCompany("Siemens AG");
|
|
164
405
|
|
|
@@ -182,6 +423,21 @@ for (const file of details.files) {
|
|
|
182
423
|
Merge financial and business data:
|
|
183
424
|
|
|
184
425
|
```typescript
|
|
426
|
+
import { OpenData, StockPriceService, MarketstackProvider } from '@fin.cx/opendata';
|
|
427
|
+
import * as path from 'path';
|
|
428
|
+
|
|
429
|
+
// Configure OpenData with paths
|
|
430
|
+
const openData = new OpenData({
|
|
431
|
+
nogitDir: path.join(process.cwd(), '.nogit'),
|
|
432
|
+
downloadDir: path.join(process.cwd(), '.nogit', 'downloads'),
|
|
433
|
+
germanBusinessDataDir: path.join(process.cwd(), '.nogit', 'germanbusinessdata')
|
|
434
|
+
});
|
|
435
|
+
await openData.start();
|
|
436
|
+
|
|
437
|
+
// Setup stock service
|
|
438
|
+
const stockService = new StockPriceService({ ttl: 60000, maxEntries: 1000 });
|
|
439
|
+
stockService.register(new MarketstackProvider('YOUR_API_KEY'));
|
|
440
|
+
|
|
185
441
|
// Find all public German companies (AG)
|
|
186
442
|
const publicCompanies = await openData.db
|
|
187
443
|
.collection('businessrecords')
|
|
@@ -212,6 +468,48 @@ for (const company of publicCompanies) {
|
|
|
212
468
|
|
|
213
469
|
## Configuration
|
|
214
470
|
|
|
471
|
+
### Directory Configuration (Required for German Business Data)
|
|
472
|
+
|
|
473
|
+
**All directory paths are mandatory when using `OpenData`.** Here are examples for different environments:
|
|
474
|
+
|
|
475
|
+
#### Development Environment
|
|
476
|
+
```typescript
|
|
477
|
+
import { OpenData } from '@fin.cx/opendata';
|
|
478
|
+
import * as path from 'path';
|
|
479
|
+
|
|
480
|
+
const openData = new OpenData({
|
|
481
|
+
nogitDir: path.join(process.cwd(), '.nogit'),
|
|
482
|
+
downloadDir: path.join(process.cwd(), '.nogit', 'downloads'),
|
|
483
|
+
germanBusinessDataDir: path.join(process.cwd(), '.nogit', 'germanbusinessdata')
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### Production Environment
|
|
488
|
+
```typescript
|
|
489
|
+
import { OpenData } from '@fin.cx/opendata';
|
|
490
|
+
import * as path from 'path';
|
|
491
|
+
|
|
492
|
+
const openData = new OpenData({
|
|
493
|
+
nogitDir: '/var/lib/myapp/data',
|
|
494
|
+
downloadDir: '/var/lib/myapp/data/downloads',
|
|
495
|
+
germanBusinessDataDir: '/var/lib/myapp/data/germanbusinessdata'
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### Deno Compiled Binaries (or other read-only filesystems)
|
|
500
|
+
```typescript
|
|
501
|
+
import { OpenData } from '@fin.cx/opendata';
|
|
502
|
+
|
|
503
|
+
// Use OS temp directory or user data directory
|
|
504
|
+
const dataDir = Deno.env.get('HOME') + '/.myapp/data';
|
|
505
|
+
|
|
506
|
+
const openData = new OpenData({
|
|
507
|
+
nogitDir: dataDir,
|
|
508
|
+
downloadDir: dataDir + '/downloads',
|
|
509
|
+
germanBusinessDataDir: dataDir + '/germanbusinessdata'
|
|
510
|
+
});
|
|
511
|
+
```
|
|
512
|
+
|
|
215
513
|
### Stock Service Options
|
|
216
514
|
|
|
217
515
|
```typescript
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@fin.cx/opendata',
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '2.1.0',
|
|
7
7
|
description: 'A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.'
|
|
8
8
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { BusinessRecord } from './classes.businessrecord.js';
|
|
2
2
|
import type { OpenData } from './classes.main.opendata.js';
|
|
3
3
|
import * as plugins from './plugins.js';
|
|
4
|
-
import * as paths from './paths.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* the HandlesRegister exposed as a class
|
|
@@ -9,13 +8,16 @@ import * as paths from './paths.js';
|
|
|
9
8
|
export class HandelsRegister {
|
|
10
9
|
private openDataRef: OpenData;
|
|
11
10
|
private asyncExecutionStack = new plugins.lik.AsyncExecutionStack();
|
|
12
|
-
private
|
|
11
|
+
private downloadDir: string;
|
|
12
|
+
private uniqueDowloadFolder: string;
|
|
13
13
|
|
|
14
14
|
// Puppeteer wrapper instance
|
|
15
15
|
public smartbrowserInstance = new plugins.smartbrowser.SmartBrowser();
|
|
16
16
|
|
|
17
|
-
constructor(openDataRef: OpenData) {
|
|
17
|
+
constructor(openDataRef: OpenData, downloadDirArg: string) {
|
|
18
18
|
this.openDataRef = openDataRef;
|
|
19
|
+
this.downloadDir = downloadDirArg;
|
|
20
|
+
this.uniqueDowloadFolder = plugins.path.join(this.downloadDir, plugins.smartunique.uniSimple());
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
public async start() {
|
|
@@ -76,7 +78,7 @@ export class HandelsRegister {
|
|
|
76
78
|
timeout: 30000,
|
|
77
79
|
})
|
|
78
80
|
.catch(async (err) => {
|
|
79
|
-
await pageArg.screenshot({ path:
|
|
81
|
+
await pageArg.screenshot({ path: this.downloadDir + '/error.png' });
|
|
80
82
|
throw err;
|
|
81
83
|
});
|
|
82
84
|
|
package/ts/classes.jsonldata.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
|
-
import * as paths from './paths.js';
|
|
3
2
|
import type { OpenData } from './classes.main.opendata.js';
|
|
4
3
|
|
|
5
4
|
export type SeedEntryType = {
|
|
@@ -41,8 +40,11 @@ export type SeedEntryType = {
|
|
|
41
40
|
};
|
|
42
41
|
|
|
43
42
|
export class JsonlDataProcessor<T> {
|
|
43
|
+
private germanBusinessDataDir: string;
|
|
44
44
|
public forEachFunction: (entryArg: T) => Promise<void>;
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
constructor(germanBusinessDataDirArg: string, forEachFunctionArg: typeof this.forEachFunction) {
|
|
47
|
+
this.germanBusinessDataDir = germanBusinessDataDirArg;
|
|
46
48
|
this.forEachFunction = forEachFunctionArg;
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -51,9 +53,9 @@ export class JsonlDataProcessor<T> {
|
|
|
51
53
|
dataUrlArg = 'https://daten.offeneregister.de/de_companies_ocdata.jsonl.bz2'
|
|
52
54
|
) {
|
|
53
55
|
const done = plugins.smartpromise.defer();
|
|
54
|
-
const dataExists = await plugins.smartfile.fs.isDirectory(
|
|
56
|
+
const dataExists = await plugins.smartfile.fs.isDirectory(this.germanBusinessDataDir);
|
|
55
57
|
if (!dataExists) {
|
|
56
|
-
await plugins.smartfile.fs.ensureDir(
|
|
58
|
+
await plugins.smartfile.fs.ensureDir(this.germanBusinessDataDir);
|
|
57
59
|
} else {
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -4,16 +4,39 @@ import { JsonlDataProcessor, type SeedEntryType } from './classes.jsonldata.js';
|
|
|
4
4
|
import * as paths from './paths.js';
|
|
5
5
|
import * as plugins from './plugins.js';
|
|
6
6
|
|
|
7
|
+
export interface IOpenDataConfig {
|
|
8
|
+
downloadDir: string;
|
|
9
|
+
germanBusinessDataDir: string;
|
|
10
|
+
nogitDir: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
export class OpenData {
|
|
8
14
|
public db: plugins.smartdata.SmartdataDb;
|
|
9
|
-
private serviceQenv
|
|
15
|
+
private serviceQenv: plugins.qenv.Qenv;
|
|
16
|
+
private config: IOpenDataConfig;
|
|
10
17
|
|
|
11
18
|
public jsonLDataProcessor: JsonlDataProcessor<SeedEntryType>;
|
|
12
19
|
public handelsregister: HandelsRegister;
|
|
13
20
|
|
|
14
21
|
public CBusinessRecord = plugins.smartdata.setDefaultManagerForDoc(this, BusinessRecord);
|
|
15
22
|
|
|
23
|
+
constructor(configArg: IOpenDataConfig) {
|
|
24
|
+
if (!configArg) {
|
|
25
|
+
throw new Error('@fin.cx/opendata: Configuration is required. You must provide downloadDir, germanBusinessDataDir, and nogitDir paths.');
|
|
26
|
+
}
|
|
27
|
+
if (!configArg.downloadDir || !configArg.germanBusinessDataDir || !configArg.nogitDir) {
|
|
28
|
+
throw new Error('@fin.cx/opendata: All directory paths are required (downloadDir, germanBusinessDataDir, nogitDir).');
|
|
29
|
+
}
|
|
30
|
+
this.config = configArg;
|
|
31
|
+
this.serviceQenv = new plugins.qenv.Qenv(paths.packageDir, this.config.nogitDir);
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
public async start() {
|
|
35
|
+
// Ensure configured directories exist
|
|
36
|
+
await plugins.smartfile.fs.ensureDir(this.config.nogitDir);
|
|
37
|
+
await plugins.smartfile.fs.ensureDir(this.config.downloadDir);
|
|
38
|
+
await plugins.smartfile.fs.ensureDir(this.config.germanBusinessDataDir);
|
|
39
|
+
|
|
17
40
|
this.db = new plugins.smartdata.SmartdataDb({
|
|
18
41
|
mongoDbUrl: await this.serviceQenv.getEnvVarOnDemand('MONGODB_URL'),
|
|
19
42
|
mongoDbName: await this.serviceQenv.getEnvVarOnDemand('MONGODB_NAME'),
|
|
@@ -21,18 +44,21 @@ export class OpenData {
|
|
|
21
44
|
mongoDbPass: await this.serviceQenv.getEnvVarOnDemand('MONGODB_PASS'),
|
|
22
45
|
});
|
|
23
46
|
await this.db.init();
|
|
24
|
-
this.jsonLDataProcessor = new JsonlDataProcessor(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
this.jsonLDataProcessor = new JsonlDataProcessor(
|
|
48
|
+
this.config.germanBusinessDataDir,
|
|
49
|
+
async (entryArg) => {
|
|
50
|
+
const businessRecord = new this.CBusinessRecord();
|
|
51
|
+
businessRecord.id = await this.CBusinessRecord.getNewId();
|
|
52
|
+
businessRecord.data.name = entryArg.name;
|
|
53
|
+
businessRecord.data.germanParsedRegistration = {
|
|
54
|
+
court: entryArg.all_attributes.registered_office,
|
|
55
|
+
number: entryArg.all_attributes._registerNummer,
|
|
56
|
+
type: entryArg.all_attributes._registerArt as 'HRA' | 'HRB',
|
|
57
|
+
};
|
|
58
|
+
await businessRecord.save();
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
this.handelsregister = new HandelsRegister(this, this.config.downloadDir);
|
|
36
62
|
await this.handelsregister.start();
|
|
37
63
|
}
|
|
38
64
|
|
package/ts/paths.ts
CHANGED
|
@@ -3,13 +3,4 @@ import * as plugins from './plugins.js';
|
|
|
3
3
|
export const packageDir = plugins.path.join(
|
|
4
4
|
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
|
5
5
|
'../'
|
|
6
|
-
);
|
|
7
|
-
|
|
8
|
-
export const nogitDir = plugins.path.join(packageDir, './.nogit/');
|
|
9
|
-
plugins.smartfile.fs.ensureDirSync(nogitDir);
|
|
10
|
-
|
|
11
|
-
export const downloadDir = plugins.path.join(nogitDir, 'downloads');
|
|
12
|
-
plugins.smartfile.fs.ensureDirSync(downloadDir);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export const germanBusinessDataDir = plugins.path.join(nogitDir, 'germanbusinessdata');
|
|
6
|
+
);
|