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