@xbbg/core 1.1.2
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/README.md +145 -0
- package/errors.js +160 -0
- package/index.d.ts +792 -0
- package/index.js +1427 -0
- package/lib/platform-map.js +14 -0
- package/lib/resolve-native.js +49 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# @xbbg/core
|
|
2
|
+
|
|
3
|
+
Bloomberg data API for Node.js — powered by Rust.
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
🚧 **Experimental alpha** — native N-API bindings are implemented, high-level API is in active development.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Supported prebuilt addon targets:
|
|
12
|
+
- macOS arm64
|
|
13
|
+
- Linux x64
|
|
14
|
+
- Windows x64
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun add @xbbg/core
|
|
18
|
+
# or
|
|
19
|
+
npm install @xbbg/core
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`@xbbg/core` loads a packaged native `napi_xbbg.node` addon via platform-specific optional dependencies on supported targets. If no packaged addon is available for your platform, build from source locally instead.
|
|
23
|
+
|
|
24
|
+
## Local Development
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Preferred: build and copy js-xbbg/napi_xbbg.node into the package directory
|
|
28
|
+
npm --prefix js-xbbg run build
|
|
29
|
+
|
|
30
|
+
# Lower-level Rust build (useful while hacking on napi-xbbg itself)
|
|
31
|
+
cargo build -p napi-xbbg
|
|
32
|
+
|
|
33
|
+
# Stage the current platform package template with the built addon
|
|
34
|
+
npm --prefix js-xbbg run stage:native-package
|
|
35
|
+
|
|
36
|
+
# Run JS smoke test from js-xbbg/
|
|
37
|
+
npm test
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The JS package automatically loads a local `js-xbbg/napi_xbbg.node` addon first, then falls back to packaged optional native dependencies for supported platforms.
|
|
41
|
+
|
|
42
|
+
## Planned Usage
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import * as xbbg from '@xbbg/core';
|
|
46
|
+
|
|
47
|
+
xbbg.configure({
|
|
48
|
+
host: 'localhost',
|
|
49
|
+
port: 8194,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// BPIPE / leased-line capable session config
|
|
53
|
+
const engine = await xbbg.connect({
|
|
54
|
+
servers: [
|
|
55
|
+
{ host: 'bpipe-primary.example.com', port: 8194 },
|
|
56
|
+
{ host: 'bpipe-secondary.example.com', port: 8196 },
|
|
57
|
+
],
|
|
58
|
+
auth: { method: 'userapp', appName: 'my-bpipe-app' },
|
|
59
|
+
tls: {
|
|
60
|
+
clientCredentials: '/secure/client.p12',
|
|
61
|
+
clientCredentialsPassword: process.env.BPIPE_TLS_PASSWORD,
|
|
62
|
+
trustMaterial: '/secure/trust.p7',
|
|
63
|
+
},
|
|
64
|
+
zfpRemote: '8194',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Python-style blp namespace
|
|
68
|
+
const hist = await xbbg.blp.abdh(['AAPL US Equity'], ['PX_LAST'], '2024-01-01', '2024-12-31');
|
|
69
|
+
const ref = await xbbg.blp.abdp(['AAPL US Equity'], ['PX_LAST', 'SECURITY_NAME']);
|
|
70
|
+
const bulk = await xbbg.blp.abds(['ES1 Index'], ['FUT_CHAIN_LAST_TRADE_DATES']);
|
|
71
|
+
const bars = await xbbg.blp.abdib('AAPL US Equity', '2024-12-01', 5);
|
|
72
|
+
const ticks = await xbbg.blp.abdtick('AAPL US Equity', '2024-12-01T09:30:00', '2024-12-01T10:00:00');
|
|
73
|
+
|
|
74
|
+
// Live streaming
|
|
75
|
+
const sub = await xbbg.blp.asubscribe(['AAPL US Equity'], ['LAST_PRICE', 'BID', 'ASK']);
|
|
76
|
+
for await (const tick of sub) {
|
|
77
|
+
console.log(tick);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// CDX analytics
|
|
81
|
+
const cdxInfo = await xbbg.ext.cdx.acdx_info('CDX IG CDSI GEN 5Y Corp');
|
|
82
|
+
const cdxPricing = await xbbg.ext.cdx.acdx_pricing('CDX IG CDSI GEN 5Y Corp');
|
|
83
|
+
const cdxRisk = await xbbg.ext.cdx.acdx_risk('CDX IG CDSI GEN 5Y Corp');
|
|
84
|
+
|
|
85
|
+
engine.signalShutdown();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Recipes
|
|
89
|
+
|
|
90
|
+
High-level workflows that wrap common Bloomberg request patterns. Each recipe returns an Arrow `Table` by default (or a JSON/Polars result when `backend` is set) and errors are mapped to the standard `BlpError` hierarchy.
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// Fixed income
|
|
94
|
+
const yas = await engine.yas(['US912810TM69 Govt'], ['YAS_BOND_YLD'], {
|
|
95
|
+
settleDt: '20240115',
|
|
96
|
+
yieldType: 1, // 1=YTM, 2=YTC, 3=YTW, 4=YTB, 5=YTP, 6=YTN, 7=OAS, 8=YTS, 9=YTAL
|
|
97
|
+
price: 99.5,
|
|
98
|
+
});
|
|
99
|
+
const bqr = await engine.bqr('US912810TM69 Govt', {
|
|
100
|
+
startDatetime: '2024-06-03T14:30:00',
|
|
101
|
+
endDatetime: '2024-06-03T15:00:00',
|
|
102
|
+
eventTypes: ['BID', 'ASK'],
|
|
103
|
+
});
|
|
104
|
+
const preferreds = await engine.preferreds('BAC US Equity');
|
|
105
|
+
const corpBonds = await engine.corporateBonds('AAPL', { ccy: 'USD' });
|
|
106
|
+
|
|
107
|
+
// Futures and CDX resolution
|
|
108
|
+
const front = await engine.futTicker('ES1 Index', '20240301');
|
|
109
|
+
const active = await engine.activeFutures('CL1 Comdty', '20240301', { freq: 'M' });
|
|
110
|
+
const cdx = await engine.cdxTicker('CDX IG CDSI GEN 5Y Corp', '20240301');
|
|
111
|
+
const activeCdx = await engine.activeCdx('CDX IG CDSI GEN 5Y Corp', '20240301', {
|
|
112
|
+
lookbackDays: 10,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Historical helpers
|
|
116
|
+
const dvd = await engine.dividend(['AAPL US Equity'], '20230101', '20231231');
|
|
117
|
+
const turn = await engine.turnover(['AAPL US Equity'], '20240101', '20240131', {
|
|
118
|
+
ccy: 'USD',
|
|
119
|
+
});
|
|
120
|
+
const holdings = await engine.etfHoldings('SPY US Equity');
|
|
121
|
+
|
|
122
|
+
// Currency-converted prices
|
|
123
|
+
const px = await engine.currencyConversion('700 HK Equity', 'USD', '20240101', '20240131');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Engine configuration
|
|
127
|
+
|
|
128
|
+
`connect()` and `configure()` accept a structured `EngineConfig` object. The most important connection controls are:
|
|
129
|
+
|
|
130
|
+
- `host` / `port` for a single Bloomberg session endpoint
|
|
131
|
+
- `servers` for ordered failover across multiple Bloomberg hosts
|
|
132
|
+
- `auth` for Bloomberg session identity auth: `user`, `app`, `userapp`, `dir`, `manual`, or `token`
|
|
133
|
+
- `tls` plus `zfpRemote` for leased-line / BPIPE-style sessions
|
|
134
|
+
- `socks5` for proxied Bloomberg connectivity
|
|
135
|
+
- `retryPolicy`, `numStartAttempts`, and recovery settings for reconnect behavior
|
|
136
|
+
|
|
137
|
+
The JS binding now forwards these fields directly to the Rust engine, so Node can configure the same auth and transport features already available in the core runtime.
|
|
138
|
+
|
|
139
|
+
## Features (planned)
|
|
140
|
+
|
|
141
|
+
- Native N-API bindings (no HTTP overhead)
|
|
142
|
+
- Zero-copy Arrow buffers via `apache-arrow`
|
|
143
|
+
- Async/await with proper backpressure
|
|
144
|
+
- TypeScript-first with full type definitions
|
|
145
|
+
- Cross-platform prebuilt addon packaging: macOS arm64, Linux x64, Windows x64
|
package/errors.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base error class for all Bloomberg API errors.
|
|
5
|
+
* All xbbg errors inherit from BlpError, allowing users to catch all
|
|
6
|
+
* Bloomberg-related errors with a single except clause.
|
|
7
|
+
*/
|
|
8
|
+
class BlpError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = this.constructor.name;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Session lifecycle errors (start, connect, service open).
|
|
17
|
+
*/
|
|
18
|
+
class BlpSessionError extends BlpError {}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Request-level errors from the Bloomberg API.
|
|
22
|
+
*
|
|
23
|
+
* Attributes:
|
|
24
|
+
* service: The Bloomberg service URI (e.g., "//blp/refdata").
|
|
25
|
+
* operation: The request operation name (e.g., "ReferenceDataRequest").
|
|
26
|
+
* request_id: Optional correlation ID for debugging.
|
|
27
|
+
* code: Optional Bloomberg error code.
|
|
28
|
+
*/
|
|
29
|
+
class BlpRequestError extends BlpError {
|
|
30
|
+
constructor(message, options = {}) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.service = options.service;
|
|
33
|
+
this.operation = options.operation;
|
|
34
|
+
this.request_id = options.request_id;
|
|
35
|
+
this.code = options.code;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Request validation errors.
|
|
41
|
+
*
|
|
42
|
+
* Raised when request parameters fail validation against Bloomberg schemas.
|
|
43
|
+
* Includes helpful suggestions for typos and invalid enum values.
|
|
44
|
+
*
|
|
45
|
+
* Attributes:
|
|
46
|
+
* element: The element name that caused the error (if available).
|
|
47
|
+
* suggestion: Suggested correction for typos (if available).
|
|
48
|
+
*/
|
|
49
|
+
class BlpValidationError extends BlpError {
|
|
50
|
+
constructor(message, options = {}) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.element = options.element;
|
|
53
|
+
this.suggestion = options.suggestion;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Request timeout.
|
|
59
|
+
*/
|
|
60
|
+
class BlpTimeoutError extends BlpError {}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Internal errors (should not happen in normal operation).
|
|
64
|
+
* If you encounter this error, please report it as a bug.
|
|
65
|
+
*/
|
|
66
|
+
class BlpInternalError extends BlpError {}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Wraps a native NAPI error into the appropriate xbbg error class.
|
|
70
|
+
*
|
|
71
|
+
* Pattern-matches on error message to determine the error type.
|
|
72
|
+
*
|
|
73
|
+
* @param {Error} napiError - The native NAPI error to wrap
|
|
74
|
+
* @returns {BlpError} - An instance of the appropriate error class
|
|
75
|
+
*/
|
|
76
|
+
function wrapError(napiError) {
|
|
77
|
+
const msg = napiError.message || '';
|
|
78
|
+
|
|
79
|
+
// Session errors
|
|
80
|
+
if (
|
|
81
|
+
msg.includes('Session start failed') ||
|
|
82
|
+
msg.includes('session start failed') ||
|
|
83
|
+
msg.includes('Failed to start session') ||
|
|
84
|
+
msg.includes('Failed to open service') ||
|
|
85
|
+
msg.includes('failed to spawn worker') ||
|
|
86
|
+
msg.includes('connect event failed')
|
|
87
|
+
) {
|
|
88
|
+
return new BlpSessionError(msg);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Request errors
|
|
92
|
+
if (msg.includes('Request failed') || msg.includes('Subscription failed')) {
|
|
93
|
+
const options = {};
|
|
94
|
+
|
|
95
|
+
// Parse service and operation from "Request failed on {service}::{op}"
|
|
96
|
+
const serviceOpMatch = msg.match(/on ([^:]+)::([^ (]+)/);
|
|
97
|
+
if (serviceOpMatch) {
|
|
98
|
+
options.service = serviceOpMatch[1];
|
|
99
|
+
options.operation = serviceOpMatch[2];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Native messages append " [request_id=<uuid>]" when a correlation id is known.
|
|
103
|
+
const requestIdMatch = msg.match(/\[request_id=([^\]]+)\]/);
|
|
104
|
+
if (requestIdMatch) {
|
|
105
|
+
options.request_id = requestIdMatch[1];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return new BlpRequestError(msg, options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Validation errors
|
|
112
|
+
if (
|
|
113
|
+
msg.includes('Invalid argument') ||
|
|
114
|
+
msg.includes('Configuration error') ||
|
|
115
|
+
msg.includes('Operation not found') ||
|
|
116
|
+
msg.includes('Schema element not found') ||
|
|
117
|
+
msg.includes('Schema type mismatch') ||
|
|
118
|
+
msg.includes('Unsupported schema') ||
|
|
119
|
+
msg.includes('invalid extractor') ||
|
|
120
|
+
msg.includes('(did you mean') // Validation with suggestion
|
|
121
|
+
) {
|
|
122
|
+
const options = {};
|
|
123
|
+
|
|
124
|
+
// Parse suggestion from "(did you mean 'xxx'?)" pattern
|
|
125
|
+
const suggestionMatch = msg.match(/\(did you mean '([^']+)'\?\)/);
|
|
126
|
+
if (suggestionMatch) {
|
|
127
|
+
options.suggestion = suggestionMatch[1];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return new BlpValidationError(msg, options);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Timeout errors
|
|
134
|
+
if (msg.includes('Request timed out')) {
|
|
135
|
+
return new BlpTimeoutError(msg);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Internal errors
|
|
139
|
+
if (
|
|
140
|
+
msg.includes('Internal error') ||
|
|
141
|
+
msg.includes('Channel closed') ||
|
|
142
|
+
msg.includes('Stream buffer full') ||
|
|
143
|
+
msg.includes('Request was cancelled')
|
|
144
|
+
) {
|
|
145
|
+
return new BlpInternalError(msg);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Default fallback
|
|
149
|
+
return new BlpError(msg);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = {
|
|
153
|
+
BlpError,
|
|
154
|
+
BlpSessionError,
|
|
155
|
+
BlpRequestError,
|
|
156
|
+
BlpValidationError,
|
|
157
|
+
BlpTimeoutError,
|
|
158
|
+
BlpInternalError,
|
|
159
|
+
wrapError,
|
|
160
|
+
};
|