@adaptic/utils 0.0.379 → 0.0.381
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/index.cjs +125 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +125 -12
- package/dist/index.mjs.map +1 -1
- package/dist/test.js +125 -12
- package/dist/test.js.map +1 -1
- package/dist/types/alpaca-market-data-api.d.ts +16 -3
- package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types/types/alpaca-types.d.ts +89 -0
- package/dist/types/types/alpaca-types.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -11456,22 +11456,28 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11456
11456
|
v1beta1url;
|
|
11457
11457
|
stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip'; // production values
|
|
11458
11458
|
optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values
|
|
11459
|
+
cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us'; // production values
|
|
11459
11460
|
stockWs = null;
|
|
11460
11461
|
optionWs = null;
|
|
11462
|
+
cryptoWs = null;
|
|
11461
11463
|
stockSubscriptions = { trades: [], quotes: [], bars: [] };
|
|
11462
11464
|
optionSubscriptions = { trades: [], quotes: [], bars: [] };
|
|
11465
|
+
cryptoSubscriptions = { trades: [], quotes: [], bars: [] };
|
|
11463
11466
|
setMode(mode = 'production') {
|
|
11464
11467
|
if (mode === 'sandbox') { // sandbox mode
|
|
11465
11468
|
this.stockStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v2/sip';
|
|
11466
11469
|
this.optionStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/options';
|
|
11470
|
+
this.cryptoStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/crypto/us';
|
|
11467
11471
|
}
|
|
11468
11472
|
else if (mode === 'test') { // test mode, can only use ticker FAKEPACA
|
|
11469
11473
|
this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/test';
|
|
11470
11474
|
this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // there's no test mode for options
|
|
11475
|
+
this.cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us'; // there's no test mode for crypto
|
|
11471
11476
|
}
|
|
11472
11477
|
else { // production
|
|
11473
11478
|
this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip';
|
|
11474
11479
|
this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options';
|
|
11480
|
+
this.cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us';
|
|
11475
11481
|
}
|
|
11476
11482
|
}
|
|
11477
11483
|
getMode() {
|
|
@@ -11513,14 +11519,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11513
11519
|
return super.emit(event, ...args);
|
|
11514
11520
|
}
|
|
11515
11521
|
connect(streamType) {
|
|
11516
|
-
|
|
11522
|
+
let url;
|
|
11523
|
+
if (streamType === 'stock') {
|
|
11524
|
+
url = this.stockStreamUrl;
|
|
11525
|
+
}
|
|
11526
|
+
else if (streamType === 'option') {
|
|
11527
|
+
url = this.optionStreamUrl;
|
|
11528
|
+
}
|
|
11529
|
+
else {
|
|
11530
|
+
url = this.cryptoStreamUrl;
|
|
11531
|
+
}
|
|
11517
11532
|
const ws = new WebSocket(url);
|
|
11518
11533
|
if (streamType === 'stock') {
|
|
11519
11534
|
this.stockWs = ws;
|
|
11520
11535
|
}
|
|
11521
|
-
else {
|
|
11536
|
+
else if (streamType === 'option') {
|
|
11522
11537
|
this.optionWs = ws;
|
|
11523
11538
|
}
|
|
11539
|
+
else {
|
|
11540
|
+
this.cryptoWs = ws;
|
|
11541
|
+
}
|
|
11524
11542
|
ws.on('open', () => {
|
|
11525
11543
|
log(`${streamType} stream connected`, { type: 'info' });
|
|
11526
11544
|
const authMessage = {
|
|
@@ -11531,20 +11549,36 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11531
11549
|
ws.send(JSON.stringify(authMessage));
|
|
11532
11550
|
});
|
|
11533
11551
|
ws.on('message', (data) => {
|
|
11534
|
-
|
|
11535
|
-
|
|
11552
|
+
const rawData = data.toString();
|
|
11553
|
+
let messages;
|
|
11554
|
+
try {
|
|
11555
|
+
messages = JSON.parse(rawData);
|
|
11556
|
+
}
|
|
11557
|
+
catch (e) {
|
|
11558
|
+
log(`${streamType} stream received invalid JSON: ${rawData.substring(0, 200)}`, { type: 'error' });
|
|
11559
|
+
return;
|
|
11560
|
+
}
|
|
11536
11561
|
for (const message of messages) {
|
|
11537
11562
|
if (message.T === 'success' && message.msg === 'authenticated') {
|
|
11538
11563
|
log(`${streamType} stream authenticated`, { type: 'info' });
|
|
11539
11564
|
this.sendSubscription(streamType);
|
|
11540
11565
|
}
|
|
11566
|
+
else if (message.T === 'success' && message.msg === 'connected') {
|
|
11567
|
+
log(`${streamType} stream connected message received`, { type: 'debug' });
|
|
11568
|
+
}
|
|
11569
|
+
else if (message.T === 'subscription') {
|
|
11570
|
+
log(`${streamType} subscription confirmed: trades=${message.trades?.length || 0}, quotes=${message.quotes?.length || 0}, bars=${message.bars?.length || 0}`, { type: 'info' });
|
|
11571
|
+
}
|
|
11541
11572
|
else if (message.T === 'error') {
|
|
11542
|
-
log(`${streamType} stream error: ${message.msg}`, { type: 'error' });
|
|
11573
|
+
log(`${streamType} stream error: ${message.msg} (code: ${message.code}, raw: ${JSON.stringify(message)})`, { type: 'error' });
|
|
11543
11574
|
}
|
|
11544
11575
|
else if (message.S) {
|
|
11545
11576
|
super.emit(`${streamType}-${message.T}`, message);
|
|
11546
11577
|
super.emit(`${streamType}-data`, message);
|
|
11547
11578
|
}
|
|
11579
|
+
else {
|
|
11580
|
+
log(`${streamType} received unknown message type: ${JSON.stringify(message)}`, { type: 'debug' });
|
|
11581
|
+
}
|
|
11548
11582
|
}
|
|
11549
11583
|
});
|
|
11550
11584
|
ws.on('close', () => {
|
|
@@ -11552,9 +11586,12 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11552
11586
|
if (streamType === 'stock') {
|
|
11553
11587
|
this.stockWs = null;
|
|
11554
11588
|
}
|
|
11555
|
-
else {
|
|
11589
|
+
else if (streamType === 'option') {
|
|
11556
11590
|
this.optionWs = null;
|
|
11557
11591
|
}
|
|
11592
|
+
else {
|
|
11593
|
+
this.cryptoWs = null;
|
|
11594
|
+
}
|
|
11558
11595
|
// Optional: implement reconnect logic
|
|
11559
11596
|
});
|
|
11560
11597
|
ws.on('error', (error) => {
|
|
@@ -11562,8 +11599,23 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11562
11599
|
});
|
|
11563
11600
|
}
|
|
11564
11601
|
sendSubscription(streamType) {
|
|
11565
|
-
|
|
11566
|
-
|
|
11602
|
+
let ws;
|
|
11603
|
+
let subscriptions;
|
|
11604
|
+
if (streamType === 'stock') {
|
|
11605
|
+
ws = this.stockWs;
|
|
11606
|
+
subscriptions = this.stockSubscriptions;
|
|
11607
|
+
}
|
|
11608
|
+
else if (streamType === 'option') {
|
|
11609
|
+
ws = this.optionWs;
|
|
11610
|
+
subscriptions = this.optionSubscriptions;
|
|
11611
|
+
}
|
|
11612
|
+
else {
|
|
11613
|
+
ws = this.cryptoWs;
|
|
11614
|
+
subscriptions = this.cryptoSubscriptions;
|
|
11615
|
+
}
|
|
11616
|
+
log(`sendSubscription called for ${streamType} (wsReady=${ws?.readyState === WebSocket.OPEN}, trades=${subscriptions.trades?.length || 0}, quotes=${subscriptions.quotes?.length || 0}, bars=${subscriptions.bars?.length || 0})`, {
|
|
11617
|
+
type: 'debug',
|
|
11618
|
+
});
|
|
11567
11619
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
11568
11620
|
const subMessagePayload = {};
|
|
11569
11621
|
if (subscriptions.trades.length > 0) {
|
|
@@ -11580,8 +11632,16 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11580
11632
|
action: 'subscribe',
|
|
11581
11633
|
...subMessagePayload,
|
|
11582
11634
|
};
|
|
11583
|
-
|
|
11635
|
+
const messageJson = JSON.stringify(subMessage);
|
|
11636
|
+
log(`Sending ${streamType} subscription: ${messageJson}`, { type: 'info' });
|
|
11637
|
+
ws.send(messageJson);
|
|
11584
11638
|
}
|
|
11639
|
+
else {
|
|
11640
|
+
log(`No ${streamType} subscriptions to send (all arrays empty)`, { type: 'debug' });
|
|
11641
|
+
}
|
|
11642
|
+
}
|
|
11643
|
+
else {
|
|
11644
|
+
log(`Cannot send ${streamType} subscription: WebSocket not ready`, { type: 'warn' });
|
|
11585
11645
|
}
|
|
11586
11646
|
}
|
|
11587
11647
|
connectStockStream() {
|
|
@@ -11594,6 +11654,11 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11594
11654
|
this.connect('option');
|
|
11595
11655
|
}
|
|
11596
11656
|
}
|
|
11657
|
+
connectCryptoStream() {
|
|
11658
|
+
if (!this.cryptoWs) {
|
|
11659
|
+
this.connect('crypto');
|
|
11660
|
+
}
|
|
11661
|
+
}
|
|
11597
11662
|
disconnectStockStream() {
|
|
11598
11663
|
if (this.stockWs) {
|
|
11599
11664
|
this.stockWs.close();
|
|
@@ -11604,8 +11669,38 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11604
11669
|
this.optionWs.close();
|
|
11605
11670
|
}
|
|
11606
11671
|
}
|
|
11672
|
+
disconnectCryptoStream() {
|
|
11673
|
+
if (this.cryptoWs) {
|
|
11674
|
+
this.cryptoWs.close();
|
|
11675
|
+
}
|
|
11676
|
+
}
|
|
11677
|
+
/**
|
|
11678
|
+
* Check if a specific stream is connected
|
|
11679
|
+
* @param streamType - The type of stream to check
|
|
11680
|
+
* @returns True if the stream is connected
|
|
11681
|
+
*/
|
|
11682
|
+
isStreamConnected(streamType) {
|
|
11683
|
+
if (streamType === 'stock') {
|
|
11684
|
+
return this.stockWs !== null && this.stockWs.readyState === WebSocket.OPEN;
|
|
11685
|
+
}
|
|
11686
|
+
else if (streamType === 'option') {
|
|
11687
|
+
return this.optionWs !== null && this.optionWs.readyState === WebSocket.OPEN;
|
|
11688
|
+
}
|
|
11689
|
+
else {
|
|
11690
|
+
return this.cryptoWs !== null && this.cryptoWs.readyState === WebSocket.OPEN;
|
|
11691
|
+
}
|
|
11692
|
+
}
|
|
11607
11693
|
subscribe(streamType, subscriptions) {
|
|
11608
|
-
|
|
11694
|
+
let currentSubscriptions;
|
|
11695
|
+
if (streamType === 'stock') {
|
|
11696
|
+
currentSubscriptions = this.stockSubscriptions;
|
|
11697
|
+
}
|
|
11698
|
+
else if (streamType === 'option') {
|
|
11699
|
+
currentSubscriptions = this.optionSubscriptions;
|
|
11700
|
+
}
|
|
11701
|
+
else {
|
|
11702
|
+
currentSubscriptions = this.cryptoSubscriptions;
|
|
11703
|
+
}
|
|
11609
11704
|
Object.entries(subscriptions).forEach(([key, value]) => {
|
|
11610
11705
|
if (value) {
|
|
11611
11706
|
currentSubscriptions[key] = [...new Set([...(currentSubscriptions[key] || []), ...value])];
|
|
@@ -11614,7 +11709,16 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11614
11709
|
this.sendSubscription(streamType);
|
|
11615
11710
|
}
|
|
11616
11711
|
unsubscribe(streamType, subscriptions) {
|
|
11617
|
-
|
|
11712
|
+
let currentSubscriptions;
|
|
11713
|
+
if (streamType === 'stock') {
|
|
11714
|
+
currentSubscriptions = this.stockSubscriptions;
|
|
11715
|
+
}
|
|
11716
|
+
else if (streamType === 'option') {
|
|
11717
|
+
currentSubscriptions = this.optionSubscriptions;
|
|
11718
|
+
}
|
|
11719
|
+
else {
|
|
11720
|
+
currentSubscriptions = this.cryptoSubscriptions;
|
|
11721
|
+
}
|
|
11618
11722
|
Object.entries(subscriptions).forEach(([key, value]) => {
|
|
11619
11723
|
if (value) {
|
|
11620
11724
|
currentSubscriptions[key] = (currentSubscriptions[key] || []).filter(s => !value.includes(s));
|
|
@@ -11624,7 +11728,16 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
11624
11728
|
action: 'unsubscribe',
|
|
11625
11729
|
...subscriptions,
|
|
11626
11730
|
};
|
|
11627
|
-
|
|
11731
|
+
let ws;
|
|
11732
|
+
if (streamType === 'stock') {
|
|
11733
|
+
ws = this.stockWs;
|
|
11734
|
+
}
|
|
11735
|
+
else if (streamType === 'option') {
|
|
11736
|
+
ws = this.optionWs;
|
|
11737
|
+
}
|
|
11738
|
+
else {
|
|
11739
|
+
ws = this.cryptoWs;
|
|
11740
|
+
}
|
|
11628
11741
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
11629
11742
|
ws.send(JSON.stringify(unsubMessage));
|
|
11630
11743
|
}
|