@fin.cx/opendata 3.5.0 โ†’ 3.6.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 (54) hide show
  1. package/{npmextra.json โ†’ .smartconfig.json} +12 -6
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.businessrecord.js +86 -43
  4. package/dist_ts/classes.handelsregister.d.ts +2 -0
  5. package/dist_ts/classes.handelsregister.js +126 -107
  6. package/dist_ts/classes.jsonldata.js +9 -6
  7. package/dist_ts/classes.main.opendata.d.ts +2 -1
  8. package/dist_ts/classes.main.opendata.js +59 -26
  9. package/dist_ts/index.d.ts +1 -0
  10. package/dist_ts/index.js +2 -1
  11. package/dist_ts/laws/classes.lawrecord.d.ts +24 -0
  12. package/dist_ts/laws/classes.lawrecord.js +181 -0
  13. package/dist_ts/laws/classes.lawservice.d.ts +52 -0
  14. package/dist_ts/laws/classes.lawservice.js +740 -0
  15. package/dist_ts/laws/index.d.ts +3 -0
  16. package/dist_ts/laws/index.js +4 -0
  17. package/dist_ts/laws/interfaces.law.d.ts +35 -0
  18. package/dist_ts/laws/interfaces.law.js +2 -0
  19. package/dist_ts/plugins.d.ts +8 -2
  20. package/dist_ts/plugins.js +14 -3
  21. package/dist_ts/stocks/classes.baseproviderservice.js +8 -8
  22. package/dist_ts/stocks/classes.fundamentalsservice.js +9 -9
  23. package/dist_ts/stocks/classes.stockdataservice.js +23 -23
  24. package/dist_ts/stocks/classes.stockservice.js +9 -9
  25. package/dist_ts/stocks/providers/provider.coingecko.d.ts +1 -1
  26. package/dist_ts/stocks/providers/provider.coingecko.js +45 -39
  27. package/dist_ts/stocks/providers/provider.marketstack.d.ts +3 -3
  28. package/dist_ts/stocks/providers/provider.marketstack.js +20 -16
  29. package/dist_ts/stocks/providers/provider.secedgar.d.ts +1 -1
  30. package/dist_ts/stocks/providers/provider.secedgar.js +22 -22
  31. package/dist_ts/stocks/providers/provider.yahoo.d.ts +2 -2
  32. package/dist_ts/stocks/providers/provider.yahoo.js +14 -13
  33. package/package.json +22 -19
  34. package/readme.md +280 -676
  35. package/ts/00_commitinfo_data.ts +1 -1
  36. package/ts/classes.businessrecord.ts +1 -1
  37. package/ts/classes.handelsregister.ts +45 -20
  38. package/ts/classes.jsonldata.ts +7 -6
  39. package/ts/classes.main.opendata.ts +63 -30
  40. package/ts/index.ts +1 -0
  41. package/ts/laws/classes.lawrecord.ts +81 -0
  42. package/ts/laws/classes.lawservice.ts +1010 -0
  43. package/ts/laws/index.ts +3 -0
  44. package/ts/laws/interfaces.law.ts +48 -0
  45. package/ts/plugins.ts +19 -0
  46. package/ts/stocks/classes.fundamentalsservice.ts +1 -1
  47. package/ts/stocks/classes.stockdataservice.ts +17 -7
  48. package/ts/stocks/classes.stockservice.ts +2 -2
  49. package/ts/stocks/providers/provider.marketstack.ts +9 -7
  50. package/ts/stocks/providers/provider.secedgar.ts +2 -2
  51. package/ts/stocks/providers/provider.yahoo.ts +3 -3
  52. package/dist_ts/classes.germanbusinessdata.d.ts +0 -9
  53. package/dist_ts/classes.germanbusinessdata.js +0 -78
  54. package/readme.plan.md +0 -193
package/readme.md CHANGED
@@ -1,801 +1,405 @@
1
1
  # @fin.cx/opendata
2
2
 
3
- ๐Ÿš€ **Complete financial intelligence toolkit for TypeScript**
3
+ `@fin.cx/opendata` is a TypeScript toolbox for serious data plumbing: market data, SEC fundamentals, German company registry workflows, and locally synced law corpora. It is built for programmers who want scriptable APIs, local persistence, and real workflows instead of a thin wrapper around one remote endpoint.
4
4
 
5
- Access real-time stock prices, fundamental financial data, and comprehensive German company information - all through a single, unified API.
5
+ It currently gives you four practical lanes in one package:
6
+
7
+ - `StockPriceService` for stock and crypto prices with caching, retries, failover, historical ranges, and intraday support
8
+ - `FundamentalsService` and `StockDataService` for SEC fundamentals and combined price + fundamentals payloads
9
+ - `OpenData` for German company ingestion plus browser-driven Handelsregister lookup and document download
10
+ - `LawService` for syncing and searching German, EU, and US law texts in a local embedded database
11
+
12
+ ## Issue Reporting and Security
13
+
14
+ For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
6
15
 
7
16
  ## Installation
8
17
 
9
18
  ```bash
10
- npm install @fin.cx/opendata
11
- # or
12
19
  pnpm add @fin.cx/opendata
13
20
  ```
14
21
 
15
- ## Quick Start
22
+ ## What You Get
16
23
 
17
- ### โœจ Unified Stock Data API (Recommended)
24
+ ### Market Data
18
25
 
19
- Get complete stock data with automatic enrichment - the elegant way:
26
+ - `StockPriceService`
27
+ Fetches current, batch, historical, and intraday price data.
28
+ - `FundamentalsService`
29
+ Fetches SEC EDGAR fundamentals for US-listed companies.
30
+ - `StockDataService`
31
+ Combines price + fundamentals and enriches fundamentals with metrics like `marketCap`, `priceToEarnings`, and `priceToBook`.
32
+ - `MarketstackProvider`
33
+ Authenticated stock market provider with current, batch, historical, and intraday support.
34
+ - `CoinGeckoProvider`
35
+ Crypto market provider behind the same stock-price interface.
36
+ - `SecEdgarProvider`
37
+ Fundamentals provider backed by SEC EDGAR company facts.
20
38
 
