@fin.cx/opendata 1.5.4 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/stocks/interfaces/stockprice.js +2 -2
- package/dist_ts/stocks/providers/provider.yahoo.js +17 -15
- package/package.json +12 -12
- package/readme.md +209 -560
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/stocks/interfaces/stockprice.ts +7 -1
- package/ts/stocks/providers/provider.yahoo.ts +14 -12
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@fin.cx/opendata',
|
|
6
|
-
version: '1.
|
|
7
|
-
description: 'A comprehensive TypeScript library
|
|
6
|
+
version: '1.6.1',
|
|
7
|
+
description: 'A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.'
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxrQkFBa0I7SUFDeEIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHVTQUF1UztDQUNyVCxDQUFBIn0=
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvY2twcmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3N0b2Nrcy9pbnRlcmZhY2VzL3N0b2NrcHJpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQyJ9
|
|
@@ -16,13 +16,14 @@ export class YahooFinanceProvider {
|
|
|
16
16
|
async fetchPrice(request) {
|
|
17
17
|
try {
|
|
18
18
|
const url = `${this.baseUrl}/v8/finance/chart/${request.ticker}`;
|
|
19
|
-
const response = await plugins.smartrequest.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const response = await plugins.smartrequest.SmartRequest.create()
|
|
20
|
+
.url(url)
|
|
21
|
+
.headers({
|
|
22
|
+
'User-Agent': this.userAgent
|
|
23
|
+
})
|
|
24
|
+
.timeout(this.config?.timeout || 10000)
|
|
25
|
+
.get();
|
|
26
|
+
const responseData = await response.json();
|
|
26
27
|
if (!responseData?.chart?.result?.[0]) {
|
|
27
28
|
throw new Error(`No data found for ticker ${request.ticker}`);
|
|
28
29
|
}
|
|
@@ -55,13 +56,14 @@ export class YahooFinanceProvider {
|
|
|
55
56
|
try {
|
|
56
57
|
const symbols = request.tickers.join(',');
|
|
57
58
|
const url = `${this.baseUrl}/v8/finance/spark?symbols=${symbols}&range=1d&interval=5m`;
|
|
58
|
-
const response = await plugins.smartrequest.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
const response = await plugins.smartrequest.SmartRequest.create()
|
|
60
|
+
.url(url)
|
|
61
|
+
.headers({
|
|
62
|
+
'User-Agent': this.userAgent
|
|
63
|
+
})
|
|
64
|
+
.timeout(this.config?.timeout || 15000)
|
|
65
|
+
.get();
|
|
66
|
+
const responseData = await response.json();
|
|
65
67
|
const prices = [];
|
|
66
68
|
for (const [ticker, data] of Object.entries(responseData)) {
|
|
67
69
|
if (!data || typeof data !== 'object')
|
|
@@ -136,4 +138,4 @@ export class YahooFinanceProvider {
|
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
141
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXIueWFob28uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9zdG9ja3MvcHJvdmlkZXJzL3Byb3ZpZGVyLnlhaG9vLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFJNUMsTUFBTSxPQUFPLG9CQUFvQjtJQWEvQixZQUFvQixNQUF3QjtRQUF4QixXQUFNLEdBQU4sTUFBTSxDQUFrQjtRQVpyQyxTQUFJLEdBQUcsZUFBZSxDQUFDO1FBQ3ZCLGFBQVEsR0FBRyxHQUFHLENBQUM7UUFDTixpQkFBWSxHQUFHLEtBQUssQ0FBQztRQUNyQixjQUFTLEdBQUc7WUFDMUIsaUJBQWlCLEVBQUUsR0FBRyxFQUFFLHdCQUF3QjtZQUNoRCxjQUFjLEVBQUUsU0FBUztTQUMxQixDQUFDO1FBRU0sV0FBTSxHQUFHLE9BQU8sQ0FBQztRQUNqQixZQUFPLEdBQUcsa0NBQWtDLENBQUM7UUFDN0MsY0FBUyxHQUFHLGlIQUFpSCxDQUFDO0lBRXZGLENBQUM7SUFFekMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUEyQjtRQUNqRCxJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLHFCQUFxQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakUsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUU7aUJBQzlELEdBQUcsQ0FBQyxHQUFHLENBQUM7aUJBQ1IsT0FBTyxDQUFDO2dCQUNQLFlBQVksRUFBRSxJQUFJLENBQUMsU0FBUzthQUM3QixDQUFDO2lCQUNELE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLE9BQU8sSUFBSSxLQUFLLENBQUM7aUJBQ3RDLEdBQUcsRUFBRSxDQUFDO1lBRVQsTUFBTSxZQUFZLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFTLENBQUM7WUFF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
|
package/package.json
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fin.cx/opendata",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "A comprehensive TypeScript library
|
|
5
|
+
"description": "A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
7
7
|
"typings": "dist_ts/index.d.ts",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"author": "Task Venture Capital GmbH",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@git.zone/tsbuild": "^2.6.
|
|
12
|
+
"@git.zone/tsbuild": "^2.6.8",
|
|
13
13
|
"@git.zone/tsbundle": "^2.5.1",
|
|
14
14
|
"@git.zone/tsrun": "^1.3.3",
|
|
15
|
-
"@git.zone/tstest": "^2.3.
|
|
15
|
+
"@git.zone/tstest": "^2.3.8",
|
|
16
16
|
"@types/node": "^22.14.0"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@push.rocks/lik": "^6.2.2",
|
|
20
|
-
"@push.rocks/qenv": "^6.1.
|
|
21
|
-
"@push.rocks/smartarchive": "^4.
|
|
20
|
+
"@push.rocks/qenv": "^6.1.3",
|
|
21
|
+
"@push.rocks/smartarchive": "^4.2.2",
|
|
22
22
|
"@push.rocks/smartarray": "^1.1.0",
|
|
23
23
|
"@push.rocks/smartbrowser": "^2.0.8",
|
|
24
|
-
"@push.rocks/smartdata": "^5.
|
|
24
|
+
"@push.rocks/smartdata": "^5.16.4",
|
|
25
25
|
"@push.rocks/smartdelay": "^3.0.5",
|
|
26
|
-
"@push.rocks/smartfile": "^11.2.
|
|
27
|
-
"@push.rocks/smartlog": "^3.1.
|
|
28
|
-
"@push.rocks/smartpath": "^
|
|
26
|
+
"@push.rocks/smartfile": "^11.2.7",
|
|
27
|
+
"@push.rocks/smartlog": "^3.1.10",
|
|
28
|
+
"@push.rocks/smartpath": "^6.0.0",
|
|
29
29
|
"@push.rocks/smartpromise": "^4.2.3",
|
|
30
|
-
"@push.rocks/smartrequest": "^
|
|
30
|
+
"@push.rocks/smartrequest": "^4.3.1",
|
|
31
31
|
"@push.rocks/smartstream": "^3.2.5",
|
|
32
32
|
"@push.rocks/smartunique": "^3.0.9",
|
|
33
33
|
"@push.rocks/smartxml": "^1.1.1",
|
|
34
|
-
"@tsclass/tsclass": "^9.
|
|
34
|
+
"@tsclass/tsclass": "^9.3.0"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|
package/readme.md
CHANGED
|
@@ -1,649 +1,298 @@
|
|
|
1
1
|
# @fin.cx/opendata
|
|
2
|
-
|
|
2
|
+
🚀 **Real-time financial data and German business intelligence in one powerful TypeScript library**
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Access live stock prices, cryptocurrencies, forex, commodities AND comprehensive German company data - all through a single, unified API.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Using npm:
|
|
9
|
-
|
|
10
|
-
npm install @fin.cx/opendata
|
|
11
|
-
|
|
12
|
-
Using yarn:
|
|
13
|
-
|
|
14
|
-
yarn add @fin.cx/opendata
|
|
15
|
-
|
|
16
|
-
## Usage
|
|
17
|
-
|
|
18
|
-
The @fin.cx/opendata library is a versatile tool that empowers developers to integrate comprehensive open business data into their systems. This library is particularly tailored for German companies, offering functionalities that include creating, retrieving, updating, and deleting business records as well as processing large volumes of JSONL data from external sources. In addition to core database operations via MongoDB, the library provides integration with web-based services, primarily through a hands-on Handelsregister processor that utilizes browser automation for searching and downloading documents.
|
|
19
|
-
|
|
20
|
-
In this section, we will extensively detail multiple usage scenarios, ensuring that every feature the module offers is thoroughly explored. All examples in this documentation employ ECMAScript Module (ESM) syntax and TypeScript, highlighting proper asynchronous handling, error management, and advanced integration with other dependencies. We will walk you through environment setup, initializing the package, managing business records, processing bulk JSONL data, interacting with the Handelsregister for on-demand document retrieval, and much more. Each example is constructed to expose every nuance of the module's behavior and usage.
|
|
21
|
-
|
|
22
|
-
For clarity, we will split this section into multiple parts:
|
|
23
|
-
|
|
24
|
-
1. Environment Setup and Initializing the Library
|
|
25
|
-
2. Managing Business Records (CRUD Operations)
|
|
26
|
-
3. Bulk Data Processing and Importing via JSONL Streams
|
|
27
|
-
4. Integrating with the Handelsregister: Detailed Demonstrations
|
|
28
|
-
5. Advanced Examples: Combined Operations and Edge Cases
|
|
29
|
-
6. Error Handling and Data Validation
|
|
30
|
-
7. Testing and Automated Workflows
|
|
31
|
-
|
|
32
|
-
Throughout these examples, we will examine how each class and method interacts with the underlying MongoDB database and the system's file structure. We assume you have a running MongoDB instance and that your environment is configured with the necessary variables.
|
|
33
|
-
|
|
34
|
-
────────────────────────────────────────────
|
|
35
|
-
### 1. Environment Setup and Initializing the Library
|
|
36
|
-
|
|
37
|
-
Before diving into any operations, ensure that your development environment is properly configured. The @fin.cx/opendata library mandates several environment variables for connecting to your MongoDB instance. For a smooth experience, it is advisable to use a .env file or any secure secrets management tool that suits your workflow. The required environment variables include:
|
|
38
|
-
|
|
39
|
-
• MONGODB_URL – The connection string URL for your MongoDB instance.
|
|
40
|
-
• MONGODB_NAME – The name of the database that the module will interact with.
|
|
41
|
-
• MONGODB_USER – MongoDB username required for authentication.
|
|
42
|
-
• MONGODB_PASS – The password for the MongoDB user.
|
|
43
|
-
|
|
44
|
-
Below is an example .env file for local development:
|
|
6
|
+
## Installation
|
|
45
7
|
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
MONGODB_PASS=myPass
|
|
8
|
+
```bash
|
|
9
|
+
npm install @fin.cx/opendata
|
|
10
|
+
# or
|
|
11
|
+
yarn add @fin.cx/opendata
|
|
51
12
|
```
|
|
52
13
|
|
|
53
|
-
|
|
14
|
+
## Quick Start
|
|
54
15
|
|
|
55
|
-
|
|
56
|
-
import { OpenData } from '@fin.cx/opendata';
|
|
16
|
+
### 📈 Real-Time Stock Data
|
|
57
17
|
|
|
58
|
-
|
|
59
|
-
const openData = new OpenData();
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
console.log('Starting OpenData instance...');
|
|
63
|
-
await openData.start();
|
|
64
|
-
console.log('OpenData instance started successfully.');
|
|
65
|
-
|
|
66
|
-
// Invoke sample operations:
|
|
67
|
-
await demonstrateBusinessRecordsOperations(openData);
|
|
68
|
-
await demonstrateBulkDataProcessing(openData);
|
|
69
|
-
await demonstrateHandelsregisterOperations(openData);
|
|
70
|
-
|
|
71
|
-
} catch (error) {
|
|
72
|
-
console.error('Error during initialization:', error);
|
|
73
|
-
} finally {
|
|
74
|
-
console.log('Stopping OpenData instance...');
|
|
75
|
-
await openData.stop();
|
|
76
|
-
console.log('OpenData instance stopped.');
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
startOpenDataInstance();
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
In this snippet, we import the OpenData class from the module and execute its start and stop routines to ensure that the MongoDB connection is properly initialized and terminated. Notice that we move on to different demonstration functions that showcase individual features.
|
|
84
|
-
|
|
85
|
-
────────────────────────────────────────────
|
|
86
|
-
### 2. Managing Business Records (CRUD Operations)
|
|
87
|
-
|
|
88
|
-
Central to the @fin.cx/opendata library is the management of business records. The BusinessRecord class encapsulates data pertaining to companies, allowing you to create new records, retrieve existing ones, update information, and delete entries when necessary. The following examples illustrate each operation within a robust context.
|
|
89
|
-
|
|
90
|
-
#### a) Creating a Business Record
|
|
91
|
-
|
|
92
|
-
Creating a new business record in the openData instance is straightforward. You instantiate a new record and populate its data properties with relevant details such as company name, address, registration number, managing directors, and much more. The sample below uses the embedded CBusinessRecord manager to generate a new record:
|
|
18
|
+
Get live market data in seconds:
|
|
93
19
|
|
|
94
20
|
```typescript
|
|
95
|
-
import {
|
|
21
|
+
import { StockPriceService, YahooFinanceProvider } from '@fin.cx/opendata';
|
|
96
22
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
businessRecord.data = {
|
|
101
|
-
name: "Innovative Solutions GmbH",
|
|
102
|
-
address: "Musterstraße 1",
|
|
103
|
-
postalCode: "10115",
|
|
104
|
-
city: "Berlin",
|
|
105
|
-
country: "Germany",
|
|
106
|
-
phone: "+49 30 123456",
|
|
107
|
-
email: "contact@innovativesolutions.de",
|
|
108
|
-
website: "https://innovativesolutions.de",
|
|
109
|
-
businessType: "GmbH",
|
|
110
|
-
registrationId: "District court Berlin HRB 987654",
|
|
111
|
-
legalForm: "GmbH",
|
|
112
|
-
managingDirectors: ["Max Mustermann", "Erika Musterfrau"],
|
|
113
|
-
foundingDate: new Date("2018-05-10").toISOString(),
|
|
114
|
-
capital: "250,000 EUR",
|
|
115
|
-
purpose: "Technology development and consulting services",
|
|
116
|
-
lastUpdate: new Date().toISOString()
|
|
117
|
-
};
|
|
23
|
+
// Initialize the service
|
|
24
|
+
const stockService = new StockPriceService();
|
|
25
|
+
stockService.register(new YahooFinanceProvider());
|
|
118
26
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('Error creating business record:', error);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
```
|
|
27
|
+
// Get single stock price
|
|
28
|
+
const apple = await stockService.getPrice({ ticker: 'AAPL' });
|
|
29
|
+
console.log(`Apple: $${apple.price} (${apple.changePercent.toFixed(2)}%)`);
|
|
127
30
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
To retrieve business records, you can search by various fields such as city, business name, or registration details. The system utilizes MongoDB queries to filter and return relevant documents. Below is a sample function that retrieves all records for companies based in a particular city:
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
import { OpenData } from '@fin.cx/opendata';
|
|
136
|
-
import type { BusinessRecord } from '@fin.cx/opendata';
|
|
31
|
+
// Get multiple prices at once
|
|
32
|
+
const prices = await stockService.getPrices({
|
|
33
|
+
tickers: ['AAPL', 'MSFT', 'GOOGL', 'BTC-USD', 'ETH-USD']
|
|
34
|
+
});
|
|
137
35
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.find({ city })
|
|
143
|
-
.toArray();
|
|
144
|
-
|
|
145
|
-
console.log(`Retrieved ${records.length} records for city ${city}.`);
|
|
146
|
-
console.log(records);
|
|
147
|
-
return records;
|
|
148
|
-
} catch (error) {
|
|
149
|
-
console.error('Error retrieving business records:', error);
|
|
150
|
-
}
|
|
151
|
-
};
|
|
36
|
+
// Market indices, crypto, forex, commodities - all supported!
|
|
37
|
+
const marketData = await stockService.getPrices({
|
|
38
|
+
tickers: ['^GSPC', '^DJI', 'BTC-USD', 'EURUSD=X', 'GC=F']
|
|
39
|
+
});
|
|
152
40
|
```
|
|
153
41
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
#### c) Updating an Existing Business Record
|
|
42
|
+
### 🏢 German Business Data
|
|
157
43
|
|
|
158
|
-
|
|
44
|
+
Access comprehensive data on German companies:
|
|
159
45
|
|
|
160
46
|
```typescript
|
|
161
47
|
import { OpenData } from '@fin.cx/opendata';
|
|
162
48
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// Retrieve the record by its id using the manager’s helper
|
|
166
|
-
const businessRecord = await openData.CBusinessRecord.getInstance(recordId);
|
|
167
|
-
if (!businessRecord) {
|
|
168
|
-
console.log(`No business record found with id: ${recordId}`);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
49
|
+
const openData = new OpenData();
|
|
50
|
+
await openData.start();
|
|
171
51
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
} catch (error) {
|
|
180
|
-
console.error('Error updating business record:', error);
|
|
181
|
-
}
|
|
52
|
+
// Create a business record
|
|
53
|
+
const company = new openData.CBusinessRecord();
|
|
54
|
+
company.data = {
|
|
55
|
+
name: "TechStart GmbH",
|
|
56
|
+
city: "Berlin",
|
|
57
|
+
registrationId: "HRB 123456",
|
|
58
|
+
// ... more fields
|
|
182
59
|
};
|
|
183
|
-
|
|
60
|
+
await company.save();
|
|
184
61
|
|
|
185
|
-
|
|
62
|
+
// Search companies by city
|
|
63
|
+
const berlinCompanies = await openData.db
|
|
64
|
+
.collection('businessrecords')
|
|
65
|
+
.find({ city: "Berlin" })
|
|
66
|
+
.toArray();
|
|
186
67
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
The deletion of a record is as vital as its creation and modification. The library provides a delete method that removes the specified record from the database. Below is a simple function to delete a business record by its identifier:
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
import { OpenData } from '@fin.cx/opendata';
|
|
193
|
-
|
|
194
|
-
export const deleteBusinessRecordExample = async (openData: OpenData, recordId: string) => {
|
|
195
|
-
try {
|
|
196
|
-
const businessRecord = await openData.CBusinessRecord.getInstance(recordId);
|
|
197
|
-
if (businessRecord) {
|
|
198
|
-
await businessRecord.delete();
|
|
199
|
-
console.log(`Successfully deleted business record with id: ${recordId}`);
|
|
200
|
-
} else {
|
|
201
|
-
console.log(`No business record found with id: ${recordId}`);
|
|
202
|
-
}
|
|
203
|
-
} catch (error) {
|
|
204
|
-
console.error('Error deleting business record:', error);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
68
|
+
// Import bulk data from official sources
|
|
69
|
+
await openData.buildInitialDb();
|
|
207
70
|
```
|
|
208
71
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
────────────────────────────────────────────
|
|
212
|
-
### 3. Bulk Data Processing and Importing via JSONL Streams
|
|
72
|
+
## Features
|
|
213
73
|
|
|
214
|
-
|
|
74
|
+
### 🎯 Stock Market Module
|
|
215
75
|
|
|
216
|
-
|
|
76
|
+
- **Real-time prices** for stocks, ETFs, indices, crypto, forex, and commodities
|
|
77
|
+
- **Batch operations** - fetch 100+ symbols in one request
|
|
78
|
+
- **Smart caching** - configurable TTL, automatic invalidation
|
|
79
|
+
- **Provider system** - easily extensible for new data sources
|
|
80
|
+
- **Automatic retries** and fallback mechanisms
|
|
81
|
+
- **Type-safe** - full TypeScript support with detailed interfaces
|
|
217
82
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
import { OpenData } from '@fin.cx/opendata';
|
|
83
|
+
### 🇩🇪 German Business Intelligence
|
|
222
84
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
await openData.jsonLDataProcessor.processDataFromUrl(dataUrl);
|
|
229
|
-
console.log('Bulk data processing completed successfully.');
|
|
230
|
-
} catch (error) {
|
|
231
|
-
console.error('Error during bulk data processing:', error);
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
```
|
|
85
|
+
- **MongoDB integration** for scalable data storage
|
|
86
|
+
- **Bulk JSONL import** from official German data sources
|
|
87
|
+
- **Handelsregister automation** - automated document retrieval
|
|
88
|
+
- **CRUD operations** with validation
|
|
89
|
+
- **Streaming processing** for multi-GB datasets
|
|
235
90
|
|
|
236
|
-
|
|
91
|
+
## Advanced Examples
|
|
237
92
|
|
|
238
|
-
|
|
239
|
-
• The JSONL data is received as a binary (Buffer) stream.
|
|
240
|
-
• The stream is piped into a duplex stream that splits the text by newline characters.
|
|
241
|
-
• Each line is parsed into a JSON object and passed into an asynchronous processing function.
|
|
242
|
-
• This function creates a new business record and sets properties such as the company name and its registration details, derived from the JSON entry.
|
|
243
|
-
• As the processor moves through the stream, it logs progress every 10,000 records to give feedback on its bulk processing status.
|
|
93
|
+
### Market Dashboard
|
|
244
94
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
────────────────────────────────────────────
|
|
248
|
-
### 4. Integrating with the Handelsregister: Detailed Demonstrations
|
|
249
|
-
|
|
250
|
-
In addition to CRUD operations and bulk processing, the module includes an integrated Handelsregister system. This sophisticated component leverages a headless browser (via the smartbrowser instance) to interact with the official Handelsregister website. Through this integration, you can search for companies, navigate to specific pages, trigger file downloads (such as PDF or XML data), and parse the downloaded content for further processing.
|
|
251
|
-
|
|
252
|
-
#### a) Starting the Handelsregister
|
|
253
|
-
|
|
254
|
-
Before executing any search or download operations, the Handelsregister system must be started. The start method initializes required resources including starting a headless browser, ensuring download directories are created, and preparing asynchronous stacks for exclusive execution.
|
|
95
|
+
Create a real-time market overview:
|
|
255
96
|
|
|
256
97
|
```typescript
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
98
|
+
const indicators = [
|
|
99
|
+
// Indices
|
|
100
|
+
{ ticker: '^GSPC', name: 'S&P 500' },
|
|
101
|
+
{ ticker: '^IXIC', name: 'NASDAQ' },
|
|
102
|
+
|
|
103
|
+
// Tech Giants
|
|
104
|
+
{ ticker: 'AAPL', name: 'Apple' },
|
|
105
|
+
{ ticker: 'MSFT', name: 'Microsoft' },
|
|
106
|
+
|
|
107
|
+
// Crypto
|
|
108
|
+
{ ticker: 'BTC-USD', name: 'Bitcoin' },
|
|
109
|
+
{ ticker: 'ETH-USD', name: 'Ethereum' },
|
|
110
|
+
|
|
111
|
+
// Commodities
|
|
112
|
+
{ ticker: 'GC=F', name: 'Gold' },
|
|
113
|
+
{ ticker: 'CL=F', name: 'Oil' }
|
|
114
|
+
];
|
|
273
115
|
|
|
274
|
-
|
|
275
|
-
|
|
116
|
+
const prices = await stockService.getPrices({
|
|
117
|
+
tickers: indicators.map(i => i.ticker)
|
|
118
|
+
});
|
|
276
119
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
};
|
|
120
|
+
// Display with color-coded changes
|
|
121
|
+
prices.forEach(price => {
|
|
122
|
+
const indicator = indicators.find(i => i.ticker === price.ticker);
|
|
123
|
+
const arrow = price.change >= 0 ? '↑' : '↓';
|
|
124
|
+
const color = price.change >= 0 ? '\x1b[32m' : '\x1b[31m';
|
|
125
|
+
|
|
126
|
+
console.log(
|
|
127
|
+
`${indicator.name.padEnd(15)} ${price.price.toFixed(2).padStart(10)} ` +
|
|
128
|
+
`${color}${arrow} ${price.changePercent.toFixed(2)}%\x1b[0m`
|
|
129
|
+
);
|
|
130
|
+
});
|
|
288
131
|
```
|
|
289
132
|
|
|
290
|
-
|
|
291
|
-
• getNewPage – to create a new browser page with file download behavior enabled.
|
|
292
|
-
• navigateToPage – which navigates to the “Normal search” page.
|
|
293
|
-
• Input events – to simulate typing in search criteria.
|
|
294
|
-
• UI interactions – to select options and trigger the search.
|
|
295
|
-
|
|
296
|
-
#### c) Retrieving Detailed Data and Triggering Downloads
|
|
297
|
-
|
|
298
|
-
After obtaining general search results, you may wish to retrieve more detailed information about a specific company. Provided you have the parsed registration data (which typically includes the registration court, type, and number), you can instruct the system to navigate to a detailed view and trigger file downloads. These files might include the company’s official registry entry (as an XML file) and additional documents (such as a PDF summary).
|
|
133
|
+
### Handelsregister Integration
|
|
299
134
|
|
|
300
|
-
|
|
135
|
+
Automate German company data retrieval:
|
|
301
136
|
|
|
302
137
|
```typescript
|
|
303
|
-
|
|
138
|
+
// Search for a company
|
|
139
|
+
const results = await openData.handelsregister.searchCompany("Siemens AG");
|
|
140
|
+
|
|
141
|
+
// Get detailed information and documents
|
|
142
|
+
const details = await openData.handelsregister.getSpecificCompany({
|
|
143
|
+
court: "Munich",
|
|
144
|
+
type: "HRB",
|
|
145
|
+
number: "6684"
|
|
146
|
+
});
|
|
304
147
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
console.log('Downloaded Files:', result.files);
|
|
312
|
-
return result;
|
|
313
|
-
} catch (error) {
|
|
314
|
-
console.error('Error retrieving detailed company data:', error);
|
|
315
|
-
}
|
|
316
|
-
};
|
|
148
|
+
// Downloaded files include:
|
|
149
|
+
// - XML data (SI files)
|
|
150
|
+
// - PDF documents (AD files)
|
|
151
|
+
for (const file of details.files) {
|
|
152
|
+
await file.writeToDir('./downloads');
|
|
153
|
+
}
|
|
317
154
|
```
|
|
318
155
|
|
|
319
|
-
|
|
320
|
-
• The getSpecificCompany method triggers navigation through various UI elements:
|
|
321
|
-
– Selecting the register type via a dropdown.
|
|
322
|
-
– Inputting the register number.
|
|
323
|
-
– Choosing the appropriate register court.
|
|
324
|
-
• Then, after clicking the “Find” button, the system waits for the results, verifies the visual components on the page, and initiates file downloads.
|
|
325
|
-
• The downloaded files are renamed according to their type (SI for XML and AD for PDF) and are returned for further processing or storage.
|
|
326
|
-
|
|
327
|
-
#### d) Downloading and Processing Files
|
|
328
|
-
|
|
329
|
-
The Handelsregister component not only triggers file downloads but also includes utility functions that wait for downloads to complete, clear temporary directories, and output the file objects. You may want to use these file objects to persist data locally, parse file content, or send the data downstream for further analysis.
|
|
156
|
+
### Combined Data Analysis
|
|
330
157
|
|
|
331
|
-
|
|
158
|
+
Merge financial and business data:
|
|
332
159
|
|
|
333
160
|
```typescript
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
161
|
+
// Find all public German companies (AG)
|
|
162
|
+
const publicCompanies = await openData.db
|
|
163
|
+
.collection('businessrecords')
|
|
164
|
+
.find({ legalForm: 'AG' })
|
|
165
|
+
.toArray();
|
|
166
|
+
|
|
167
|
+
// Enrich with stock data
|
|
168
|
+
for (const company of publicCompanies) {
|
|
338
169
|
try {
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
170
|
+
// Map company to ticker (custom logic needed)
|
|
171
|
+
const ticker = mapCompanyToTicker(company.data.name);
|
|
172
|
+
|
|
173
|
+
if (ticker) {
|
|
174
|
+
const stock = await stockService.getPrice({ ticker });
|
|
175
|
+
|
|
176
|
+
// Add financial metrics
|
|
177
|
+
company.data.stockPrice = stock.price;
|
|
178
|
+
company.data.marketCap = stock.price * getSharesOutstanding(ticker);
|
|
179
|
+
company.data.priceChange = stock.changePercent;
|
|
180
|
+
|
|
181
|
+
await company.save();
|
|
347
182
|
}
|
|
348
183
|
} catch (error) {
|
|
349
|
-
|
|
184
|
+
// Handle missing tickers gracefully
|
|
350
185
|
}
|
|
351
|
-
}
|
|
186
|
+
}
|
|
352
187
|
```
|
|
353
188
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
────────────────────────────────────────────
|
|
357
|
-
### 5. Advanced Examples: Combined Operations and Edge Cases
|
|
358
|
-
|
|
359
|
-
Given the numerous functionalities offered by the library, you can combine various operations to create more complex workflows. One such example is an end-to-end pipeline that:
|
|
360
|
-
1. Initializes the open data instance.
|
|
361
|
-
2. Processes an initial bulk data import.
|
|
362
|
-
3. Searches for key business records that match specific criteria.
|
|
363
|
-
4. Updates individual records based on additional data retrieved from the Handelsregister.
|
|
364
|
-
5. Handles error conditions and retries processes where necessary.
|
|
189
|
+
## Configuration
|
|
365
190
|
|
|
366
|
-
|
|
191
|
+
### Stock Service Options
|
|
367
192
|
|
|
368
193
|
```typescript
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
try {
|
|
375
|
-
console.log('Starting advanced workflow...');
|
|
376
|
-
await openData.start();
|
|
377
|
-
|
|
378
|
-
// Step 1: Bulk data import from external JSONL source
|
|
379
|
-
console.log('Building initial database from bulk import...');
|
|
380
|
-
await openData.buildInitialDb();
|
|
381
|
-
|
|
382
|
-
// Step 2: Search for companies in a selected area (for instance, Munich)
|
|
383
|
-
console.log('Retrieving companies located in Munich...');
|
|
384
|
-
const munichRecords = await openData.db
|
|
385
|
-
.collection('businessrecords')
|
|
386
|
-
.find({ city: "Munich" })
|
|
387
|
-
.toArray();
|
|
388
|
-
console.log(`Found ${munichRecords.length} companies in Munich.`);
|
|
389
|
-
|
|
390
|
-
// Step 3: For each record, perform an update operation based on new file downloads
|
|
391
|
-
for (const record of munichRecords) {
|
|
392
|
-
try {
|
|
393
|
-
console.log(`Updating record for company: ${record.data.name}`);
|
|
394
|
-
// Assuming the record contains parsed registration info
|
|
395
|
-
if (record.data.germanParsedRegistration) {
|
|
396
|
-
const detailedData = await openData.handelsregister.getSpecificCompany(record.data.germanParsedRegistration);
|
|
397
|
-
// Update business record with new information (e.g., registration files or updated details)
|
|
398
|
-
record.data.lastUpdate = new Date().toISOString();
|
|
399
|
-
// You might want to add additional fields based on the downloaded file data
|
|
400
|
-
await record.save();
|
|
401
|
-
console.log(`Updated record for ${record.data.name}.`);
|
|
402
|
-
} else {
|
|
403
|
-
console.log(`No registration data available for ${record.data.name}; skipping update.`);
|
|
404
|
-
}
|
|
405
|
-
} catch (innerError) {
|
|
406
|
-
console.error(`Error updating record for ${record.data.name}:`, innerError);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Step 4: Demonstrate retrieval and deletion
|
|
411
|
-
const recordToDeleteId = munichRecords.length > 0 ? munichRecords[0].id : null;
|
|
412
|
-
if (recordToDeleteId) {
|
|
413
|
-
console.log(`Deleting record with id: ${recordToDeleteId}`);
|
|
414
|
-
const recordToDelete = await openData.CBusinessRecord.getInstance(recordToDeleteId);
|
|
415
|
-
if (recordToDelete) {
|
|
416
|
-
await recordToDelete.delete();
|
|
417
|
-
console.log(`Record ${recordToDeleteId} deleted successfully.`);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
} catch (error) {
|
|
422
|
-
console.error('Advanced workflow encountered an error:', error);
|
|
423
|
-
} finally {
|
|
424
|
-
console.log('Ending advanced workflow and stopping OpenData instance.');
|
|
425
|
-
await openData.stop();
|
|
426
|
-
}
|
|
427
|
-
};
|
|
194
|
+
const stockService = new StockPriceService({
|
|
195
|
+
ttl: 60000, // Cache for 1 minute
|
|
196
|
+
maxEntries: 1000 // Max cached symbols
|
|
197
|
+
});
|
|
428
198
|
|
|
429
|
-
|
|
199
|
+
// Provider configuration
|
|
200
|
+
stockService.register(new YahooFinanceProvider(), {
|
|
201
|
+
enabled: true,
|
|
202
|
+
priority: 100,
|
|
203
|
+
timeout: 10000,
|
|
204
|
+
retryAttempts: 3,
|
|
205
|
+
retryDelay: 1000
|
|
206
|
+
});
|
|
430
207
|
```
|
|
431
208
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
────────────────────────────────────────────
|
|
435
|
-
### 6. Error Handling and Data Validation
|
|
436
|
-
|
|
437
|
-
Robust systems must gracefully handle errors and ensure data consistency. The @fin.cx/opendata library has built-in error handling for asynchronous operations, whether connecting to MongoDB, processing JSON streams, or interacting with web pages. In addition, each BusinessRecord instance provides a validate method that performs basic checks (for instance, ensuring that a company name is present) before a record is saved into the database.
|
|
209
|
+
### MongoDB Setup
|
|
438
210
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
```typescript
|
|
442
|
-
import { OpenData } from '@fin.cx/opendata';
|
|
211
|
+
Set environment variables:
|
|
443
212
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
postalCode: "12345",
|
|
450
|
-
city: "Teststadt",
|
|
451
|
-
country: "Germany",
|
|
452
|
-
phone: "+49 123 456789",
|
|
453
|
-
email: "test@testcorp.de",
|
|
454
|
-
businessType: "AG",
|
|
455
|
-
registrationId: "District court Teststadt HRB 111111",
|
|
456
|
-
legalForm: "AG",
|
|
457
|
-
managingDirectors: ["Test Director"],
|
|
458
|
-
foundingDate: new Date().toISOString(),
|
|
459
|
-
capital: "1,000,000 EUR",
|
|
460
|
-
purpose: "Testing for data validation",
|
|
461
|
-
lastUpdate: new Date().toISOString()
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
try {
|
|
465
|
-
// Validate record data before saving.
|
|
466
|
-
await record.validate();
|
|
467
|
-
await record.save();
|
|
468
|
-
console.log("Record validated and saved successfully.");
|
|
469
|
-
} catch (error) {
|
|
470
|
-
console.error("Error validating or saving record:", error);
|
|
471
|
-
}
|
|
472
|
-
};
|
|
213
|
+
```env
|
|
214
|
+
MONGODB_URL=mongodb://localhost:27017
|
|
215
|
+
MONGODB_NAME=opendata
|
|
216
|
+
MONGODB_USER=myuser
|
|
217
|
+
MONGODB_PASS=mypass
|
|
473
218
|
```
|
|
474
219
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
────────────────────────────────────────────
|
|
478
|
-
### 7. Testing and Automated Workflows
|
|
479
|
-
|
|
480
|
-
To support continuous integration and adherence to best practices, the @fin.cx/opendata module includes tests written with @push.rocks/tapbundle. You should consider incorporating these tests in your development workflow. The tests verify all main functionalities including instance initialization, bulk data import, Handelsregister operations, and CRUD operations for BusinessRecords.
|
|
220
|
+
## API Reference
|
|
481
221
|
|
|
482
|
-
|
|
222
|
+
### Stock Types
|
|
483
223
|
|
|
484
224
|
```typescript
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
tap.test('Perform bulk import', async () => {
|
|
500
|
-
await testOpenDataInstance.buildInitialDb();
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
tap.test('Stop instance', async () => {
|
|
504
|
-
await testOpenDataInstance.stop();
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
tap.start();
|
|
225
|
+
interface IStockPrice {
|
|
226
|
+
ticker: string;
|
|
227
|
+
price: number;
|
|
228
|
+
currency: string;
|
|
229
|
+
change: number;
|
|
230
|
+
changePercent: number;
|
|
231
|
+
previousClose: number;
|
|
232
|
+
timestamp: Date;
|
|
233
|
+
provider: string;
|
|
234
|
+
marketState: 'PRE' | 'REGULAR' | 'POST' | 'CLOSED';
|
|
235
|
+
exchange?: string;
|
|
236
|
+
exchangeName?: string;
|
|
237
|
+
}
|
|
508
238
|
```
|
|
509
239
|
|
|
510
|
-
|
|
240
|
+
### Key Methods
|
|
511
241
|
|
|
512
|
-
|
|
513
|
-
|
|
242
|
+
**StockPriceService**
|
|
243
|
+
- `getPrice(request)` - Single stock price
|
|
244
|
+
- `getPrices(request)` - Batch prices
|
|
245
|
+
- `register(provider)` - Add data provider
|
|
246
|
+
- `clearCache()` - Clear price cache
|
|
514
247
|
|
|
515
|
-
|
|
248
|
+
**OpenData**
|
|
249
|
+
- `start()` - Initialize MongoDB connection
|
|
250
|
+
- `buildInitialDb()` - Import bulk data
|
|
251
|
+
- `CBusinessRecord` - Business record class
|
|
252
|
+
- `handelsregister` - Registry automation
|
|
516
253
|
|
|
517
|
-
|
|
518
|
-
import { OpenData } from '@fin.cx/opendata';
|
|
254
|
+
## Performance
|
|
519
255
|
|
|
520
|
-
|
|
521
|
-
|
|
256
|
+
- **Batch fetching**: Get 100+ prices in <500ms
|
|
257
|
+
- **Caching**: Instant repeated queries
|
|
258
|
+
- **Concurrent processing**: Handle 1000+ records/second
|
|
259
|
+
- **Streaming**: Process GB-sized datasets without memory issues
|
|
522
260
|
|
|
523
|
-
|
|
524
|
-
// Initialize the module and connect to MongoDB
|
|
525
|
-
console.log('Initializing the OpenData module...');
|
|
526
|
-
await openData.start();
|
|
527
|
-
|
|
528
|
-
// Step 1: Bulk Import - Build the initial database from downloaded open data
|
|
529
|
-
console.log('Starting bulk data import from JSONL source...');
|
|
530
|
-
await openData.buildInitialDb();
|
|
531
|
-
|
|
532
|
-
// Step 2: Business Record Management - Create a sample business record
|
|
533
|
-
console.log('Creating a new business record...');
|
|
534
|
-
const sampleRecord = new openData.CBusinessRecord();
|
|
535
|
-
sampleRecord.data = {
|
|
536
|
-
name: "Sample Enterprise GmbH",
|
|
537
|
-
address: "Innovation Avenue 101",
|
|
538
|
-
postalCode: "80807",
|
|
539
|
-
city: "Munich",
|
|
540
|
-
country: "Germany",
|
|
541
|
-
phone: "+49 89 111222",
|
|
542
|
-
email: "info@sampleenterprise.de",
|
|
543
|
-
website: "https://sampleenterprise.de",
|
|
544
|
-
businessType: "GmbH",
|
|
545
|
-
registrationId: "District court Munich HRB 555555",
|
|
546
|
-
legalForm: "GmbH",
|
|
547
|
-
managingDirectors: ["Director A", "Director B"],
|
|
548
|
-
foundingDate: new Date("2015-06-15").toISOString(),
|
|
549
|
-
capital: "500,000 EUR",
|
|
550
|
-
purpose: "Holistic business solutions and data processing",
|
|
551
|
-
lastUpdate: new Date().toISOString()
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
await sampleRecord.save();
|
|
555
|
-
console.log('Sample business record created with id:', sampleRecord.id);
|
|
556
|
-
|
|
557
|
-
// Step 3: Retrieve business records for a specific location
|
|
558
|
-
console.log('Retrieving business records for Munich...');
|
|
559
|
-
const munichRecords = await openData.db
|
|
560
|
-
.collection('businessrecords')
|
|
561
|
-
.find({ city: "Munich" })
|
|
562
|
-
.toArray();
|
|
563
|
-
console.log(`Found ${munichRecords.length} records for Munich.`);
|
|
564
|
-
|
|
565
|
-
// Step 4: Update an existing record
|
|
566
|
-
if (munichRecords.length > 0) {
|
|
567
|
-
const recordToUpdateId = munichRecords[0].id;
|
|
568
|
-
console.log(`Updating business record with id: ${recordToUpdateId}`);
|
|
569
|
-
const recordToUpdate = await openData.CBusinessRecord.getInstance(recordToUpdateId);
|
|
570
|
-
if (recordToUpdate) {
|
|
571
|
-
recordToUpdate.data.phone = "+49 89 999888";
|
|
572
|
-
recordToUpdate.data.lastUpdate = new Date().toISOString();
|
|
573
|
-
await recordToUpdate.save();
|
|
574
|
-
console.log('Business record updated:', recordToUpdate);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
261
|
+
## Extensibility
|
|
577
262
|
|
|
578
|
-
|
|
579
|
-
console.log('Using Handelsregister to search for a specific company...');
|
|
580
|
-
const searchResults = await openData.handelsregister.searchCompany("Step Beyond GmbH", 20);
|
|
581
|
-
if (searchResults && searchResults.length > 0) {
|
|
582
|
-
const registrationData = searchResults[0].germanParsedRegistration;
|
|
583
|
-
console.log('Retrieved registration data:', registrationData);
|
|
584
|
-
|
|
585
|
-
// Step 6: Retrieve detailed info and download files for the specific company
|
|
586
|
-
console.log('Fetching detailed data for the identified company...');
|
|
587
|
-
const detailedInfo = await openData.handelsregister.getSpecificCompany(registrationData);
|
|
588
|
-
console.log('Detailed company data received:', detailedInfo);
|
|
589
|
-
|
|
590
|
-
// Optionally, save the downloaded files to a designated directory
|
|
591
|
-
for (const downloadedFile of detailedInfo.files) {
|
|
592
|
-
await downloadedFile.writeToDir('./output_files');
|
|
593
|
-
console.log(`Downloaded file saved at: ${downloadedFile.path}`);
|
|
594
|
-
}
|
|
595
|
-
} else {
|
|
596
|
-
console.log('No matching records found for detailed company data retrieval.');
|
|
597
|
-
}
|
|
263
|
+
The provider architecture makes it easy to add new data sources:
|
|
598
264
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
} finally {
|
|
606
|
-
// Final cleanup: Stop the OpenData module and release all resources
|
|
607
|
-
console.log('Finalizing: stopping the OpenData module...');
|
|
608
|
-
await openData.stop();
|
|
609
|
-
console.log('Pipeline completed and all resources have been cleaned up.');
|
|
265
|
+
```typescript
|
|
266
|
+
class MyCustomProvider implements IStockProvider {
|
|
267
|
+
name = 'My Provider';
|
|
268
|
+
|
|
269
|
+
async fetchPrice(request: IStockQuoteRequest): Promise<IStockPrice> {
|
|
270
|
+
// Your implementation
|
|
610
271
|
}
|
|
611
|
-
|
|
272
|
+
|
|
273
|
+
// ... other required methods
|
|
274
|
+
}
|
|
612
275
|
|
|
613
|
-
|
|
276
|
+
stockService.register(new MyCustomProvider());
|
|
614
277
|
```
|
|
615
278
|
|
|
616
|
-
|
|
617
|
-
• Starts by connecting to your database.
|
|
618
|
-
• Imports extensive JSONL open data.
|
|
619
|
-
• Creates, retrieves, updates, and deletes business records.
|
|
620
|
-
• Interacts with the Handelsregister for advanced company-specific operations.
|
|
621
|
-
• Implements robust error handling and validation routines, ensuring that each step is verifiable.
|
|
622
|
-
• Finally, ensures that resources such as MongoDB connections and headless browser sessions are responsibly closed.
|
|
623
|
-
|
|
624
|
-
────────────────────────────────────────────
|
|
625
|
-
### Final Thoughts on Module Integration
|
|
279
|
+
## Testing
|
|
626
280
|
|
|
627
|
-
|
|
281
|
+
Run the comprehensive test suite:
|
|
628
282
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
By following the usage scenarios provided in this documentation, you should now have a deep understanding of how to:
|
|
634
|
-
• Set up your environment and initialize the OpenData instance.
|
|
635
|
-
• Perform CRUD operations on business records.
|
|
636
|
-
• Efficiently process thousands of records from external JSONL sources.
|
|
637
|
-
• Integrate and automate Handelsregister interactions for detailed company data retrieval.
|
|
638
|
-
• Combine all building blocks into advanced automated workflows that support large-scale enterprise applications.
|
|
639
|
-
|
|
640
|
-
Feel free to explore, extend, and customize these examples to suit your project’s unique requirements. The library is designed with extensibility in mind, and additional utility functions or integrations can be added based on your needs.
|
|
283
|
+
```bash
|
|
284
|
+
npm test
|
|
285
|
+
```
|
|
641
286
|
|
|
642
|
-
|
|
287
|
+
View live market data:
|
|
643
288
|
|
|
644
|
-
|
|
289
|
+
```bash
|
|
290
|
+
npm test -- --grep "market indicators"
|
|
291
|
+
```
|
|
645
292
|
|
|
293
|
+
## Contributing
|
|
646
294
|
|
|
295
|
+
We welcome contributions! Please see our contributing guidelines for details.
|
|
647
296
|
|
|
648
297
|
## License and Legal Information
|
|
649
298
|
|
|
@@ -662,4 +311,4 @@ Registered at District court Bremen HRB 35230 HB, Germany
|
|
|
662
311
|
|
|
663
312
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
|
664
313
|
|
|
665
|
-
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.
|
|
314
|
+
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.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@fin.cx/opendata',
|
|
6
|
-
version: '1.
|
|
7
|
-
description: 'A comprehensive TypeScript library
|
|
6
|
+
version: '1.6.1',
|
|
7
|
+
description: 'A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.'
|
|
8
8
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
|
|
1
3
|
export interface IStockPrice {
|
|
2
4
|
ticker: string;
|
|
3
5
|
price: number;
|
|
@@ -11,6 +13,10 @@ export interface IStockPrice {
|
|
|
11
13
|
exchange?: string;
|
|
12
14
|
exchangeName?: string;
|
|
13
15
|
}
|
|
16
|
+
type CheckStockPrice = plugins.tsclass.typeFest.IsEqual<
|
|
17
|
+
IStockPrice,
|
|
18
|
+
plugins.tsclass.finance.IStockPrice
|
|
19
|
+
>;
|
|
14
20
|
|
|
15
21
|
export interface IStockPriceError {
|
|
16
22
|
ticker: string;
|
|
@@ -27,4 +33,4 @@ export interface IStockQuoteRequest {
|
|
|
27
33
|
export interface IStockBatchQuoteRequest {
|
|
28
34
|
tickers: string[];
|
|
29
35
|
includeExtendedHours?: boolean;
|
|
30
|
-
}
|
|
36
|
+
}
|
|
@@ -20,14 +20,15 @@ export class YahooFinanceProvider implements IStockProvider {
|
|
|
20
20
|
public async fetchPrice(request: IStockQuoteRequest): Promise<IStockPrice> {
|
|
21
21
|
try {
|
|
22
22
|
const url = `${this.baseUrl}/v8/finance/chart/${request.ticker}`;
|
|
23
|
-
const response = await plugins.smartrequest.
|
|
24
|
-
|
|
23
|
+
const response = await plugins.smartrequest.SmartRequest.create()
|
|
24
|
+
.url(url)
|
|
25
|
+
.headers({
|
|
25
26
|
'User-Agent': this.userAgent
|
|
26
|
-
}
|
|
27
|
-
timeout
|
|
28
|
-
|
|
27
|
+
})
|
|
28
|
+
.timeout(this.config?.timeout || 10000)
|
|
29
|
+
.get();
|
|
29
30
|
|
|
30
|
-
const responseData = response.
|
|
31
|
+
const responseData = await response.json() as any;
|
|
31
32
|
|
|
32
33
|
if (!responseData?.chart?.result?.[0]) {
|
|
33
34
|
throw new Error(`No data found for ticker ${request.ticker}`);
|
|
@@ -66,14 +67,15 @@ export class YahooFinanceProvider implements IStockProvider {
|
|
|
66
67
|
const symbols = request.tickers.join(',');
|
|
67
68
|
const url = `${this.baseUrl}/v8/finance/spark?symbols=${symbols}&range=1d&interval=5m`;
|
|
68
69
|
|
|
69
|
-
const response = await plugins.smartrequest.
|
|
70
|
-
|
|
70
|
+
const response = await plugins.smartrequest.SmartRequest.create()
|
|
71
|
+
.url(url)
|
|
72
|
+
.headers({
|
|
71
73
|
'User-Agent': this.userAgent
|
|
72
|
-
}
|
|
73
|
-
timeout
|
|
74
|
-
|
|
74
|
+
})
|
|
75
|
+
.timeout(this.config?.timeout || 15000)
|
|
76
|
+
.get();
|
|
75
77
|
|
|
76
|
-
const responseData = response.
|
|
78
|
+
const responseData = await response.json() as any;
|
|
77
79
|
const prices: IStockPrice[] = [];
|
|
78
80
|
|
|
79
81
|
for (const [ticker, data] of Object.entries(responseData)) {
|