diff --git a/.codeclimate.yml b/.codeclimate.yml index 47cec7d0..451f14f3 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,2 +1,3 @@ exclude_patterns: - "ref/" + - "src/tests" diff --git a/.vscode/settings.json b/.vscode/settings.json index 59f72d0f..57107f7c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,9 @@ { "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.fixAll.format": true, - "source.organizeImports": true, - "source.sortPackageJson": true + "source.fixAll.eslint": "explicit", + "source.fixAll.format": "explicit", + "source.organizeImports": "explicit", + "source.sortPackageJson": "explicit" }, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, diff --git a/package.json b/package.json index 77940eb3..4411b022 100644 --- a/package.json +++ b/package.json @@ -74,20 +74,20 @@ "rxjs": "^7.8.1" }, "devDependencies": { - "@types/jest": "^29.5.5", + "@types/jest": "^29.5.11", "@types/node": "^18.17.15", - "@types/source-map-support": "^0.5.8", - "@typescript-eslint/eslint-plugin": "^6.7.4", - "@typescript-eslint/parser": "^6.7.4", + "@types/source-map-support": "^0.5.10", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "ajv": "^8.12.0", - "eslint": "^8.51.0", - "eslint-plugin-jest": "^27.4.2", + "eslint": "^8.56.0", + "eslint-plugin-jest": "^27.6.2", "eslint-plugin-rxjs": "^5.0.3", "jest": "^29.7.0", "jest-environment-node": "^29.7.0", "jest-junit": "^16.0.0", "ts-jest": "^29.1.1", - "typedoc": "^0.25.1", + "typedoc": "^0.25.7", "typescript": "^5.2.2" }, "engines": { diff --git a/src/common/errorCode.ts b/src/common/errorCode.ts index c4a6ea0b..cdd54bbe 100644 --- a/src/common/errorCode.ts +++ b/src/common/errorCode.ts @@ -7,6 +7,9 @@ export enum ErrorCode { /** Order Canceled - reason: */ ORDER_CANCELLED = 202, + /** ou must subscribe for additional permissions to obtain precise results for scanner.Parameter:Most Active,Filter:Price;Real-Time Market Data:Pink Sheets */ + SCANNER_LOW_PRECISION = 492, + /** Already connected. */ ALREADY_CONNECTED = 501, diff --git a/src/core/io/decoder.ts b/src/core/io/decoder.ts index 3199df0e..d51afc17 100644 --- a/src/core/io/decoder.ts +++ b/src/core/io/decoder.ts @@ -2507,409 +2507,80 @@ export class Decoder { const contract: Contract = {}; const order: Order = {}; const orderState: OrderState = {}; + const orderDecoder = new OrderDecoder( + this, + contract, + order, + orderState, + Number.MAX_VALUE, + this.serverVersion, + ); - if (this.serverVersion >= 12) { - contract.conId = this.readInt(); - } - contract.symbol = this.readStr(); - contract.secType = this.readStr() as SecType; - contract.lastTradeDateOrContractMonth = this.readStr(); - contract.strike = this.readDouble(); - contract.right = validateOptionType(this.readStr() as OptionType); - if (this.serverVersion >= 32) { - contract.multiplier = this.readDouble(); - } - contract.exchange = this.readStr(); - contract.currency = this.readStr(); - if (this.serverVersion >= 2) { - contract.localSymbol = this.readStr(); - } - if (this.serverVersion >= 32) { - contract.tradingClass = this.readStr(); - } - order.action = this.readStr() as OrderAction; - if (this.serverVersion >= MIN_SERVER_VER.FRACTIONAL_POSITIONS) { - order.totalQuantity = this.readDouble(); - } else { - order.totalQuantity = this.readInt(); - } - order.orderType = this.readStr() as OrderType; - if (this.serverVersion < 29) { - order.lmtPrice = this.readDouble(); - } else { - order.lmtPrice = this.readDoubleOrUndefined(); - } - if (this.serverVersion < 30) { - order.auxPrice = this.readDouble(); - } else { - order.auxPrice = this.readDoubleOrUndefined(); - } - order.tif = this.readStr() as TimeInForce; - order.ocaGroup = this.readStr(); - order.account = this.readStr(); - order.openClose = this.readStr(); - order.origin = this.readInt(); - order.orderRef = this.readStr(); - if (this.serverVersion >= 3) { - order.permId = this.readInt(); - } - if (this.serverVersion >= 4) { - order.hidden = this.readBool(); - } - order.discretionaryAmt = - this.serverVersion >= 4 ? this.readDouble() : undefined; - order.goodAfterTime = this.serverVersion >= 4 ? this.readStr() : undefined; - - if (this.serverVersion >= 4) { - if (this.serverVersion < 18) { - // will never happen - /* ignoreRth = */ this.readBool(); - } else { - order.outsideRth = this.readBool(); - } - } - - if (this.serverVersion >= 7) { - order.faGroup = this.readStr(); - order.faMethod = this.readStr(); - order.faPercentage = this.readStr(); - order.faProfile = this.readStr(); - } - - if (this.serverVersion >= MIN_SERVER_VER.MODELS_SUPPORT) { - order.modelCode = this.readStr(); - } - - if (this.serverVersion >= 8) { - order.goodTillDate = this.readStr(); - } - - if (this.serverVersion >= 9) { - order.rule80A = this.readStr(); - order.percentOffset = this.readDoubleOrUndefined(); - order.settlingFirm = this.readStr(); - - order.shortSaleSlot = this.readInt(); - order.designatedLocation = this.readStr(); - if (this.serverVersion == 51) { - this.readInt(); // exemptCode - } else if (this.serverVersion >= 23) { - order.exemptCode = this.readInt(); - } - - order.startingPrice = this.readDoubleOrUndefined(); - order.stockRefPrice = this.readDoubleOrUndefined(); - order.delta = this.readDoubleOrUndefined(); - - order.stockRangeLower = this.readDoubleOrUndefined(); - order.stockRangeUpper = this.readDoubleOrUndefined(); - - order.displaySize = this.readInt(); - - order.sweepToFill = this.readBool(); - order.allOrNone = this.readBool(); - order.minQty = this.readIntOrUndefined(); - order.ocaType = this.readInt(); - } - - order.triggerMethod = this.serverVersion >= 10 ? this.readInt() : undefined; - - if (this.serverVersion >= 11) { - order.volatility = this.readDoubleOrUndefined(); - order.volatilityType = this.readInt(); - if (this.serverVersion == 11) { - order.deltaNeutralOrderType = this.readInt() == 0 ? "NONE" : "MKT"; - } else { - order.deltaNeutralOrderType = this.readStr(); - order.deltaNeutralAuxPrice = this.readDoubleOrUndefined(); - - if (this.serverVersion >= 27 && order.deltaNeutralOrderType !== "") { - order.deltaNeutralConId = this.readInt(); - } - - if (this.serverVersion >= 31 && order.deltaNeutralOrderType !== "") { - order.deltaNeutralShortSale = this.readBool(); - order.deltaNeutralShortSaleSlot = this.readInt(); - order.deltaNeutralDesignatedLocation = this.readStr(); - } - } - order.continuousUpdate = this.readInt(); - if (this.serverVersion == 26) { - order.stockRangeLower = this.readDouble(); - order.stockRangeUpper = this.readDouble(); - } - order.referencePriceType = this.readInt(); - } - - if (this.serverVersion >= 13) { - order.trailStopPrice = this.readDoubleOrUndefined(); - } - - if (this.serverVersion >= 30) { - order.trailStopPrice = this.readDoubleOrUndefined(); - } - - if (this.serverVersion >= 1) { - contract.comboLegsDescription = this.readStr(); - } - - if (this.serverVersion >= 29) { - const comboLegsCount = this.readInt(); - - const comboLegs = new Array(comboLegsCount); - for (let i = 0; i < comboLegsCount; i++) { - comboLegs[i] = { - conId: this.readInt(), - ratio: this.readInt(), - action: this.readStr(), - exchange: this.readStr(), - openClose: this.readInt(), - shortSaleSlot: this.readInt(), - designatedLocation: this.readStr(), - exemptCode: this.readInt(), - }; - } - contract.comboLegs = comboLegs; - - const orderComboLegsCount = this.readInt(); - const orderComboLegs = new Array(orderComboLegsCount); - for (let i = 0; i < orderComboLegsCount; i++) { - orderComboLegs[i] = { price: this.readDoubleOrUndefined() }; - } - order.orderComboLegs = orderComboLegs; - } - - if (this.serverVersion >= 26) { - const smartComboRoutingParamsCount = this.readInt(); - - const smartComboRoutingParams = new Array(smartComboRoutingParamsCount); - for (let i = 0; i < smartComboRoutingParamsCount; i++) { - smartComboRoutingParams[i] = { - tag: this.readStr(), - value: this.readStr(), - }; - } - order.smartComboRoutingParams = smartComboRoutingParams; - } - - if (this.serverVersion >= 15) { - if (this.serverVersion >= 20) { - order.scaleInitLevelSize = this.readIntOrUndefined(); - order.scaleSubsLevelSize = this.readIntOrUndefined(); - } else { - /* notSuppScaleNumComponents = */ this.readIntOrUndefined(); - order.scaleSubsLevelSize = this.readIntOrUndefined(); - } - order.scalePriceIncrement = this.readDoubleOrUndefined(); - } - - if (this.serverVersion >= 28 && order.scalePriceIncrement != undefined) { - order.scalePriceAdjustValue = this.readDoubleOrUndefined(); - order.scalePriceAdjustInterval = this.readIntOrUndefined(); - order.scaleProfitOffset = this.readDoubleOrUndefined(); - order.scaleAutoReset = this.readBool(); - order.scaleInitPosition = this.readIntOrUndefined(); - order.scaleInitFillQty = this.readIntOrUndefined(); - order.scaleRandomPercent = this.readBool(); - } - - if (this.serverVersion >= 24) { - order.hedgeType = this.readStr(); - if (order.hedgeType !== "") { - order.hedgeParam = this.readStr(); - } - } - - if (this.serverVersion >= 19) { - order.clearingAccount = this.readStr(); - order.clearingIntent = this.readStr(); - } - - if (this.serverVersion >= 22) { - order.notHeld = this.readBool(); - } - - if (this.serverVersion >= 20) { - if (this.readBool()) { - contract.deltaNeutralContract = { - conId: this.readInt(), - delta: this.readDouble(), - price: this.readDouble(), - }; - } - } - - if (this.serverVersion >= 21) { - order.algoStrategy = this.readStr(); - if (order.algoStrategy !== "") { - const algoParamsCount = this.readInt(); - const allParams = new Array(algoParamsCount); - for (let i = 0; i < algoParamsCount; i++) { - allParams[i] = { tag: this.readStr(), value: this.readStr() }; - } - order.algoParams = allParams; - } - } - - if (this.serverVersion >= 33) { - order.solicited = this.readBool(); - } - - orderState.status = this.readStr() as OrderStatus; - - if (this.serverVersion >= 34) { - order.randomizeSize = this.readBool(); - order.randomizePrice = this.readBool(); - } - - if (this.serverVersion >= MIN_SERVER_VER.PEGGED_TO_BENCHMARK) { - if (order.orderType == OrderType.PEG_BENCH) { - order.referenceContractId = this.readInt(); - order.isPeggedChangeAmountDecrease = this.readBool(); - order.peggedChangeAmount = this.readDouble(); - order.referenceChangeAmount = this.readDouble(); - order.referenceExchangeId = this.readStr(); - } - - const nConditions = this.readInt(); - order.conditions = new Array(nConditions); - for (let i = 0; i < nConditions; i++) { - const type = this.readInt(); - - // OrderCondition - const conjunctionConnection = this.readStr()?.toLocaleLowerCase(); - - switch (type) { - case OrderConditionType.Execution: { - const secType = this.readStr() as SecType; - const exchange = this.readStr(); - const symbol = this.readStr(); - - order.conditions[i] = new ExecutionCondition( - exchange, - secType, - symbol, - conjunctionConnection as ConjunctionConnection, - ); - break; - } - - case OrderConditionType.Margin: { - // OperatorCondition - const isMore = this.readBool(); - const value = this.readInt(); - - order.conditions[i] = new MarginCondition( - value, - isMore, - conjunctionConnection as ConjunctionConnection, - ); - break; - } - - case OrderConditionType.PercentChange: { - // OperatorCondition - const isMore = this.readBool(); - const value = this.readDouble(); - // ContractCondition - const condId = this.readInt(); - const exchange = this.readStr(); - - order.conditions[i] = new PercentChangeCondition( - value, - condId, - exchange, - isMore, - conjunctionConnection as ConjunctionConnection, - ); - break; - } - - case OrderConditionType.Price: { - // OperatorCondition - const isMore = this.readBool(); - const value = this.readDouble(); - // ContractCondition - const condId = this.readInt(); - const exchange = this.readStr(); - // PriceCondition - const triggerMethod = this.readInt() as TriggerMethod; - - order.conditions[i] = new PriceCondition( - value, - triggerMethod, - condId, - exchange, - isMore, - conjunctionConnection as ConjunctionConnection, - ); - break; - } - - case OrderConditionType.Time: { - // OperatorCondition - const isMore = this.readBool(); - const value = this.readStr(); - - order.conditions[i] = new TimeCondition( - value, - isMore, - conjunctionConnection as ConjunctionConnection, - ); - break; - } - - case OrderConditionType.Volume: { - // OperatorCondition - const isMore = this.readBool(); - const value = this.readInt(); - // ContractCondition - const condId = this.readInt(); - const exchange = this.readStr(); - - order.conditions[i] = new VolumeCondition( - value, - condId, - exchange, - isMore, - conjunctionConnection as ConjunctionConnection, - ); - break; - } - } - } - - if (order.conditions.length) { - order.conditionsIgnoreRth = this.readBool(); - order.conditionsCancelOrder = this.readBool(); - } - } - - order.trailStopPrice = this.readDoubleOrUndefined(); - order.lmtPriceOffset = this.readDoubleOrUndefined(); - - if (this.serverVersion >= MIN_SERVER_VER.CASH_QTY) { - order.cashQty = this.readDoubleOrUndefined(); - } - - if (this.serverVersion >= MIN_SERVER_VER.AUTO_PRICE_FOR_HEDGE) { - order.dontUseAutoPriceForHedge = this.readBool(); - } - - if (this.serverVersion >= MIN_SERVER_VER.ORDER_CONTAINER) { - order.isOmsContainer = this.readBool(); - } + // read contract fields + orderDecoder.readContractFields(); - order.autoCancelDate = this.readStr(); - order.filledQuantity = this.readDoubleOrUndefined(); - order.refFuturesConId = this.readInt(); - order.autoCancelParent = this.readBool(); - order.shareholder = this.readStr(); - order.imbalanceOnly = this.readBool(); - order.routeMarketableToBbo = this.readBool(); - order.parentPermId = this.readInt(); - orderState.completedTime = this.readStr(); - orderState.completedStatus = this.readStr(); + // read order fields + orderDecoder.readAction(); + orderDecoder.readTotalQuantity(); + orderDecoder.readOrderType(); + orderDecoder.readLmtPrice(); + orderDecoder.readAuxPrice(); + orderDecoder.readTIF(); + orderDecoder.readOcaGroup(); + orderDecoder.readAccount(); + orderDecoder.readOpenClose(); + orderDecoder.readOrigin(); + orderDecoder.readOrderRef(); + orderDecoder.readPermId(); + orderDecoder.readOutsideRth(); + orderDecoder.readHidden(); + orderDecoder.readDiscretionaryAmount(); + orderDecoder.readGoodAfterTime(); + orderDecoder.readFAParams(); + orderDecoder.readModelCode(); + orderDecoder.readGoodTillDate(); + orderDecoder.readRule80A(); + orderDecoder.readPercentOffset(); + orderDecoder.readSettlingFirm(); + orderDecoder.readShortSaleParams(); + orderDecoder.readBoxOrderParams(); + orderDecoder.readPegToStkOrVolOrderParams(); + orderDecoder.readDisplaySize(); + orderDecoder.readSweepToFill(); + orderDecoder.readAllOrNone(); + orderDecoder.readMinQty(); + orderDecoder.readOcaType(); + orderDecoder.readTriggerMethod(); + orderDecoder.readVolOrderParams(false); + orderDecoder.readTrailParams(); + orderDecoder.readComboLegs(); + orderDecoder.readSmartComboRoutingParams(); + orderDecoder.readScaleOrderParams(); + orderDecoder.readHedgeParams(); + orderDecoder.readClearingParams(); + orderDecoder.readNotHeld(); + orderDecoder.readDeltaNeutral(); + orderDecoder.readAlgoParams(); + orderDecoder.readSolicited(); + orderDecoder.readOrderStatus(); + orderDecoder.readVolRandomizeFlags(); + orderDecoder.readPegToBenchParams(); + orderDecoder.readConditions(); + orderDecoder.readStopPriceAndLmtPriceOffset(); + orderDecoder.readCashQty(); + orderDecoder.readDontUseAutoPriceForHedge(); + orderDecoder.readIsOmsContainer(); + orderDecoder.readAutoCancelDate(); + orderDecoder.readFilledQuantity(); + orderDecoder.readRefFuturesConId(); + orderDecoder.readAutoCancelParent(); + orderDecoder.readShareholder(); + orderDecoder.readImbalanceOnly(); + orderDecoder.readRouteMarketableToBbo(); + orderDecoder.readParentPermId(); + orderDecoder.readCompletedTime(); + orderDecoder.readCompletedStatus(); + orderDecoder.readPegBestPegMidOrderAttributes(); this.emit(EventName.completedOrder, contract, order, orderState); } @@ -3326,8 +2997,7 @@ class OrderDecoder { this.order.faGroup = this.decoder.readStr(); this.order.faMethod = this.decoder.readStr(); this.order.faPercentage = this.decoder.readStr(); - if (this.serverVersion < MIN_SERVER_VER.FA_PROFILE_DESUPPORT) - this.order.faProfile = this.decoder.readStr(); + this.order.faProfile = this.decoder.readStr(); } } diff --git a/src/core/io/encoder.ts b/src/core/io/encoder.ts index dbcbb41d..e23eb906 100644 --- a/src/core/io/encoder.ts +++ b/src/core/io/encoder.ts @@ -216,12 +216,11 @@ export class Encoder { contract.right, contract.multiplier, contract.exchange, + contract.primaryExch, contract.currency, contract.localSymbol, contract.tradingClass, - contract.primaryExch, - contract.secIdType, - contract.secId, + contract.includeExpired ? 1 : 0, ]; } @@ -1856,8 +1855,8 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { OUT_MSG_ID.REQ_HEAD_TIMESTAMP, reqId, this.encodeContract(contract), - whatToShow, useRTH ? 1 : 0, + whatToShow, formatDate, ); } @@ -2232,21 +2231,11 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { ); } - const args: unknown[] = [OUT_MSG_ID.REQ_HISTORICAL_TICKS, tickerId]; - - args.push(contract.conId); - args.push(contract.symbol); - args.push(contract.secType); - args.push(contract.lastTradeDateOrContractMonth); - args.push(contract.strike); - args.push(contract.right); - args.push(contract.multiplier); - args.push(contract.exchange); - args.push(contract.primaryExch); - args.push(contract.currency); - args.push(contract.localSymbol); - args.push(contract.tradingClass); - args.push(contract.includeExpired); + const args: unknown[] = [ + OUT_MSG_ID.REQ_HISTORICAL_TICKS, + tickerId, + ...this.encodeContract(contract), + ]; args.push(startDateTime); args.push(endDateTime); args.push(numberOfTicks); @@ -3127,8 +3116,8 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { OUT_MSG_ID.REQ_HISTOGRAM_DATA, tickerId, this.encodeContract(contract), - timePeriod, useRTH ? 1 : 0, + timePeriod, ); } diff --git a/src/tests/unit/api-next-live/get-contract-details.test.ts b/src/tests/unit/api-next-live/get-contract-details.test.ts new file mode 100644 index 00000000..c807f5db --- /dev/null +++ b/src/tests/unit/api-next-live/get-contract-details.test.ts @@ -0,0 +1,128 @@ +/** + * This file implements tests for the [[IBApiNext.getContractDetails]] function. + */ + +import { Subscription } from "rxjs"; +import { IBApiNext, IBApiNextError } from "../../.."; +import { + sample_bond, + sample_future, + sample_option, + sample_stock, +} from "../contracts"; + +describe("ApiNext: getContractDetails()", () => { + jest.setTimeout(10 * 1000); + + const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client + + let subscription$: Subscription; + let api: IBApiNext; + let error$: Subscription; + + beforeEach(() => { + api = new IBApiNext(); + + if (!error$) { + error$ = api.errorSubject.subscribe((error) => { + if (error.reqId === -1) { + console.warn(`${error.error.message} (Error #${error.code})`); + } else { + console.error( + `${error.error.message} (Error #${error.code}) ${ + error.advancedOrderReject ? error.advancedOrderReject : "" + }`, + ); + } + }); + } + + try { + api.connect(clientId); + } catch (error) { + console.error(error.message); + } + }); + + afterEach(() => { + if (api) { + api.disconnect(); + api = undefined; + } + }); + + test("Stock contract details", (done) => { + api + .getContractDetails(sample_stock) + .then((result) => { + // console.log(result); + expect(result.length).toBeGreaterThan(0); + if (result.length) { + expect(result[0].contract.symbol).toEqual(sample_stock.symbol); + expect(result[0].contract.secType).toEqual(sample_stock.secType); + } + done(); + }) + .catch((err: IBApiNextError) => { + done( + `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, + ); + }); + }); + + test("Future contract details", (done) => { + api + .getContractDetails(sample_future) + .then((result) => { + // console.log(result); + expect(result.length).toBeGreaterThan(0); + if (result.length) { + expect(result[0].contract.symbol).toEqual(sample_future.symbol); + expect(result[0].contract.secType).toEqual(sample_future.secType); + } + done(); + }) + .catch((err: IBApiNextError) => { + done( + `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, + ); + }); + }); + + test("Option contract details", (done) => { + api + .getContractDetails(sample_option) + .then((result) => { + // console.log(result); + expect(result.length).toBeGreaterThan(0); + if (result.length) { + expect(result[0].contract.symbol).toEqual(sample_option.symbol); + expect(result[0].contract.secType).toEqual(sample_option.secType); + } + done(); + }) + .catch((err: IBApiNextError) => { + done( + `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, + ); + }); + }); + + test("Bond contract details", (done) => { + api + .getContractDetails(sample_bond) + .then((result) => { + // console.log(result); + expect(result.length).toBeGreaterThan(0); + if (result.length) { + expect(result[0].contract.secType).toEqual(sample_bond.secType); + } + done(); + }) + .catch((err: IBApiNextError) => { + done( + `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, + ); + }); + }); +}); diff --git a/src/tests/unit/api-next/subscription-registry.test.ts b/src/tests/unit/api-next-live/subscription-registry.test.ts similarity index 89% rename from src/tests/unit/api-next/subscription-registry.test.ts rename to src/tests/unit/api-next-live/subscription-registry.test.ts index 0de7070f..533a902f 100644 --- a/src/tests/unit/api-next/subscription-registry.test.ts +++ b/src/tests/unit/api-next-live/subscription-registry.test.ts @@ -1,9 +1,6 @@ import { Subscription } from "rxjs"; import { IBApiNext, IBApiNextError } from "../../.."; -const _awaitTimeout = (delay: number): Promise => - new Promise((resolve): NodeJS.Timeout => setTimeout(resolve, delay * 1000)); - describe("Subscription registry Tests", () => { jest.setTimeout(20000); @@ -45,7 +42,7 @@ describe("Subscription registry Tests", () => { }); it("Twice the same event callback bug", (done) => { - // Disable this test for the time to commit other changes + // Two active subscriptions for the same Event #193 done(); return; subscription$ = api.getOpenOrders().subscribe({ diff --git a/src/tests/unit/api-next/get-contract-details.test.ts b/src/tests/unit/api-next/get-contract-details.test.ts index c3666c98..4e5d0fe9 100644 --- a/src/tests/unit/api-next/get-contract-details.test.ts +++ b/src/tests/unit/api-next/get-contract-details.test.ts @@ -2,7 +2,6 @@ * This file implements tests for the [[IBApiNext.getContractDetails]] function. */ -import { Subscription } from "rxjs"; import { ContractDetails, EventName, @@ -10,12 +9,6 @@ import { IBApiNext, IBApiNextError, } from "../../.."; -import { - sample_bond, - sample_future, - sample_option, - sample_stock, -} from "../contracts"; describe("RxJS Wrapper: getContractDetails()", () => { test("Error Event", (done) => { @@ -75,119 +68,3 @@ describe("RxJS Wrapper: getContractDetails()", () => { api.emit(EventName.contractDetailsEnd, 1); }); }); - -describe("ApiNext: getContractDetails()", () => { - jest.setTimeout(10 * 1000); - - const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client - - let subscription$: Subscription; - let api: IBApiNext; - let error$: Subscription; - - beforeEach(() => { - api = new IBApiNext(); - - if (!error$) { - error$ = api.errorSubject.subscribe((error) => { - if (error.reqId === -1) { - console.warn(`${error.error.message} (Error #${error.code})`); - } else { - console.error( - `${error.error.message} (Error #${error.code}) ${ - error.advancedOrderReject ? error.advancedOrderReject : "" - }`, - ); - } - }); - } - - try { - api.connect(clientId); - } catch (error) { - console.error(error.message); - } - }); - - afterEach(() => { - if (api) { - api.disconnect(); - api = undefined; - } - }); - - test("Stock contract details", (done) => { - api - .getContractDetails(sample_stock) - .then((result) => { - // console.log(result); - expect(result.length).toBeGreaterThan(0); - if (result.length) { - expect(result[0].contract.symbol).toEqual(sample_stock.symbol); - expect(result[0].contract.secType).toEqual(sample_stock.secType); - } - done(); - }) - .catch((err: IBApiNextError) => { - done( - `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, - ); - }); - }); - - test("Future contract details", (done) => { - api - .getContractDetails(sample_future) - .then((result) => { - // console.log(result); - expect(result.length).toBeGreaterThan(0); - if (result.length) { - expect(result[0].contract.symbol).toEqual(sample_future.symbol); - expect(result[0].contract.secType).toEqual(sample_future.secType); - } - done(); - }) - .catch((err: IBApiNextError) => { - done( - `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, - ); - }); - }); - - test("Option contract details", (done) => { - api - .getContractDetails(sample_option) - .then((result) => { - // console.log(result); - expect(result.length).toBeGreaterThan(0); - if (result.length) { - expect(result[0].contract.symbol).toEqual(sample_option.symbol); - expect(result[0].contract.secType).toEqual(sample_option.secType); - } - done(); - }) - .catch((err: IBApiNextError) => { - done( - `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, - ); - }); - }); - - test("Bond contract details", (done) => { - api - .getContractDetails(sample_bond) - .then((result) => { - // console.log(result); - expect(result.length).toBeGreaterThan(0); - if (result.length) { - expect(result[0].contract.secType).toEqual(sample_bond.secType); - } - done(); - }) - .catch((err: IBApiNextError) => { - done( - `getContractDetails failed with '${err.error.message}' (Error #${err.code})`, - ); - }); - }); -}); diff --git a/src/tests/unit/api/head-timestamp.test.ts b/src/tests/unit/api/head-timestamp.test.ts new file mode 100644 index 00000000..247a75ba --- /dev/null +++ b/src/tests/unit/api/head-timestamp.test.ts @@ -0,0 +1,53 @@ +/** + * This file implement test code for the public API interfaces. + */ +import { Contract, EventName, IBApi, Stock, WhatToShow } from "../../.."; +import configuration from "../../../common/configuration"; + +describe("IBApi Historical data Tests", () => { + jest.setTimeout(10 * 1000); + + let ib: IBApi; + const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client + + beforeEach(() => { + ib = new IBApi({ + host: configuration.ib_host, + port: configuration.ib_port, + clientId, + }); + // logger.info("IBApi created"); + }); + + afterEach(() => { + if (ib) { + ib.disconnect(); + ib = undefined; + } + // logger.info("IBApi disconnected"); + }); + + it("Returns the correct head timestamp", (done) => { + const referenceID = 42; + + ib.once(EventName.connected, () => { + const contract: Contract = new Stock("AAPL"); + + ib.reqHeadTimestamp(referenceID, contract, WhatToShow.TRADES, true, 2) + .on(EventName.headTimestamp, (requestId, headTimestamp) => { + if (requestId === referenceID) { + expect(headTimestamp).toEqual("345479400"); + ib.disconnect(); + } + }) + .on(EventName.disconnected, done) + .on(EventName.error, (err, code, requestId) => { + if (requestId === referenceID) { + done(`[${requestId}] ${err.message} (#${code})`); + } + }); + }); + + ib.connect(); + }); +}); diff --git a/src/tests/unit/api/histogram-data.test.ts b/src/tests/unit/api/histogram-data.test.ts new file mode 100644 index 00000000..f7fd77dc --- /dev/null +++ b/src/tests/unit/api/histogram-data.test.ts @@ -0,0 +1,54 @@ +/** + * This file implement test code for the public API interfaces. + */ +import { Contract, DurationUnit, EventName, IBApi, Stock } from "../../.."; +import configuration from "../../../common/configuration"; + +describe("IBApi Histogram data Tests", () => { + jest.setTimeout(10 * 1000); + + let ib: IBApi; + const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client + + beforeEach(() => { + ib = new IBApi({ + host: configuration.ib_host, + port: configuration.ib_port, + clientId, + }); + // logger.info("IBApi created"); + }); + + afterEach(() => { + if (ib) { + ib.disconnect(); + ib = undefined; + } + // logger.info("IBApi disconnected"); + }); + + it("Histogram market data", (done) => { + const referenceID = 46; + + ib.once(EventName.connected, () => { + const contract: Contract = new Stock("AAPL"); + + ib.reqHistogramData(referenceID, contract, true, 1, DurationUnit.WEEK) + .on(EventName.histogramData, (requestID, data) => { + if (requestID === referenceID) { + expect(requestID).toEqual(referenceID); + expect(data.length).toBeGreaterThan(0); + ib.disconnect(); + } + }) + .on(EventName.disconnected, done) + .on(EventName.error, (err, code, requestID) => { + if (requestID == referenceID) { + done(`[${requestID}] ${err.message} (#${code})`); + } + }); + }); + + ib.connect(); + }); +}); diff --git a/src/tests/unit/api/historical-data.test.ts b/src/tests/unit/api/historical-data.test.ts index be2273ad..7f26f8a8 100644 --- a/src/tests/unit/api/historical-data.test.ts +++ b/src/tests/unit/api/historical-data.test.ts @@ -115,7 +115,7 @@ describe("IBApi Historical data Tests", () => { ib.reqHistoricalData( refId, contract, - "20231006-20:00:00", + "20240110-20:00:00", "30 S", BarSizeSetting.SECONDS_FIFTEEN, WhatToShow.BID_ASK, @@ -137,27 +137,27 @@ describe("IBApi Historical data Tests", () => { count: number | undefined, WAP: number, ) => { - // console.log( - // counter, - // time, - // open, - // high, - // low, - // close, - // volume, - // count, - // WAP, - // ); + // console.log( + // counter, + // time, + // open, + // high, + // low, + // close, + // volume, + // count, + // WAP, + // ); expect(reqId).toEqual(refId); if (time.startsWith("finished")) { expect(counter).toEqual(2); done(); } else if (counter++ == 1) { - expect(time).toEqual("1696622385"); - expect(open).toEqual(31.85); - expect(high).toEqual(31.85); - expect(low).toEqual(31.85); - expect(close).toEqual(31.85); + expect(time).toEqual("1704916785"); + expect(open).toEqual(25.65); + expect(high).toEqual(25.65); + expect(low).toEqual(25.65); + expect(close).toEqual(25.65); expect(volume).toEqual(-1); expect(count).toEqual(-1); expect(WAP).toEqual(-1); diff --git a/src/tests/unit/api/market-data.test.ts b/src/tests/unit/api/market-data.test.ts index 088c8ba3..7ce5df4b 100644 --- a/src/tests/unit/api/market-data.test.ts +++ b/src/tests/unit/api/market-data.test.ts @@ -2,19 +2,21 @@ * This file implement test code for the public API interfaces. */ import { - Contract, ErrorCode, EventName, - Future, IBApi, - Index, MarketDataType, - Option, - OptionType, - Stock, TickType, } from "../../.."; import configuration from "../../../common/configuration"; +import { + sample_dax_index, + sample_etf, + sample_future, + sample_index, + sample_option, + sample_stock, +} from "../contracts"; describe("IBApi Market data Tests", () => { jest.setTimeout(15 * 1000); @@ -43,13 +45,12 @@ describe("IBApi Market data Tests", () => { code !== ErrorCode.REQ_MKT_DATA_NOT_AVAIL && code !== ErrorCode.DISPLAYING_DELAYED_DATA; - it("Stock market data", (done) => { + it("ETF market data", (done) => { const refId = 45; let received = false; ib.once(EventName.connected, () => { - const contract: Contract = new Stock("AAPL"); - ib.reqMktData(refId, contract, "", true, false); + ib.reqMktData(refId, sample_etf, "", true, false); }) .on( EventName.tickPrice, @@ -71,13 +72,12 @@ describe("IBApi Market data Tests", () => { ib.connect().reqMarketDataType(MarketDataType.DELAYED_FROZEN); }); - it("SPY market data", (done) => { + it("Stock market data", (done) => { const refId = 46; let received = false; ib.once(EventName.connected, () => { - const contract: Contract = new Stock("SPY"); - ib.reqMktData(refId, contract, "", true, false); + ib.reqMktData(refId, sample_stock, "", true, false); }) .on( EventName.tickPrice, @@ -104,13 +104,7 @@ describe("IBApi Market data Tests", () => { let received = false; ib.once(EventName.connected, () => { - const contract: Option = new Option( - "AAPL", - "20251219", - 200, - OptionType.Put, - ); - ib.reqMktData(refId, contract, "", true, false); + ib.reqMktData(refId, sample_option, "", true, false); }) .on( EventName.tickPrice, @@ -136,8 +130,7 @@ describe("IBApi Market data Tests", () => { let received = false; ib.once(EventName.connected, () => { - const contract: Contract = new Future("ES", "ESZ3", "202312", "CME", 50); - ib.reqMktData(refId, contract, "", true, false); + ib.reqMktData(refId, sample_future, "", true, false); }) .on( EventName.tickPrice, @@ -164,8 +157,7 @@ describe("IBApi Market data Tests", () => { let received = false; ib.once(EventName.connected, () => { - const contract: Contract = new Index("DAX", "EUR", "EUREX"); - ib.reqMktData(refId, contract, "", true, false); + ib.reqMktData(refId, sample_dax_index, "", true, false); }) .on( EventName.tickPrice, @@ -192,8 +184,7 @@ describe("IBApi Market data Tests", () => { let received = false; ib.once(EventName.connected, () => { - const contract: Contract = new Index("ES"); - ib.reqMktData(refId, contract, "", true, false); + ib.reqMktData(refId, sample_index, "", true, false); }) .on( EventName.tickPrice, diff --git a/src/tests/unit/api/market-scanner.test.ts b/src/tests/unit/api/market-scanner.test.ts index 3cc05ca7..e743234d 100644 --- a/src/tests/unit/api/market-scanner.test.ts +++ b/src/tests/unit/api/market-scanner.test.ts @@ -1,5 +1,6 @@ import { ContractDetails, + ErrorCode, EventName, IBApi, Instrument, @@ -9,7 +10,7 @@ import { import configuration from "../../../common/configuration"; describe("IBApi market scanner tests", () => { - jest.setTimeout(5000); + jest.setTimeout(10 * 1000); let ib: IBApi; const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client @@ -38,7 +39,7 @@ describe("IBApi market scanner tests", () => { .on(EventName.disconnected, () => { done(); }) - .on(EventName.error, (err, code, reqId) => { + .on(EventName.error, (err, code: ErrorCode, reqId) => { if (reqId !== -1) done(`[${reqId}] ${err.message} (#${code})`); }); @@ -78,7 +79,10 @@ describe("IBApi market scanner tests", () => { done(); }) .on(EventName.error, (err, code, reqId) => { - if (reqId == refId) done(`[${reqId}] ${err.message} (#${code})`); + if (reqId == refId) { + if (code == ErrorCode.SCANNER_LOW_PRECISION) return; + done(`[${reqId}] ${err.message} (#${code})`); + } }); ib.connect(); diff --git a/src/tests/unit/api/order/reqAllOpenOrders.test.ts b/src/tests/unit/api/order/reqAllOpenOrders.test.ts index 73dc93c4..a32ff32d 100644 --- a/src/tests/unit/api/order/reqAllOpenOrders.test.ts +++ b/src/tests/unit/api/order/reqAllOpenOrders.test.ts @@ -5,11 +5,8 @@ import { EventName, IBApi } from "../../../.."; import configuration from "../../../../common/configuration"; -const TEST_SERVER_HOST = configuration.ib_host; -const TEST_SERVER_POST = configuration.ib_port; - describe("RequestAllOpenOrders", () => { - jest.setTimeout(10000); + jest.setTimeout(10 * 1000); let ib: IBApi; const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client @@ -32,14 +29,11 @@ describe("RequestAllOpenOrders", () => { }); it("Test reqAllOpenOrders", (done) => { - ib.once(EventName.nextValidId, (orderId: number) => { - ib.reqAllOpenOrders(); + ib.on(EventName.openOrder, (orderId, contract, order, orderState) => { + // logger.info("openOrder message received"); + // todo add proper verification code here + // expect(orderId).toBeTruthy(); We sometimes get zeros }) - .on(EventName.openOrder, (orderId, contract, order, orderState) => { - // logger.info("openOrder message received"); - // todo add proper verification code here - // expect(orderId).toBeTruthy(); We sometimes get zeros - }) .on(EventName.openOrderEnd, () => { if (ib) ib.disconnect(); }) @@ -50,6 +44,6 @@ describe("RequestAllOpenOrders", () => { done(`[${reqId}] ${err.message} (#${code})`); }); - ib.connect(); + ib.connect().reqAllOpenOrders(); }); }); diff --git a/src/tests/unit/api/order/reqCompletedOrders.test.ts b/src/tests/unit/api/order/reqCompletedOrders.test.ts new file mode 100644 index 00000000..3998080e --- /dev/null +++ b/src/tests/unit/api/order/reqCompletedOrders.test.ts @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/** + * This file implement test code for the reqAllOpenOrders function and openOrder event. + */ +import { EventName, IBApi } from "../../../.."; +import configuration from "../../../../common/configuration"; + +describe("RequestAllOpenOrders", () => { + jest.setTimeout(10 * 1000); + + let ib: IBApi; + const clientId = Math.floor(Math.random() * 32766) + 1; // ensure unique client + + beforeEach(() => { + ib = new IBApi({ + host: configuration.ib_host, + port: configuration.ib_port, + clientId, + }); + // logger.info("IBApi created"); + }); + + afterEach(() => { + if (ib) { + ib.disconnect(); + ib = undefined; + } + // logger.info("IBApi disconnected"); + }); + + it("Test reqCompletedOrders", (done) => { + ib.on(EventName.completedOrder, (contract, order, orderState) => { + expect(orderState.status).toBeTruthy(); + }) + .on(EventName.completedOrdersEnd, () => { + if (ib) ib.disconnect(); + }) + .on(EventName.disconnected, () => { + done(); + }) + .on(EventName.error, (err, code, reqId) => { + done(`[${reqId}] ${err.message} (#${code})`); + }); + + ib.connect().reqCompletedOrders(false); + }); +}); diff --git a/src/tests/unit/contracts.ts b/src/tests/unit/contracts.ts index 02e10959..81d72858 100644 --- a/src/tests/unit/contracts.ts +++ b/src/tests/unit/contracts.ts @@ -1,14 +1,22 @@ /** * This file describe sample contracts to be used in various tests code. */ -import { Bond, Contract, Future, Option, OptionType, Stock } from "../.."; +import { + Bond, + Contract, + Future, + Index, + Option, + OptionType, + Stock, +} from "../.."; export const sample_stock: Contract = new Stock("AAPL"); export const sample_etf: Contract = new Stock("SPY"); export const sample_future: Contract = new Future( "ES", - "ESZ3", - "202312", + "ESH4", + "202403", "CME", 50, ); @@ -19,3 +27,5 @@ export const sample_option: Contract = new Option( OptionType.Put, ); export const sample_bond: Contract = new Bond("912828C57"); +export const sample_index: Contract = new Index("ES", "USD"); +export const sample_dax_index: Contract = new Index("DAX", "EUR", "EUREX"); diff --git a/yarn.lock b/yarn.lock index f933430c..92ac5015 100644 --- a/yarn.lock +++ b/yarn.lock @@ -417,10 +417,10 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -432,18 +432,18 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.51.0": - version "8.51.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" - integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== +"@eslint/js@8.56.0": + version "8.56.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" + integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -451,10 +451,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -807,10 +807,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.5.5": - version "29.5.5" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.5.tgz#727204e06228fe24373df9bae76b90f3e8236a2a" - integrity sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg== +"@types/jest@^29.5.11": + version "29.5.11" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.11.tgz#0c13aa0da7d0929f078ab080ae5d4ced80fa2f2c" + integrity sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -835,10 +835,10 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367" integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg== -"@types/source-map-support@^0.5.8": - version "0.5.8" - resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.5.8.tgz#ec9bd9d4c6ef9183f516109f26225350b73f91be" - integrity sha512-u5nwLcaENciDwebPwwZb2AM1LvdlgFQfqCKxWQxcgNsQhUQciGuUnJ2LjGFAkInY2APXQzIypiUSa9zB6Epddg== +"@types/source-map-support@^0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.5.10.tgz#824dcef989496bae98e9d04c8dc1ac1d70e1bd39" + integrity sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA== dependencies: source-map "^0.6.0" @@ -859,16 +859,16 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d" - integrity sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA== +"@typescript-eslint/eslint-plugin@^6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz#0df881a47da1c1a9774f39495f5f7052f86b72e0" + integrity sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/type-utils" "6.7.4" - "@typescript-eslint/utils" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/type-utils" "6.18.1" + "@typescript-eslint/utils" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -883,15 +883,15 @@ dependencies: "@typescript-eslint/utils" "5.62.0" -"@typescript-eslint/parser@^6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.4.tgz#23d1dd4fe5d295c7fa2ab651f5406cd9ad0bd435" - integrity sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA== +"@typescript-eslint/parser@^6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.18.1.tgz#3c3987e186b38c77b30b6bfa5edf7c98ae2ec9d3" + integrity sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA== dependencies: - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/typescript-estree" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/typescript-estree" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" debug "^4.3.4" "@typescript-eslint/scope-manager@5.62.0": @@ -902,21 +902,21 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/scope-manager@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz#a484a17aa219e96044db40813429eb7214d7b386" - integrity sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A== +"@typescript-eslint/scope-manager@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz#28c31c60f6e5827996aa3560a538693cb4bd3848" + integrity sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw== dependencies: - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" -"@typescript-eslint/type-utils@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz#847cd3b59baf948984499be3e0a12ff07373e321" - integrity sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ== +"@typescript-eslint/type-utils@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz#115cf535f8b39db8301677199ce51151e2daee96" + integrity sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q== dependencies: - "@typescript-eslint/typescript-estree" "6.7.4" - "@typescript-eslint/utils" "6.7.4" + "@typescript-eslint/typescript-estree" "6.18.1" + "@typescript-eslint/utils" "6.18.1" debug "^4.3.4" ts-api-utils "^1.0.1" @@ -925,10 +925,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/types@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.4.tgz#5d358484d2be986980c039de68e9f1eb62ea7897" - integrity sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA== +"@typescript-eslint/types@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.18.1.tgz#91617d8080bcd99ac355d9157079970d1d49fefc" + integrity sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw== "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" @@ -943,16 +943,17 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz#f2baece09f7bb1df9296e32638b2e1130014ef1a" - integrity sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ== +"@typescript-eslint/typescript-estree@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz#a12b6440175b4cbc9d09ab3c4966c6b245215ab4" + integrity sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA== dependencies: - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" + minimatch "9.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" @@ -970,17 +971,17 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.4.tgz#2236f72b10e38277ee05ef06142522e1de470ff2" - integrity sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA== +"@typescript-eslint/utils@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.18.1.tgz#3451cfe2e56babb6ac657e10b6703393d4b82955" + integrity sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/typescript-estree" "6.18.1" semver "^7.5.4" "@typescript-eslint/visitor-keys@5.62.0": @@ -991,14 +992,19 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz#80dfecf820fc67574012375859085f91a4dff043" - integrity sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA== +"@typescript-eslint/visitor-keys@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz#704d789bda2565a15475e7d22f145b8fe77443f4" + integrity sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA== dependencies: - "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/types" "6.18.1" eslint-visitor-keys "^3.4.1" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -1381,7 +1387,7 @@ debug@^4.1.0, debug@^4.1.1: dependencies: ms "2.1.2" -debug@^4.3.2, debug@^4.3.4: +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1488,10 +1494,10 @@ eslint-etc@^5.1.0: tsutils "^3.17.1" tsutils-etc "^1.4.1" -eslint-plugin-jest@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.4.2.tgz#181d999ac67a9b6040db1d27935887cf5a2882ed" - integrity sha512-3Nfvv3wbq2+PZlRTf2oaAWXWwbdBejFRBR2O8tAO67o+P8zno+QGbcDYaAXODlreXVg+9gvWhKKmG2rgfb8GEg== +eslint-plugin-jest@^27.6.2: + version "27.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.6.2.tgz#8e69404fcd5dfeac03cac478f0ebb9bf2d8db56b" + integrity sha512-CI1AlKrsNhYFoP48VU8BVWOi7+qHTq4bRxyUlGjeU8SfFt8abjXhjOuDzUoMp68DoXIx17KpNpIkMrl4s4ZW0g== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -1531,18 +1537,19 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.51.0: - version "8.51.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" - integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== +eslint@^8.56.0: + version "8.56.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" + integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.51.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.56.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2633,6 +2640,13 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +minimatch@9.0.3, minimatch@^9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -2640,13 +2654,6 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -2977,10 +2984,10 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shiki@^0.14.1: - version "0.14.4" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.4.tgz#2454969b466a5f75067d0f2fa0d7426d32881b20" - integrity sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ== +shiki@^0.14.7: + version "0.14.7" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.7.tgz#c3c9e1853e9737845f1d2ef81b31bcfb07056d4e" + integrity sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg== dependencies: ansi-sequence-parser "^1.1.0" jsonc-parser "^3.2.0" @@ -3189,15 +3196,15 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typedoc@^0.25.1: - version "0.25.1" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.1.tgz#50de2d8fb93623fbfb59e2fa6407ff40e3d3f438" - integrity sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA== +typedoc@^0.25.7: + version "0.25.7" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.7.tgz#11e3f527ca80ca3c029cb8e15f362e6d9f715e25" + integrity sha512-m6A6JjQRg39p2ZVRIN3NKXgrN8vzlHhOS+r9ymUYtcUP/TIQPvWSq7YgE5ZjASfv5Vd5BW5xrir6Gm2XNNcOow== dependencies: lunr "^2.3.9" marked "^4.3.0" minimatch "^9.0.3" - shiki "^0.14.1" + shiki "^0.14.7" typescript@^5.2.2: version "5.2.2"