21
- ```typescript
22
- import { StockDataService, YahooFinanceProvider, SecEdgarProvider } from '@fin.cx/opendata';
39
+ ### German Company Data
23
40
 
24
- // Initialize unified service
25
- const stockData = new StockDataService();
41
+ - `OpenData`
42
+ Starts a local embedded database, imports the public German company JSONL dump, and exposes a `handelsregister` helper for company lookup and file download.
26
43
 
27
- // Register providers
28
- stockData.registerPriceProvider(new YahooFinanceProvider());
29
- stockData.registerFundamentalsProvider(new SecEdgarProvider({
30
- userAgent: 'YourCompany youremail@example.com'
31
- }));
44
+ ### Laws
32
45
 
33
- // โœจ Get complete stock data with ONE method call
34
- const apple = await stockData.getStockData('AAPL');
46
+ - `LawService`
47
+ Syncs laws into a local embedded database and lets you search them later.
48
+ - `LawRecord`
49
+ The stored law document model returned by sync and search operations.
35
50
 
36
- console.log({
37
- company: apple.fundamentals.companyName, // "Apple Inc."
38
- price: apple.price.price, // $270.37
39
- marketCap: apple.fundamentals.marketCap, // $4.13T (auto-calculated!)
40
- peRatio: apple.fundamentals.priceToEarnings, // 28.42 (auto-calculated!)
41
- pbRatio: apple.fundamentals.priceToBook, // 45.12 (auto-calculated!)
42
- eps: apple.fundamentals.earningsPerShareDiluted, // $6.13
43
- revenue: apple.fundamentals.revenue // $385.6B
44
- });
51
+ ## Before You Start
45
52
 
46
- // Batch fetch with automatic enrichment
47
- const stocks = await stockData.getBatchStockData(['AAPL', 'MSFT', 'GOOGL']);
53
+ - No stock or fundamentals providers are pre-registered. You must register them before calling the services.
54
+ - `MarketstackProvider` requires an API key.
55
+ - `SecEdgarProvider` requires a valid `User-Agent` string in the format `Company Name email@example.com`.
56
+ - `CoinGeckoProvider` works without an API key, but a key gives you better rate limits.
57
+ - `OpenData` requires `nogitDir`, `downloadDir`, and `germanBusinessDataDir`.
58
+ - `OpenData.start()` is required before using `OpenData.handelsregister` or `buildInitialDb()`.
59
+ - `LawService` stores data locally. It auto-starts on demand, but explicit `start()` and `stop()` keep lifecycle handling cleaner.
60
+ - EU law syncing and Handelsregister access use a headless browser under the hood.
61
+ - `StockDataService` defaults to a 24 hour price cache. If you want fresher quote caching, pass `cache.priceTTL` explicitly or use `StockPriceService` directly.
48
62
 
49
- stocks.forEach(stock => {
50
- console.log(`${stock.ticker}: $${stock.price.price.toFixed(2)}, ` +
51
- `P/E ${stock.fundamentals?.priceToEarnings?.toFixed(2)}`);
52
- });
53
- // Output:
54
- // AAPL: $270.37, P/E 28.42
55
- // MSFT: $425.50, P/E 34.21
56
- // GOOGL: $142.15, P/E 25.63
57
- ```
58
-
59
- **Why use the unified API?**
60
- - โœ… **Single service** for both prices and fundamentals
61
- - โœ… **Automatic enrichment** - Market cap, P/E, P/B calculated automatically
62
- - โœ… **One method call** - No manual `enrichWithPrice()` calls
63
- - โœ… **Simplified code** - Less boilerplate, more readable
64
- - โœ… **Type-safe** - Full TypeScript support
63
+ ## Quick Start
65
64
 
66
- ### ๐Ÿ“ˆ Price-Only Data (Alternative)
65
+ ### Combined Stock Data
67
66
 
68
- If you only need prices without fundamentals:
67
+ Use `StockDataService` when you want one call that returns both the latest price and SEC fundamentals.
69
68
 
70
- ```typescript
71
- import { StockDataService, YahooFinanceProvider } from '@fin.cx/opendata';
69
+ ```ts
70
+ import {
71
+ MarketstackProvider,
72
+ SecEdgarProvider,
73
+ StockDataService,
74
+ } from '@fin.cx/opendata';
72
75
 
73
- const stockData = new StockDataService();
74
- stockData.registerPriceProvider(new YahooFinanceProvider());
76
+ const stocks = new StockDataService({
77
+ cache: {
78
+ priceTTL: 60_000,
79
+ },
80
+ });
75
81
 
76
- // Get just the price
77
- const price = await stockData.getPrice('AAPL');
78
- console.log(`${price.ticker}: $${price.price}`);
82
+ stocks.registerPriceProvider(
83
+ new MarketstackProvider(process.env.MARKETSTACK_API_KEY!)
84
+ );
79
85
 
80
- // Or use StockPriceService directly for more control
81
- import { StockPriceService } from '@fin.cx/opendata';
86
+ stocks.registerFundamentalsProvider(
87
+ new SecEdgarProvider({
88
+ userAgent: 'Acme Inc. dev@acme.dev',
89
+ })
90
+ );
82
91
 
83
- const stockService = new StockPriceService({ ttl: 60000 });
84
- stockService.register(new YahooFinanceProvider());
92
+ const apple = await stocks.getStockData('AAPL');
85
93
 
86
- const apple = await stockService.getData({ type: 'current', ticker: 'AAPL' });
87
- console.log(`${apple.companyFullName}: $${apple.price}`);
94
+ console.log({
95
+ ticker: apple.ticker,
96
+ price: apple.price.price,
97
+ provider: apple.price.provider,
98
+ companyName: apple.fundamentals?.companyName,
99
+ marketCap: apple.fundamentals?.marketCap,
100
+ priceToEarnings: apple.fundamentals?.priceToEarnings,
101
+ fetchedAt: apple.fetchedAt,
102
+ });
88
103
  ```
89
104
 
90
- ### ๐Ÿช™ Cryptocurrency Prices
91
-
92
- Get real-time crypto prices with the CoinGecko provider:
93
-
94
- ```typescript
95
- import { StockPriceService, CoinGeckoProvider } from '@fin.cx/opendata';
105
+ You can also batch this:
96
106
 
97
- const stockService = new StockPriceService({ ttl: 30000 });
107
+ ```ts
108
+ const batch = await stocks.getBatchStockData(['AAPL', 'MSFT', 'NVDA']);
109
+ ```
98
110
 
99
- // Optional: Pass API key for higher rate limits
100
- // const provider = new CoinGeckoProvider('your-api-key');
101
- const provider = new CoinGeckoProvider();
111
+ ### Price-Only Stocks And Intraday Data
102
112
 
