@huskly/ibkr-client 1.0.0 → 1.1.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/README.md +25 -13
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +14 -9
- package/dist/helpers.js.map +1 -1
- package/dist/ibkr/ibkrApiTypes.d.ts +1 -1
- package/dist/ibkr/ibkrApiTypes.d.ts.map +1 -1
- package/dist/ibkr/ibkrClient.d.ts +11 -3
- package/dist/ibkr/ibkrClient.d.ts.map +1 -1
- package/dist/ibkr/ibkrClient.js +233 -73
- package/dist/ibkr/ibkrClient.js.map +1 -1
- package/dist/ibkr/requestScheduler.d.ts +8 -0
- package/dist/ibkr/requestScheduler.d.ts.map +1 -1
- package/dist/ibkr/requestScheduler.js +33 -6
- package/dist/ibkr/requestScheduler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/ibkr/ibkrClient.js
CHANGED
|
@@ -259,10 +259,12 @@ export class IbkrClient {
|
|
|
259
259
|
requestNow;
|
|
260
260
|
secdefPrimingTail = Promise.resolve();
|
|
261
261
|
onPriceHistoryTelemetry;
|
|
262
|
+
onOptionDiscoveryTelemetry;
|
|
262
263
|
onRequestTelemetry;
|
|
263
264
|
constructor(config, options = {}) {
|
|
264
265
|
this.raw = new RawIbkrClientCtor(config);
|
|
265
266
|
this.onPriceHistoryTelemetry = options.onPriceHistoryTelemetry ?? (() => undefined);
|
|
267
|
+
this.onOptionDiscoveryTelemetry = options.onOptionDiscoveryTelemetry ?? (() => undefined);
|
|
266
268
|
this.onRequestTelemetry = options.onRequestTelemetry ?? (() => undefined);
|
|
267
269
|
const schedulerOptions = options.requestScheduler;
|
|
268
270
|
this.requestNow = schedulerOptions?.now ?? (() => this.now());
|
|
@@ -3283,8 +3285,8 @@ export class IbkrClient {
|
|
|
3283
3285
|
const contracts = [];
|
|
3284
3286
|
for (let index = 0; index < months.length; index += OPTION_DISCOVERY_MONTH_CONCURRENCY) {
|
|
3285
3287
|
const batch = months.slice(index, index + OPTION_DISCOVERY_MONTH_CONCURRENCY);
|
|
3286
|
-
const batchContracts =
|
|
3287
|
-
contracts.push(...batchContracts);
|
|
3288
|
+
const batchContracts = await Promise.all(batch.map((month) => this.discoverOptions(normalized, month, right)));
|
|
3289
|
+
contracts.push(...batchContracts.flatMap((result) => result.contracts));
|
|
3288
3290
|
}
|
|
3289
3291
|
return [
|
|
3290
3292
|
...new Set(contracts
|
|
@@ -3293,17 +3295,38 @@ export class IbkrClient {
|
|
|
3293
3295
|
].sort();
|
|
3294
3296
|
}
|
|
3295
3297
|
/** Build one exact-expiry chain with canonical OSI symbols and required pricing/greeks. */
|
|
3296
|
-
async getOptionChain(symbol, expiry) {
|
|
3297
|
-
const
|
|
3298
|
+
async getOptionChain(symbol, expiry, right) {
|
|
3299
|
+
const month = monthCode(expiry);
|
|
3300
|
+
const normalized = symbol.trim().toUpperCase();
|
|
3301
|
+
const discovery = await this.discoverOptions(normalized, month, right);
|
|
3302
|
+
const contracts = discovery.contracts.filter((contract) => contract.expiry === expiry && (right === undefined || contract.right === right));
|
|
3298
3303
|
if (!contracts.length) {
|
|
3299
3304
|
throw new Error(`IBKR returned no option contracts for ${symbol} ${expiry}`);
|
|
3300
3305
|
}
|
|
3301
|
-
const quoted = await this.fetchOptionQuotes(contracts, {
|
|
3306
|
+
const quoted = await this.fetchOptionQuotes(contracts, {
|
|
3307
|
+
allowIncomplete: true,
|
|
3308
|
+
telemetry: { symbol: normalized, month, right: right ?? null },
|
|
3309
|
+
});
|
|
3302
3310
|
if (!quoted.length) {
|
|
3303
3311
|
throw new Error(`IBKR returned no usable option quotes for ${symbol} ${expiry}`);
|
|
3304
3312
|
}
|
|
3305
3313
|
return quoted;
|
|
3306
3314
|
}
|
|
3315
|
+
/** Return every qualified contract for one exact expiry and side without hiding sparse data. */
|
|
3316
|
+
async getOptionChainSnapshot(symbol, expiry, right) {
|
|
3317
|
+
const month = monthCode(expiry);
|
|
3318
|
+
const normalized = symbol.trim().toUpperCase();
|
|
3319
|
+
const discovery = await this.discoverOptions(normalized, month, right);
|
|
3320
|
+
const contracts = discovery.contracts.filter((contract) => contract.expiry === expiry);
|
|
3321
|
+
if (!contracts.length) {
|
|
3322
|
+
throw new Error(`IBKR returned no ${right} option contracts for ${symbol} ${expiry}`);
|
|
3323
|
+
}
|
|
3324
|
+
return this.fetchOptionChainSnapshot(contracts, discovery.malformedDefinitionCount, {
|
|
3325
|
+
symbol: normalized,
|
|
3326
|
+
month,
|
|
3327
|
+
right,
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3307
3330
|
/** Fetch one exact option quote; null means the contract is not listed. */
|
|
3308
3331
|
async getOptionQuote(input) {
|
|
3309
3332
|
const contract = await this.resolveOptionContract(input);
|
|
@@ -3556,14 +3579,21 @@ export class IbkrClient {
|
|
|
3556
3579
|
}
|
|
3557
3580
|
return result;
|
|
3558
3581
|
}
|
|
3559
|
-
discoverOptions(symbol, month) {
|
|
3582
|
+
discoverOptions(symbol, month, right) {
|
|
3560
3583
|
const normalized = symbol.trim().toUpperCase();
|
|
3561
|
-
const key = `${normalized}:${month}`;
|
|
3584
|
+
const key = `${normalized}:${month}:${right ?? "*"}`;
|
|
3562
3585
|
let pending = this.optionDiscovery.get(key);
|
|
3563
|
-
if (!pending) {
|
|
3564
|
-
|
|
3565
|
-
|
|
3586
|
+
if (!pending && right !== undefined) {
|
|
3587
|
+
const complete = this.optionDiscovery.get(`${normalized}:${month}:*`);
|
|
3588
|
+
if (complete !== undefined) {
|
|
3589
|
+
pending = complete.then((result) => ({
|
|
3590
|
+
contracts: result.contracts.filter((contract) => contract.right === right),
|
|
3591
|
+
malformedDefinitionCount: result.malformedDefinitionCount,
|
|
3592
|
+
}));
|
|
3593
|
+
}
|
|
3566
3594
|
}
|
|
3595
|
+
pending ??= this.loadOptionContracts(normalized, month, right);
|
|
3596
|
+
this.optionDiscovery.set(key, pending);
|
|
3567
3597
|
return pending;
|
|
3568
3598
|
}
|
|
3569
3599
|
async loadOptionUnderlying(symbol) {
|
|
@@ -3611,97 +3641,211 @@ export class IbkrClient {
|
|
|
3611
3641
|
throw new Error(`IBKR lost the selected underlying for ${symbol}`);
|
|
3612
3642
|
return underlying;
|
|
3613
3643
|
}
|
|
3614
|
-
loadOptionContracts(symbol, month) {
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3644
|
+
async loadOptionContracts(symbol, month, right) {
|
|
3645
|
+
const { underlying, requests } = await this.withSecdefPriming(async () => {
|
|
3646
|
+
const searchStarted = this.requestNow();
|
|
3647
|
+
const selectedUnderlying = await this.loadOptionUnderlying(symbol);
|
|
3648
|
+
this.emitOptionDiscoveryTelemetry({
|
|
3649
|
+
phase: "SEARCH",
|
|
3650
|
+
symbol,
|
|
3651
|
+
month,
|
|
3652
|
+
right: right ?? null,
|
|
3653
|
+
durationMs: this.elapsedSince(searchStarted),
|
|
3654
|
+
definitionRequestCount: 0,
|
|
3655
|
+
snapshotBatchCount: 0,
|
|
3656
|
+
});
|
|
3657
|
+
const strikesStarted = this.requestNow();
|
|
3658
|
+
const strikes = await this.req({
|
|
3659
|
+
path: "iserver/secdef/strikes",
|
|
3660
|
+
params: { conid: String(selectedUnderlying.conid), sectype: "OPT", month },
|
|
3661
|
+
});
|
|
3662
|
+
this.emitOptionDiscoveryTelemetry({
|
|
3663
|
+
phase: "STRIKES",
|
|
3664
|
+
symbol,
|
|
3665
|
+
month,
|
|
3666
|
+
right: right ?? null,
|
|
3667
|
+
durationMs: this.elapsedSince(strikesStarted),
|
|
3668
|
+
definitionRequestCount: 0,
|
|
3669
|
+
snapshotBatchCount: 0,
|
|
3670
|
+
});
|
|
3671
|
+
const callStrikes = strikes.call ?? [];
|
|
3672
|
+
const putStrikes = strikes.put ?? [];
|
|
3673
|
+
if (callStrikes.length === 0 && putStrikes.length === 0) {
|
|
3674
|
+
throw new Error(`IBKR returned empty option strikes for ${symbol} ${month} after secdef/search priming`);
|
|
3675
|
+
}
|
|
3676
|
+
const definitionRequests = [
|
|
3677
|
+
...(right === undefined || right === "C"
|
|
3678
|
+
? callStrikes.map((strike) => ({ strike, right: "C" }))
|
|
3679
|
+
: []),
|
|
3680
|
+
...(right === undefined || right === "P"
|
|
3681
|
+
? putStrikes.map((strike) => ({ strike, right: "P" }))
|
|
3682
|
+
: []),
|
|
3683
|
+
];
|
|
3684
|
+
return { underlying: selectedUnderlying, requests: definitionRequests };
|
|
3622
3685
|
});
|
|
3623
|
-
const
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3686
|
+
const definitionsStarted = this.requestNow();
|
|
3687
|
+
const responses = await Promise.all(requests.map(({ strike, right: requestRight }) => this.req({
|
|
3688
|
+
path: "iserver/secdef/info",
|
|
3689
|
+
params: {
|
|
3690
|
+
conid: String(underlying.conid),
|
|
3691
|
+
sectype: "OPT",
|
|
3692
|
+
month,
|
|
3693
|
+
strike,
|
|
3694
|
+
right: requestRight,
|
|
3695
|
+
},
|
|
3696
|
+
})));
|
|
3697
|
+
this.emitOptionDiscoveryTelemetry({
|
|
3698
|
+
phase: "DEFINITIONS",
|
|
3699
|
+
symbol,
|
|
3700
|
+
month,
|
|
3701
|
+
right: right ?? null,
|
|
3702
|
+
durationMs: this.elapsedSince(definitionsStarted),
|
|
3703
|
+
definitionRequestCount: requests.length,
|
|
3704
|
+
snapshotBatchCount: 0,
|
|
3705
|
+
});
|
|
3706
|
+
if (requests.length === 0)
|
|
3707
|
+
return { contracts: [], malformedDefinitionCount: 0 };
|
|
3630
3708
|
const contracts = [];
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
}
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3709
|
+
let malformedDefinitionCount = 0;
|
|
3710
|
+
for (const response of responses) {
|
|
3711
|
+
if (!Array.isArray(response)) {
|
|
3712
|
+
throw new Error(`IBKR returned malformed option definitions for ${symbol} ${month}`);
|
|
3713
|
+
}
|
|
3714
|
+
for (const raw of response) {
|
|
3715
|
+
if (!isUnknownRecord(raw)) {
|
|
3716
|
+
malformedDefinitionCount += 1;
|
|
3717
|
+
continue;
|
|
3718
|
+
}
|
|
3719
|
+
let contract;
|
|
3720
|
+
try {
|
|
3721
|
+
contract = normalizeOptionContract({
|
|
3722
|
+
conid: typeof raw["conid"] === "number" ? raw["conid"] : undefined,
|
|
3723
|
+
symbol: typeof raw["symbol"] === "string" ? raw["symbol"] : underlying.symbol,
|
|
3724
|
+
maturityDate: typeof raw["maturityDate"] === "string" ? raw["maturityDate"] : undefined,
|
|
3725
|
+
right: typeof raw["right"] === "string" ? raw["right"] : undefined,
|
|
3726
|
+
strike: typeof raw["strike"] === "string" || typeof raw["strike"] === "number"
|
|
3727
|
+
? raw["strike"]
|
|
3728
|
+
: undefined,
|
|
3729
|
+
});
|
|
3730
|
+
}
|
|
3731
|
+
catch {
|
|
3732
|
+
malformedDefinitionCount += 1;
|
|
3733
|
+
continue;
|
|
3734
|
+
}
|
|
3650
3735
|
if (contract)
|
|
3651
3736
|
contracts.push(contract);
|
|
3737
|
+
else
|
|
3738
|
+
malformedDefinitionCount += 1;
|
|
3652
3739
|
}
|
|
3653
3740
|
}
|
|
3654
3741
|
const unique = [...new Map(contracts.map((contract) => [contract.conid, contract])).values()];
|
|
3655
3742
|
if (!unique.length) {
|
|
3656
|
-
throw new Error(`IBKR returned no usable option definitions for ${symbol} ${month}`);
|
|
3743
|
+
throw new Error(`IBKR returned no usable option definitions for ${symbol} ${month} (${String(malformedDefinitionCount)} malformed)`);
|
|
3744
|
+
}
|
|
3745
|
+
return { contracts: unique, malformedDefinitionCount };
|
|
3746
|
+
}
|
|
3747
|
+
async fetchOptionChainSnapshot(contracts, malformedDefinitionCount, telemetry) {
|
|
3748
|
+
const fields = [
|
|
3749
|
+
"bid",
|
|
3750
|
+
"ask",
|
|
3751
|
+
"mid",
|
|
3752
|
+
"delta",
|
|
3753
|
+
"volume",
|
|
3754
|
+
"openInterest",
|
|
3755
|
+
"availability",
|
|
3756
|
+
"timestamp",
|
|
3757
|
+
];
|
|
3758
|
+
const missingFieldCounts = Object.fromEntries(fields.map((field) => [field, 0]));
|
|
3759
|
+
const quotes = await this.fetchNullableOptionQuotes(contracts, telemetry);
|
|
3760
|
+
for (const quote of quotes) {
|
|
3761
|
+
for (const field of fields) {
|
|
3762
|
+
if (quote[field] === null)
|
|
3763
|
+
missingFieldCounts[field] += 1;
|
|
3764
|
+
}
|
|
3657
3765
|
}
|
|
3658
|
-
|
|
3766
|
+
const diagnostics = {
|
|
3767
|
+
qualifiedCount: contracts.length,
|
|
3768
|
+
returnedCount: quotes.length,
|
|
3769
|
+
malformedDefinitionCount,
|
|
3770
|
+
missingFieldCounts,
|
|
3771
|
+
};
|
|
3772
|
+
return { quotes, diagnostics };
|
|
3659
3773
|
}
|
|
3660
|
-
async
|
|
3661
|
-
const
|
|
3662
|
-
const
|
|
3663
|
-
const
|
|
3664
|
-
for (const batch of
|
|
3774
|
+
async fetchNullableOptionQuotes(contracts, telemetry) {
|
|
3775
|
+
const quotes = [];
|
|
3776
|
+
const batches = chunks(contracts, OPTION_MARKETDATA_BATCH_SIZE);
|
|
3777
|
+
const snapshotsStarted = this.requestNow();
|
|
3778
|
+
for (const batch of batches) {
|
|
3665
3779
|
const params = {
|
|
3666
3780
|
conids: batch.map((contract) => contract.conid).join(","),
|
|
3667
3781
|
fields: OPTION_QUOTE_FIELDS,
|
|
3668
3782
|
};
|
|
3669
3783
|
await this.req({ path: "iserver/marketdata/snapshot", params });
|
|
3670
3784
|
await this.wait(2000);
|
|
3671
|
-
const
|
|
3785
|
+
const response = await this.req({
|
|
3672
3786
|
path: "iserver/marketdata/snapshot",
|
|
3673
3787
|
params,
|
|
3674
3788
|
});
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3789
|
+
if (!Array.isArray(response)) {
|
|
3790
|
+
throw new Error("IBKR returned malformed option market-data snapshots");
|
|
3791
|
+
}
|
|
3792
|
+
const snapshots = response.filter((snapshot) => isUnknownRecord(snapshot) &&
|
|
3793
|
+
typeof snapshot["conid"] === "number" &&
|
|
3794
|
+
Number.isSafeInteger(snapshot["conid"]) &&
|
|
3795
|
+
snapshot["conid"] > 0);
|
|
3796
|
+
const byConid = new Map(snapshots.map((snapshot) => [snapshot.conid, snapshot]));
|
|
3678
3797
|
for (const contract of batch) {
|
|
3679
3798
|
const snapshot = byConid.get(contract.conid);
|
|
3680
|
-
const bid = snapshot ? this.snapshotNumber(snapshot, "84") :
|
|
3681
|
-
const ask = snapshot ? this.snapshotNumber(snapshot, "86") :
|
|
3682
|
-
const
|
|
3683
|
-
|
|
3684
|
-
if (allowIncomplete) {
|
|
3685
|
-
skipped.push(contract.symbol);
|
|
3686
|
-
continue;
|
|
3687
|
-
}
|
|
3688
|
-
throw new Error(`IBKR returned incomplete option market data for ${contract.symbol} (bid/ask/delta required)`);
|
|
3689
|
-
}
|
|
3690
|
-
const volume = snapshot ? (this.snapshotVolume(snapshot) ?? null) : null;
|
|
3691
|
-
const openInterest = snapshot ? (this.snapshotNumber(snapshot, "7638") ?? null) : null;
|
|
3692
|
-
result.push({
|
|
3799
|
+
const bid = snapshot ? (this.snapshotNumber(snapshot, "84") ?? null) : null;
|
|
3800
|
+
const ask = snapshot ? (this.snapshotNumber(snapshot, "86") ?? null) : null;
|
|
3801
|
+
const rawAvailability = snapshot?.["6509"];
|
|
3802
|
+
quotes.push({
|
|
3693
3803
|
...contract,
|
|
3694
3804
|
bid,
|
|
3695
3805
|
ask,
|
|
3696
|
-
mid: (bid + ask) / 2,
|
|
3697
|
-
delta,
|
|
3698
|
-
volume,
|
|
3699
|
-
openInterest,
|
|
3700
|
-
availability:
|
|
3806
|
+
mid: bid !== null && ask !== null ? (bid + ask) / 2 : null,
|
|
3807
|
+
delta: snapshot ? (this.snapshotNumber(snapshot, "7308") ?? null) : null,
|
|
3808
|
+
volume: snapshot ? (this.snapshotVolume(snapshot) ?? null) : null,
|
|
3809
|
+
openInterest: snapshot ? (this.snapshotNumber(snapshot, "7638") ?? null) : null,
|
|
3810
|
+
availability: typeof rawAvailability === "string" || typeof rawAvailability === "number"
|
|
3811
|
+
? normalizeDerivativeDataAvailability(rawAvailability)
|
|
3812
|
+
: null,
|
|
3701
3813
|
timestamp: snapshot ? this.snapshotTimestamp(snapshot) : null,
|
|
3702
3814
|
});
|
|
3703
3815
|
}
|
|
3704
3816
|
}
|
|
3817
|
+
if (telemetry !== undefined) {
|
|
3818
|
+
this.emitOptionDiscoveryTelemetry({
|
|
3819
|
+
phase: "SNAPSHOTS",
|
|
3820
|
+
...telemetry,
|
|
3821
|
+
durationMs: this.elapsedSince(snapshotsStarted),
|
|
3822
|
+
definitionRequestCount: 0,
|
|
3823
|
+
snapshotBatchCount: batches.length,
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
return quotes;
|
|
3827
|
+
}
|
|
3828
|
+
async fetchOptionQuotes(contracts, options = {}) {
|
|
3829
|
+
const { allowIncomplete = false, telemetry } = options;
|
|
3830
|
+
const result = [];
|
|
3831
|
+
const skipped = [];
|
|
3832
|
+
for (const quote of await this.fetchNullableOptionQuotes(contracts, telemetry)) {
|
|
3833
|
+
if (quote.bid === null || quote.ask === null || quote.delta === null) {
|
|
3834
|
+
if (allowIncomplete) {
|
|
3835
|
+
skipped.push(quote.symbol);
|
|
3836
|
+
continue;
|
|
3837
|
+
}
|
|
3838
|
+
throw new Error(`IBKR returned incomplete option market data for ${quote.symbol} (bid/ask/delta required)`);
|
|
3839
|
+
}
|
|
3840
|
+
result.push({
|
|
3841
|
+
...quote,
|
|
3842
|
+
bid: quote.bid,
|
|
3843
|
+
ask: quote.ask,
|
|
3844
|
+
mid: (quote.bid + quote.ask) / 2,
|
|
3845
|
+
delta: quote.delta,
|
|
3846
|
+
availability: quote.availability ?? "unavailable",
|
|
3847
|
+
});
|
|
3848
|
+
}
|
|
3705
3849
|
if (allowIncomplete && skipped.length && skipped.length === contracts.length) {
|
|
3706
3850
|
const symbol = contracts[0]?.underlying ?? "unknown";
|
|
3707
3851
|
const expiry = contracts[0]?.expiry ?? "unknown";
|
|
@@ -3728,6 +3872,21 @@ export class IbkrClient {
|
|
|
3728
3872
|
const endDay = this.utcDayStart(input.endDate);
|
|
3729
3873
|
return { start, end: endDay + DAY_MS - 1, days: (endDay - start) / DAY_MS + 1 };
|
|
3730
3874
|
}
|
|
3875
|
+
elapsedSince(startedAt) {
|
|
3876
|
+
return Math.max(0, this.requestNow() - startedAt);
|
|
3877
|
+
}
|
|
3878
|
+
emitOptionDiscoveryTelemetry(event) {
|
|
3879
|
+
try {
|
|
3880
|
+
const result = this.onOptionDiscoveryTelemetry({
|
|
3881
|
+
event: "OPTION_DISCOVERY_PHASE",
|
|
3882
|
+
...event,
|
|
3883
|
+
});
|
|
3884
|
+
void Promise.resolve(result).catch(() => undefined);
|
|
3885
|
+
}
|
|
3886
|
+
catch {
|
|
3887
|
+
// Telemetry observers cannot change discovery or quote settlement.
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3731
3890
|
async requestPriceHistory(contract, requestedSymbol, request) {
|
|
3732
3891
|
this.onPriceHistoryTelemetry({
|
|
3733
3892
|
event: "PRICE_HISTORY_REQUEST",
|
|
@@ -4370,6 +4529,7 @@ export class IbkrClient {
|
|
|
4370
4529
|
return this.requestScheduler.schedule({
|
|
4371
4530
|
endpoint: this.requestEndpoint(input.path),
|
|
4372
4531
|
priority: this.requestPriority(input.path),
|
|
4532
|
+
secdefInfo: input.path === "iserver/secdef/info",
|
|
4373
4533
|
retryable: retryPolicy !== "SINGLE_ATTEMPT",
|
|
4374
4534
|
retryServerErrors: retryPolicy === "PRICE_HISTORY",
|
|
4375
4535
|
}, async () => {
|