103
- stockService.register(provider);
113
+ Use `StockPriceService` if you want smarter per-request caching and direct access to current, historical, and intraday request types.
104
114
 
105
- // Fetch single crypto price (using ticker symbol)
106
- const btc = await stockService.getPrice({ ticker: 'BTC' });
107
- console.log(`${btc.ticker}: $${btc.price.toLocaleString()}`);
108
- console.log(`24h Change: ${btc.changePercent.toFixed(2)}%`);
109
- console.log(`24h Volume: $${btc.volume?.toLocaleString()}`);
115
+ ```ts
116
+ import { MarketstackProvider, StockPriceService } from '@fin.cx/opendata';
110
117
 
111
- // Or use CoinGecko ID directly
112
- const ethereum = await stockService.getPrice({ ticker: 'ethereum' });
118
+ const prices = new StockPriceService();
119
+ prices.register(new MarketstackProvider(process.env.MARKETSTACK_API_KEY!));
113
120
 
114
- // Batch fetch multiple cryptos
115
- const cryptos = await stockService.getPrices({
116
- tickers: ['BTC', 'ETH', 'USDT', 'BNB', 'SOL']
117
- });
121
+ const current = await prices.getPrice({ ticker: 'AAPL' });
118
122
 
119
- cryptos.forEach(crypto => {
120
- console.log(`${crypto.ticker}: $${crypto.price.toFixed(2)} (${crypto.changePercent >= 0 ? '+' : ''}${crypto.changePercent.toFixed(2)}%)`);
121
- });
122
-
123
- // Historical crypto prices
124
- const history = await stockService.getData({
123
+ const historical = await prices.getData({
125
124
  type: 'historical',
126
- ticker: 'BTC',
125
+ ticker: 'AAPL',
127
126
  from: new Date('2025-01-01'),
128
- to: new Date('2025-01-31')
127
+ to: new Date('2025-01-31'),
128
+ sort: 'DESC',
129
129
  });
130
130
 
131
- // Intraday crypto prices (hourly)
132
- const intraday = await stockService.getData({
131
+ const intraday = await prices.getData({
133
132
  type: 'intraday',
134
- ticker: 'ETH',
133
+ ticker: 'AAPL',
135
134
  interval: '1hour',
136
- limit: 24 // Last 24 hours
135
+ limit: 24,
136
+ });
137
+
138
+ console.log({
139
+ live: current.price,
140
+ candles: intraday.length,
141
+ historicalRows: historical.length,
137
142
  });
138
143
  ```
139
144
 
140
- ### ๐Ÿ’ฐ Fundamentals-Only Data (Alternative)
145
+ Supported stock request shapes:
141
146
 
142
- If you only need fundamentals without prices:
147
+ - `{ type: 'current', ticker, exchange? }`
148
+ - `{ type: 'batch', tickers, exchange? }`
149
+ - `{ type: 'historical', ticker, from, to, exchange?, sort?, limit?, offset? }`
150
+ - `{ type: 'intraday', ticker, interval, exchange?, limit?, date? }`
143
151
 
144
- ```typescript
145
- import { StockDataService, SecEdgarProvider } from '@fin.cx/opendata';
152
+ `StockPriceService` also exposes operational helpers like `checkProvidersHealth()`, `getProviderStats()`, `clearCache()`, and `getCacheStats()`.
146
153
 
147
- const stockData = new StockDataService();
148
- stockData.registerFundamentalsProvider(new SecEdgarProvider({
149
- userAgent: 'YourCompany youremail@example.com'
150
- }));
154
+ ### Crypto Prices With The Same Interface
151
155
 
152
- // Get just fundamentals
153
- const fundamentals = await stockData.getFundamentals('AAPL');
156
+ `CoinGeckoProvider` plugs into `StockPriceService`, so crypto lookups use the same request model as stock lookups.
154
157
 
155
- console.log({
156
- company: fundamentals.companyName,
157
- eps: fundamentals.earningsPerShareDiluted,
158
- revenue: fundamentals.revenue,
159
- sharesOutstanding: fundamentals.sharesOutstanding
160
- });
158
+ ```ts
159
+ import { CoinGeckoProvider, StockPriceService } from '@fin.cx/opendata';
161
160
 
162
- // Or use FundamentalsService directly
163
- import { FundamentalsService } from '@fin.cx/opendata';
161
+ const prices = new StockPriceService({ ttl: 30_000 });
162
+ prices.register(new CoinGeckoProvider(process.env.COINGECKO_API_KEY));
164
163
 
165
- const fundamentalsService = new FundamentalsService();
166
- fundamentalsService.register(new SecEdgarProvider({
167
- userAgent: 'YourCompany youremail@example.com'
168
- }));
164
+ const btc = await prices.getPrice({ ticker: 'BTC' });
165
+ const top = await prices.getPrices({ tickers: ['BTC', 'ETH', 'SOL'] });
169
166
 
170
- const data = await fundamentalsService.getFundamentals('AAPL');
167
+ console.log(btc.price, top.map((item) => item.ticker));
171
168
  ```
172
169
 
173
- ### ๐Ÿข German Business Intelligence
170
+ You can also pass CoinGecko ids like `bitcoin` or `ethereum` instead of ticker symbols.
174
171
 
175
- Access comprehensive German company data:
172
+ ### Fundamentals Only
176
173
 
177
- ```typescript
178
- import { OpenData } from '@fin.cx/opendata';
179
- import * as path from 'path';
174
+ Use `FundamentalsService` when you only care about SEC filing data.
180
175
 
181
- // Configure directory paths
182
- const openData = new OpenData({
183
- nogitDir: path.join(process.cwd(), '.nogit'),
184
- downloadDir: path.join(process.cwd(), '.nogit', 'downloads'),
185
- germanBusinessDataDir: path.join(process.cwd(), '.nogit', 'germanbusinessdata')
186
- });
187
- await openData.start();
176
+ ```ts
177
+ import { FundamentalsService, SecEdgarProvider } from '@fin.cx/opendata';
188
178
 
189
- // Search for companies
190
- const results = await openData.handelsregister.searchCompany("Siemens AG");
179
+ const fundamentals = new FundamentalsService();
180
+ fundamentals.register(
181
+ new SecEdgarProvider({
182
+ userAgent: 'Acme Inc. dev@acme.dev',
183
+ })
184
+ );
191
185
 
192
- // Get detailed information with documents
193
- const details = await openData.handelsregister.getSpecificCompany({
194
- court: "Munich",
195
- type: "HRB",
196
- number: "6684"
197
- });
198
- ```
186
+ const apple = await fundamentals.getFundamentals('AAPL');
199
187
 
200
- ## Features
201
-
202
- ### ๐Ÿ“Š Stock & Crypto Market Module
203
-
204
- - **Real-Time Prices** - Live and EOD prices from Yahoo Finance, Marketstack, and CoinGecko
205
- - **Cryptocurrency Support** - 13M+ crypto tokens with 24/7 market data via CoinGecko
206
- - **Company Names** - Automatic company name extraction (e.g., "Apple Inc (NASDAQ:AAPL)")
207
- - **Historical Data** - Up to 15 years of daily EOD prices with pagination
208
- - **OHLCV Data** - Open, High, Low, Close, Volume for technical analysis
209
- - **Exchange Filtering** - Query specific exchanges via MIC codes (XNAS, XLON, XNYS)
210
- - **Smart Caching** - Data-type aware TTL (historical cached forever, EOD 24h, live 30s)
211
- - **Batch Operations** - Fetch 100+ symbols in one request
212
- - **Type-Safe API** - Full TypeScript support with discriminated unions
213
- - **Multi-Provider** - Automatic fallback between providers
214
-
215
- ### ๐Ÿ’ฐ Fundamental Data Module
216
-
217
- - **SEC EDGAR Integration** - FREE fundamental data directly from SEC filings
218
- - **Comprehensive Metrics** - EPS, Revenue, Assets, Liabilities, Cash Flow, and more
219
- - **All US Public Companies** - Complete coverage of SEC-registered companies
220
- - **Historical Filings** - Data back to ~2009
221
- - **CIK Lookup** - Automatic ticker-to-CIK mapping with smart caching
222
- - **Calculated Ratios** - Market Cap, P/E, P/B ratios when combined with prices
223
- - **No API Key Required** - Direct access to SEC's public API
224
- - **Rate Limit Management** - Built-in 10 req/sec rate limiting
225
-
226
- ### ๐Ÿ‡ฉ๐Ÿ‡ช German Business Intelligence
227
-
228
- - **MongoDB Integration** - Scalable data storage for millions of records
229
- - **Bulk JSONL Import** - Process multi-GB datasets efficiently
230
- - **Handelsregister Automation** - Automated document retrieval
231
- - **CRUD Operations** - Full database management with validation
232
- - **Streaming Processing** - Handle large datasets without memory issues
233
-
234
- ## Advanced Examples
235
-
236
- ### Combined Market Analysis (Unified API)
237
-
238
- Analyze multiple companies with automatic enrichment:
239
-
240
- ```typescript
241
- import { StockDataService, YahooFinanceProvider, SecEdgarProvider } from '@fin.cx/opendata';
242
-
243
- // Setup unified service
244
- const stockData = new StockDataService();
245
- stockData.registerPriceProvider(new YahooFinanceProvider());
246
- stockData.registerFundamentalsProvider(new SecEdgarProvider({
247
- userAgent: 'YourCompany youremail@example.com'
248
- }));
249
-
250
- // Analyze multiple companies with ONE call
251
- const tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN'];
252
- const stocks = await stockData.getBatchStockData(tickers);
253
-
254
- // All metrics are automatically calculated!
255
- stocks.forEach(stock => {
256
- if (stock.fundamentals) {
257
- console.log(`\n${stock.fundamentals.companyName} (${stock.ticker})`);
258
- console.log(` Price: $${stock.price.price.toFixed(2)}`);
259
- console.log(` Market Cap: $${(stock.fundamentals.marketCap! / 1e9).toFixed(2)}B`);
260
- console.log(` P/E Ratio: ${stock.fundamentals.priceToEarnings!.toFixed(2)}`);
261
- console.log(` Revenue: $${(stock.fundamentals.revenue! / 1e9).toFixed(2)}B`);
262
- console.log(` EPS: $${stock.fundamentals.earningsPerShareDiluted!.toFixed(2)}`);
263
- }
188
+ console.log({
189
+ companyName: apple.companyName,
190
+ revenue: apple.revenue,
191
+ netIncome: apple.netIncome,
192
+ earningsPerShareDiluted: apple.earningsPerShareDiluted,
193
+ filingDate: apple.filingDate,
264
194
  });
265
-
266
- // Or analyze one-by-one with automatic enrichment
267
- for (const ticker of tickers) {
268
- const stock = await stockData.getStockData(ticker);
269
-
270
- // Everything is already enriched - no manual calculations needed!
271
- console.log(`${ticker}: P/E ${stock.fundamentals?.priceToEarnings?.toFixed(2)}`);
272
- }
273
195
  ```
274
196
 
275
- ### Fundamental Data Screening
197
+ ### German Company Data And Handelsregister Automation
276
198
 
277
- Screen stocks by financial metrics:
199
+ `OpenData` is the local workflow layer for German company data. It creates its directories, boots an embedded SmartDB-backed database, and starts a browser automation session for Handelsregister access.
278
200
 
279
- ```typescript
280
- // Fetch data for multiple tickers
281
- const tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', 'NVDA', 'TSLA'];
282
- const stocks = await stockData.getBatchStockData(tickers);
201
+ ```ts
202
+ import { OpenData } from '@fin.cx/opendata';
203
+ import * as path from 'node:path';
283
204
 
284
- // Filter by criteria (all metrics auto-calculated!)
285
- const valueStocks = stocks.filter(stock => {
286
- const f = stock.fundamentals;
287
- return f &&
288
- f.priceToEarnings! < 30 && // P/E under 30
289
- f.priceToBook! < 10 && // P/B under 10
290
- f.revenue! > 100_000_000_000; // Revenue > $100B
291
- });
205
+ const nogitDir = path.join(process.cwd(), '.nogit');
292
206
 
293
- console.log('\n๐Ÿ’Ž Value Stocks:');
294
- valueStocks.forEach(stock => {
295
- console.log(`${stock.ticker}: P/E ${stock.fundamentals!.priceToEarnings!.toFixed(2)}, ` +
296
- `P/B ${stock.fundamentals!.priceToBook!.toFixed(2)}`);
207
+ const openData = new OpenData({
208
+ nogitDir,
209
+ downloadDir: path.join(nogitDir, 'downloads'),
210
+ germanBusinessDataDir: path.join(nogitDir, 'germanbusinessdata'),
297
211
  });
298
- ```
299
212
 
300
- ### Historical Data Analysis
213
+ await openData.start();
301
214
 
302
- Fetch and analyze historical price trends:
215
+ const matches = await openData.handelsregister.searchCompany('Siemens AG', 20);
303
216
 
304
- ```typescript
305
- // Get 1 year of historical data
306
- const history = await stockService.getData({
307
- type: 'historical',
308
- ticker: 'AAPL',
309
- from: new Date('2024-01-01'),
310
- to: new Date('2024-12-31'),
311
- sort: 'DESC' // Newest first
217
+ const company = await openData.handelsregister.getSpecificCompany({
218
+ court: 'Munich',
219
+ type: 'HRB',
220
+ number: '6684',
312
221
  });
313
222
 
314
- // Calculate statistics
315
- const prices = history.map(p => p.price);
316
- const high52Week = Math.max(...prices);
317
- const low52Week = Math.min(...prices);
318
- const avgPrice = prices.reduce((a, b) => a + b) / prices.length;
319
-
320
- console.log(`52-Week Analysis for AAPL:`);
321
- console.log(` High: $${high52Week.toFixed(2)}`);
322
- console.log(` Low: $${low52Week.toFixed(2)}`);
323
- console.log(` Average: $${avgPrice.toFixed(2)}`);
324
- console.log(` Days: ${history.length}`);
325
-
326
- // Calculate Simple Moving Average
327
- const calculateSMA = (data: IStockPrice[], period: number) => {
328
- const sma: number[] = [];
329
- for (let i = period - 1; i < data.length; i++) {
330
- const sum = data.slice(i - period + 1, i + 1)
331
- .reduce((acc, p) => acc + p.price, 0);
332
- sma.push(sum / period);
333
- }
334
- return sma;
335
- };
336
-
337
- const sma20 = calculateSMA(history, 20);
338
- const sma50 = calculateSMA(history, 50);
339
-
340
- console.log(`\nMoving Averages:`);
341
- console.log(` 20-day SMA: $${sma20[0].toFixed(2)}`);
342
- console.log(` 50-day SMA: $${sma50[0].toFixed(2)}`);
343
- ```
344
-
345
- ### OHLCV Technical Analysis
346
-
347
- Use OHLCV data for technical indicators:
348
-
349
- ```typescript
350
- const history = await stockService.getData({
351
- type: 'historical',
352
- ticker: 'TSLA',
353
- from: new Date('2024-11-01'),
354
- to: new Date('2024-11-30')
223
+ console.log({
224
+ searchHits: matches.length,
225
+ downloadedFiles: company.files.map((file) => file.path),
355
226
  });
356
227
 
357
- // Calculate daily trading range
358
- for (const day of history) {
359
- const range = day.high! - day.low!;
360
- const rangePercent = (range / day.low!) * 100;
361
-
362
- console.log(`${day.timestamp.toISOString().split('T')[0]}:`);
363
- console.log(` Open: $${day.open}`);
364
- console.log(` High: $${day.high}`);
365
- console.log(` Low: $${day.low}`);
366
- console.log(` Close: $${day.price}`);
367
- console.log(` Volume: ${day.volume?.toLocaleString()}`);
368
- console.log(` Range: $${range.toFixed(2)} (${rangePercent.toFixed(2)}%)`);
369
- }
228
+ await openData.stop();
370
229
  ```
371
230
 
372
- ### Fundamental Data Screening
231
+ Useful `OpenData` workflows today:
373
232
 
374
- Screen stocks based on fundamental metrics:
233
+ - `await openData.start()`
234
+ - `await openData.buildInitialDb()` to ingest the public German company JSONL dataset
235
+ - `await openData.handelsregister.searchCompany(name, limit)`
236
+ - `await openData.handelsregister.getSpecificCompany({ court, type, number })`
237
+ - `await openData.handelsregister.getSpecificCompanyByName(name)`
375
238
 
376
- ```typescript
377
- const tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA', 'META', 'NVDA'];
239
+ The download workflow currently fetches the Handelsregister files into a temporary folder and returns the files to you as `SmartFile` objects.
378
240
 
379
- // Fetch fundamentals for all tickers
380
- const allFundamentals = await fundamentalsService.getBatchFundamentals(tickers);
241
+ ### Law Syncing And Search
381
242
 
382
- // Get current prices
383
- const prices = await stockService.getData({
384
- type: 'batch',
385
- tickers: tickers
386
- });
387
-
388
- // Create price map
389
- const priceMap = new Map(prices.map(p => [p.ticker, p.price]));
243
+ `LawService` stores synced laws in a local embedded database and supports three jurisdictions:
390
244
 
391
- // Enrich with prices
392
- const enriched = await fundamentalsService.enrichBatchWithPrices(
393
- allFundamentals,
394
- priceMap
395
- );
245
+ - Germany via `gesetze-im-internet`
246
+ - EU via `EUR-Lex`
247
+ - US via GovInfo and Cornell LII
396
248
 
397
- // Screen for value stocks (P/E < 25, P/B < 5)
398
- const valueStocks = enriched.filter(f =>
399
- f.priceToEarnings && f.priceToEarnings < 25 &&
400
- f.priceToBook && f.priceToBook < 5
401
- );
249
+ ```ts
250
+ import { LawService } from '@fin.cx/opendata';
402
251
 
403
- console.log('Value Stocks:');
404
- valueStocks.forEach(stock => {
405
- console.log(`\n${stock.companyName} (${stock.ticker})`);
406
- console.log(` P/E Ratio: ${stock.priceToEarnings!.toFixed(2)}`);
407
- console.log(` P/B Ratio: ${stock.priceToBook!.toFixed(2)}`);
408
- console.log(` Market Cap: $${(stock.marketCap! / 1e9).toFixed(2)}B`);
252
+ const laws = new LawService({
253
+ dbFolderPath: '.nogit/law-smartdb',
254
+ dbName: 'laws',
255
+ govInfoApiKey: process.env.GOVINFO_API_KEY,
409
256
  });
410
- ```
411
-
412
- ### Market Dashboard
413
-
414
- Create a comprehensive market overview:
415
257
 
416
- ```typescript
417
- const indicators = [
418
- { ticker: 'AAPL', name: 'Apple' },
419
- { ticker: 'MSFT', name: 'Microsoft' },
420
- { ticker: 'GOOGL', name: 'Alphabet' },
421
- { ticker: 'AMZN', name: 'Amazon' },
422
- { ticker: 'TSLA', name: 'Tesla' }
423
- ];
258
+ await laws.start();
424
259
 
425
- const prices = await stockService.getData({
426
- type: 'batch',
427
- tickers: indicators.map(i => i.ticker)
260
+ const germanLaw = await laws.syncLaw({
261
+ jurisdiction: 'de',
262
+ identifier: 'aeg',
428
263
  });
429
264
 
430
- // Display with color-coded changes
431
- prices.forEach(price => {
432
- const indicator = indicators.find(i => i.ticker === price.ticker);
433
- const arrow = price.change >= 0 ? 'โ†‘' : 'โ†“';
434
- const color = price.change >= 0 ? '\x1b[32m' : '\x1b[31m';
435
-
436
- console.log(
437
- `${price.companyName!.padEnd(25)} $${price.price.toFixed(2).padStart(8)} ` +
438
- `${color}${arrow} ${price.changePercent.toFixed(2)}%\x1b[0m`
439
- );
440
- });
441
- ```
442
-
443
- ### Exchange-Specific Trading
444
-
445
- Compare prices across different exchanges:
446
-
447
- ```typescript
448
- // Vodafone trades on both London and NYSE
449
- const exchanges = [
450
- { mic: 'XLON', name: 'London Stock Exchange' },
451
- { mic: 'XNYS', name: 'New York Stock Exchange' }
452
- ];
453
-
454
- for (const exchange of exchanges) {
455
- try {
456
- const price = await stockService.getData({
457
- type: 'current',
458
- ticker: 'VOD',
459
- exchange: exchange.mic
460
- });
461
-
462
- console.log(`${exchange.name}:`);
463
- console.log(` Price: ${price.price} ${price.currency}`);
464
- console.log(` Volume: ${price.volume?.toLocaleString()}`);
465
- console.log(` Exchange: ${price.exchangeName}`);
466
- } catch (error) {
467
- console.log(`${exchange.name}: Not available`);
468
- }
469
- }
470
- ```
471
-
472
- ## Configuration
473
-
474
- ### Stock Service Options
475
-
476
- ```typescript
477
- const stockService = new StockPriceService({
478
- ttl: 60000, // Default cache TTL in ms
479
- maxEntries: 10000 // Max cached entries
265
+ const euLaw = await laws.syncLaw({
266
+ jurisdiction: 'eu',
267
+ identifier: '32024R1689',
268
+ language: 'EN',
480
269
  });
481
270
 
482
- // Marketstack - EOD data (requires API key)
483
- stockService.register(new MarketstackProvider('YOUR_API_KEY'), {
484
- enabled: true,
485
- priority: 100,
486
- timeout: 10000,
487
- retryAttempts: 3,
488
- retryDelay: 1000
271
+ const usCode = await laws.syncLaw({
272
+ jurisdiction: 'us',
273
+ identifier: '8 U.S.C. ยง 1226',
489
274
  });
490
275
 
491
- // Yahoo Finance - Real-time data (no API key)
492
- stockService.register(new YahooFinanceProvider(), {
493
- enabled: true,
494
- priority: 50
276
+ const results = await laws.searchLaws({
277
+ jurisdiction: 'eu',
278
+ query: 'Artificial Intelligence Act',
279
+ limit: 5,
495
280
  });
496
- ```
497
-
498
- ### Fundamentals Service Options
499
281
 
500
- ```typescript
501
- const fundamentalsService = new FundamentalsService({
502
- ttl: 90 * 24 * 60 * 60 * 1000, // 90 days (quarterly refresh)
503
- maxEntries: 10000
282
+ console.log({
283
+ germany: germanLaw.title,
284
+ eu: euLaw.title,
285
+ us: usCode.title,
286
+ hits: results.length,
504
287
  });
505
288
 
506
- // SEC EDGAR provider (FREE - no API key!)
507
- fundamentalsService.register(new SecEdgarProvider({
508
- userAgent: 'YourCompany youremail@example.com',
509
- cikCacheTTL: 30 * 24 * 60 * 60 * 1000, // 30 days
510
- fundamentalsCacheTTL: 90 * 24 * 60 * 60 * 1000, // 90 days
511
- timeout: 30000
512
- }));
289
+ await laws.stop();
513
290
  ```
514
291
 
515
- ### Directory Configuration (German Business Data)
516
-
517
- All directory paths are mandatory when using German business data features:
292
+ `LawService` also supports bulk sync:
518
293
 
519
- ```typescript
520
- import { OpenData } from '@fin.cx/opendata';
521
- import * as path from 'path';
522
-
523
- // Development
524
- const openData = new OpenData({
525
- nogitDir: path.join(process.cwd(), '.nogit'),
526
- downloadDir: path.join(process.cwd(), '.nogit', 'downloads'),
527
- germanBusinessDataDir: path.join(process.cwd(), '.nogit', 'germanbusinessdata')
528
- });
529
-
530
- // Production
531
- const openDataProd = new OpenData({
532
- nogitDir: '/var/lib/myapp/data',
533
- downloadDir: '/var/lib/myapp/data/downloads',
534
- germanBusinessDataDir: '/var/lib/myapp/data/germanbusinessdata'
294
+ ```ts
295
+ await laws.syncLaws({
296
+ jurisdiction: 'us',
297
+ usCollection: 'PLAW',
298
+ limit: 25,
299
+ since: new Date('2025-01-01'),
535
300
  });
536
301
  ```
537
302
 
538
- ### Environment Variables
539
-
540
- Set environment variables for API keys and database:
541
-
542
- ```env
543
- # Marketstack API (for EOD stock data)
544
- MARKETSTACK_COM_TOKEN=your_api_key_here
545
-
546
- # MongoDB (for German business data)
547
- MONGODB_URL=mongodb://localhost:27017
548
- MONGODB_NAME=opendata
549
- MONGODB_USER=myuser
550
- MONGODB_PASS=mypass
551
- ```
552
-
553
- ## API Reference
554
-
555
- ### Stock Price Interfaces
556
-
557
- ```typescript
558
- interface IStockPrice {
559
- ticker: string;
560
- price: number;
561
- currency: string;
562
- change: number;
563
- changePercent: number;
564
- previousClose: number;
565
- timestamp: Date;
566
- provider: string;
567
- marketState: 'PRE' | 'REGULAR' | 'POST' | 'CLOSED';
568
- exchange?: string;
569
- exchangeName?: string;
570
-
571
- // OHLCV data
572
- volume?: number;
573
- open?: number;
574
- high?: number;
575
- low?: number;
576
- adjusted?: boolean;
577
- dataType: 'eod' | 'intraday' | 'live';
578
- fetchedAt: Date;
579
-
580
- // Company identification
581
- companyName?: string; // "Apple Inc"
582
- companyFullName?: string; // "Apple Inc (NASDAQ:AAPL)"
583
- }
584
- ```
585
-
586
- ### Fundamental Data Interfaces
587
-
588
- ```typescript
589
- interface IStockFundamentals {
590
- ticker: string;
591
- cik: string;
592
- companyName: string;
593
- provider: string;
594
- timestamp: Date;
595
- fetchedAt: Date;
596
-
597
- // Per-share metrics
598
- earningsPerShareBasic?: number;
599
- earningsPerShareDiluted?: number;
600
- sharesOutstanding?: number;
601
-
602
- // Income statement (annual USD)
603
- revenue?: number;
604
- netIncome?: number;
605
- operatingIncome?: number;
606
- grossProfit?: number;
607
-
608
- // Balance sheet (annual USD)
609
- assets?: number;
610
- liabilities?: number;
611
- stockholdersEquity?: number;
612
- cash?: number;
613
- propertyPlantEquipment?: number;
614
-
615
- // Calculated metrics (requires price)
616
- marketCap?: number; // price ร— sharesOutstanding
617
- priceToEarnings?: number; // price / EPS
618
- priceToBook?: number; // marketCap / stockholdersEquity
619
-
620
- // Metadata
621
- fiscalYear?: string;
622
- fiscalQuarter?: string;
623
- filingDate?: Date;
624
- form?: '10-K' | '10-Q' | string;
625
- }
626
- ```
627
-
628
- ### Key Methods
629
-
630
- **StockPriceService**
631
- - `getData(request)` - Unified method for all stock data (current, historical, batch)
632
- - `getPrice(request)` - Convenience method for single current price
633
- - `getPrices(request)` - Convenience method for batch current prices
634
- - `register(provider, config)` - Add data provider with priority and retry config
635
- - `checkProvidersHealth()` - Test all providers and return health status
636
- - `getProviderStats()` - Get success/error statistics for each provider
637
- - `clearCache()` - Clear price cache
638
- - `setCacheTTL(ttl)` - Update cache TTL dynamically
639
-
640
- **FundamentalsService**
641
- - `getFundamentals(ticker)` - Get fundamental data for single ticker
642
- - `getBatchFundamentals(tickers)` - Get fundamentals for multiple tickers
643
- - `enrichWithPrice(fundamentals, price)` - Calculate market cap, P/E, P/B ratios
644
- - `enrichBatchWithPrices(fundamentals, priceMap)` - Batch enrich with prices
645
- - `register(provider, config)` - Add fundamentals provider
646
- - `checkProvidersHealth()` - Test all providers
647
- - `getProviderStats()` - Get success/error statistics
648
- - `clearCache()` - Clear fundamentals cache
649
-
650
- **SecEdgarProvider**
651
- - โœ… FREE - No API key required
652
- - โœ… All US public companies
653
- - โœ… Comprehensive US GAAP financial metrics
654
- - โœ… Historical data back to ~2009
655
- - โœ… Direct access to SEC filings (10-K, 10-Q)
656
- - โœ… Smart caching (CIK: 30 days, Fundamentals: 90 days)
657
- - โœ… Rate limiting (10 requests/second)
658
- - โ„น๏ธ Requires User-Agent header in format: "Company Name Email"
659
-
660
- **MarketstackProvider**
661
- - โœ… End-of-Day (EOD) stock prices
662
- - โœ… 500,000+ tickers across 72+ exchanges worldwide
663
- - โœ… Historical data with pagination
664
- - โœ… Batch fetching support
665
- - โœ… OHLCV data (Open, High, Low, Close, Volume)
666
- - โœ… Company names included automatically
667
- - โš ๏ธ Requires API key (free tier: 100 requests/month)
668
-
669
- **YahooFinanceProvider**
670
- - โœ… Real-time stock prices
671
- - โœ… No API key required
672
- - โœ… Global coverage
673
- - โœ… Company names included
674
- - โš ๏ธ Rate limits may apply
675
-
676
- **CoinGeckoProvider**
677
- - โœ… Cryptocurrency prices (Bitcoin, Ethereum, 13M+ tokens)
678
- - โœ… Current, historical, and intraday data
679
- - โœ… 24/7 market data (crypto never closes)
680
- - โœ… OHLCV data with market cap and volume
681
- - โœ… Supports both ticker symbols (BTC, ETH) and CoinGecko IDs (bitcoin, ethereum)
682
- - โœ… 240+ networks, 1600+ exchanges
683
- - โ„น๏ธ Optional API key (free tier: 30 requests/min, 10K/month)
684
-
685
- **OpenData**
686
- - `start()` - Initialize MongoDB connection
687
- - `buildInitialDb()` - Import bulk data
688
- - `CBusinessRecord` - Business record class
689
- - `handelsregister` - German registry automation
690
-
691
- ## Provider Architecture
692
-
693
- Add custom data providers easily:
694
-
695
- ```typescript
696
- class MyCustomProvider implements IStockProvider {
697
- name = 'My Provider';
698
- priority = 50;
699
- requiresAuth = true;
700
- rateLimit = { requestsPerMinute: 60 };
701
-
702
- async fetchData(request: IStockDataRequest): Promise<IStockPrice | IStockPrice[]> {
703
- // Implement unified data fetching
704
- switch (request.type) {
705
- case 'current':
706
- return this.fetchCurrentPrice(request);
707
- case 'batch':
708
- return this.fetchBatchPrices(request);
709
- case 'historical':
710
- return this.fetchHistoricalPrices(request);
711
- default:
712
- throw new Error(`Unsupported request type`);
713
- }
714
- }
715
-
716
- async isAvailable(): Promise<boolean> {
717
- // Health check
718
- return true;
719
- }
720
-
721
- supportsMarket(market: string): boolean {
722
- return ['US', 'UK', 'DE'].includes(market);
723
- }
724
-
725
- supportsTicker(ticker: string): boolean {
726
- return /^[A-Z]{1,5}$/.test(ticker);
727
- }
728
- }
729
-
730
- stockService.register(new MyCustomProvider());
731
- ```
732
-
733
- ## Performance
734
-
735
- - **Batch Fetching**: Get 100+ prices in one API request
736
- - **Smart Caching**: Data-type aware TTL (historical cached forever, EOD 24h, live 30s)
737
- - **Rate Limit Management**: Automatic retry logic for API limits
738
- - **Concurrent Processing**: Handle 1000+ records/second
739
- - **Streaming**: Process GB-sized datasets without memory issues
740
- - **Provider Fallback**: Automatic failover between data sources
303
+ Useful request patterns:
304
+
305
+ - Germany: `identifier: 'aeg'`
306
+ - EU: `identifier: '32024R1689'`, `language: 'EN'`
307
+ - US public law package: `identifier: 'PLAW-119publ1'`, `usCollection: 'PLAW'`
308
+ - US Code citation: `identifier: '8 U.S.C. ยง 1226'`
309
+
310
+ ## API At A Glance
311
+
312
+ ### `StockPriceService`
313
+
314
+ - `register(provider, config?)`
315
+ - `unregister(providerName)`
316
+ - `getPrice({ ticker })`
317
+ - `getPrices({ tickers })`
318
+ - `getData(request)`
319
+ - `checkProvidersHealth()`
320
+ - `getProviderStats()`
321
+ - `clearCache()`
322
+ - `getCacheStats()`
323
+
324
+ ### `FundamentalsService`
325
+
326
+ - `register(provider, config?)`
327
+ - `getFundamentals(ticker)`
328
+ - `getBatchFundamentals(tickers)`
329
+ - `getData(request)`
330
+ - `enrichWithPrice(fundamentals, price)`
331
+ - `checkProvidersHealth()`
332
+ - `getProviderStats()`
333
+ - `clearCache()`
334
+
335
+ ### `StockDataService`
336
+
337
+ - `registerPriceProvider(provider, config?)`
338
+ - `registerFundamentalsProvider(provider, config?)`
339
+ - `getPrice(ticker)`
340
+ - `getPrices(tickers)`
341
+ - `getFundamentals(ticker)`
342
+ - `getBatchFundamentals(tickers)`
343
+ - `getStockData(ticker | request)`
344
+ - `getBatchStockData(tickers | request)`
345
+ - `checkProvidersHealth()`
346
+ - `getProviderStats()`
347
+ - `clearCache()`
348
+
349
+ ### `OpenData`
350
+
351
+ - `start()`
352
+ - `stop()`
353
+ - `buildInitialDb()`
354
+ - `handelsregister.searchCompany(name, limit?)`
355
+ - `handelsregister.getSpecificCompany({ court, type, number })`
356
+ - `handelsregister.getSpecificCompanyByName(name)`
357
+
358
+ ### `LawService`
359
+
360
+ - `start()`
361
+ - `stop()`
362
+ - `getLaw(request)`
363
+ - `syncLaw(request)`
364
+ - `syncLaws(request)`
365
+ - `searchLaws({ query, jurisdiction?, limit? })`
366
+
367
+ ## Behavior And Caveats
368
+
369
+ - Historical market data is cached aggressively because it is treated as immutable.
370
+ - Intraday data uses interval-aware caching and tries incremental refreshes for recent data.
371
+ - `StockDataService` is convenience-first. `StockPriceService` is the better low-level choice if you care about request-shape-specific cache behavior.
372
+ - `OpenData` is a real workflow layer, not just types. It writes local data, launches a browser, and manages downloads.
373
+ - Handelsregister and EUR-Lex integrations depend on current site structure. They are practical automation workflows, not guaranteed stable official APIs.
374
+ - The most useful public `OpenData` features today are startup, JSONL import, and Handelsregister operations. Some extra validation/search helper methods exist in source but are still stubs.
375
+ - `LawService` persists synced laws locally, so repeated searches can stay offline once the data has been synced.
376
+ - There is no hosted backend in this package. Everything is meant to run from your own TypeScript/Node process.
741
377
 
742
378
  ## Testing
743
379
 
744
- Run the comprehensive test suite:
745
-
746
380
  ```bash
747
381
  pnpm test
748
382
  ```
749
383
 
750
- Test specific modules:
751
-
752
- ```bash
753
- # Stock price providers
754
- pnpm tstest test/test.marketstack.node.ts --verbose
755
- pnpm tstest test/test.stocks.ts --verbose
756
-
757
- # Fundamental data
758
- pnpm tstest test/test.secedgar.provider.node.ts --verbose
759
- pnpm tstest test/test.fundamentals.service.node.ts --verbose
760
-
761
- # German business data
762
- pnpm tstest test/test.handelsregister.ts --verbose
763
- ```
764
-
765
- ## Getting API Keys
766
-
767
- ### Marketstack (EOD Stock Data)
768
-
769
- 1. Visit [marketstack.com](https://marketstack.com)
770
- 2. Sign up for a free account (100 requests/month)
771
- 3. Get your API key from the dashboard
772
- 4. Set environment variable: `MARKETSTACK_COM_TOKEN=your_key_here`
773
-
774
- ### SEC EDGAR (Fundamental Data)
775
-
776
- **No API key required!** SEC EDGAR is completely free and public. Just provide your company name and email in the User-Agent:
777
-
778
- ```typescript
779
- new SecEdgarProvider({
780
- userAgent: 'YourCompany youremail@example.com'
781
- });
782
- ```
384
+ Some tests hit live remote services, so they may depend on network access, optional API credentials, or browser automation support.
783
385
 
784
386
  ## License and Legal Information
785
387
 
786
- This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
388
+ This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./license) file.
787
389
 
788
390
  **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
789
391
 
790
392
  ### Trademarks
791
393
 
792
- This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
394
+ This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
395
+
396
+ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
793
397
 
794
398
  ### Company Information
795
399
 
796
- Task Venture Capital GmbH
797
- Registered at District court Bremen HRB 35230 HB, Germany
400
+ Task Venture Capital GmbH
401
+ Registered at District Court Bremen HRB 35230 HB, Germany
798
402
 
799
- For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
403
+ For any legal inquiries or further information, please contact us via email at hello@task.vc.
800
404
 
801
405
  By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.