diff --git a/.changeset/smooth-avocados-worry.md b/.changeset/smooth-avocados-worry.md new file mode 100644 index 0000000000..aa6e7c7881 --- /dev/null +++ b/.changeset/smooth-avocados-worry.md @@ -0,0 +1,5 @@ +--- +'@chainlink/deutsche-boerse-adapter': major +--- + +Adds first release of the Deutsche Boerse EA diff --git a/.pnp.cjs b/.pnp.cjs index 6f380e0ff5..937424214f 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -426,6 +426,10 @@ const RAW_RUNTIME_STATE = "name": "@chainlink/deribit-adapter",\ "reference": "workspace:packages/sources/deribit"\ },\ + {\ + "name": "@chainlink/deutsche-boerse-adapter",\ + "reference": "workspace:packages/sources/deutsche-boerse"\ + },\ {\ "name": "@chainlink/dlc-btc-por-adapter",\ "reference": "workspace:packages/sources/dlc-btc-por"\ @@ -1054,6 +1058,7 @@ const RAW_RUNTIME_STATE = ["@chainlink/defi-dozen-adapter", ["workspace:packages/composites/defi-dozen"]],\ ["@chainlink/defi-pulse-adapter", ["workspace:packages/composites/defi-pulse"]],\ ["@chainlink/deribit-adapter", ["workspace:packages/sources/deribit"]],\ + ["@chainlink/deutsche-boerse-adapter", ["workspace:packages/sources/deutsche-boerse"]],\ ["@chainlink/dlc-btc-por-adapter", ["workspace:packages/sources/dlc-btc-por"]],\ ["@chainlink/dns-query-adapter", ["workspace:packages/sources/dns-query"]],\ ["@chainlink/dxdao-adapter", ["workspace:packages/composites/dxdao"]],\ @@ -5077,6 +5082,94 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ + ["@bufbuild/buf", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-npm-1.57.0-2ab3bfef25/node_modules/@bufbuild/buf/",\ + "packageDependencies": [\ + ["@bufbuild/buf", "npm:1.57.0"],\ + ["@bufbuild/buf-darwin-arm64", "npm:1.57.0"],\ + ["@bufbuild/buf-darwin-x64", "npm:1.57.0"],\ + ["@bufbuild/buf-linux-aarch64", "npm:1.57.0"],\ + ["@bufbuild/buf-linux-armv7", "npm:1.57.0"],\ + ["@bufbuild/buf-linux-x64", "npm:1.57.0"],\ + ["@bufbuild/buf-win32-arm64", "npm:1.57.0"],\ + ["@bufbuild/buf-win32-x64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-darwin-arm64", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-darwin-arm64-npm-1.57.0-6f2ff0e9e6/node_modules/@bufbuild/buf-darwin-arm64/",\ + "packageDependencies": [\ + ["@bufbuild/buf-darwin-arm64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-darwin-x64", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-darwin-x64-npm-1.57.0-c2008a76e1/node_modules/@bufbuild/buf-darwin-x64/",\ + "packageDependencies": [\ + ["@bufbuild/buf-darwin-x64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-linux-aarch64", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-linux-aarch64-npm-1.57.0-e1be211b1d/node_modules/@bufbuild/buf-linux-aarch64/",\ + "packageDependencies": [\ + ["@bufbuild/buf-linux-aarch64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-linux-armv7", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-linux-armv7-npm-1.57.0-1a847128e0/node_modules/@bufbuild/buf-linux-armv7/",\ + "packageDependencies": [\ + ["@bufbuild/buf-linux-armv7", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-linux-x64", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-linux-x64-npm-1.57.0-f292389579/node_modules/@bufbuild/buf-linux-x64/",\ + "packageDependencies": [\ + ["@bufbuild/buf-linux-x64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-win32-arm64", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-win32-arm64-npm-1.57.0-6ee6dffa18/node_modules/@bufbuild/buf-win32-arm64/",\ + "packageDependencies": [\ + ["@bufbuild/buf-win32-arm64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/buf-win32-x64", [\ + ["npm:1.57.0", {\ + "packageLocation": "./.yarn/unplugged/@bufbuild-buf-win32-x64-npm-1.57.0-7ca34dacd7/node_modules/@bufbuild/buf-win32-x64/",\ + "packageDependencies": [\ + ["@bufbuild/buf-win32-x64", "npm:1.57.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@bufbuild/protobuf", [\ + ["npm:2.7.0", {\ + "packageLocation": "./.yarn/cache/@bufbuild-protobuf-npm-2.7.0-79729124a9-3610b8da21.zip/node_modules/@bufbuild/protobuf/",\ + "packageDependencies": [\ + ["@bufbuild/protobuf", "npm:2.7.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["@cardano-ogmios/client", [\ ["npm:5.6.0", {\ "packageLocation": "./.yarn/cache/@cardano-ogmios-client-npm-5.6.0-e3f0ec5f2b-1584e36a4d.zip/node_modules/@cardano-ogmios/client/",\ @@ -6339,6 +6432,28 @@ const RAW_RUNTIME_STATE = "linkType": "SOFT"\ }]\ ]],\ + ["@chainlink/deutsche-boerse-adapter", [\ + ["workspace:packages/sources/deutsche-boerse", {\ + "packageLocation": "./packages/sources/deutsche-boerse/",\ + "packageDependencies": [\ + ["@chainlink/deutsche-boerse-adapter", "workspace:packages/sources/deutsche-boerse"],\ + ["@bufbuild/buf", "npm:1.57.0"],\ + ["@bufbuild/protobuf", "npm:2.7.0"],\ + ["@chainlink/external-adapter-framework", "npm:2.7.0"],\ + ["@sinonjs/fake-timers", "npm:9.1.2"],\ + ["@types/jest", "npm:29.5.14"],\ + ["@types/node", "npm:22.14.1"],\ + ["@types/sinonjs__fake-timers", "npm:8.1.5"],\ + ["@types/ws", "npm:8.18.1"],\ + ["decimal.js", "npm:10.5.0"],\ + ["nock", "npm:13.5.6"],\ + ["tslib", "npm:2.4.1"],\ + ["typescript", "patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5"],\ + ["ws", "virtual:bdc244f853fb22ebac7b81f50917f9b470cc7237095ba56eae0d97416db6fb294de2dfb5b3ab323b141006d4a3cdee50bddf11794531ca39f6010716210e02c8#npm:8.18.3"]\ + ],\ + "linkType": "SOFT"\ + }]\ + ]],\ ["@chainlink/dlc-btc-por-adapter", [\ ["workspace:packages/sources/dlc-btc-por", {\ "packageLocation": "./packages/sources/dlc-btc-por/",\ @@ -17878,6 +17993,14 @@ const RAW_RUNTIME_STATE = ],\ "linkType": "HARD"\ }],\ + ["npm:8.18.1", {\ + "packageLocation": "./.yarn/cache/@types-ws-npm-8.18.1-61dc106ff0-1ce05e3174.zip/node_modules/@types/ws/",\ + "packageDependencies": [\ + ["@types/ws", "npm:8.18.1"],\ + ["@types/node", "npm:22.9.1"]\ + ],\ + "linkType": "HARD"\ + }],\ ["npm:8.5.13", {\ "packageLocation": "./.yarn/cache/@types-ws-npm-8.5.13-7564c96514-21369beafa.zip/node_modules/@types/ws/",\ "packageDependencies": [\ diff --git a/.yarn/cache/@bufbuild-buf-linux-x64-npm-1.57.0-f292389579-10.zip b/.yarn/cache/@bufbuild-buf-linux-x64-npm-1.57.0-f292389579-10.zip new file mode 100644 index 0000000000..5c1fa7419a Binary files /dev/null and b/.yarn/cache/@bufbuild-buf-linux-x64-npm-1.57.0-f292389579-10.zip differ diff --git a/.yarn/cache/@bufbuild-buf-npm-1.57.0-2ab3bfef25-3870772d73.zip b/.yarn/cache/@bufbuild-buf-npm-1.57.0-2ab3bfef25-3870772d73.zip new file mode 100644 index 0000000000..fbd8811e19 Binary files /dev/null and b/.yarn/cache/@bufbuild-buf-npm-1.57.0-2ab3bfef25-3870772d73.zip differ diff --git a/.yarn/cache/@bufbuild-protobuf-npm-2.7.0-79729124a9-3610b8da21.zip b/.yarn/cache/@bufbuild-protobuf-npm-2.7.0-79729124a9-3610b8da21.zip new file mode 100644 index 0000000000..04276991a9 Binary files /dev/null and b/.yarn/cache/@bufbuild-protobuf-npm-2.7.0-79729124a9-3610b8da21.zip differ diff --git a/.yarn/cache/@types-ws-npm-8.18.1-61dc106ff0-1ce05e3174.zip b/.yarn/cache/@types-ws-npm-8.18.1-61dc106ff0-1ce05e3174.zip new file mode 100644 index 0000000000..5c915f403b Binary files /dev/null and b/.yarn/cache/@types-ws-npm-8.18.1-61dc106ff0-1ce05e3174.zip differ diff --git a/packages/sources/deutsche-boerse/CHANGELOG.md b/packages/sources/deutsche-boerse/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/sources/deutsche-boerse/README.md b/packages/sources/deutsche-boerse/README.md new file mode 100644 index 0000000000..43dd1b6bde --- /dev/null +++ b/packages/sources/deutsche-boerse/README.md @@ -0,0 +1,3 @@ +# Chainlink External Adapter for deutsche-boerse + +This README will be generated automatically when code is merged to `main`. If you would like to generate a preview of the README, please run `yarn generate:readme deutsche-boerse`. diff --git a/packages/sources/deutsche-boerse/buf.gen.yaml b/packages/sources/deutsche-boerse/buf.gen.yaml new file mode 100644 index 0000000000..4d418e1e47 --- /dev/null +++ b/packages/sources/deutsche-boerse/buf.gen.yaml @@ -0,0 +1,6 @@ +version: v2 +plugins: + - remote: buf.build/bufbuild/es + out: src/gen + opt: + - target=ts diff --git a/packages/sources/deutsche-boerse/buf.yaml b/packages/sources/deutsche-boerse/buf.yaml new file mode 100644 index 0000000000..a4ca581b4a --- /dev/null +++ b/packages/sources/deutsche-boerse/buf.yaml @@ -0,0 +1,3 @@ +version: v2 +modules: + - path: src/proto diff --git a/packages/sources/deutsche-boerse/package.json b/packages/sources/deutsche-boerse/package.json new file mode 100644 index 0000000000..68d2670d51 --- /dev/null +++ b/packages/sources/deutsche-boerse/package.json @@ -0,0 +1,48 @@ +{ + "name": "@chainlink/deutsche-boerse-adapter", + "version": "0.0.0", + "description": "Chainlink deutsche-boerse adapter.", + "keywords": [ + "Chainlink", + "LINK", + "blockchain", + "oracle", + "deutsche-boerse" + ], + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "repository": { + "url": "https://github.com/smartcontractkit/external-adapters-js", + "type": "git" + }, + "license": "MIT", + "scripts": { + "clean": "rm -rf dist src/gen && rm -f tsconfig.tsbuildinfo", + "prepack": "yarn build", + "prebuild": "yarn buf generate", + "build": "tsc -b", + "server": "node -e 'require(\"./index.js\").server()'", + "server:dist": "node -e 'require(\"./dist/index.js\").server()'", + "start": "yarn server:dist" + }, + "devDependencies": { + "@bufbuild/buf": "^1.57.0", + "@sinonjs/fake-timers": "9.1.2", + "@types/jest": "^29.5.14", + "@types/node": "22.14.1", + "@types/sinonjs__fake-timers": "8.1.5", + "@types/ws": "^8", + "nock": "13.5.6", + "typescript": "5.8.3" + }, + "dependencies": { + "@bufbuild/protobuf": "^2.7.0", + "@chainlink/external-adapter-framework": "2.7.0", + "decimal.js": "10.5.0", + "tslib": "2.4.1", + "ws": "^8.18.3" + } +} diff --git a/packages/sources/deutsche-boerse/src/config/index.ts b/packages/sources/deutsche-boerse/src/config/index.ts new file mode 100644 index 0000000000..ad7cf6e0cd --- /dev/null +++ b/packages/sources/deutsche-boerse/src/config/index.ts @@ -0,0 +1,15 @@ +import { AdapterConfig } from '@chainlink/external-adapter-framework/config' + +export const config = new AdapterConfig({ + API_KEY: { + description: 'An API key for Data Provider', + type: 'string', + required: true, + sensitive: true, + }, + WS_API_ENDPOINT: { + description: 'WS endpoint for Data Provider', + type: 'string', + default: 'wss://md.deutsche-boerse.com', + }, +}) diff --git a/packages/sources/deutsche-boerse/src/endpoint/index.ts b/packages/sources/deutsche-boerse/src/endpoint/index.ts new file mode 100644 index 0000000000..8d7a7b68f6 --- /dev/null +++ b/packages/sources/deutsche-boerse/src/endpoint/index.ts @@ -0,0 +1 @@ +export { endpoint as lwba } from './lwba' diff --git a/packages/sources/deutsche-boerse/src/endpoint/lwba.ts b/packages/sources/deutsche-boerse/src/endpoint/lwba.ts new file mode 100644 index 0000000000..c0c6101a2f --- /dev/null +++ b/packages/sources/deutsche-boerse/src/endpoint/lwba.ts @@ -0,0 +1,56 @@ +import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter' +import { InputParameters } from '@chainlink/external-adapter-framework/validation' +import { config } from '../config' +import { wsTransport } from '../transport/lwba' + +export const MARKETS = ['md-xetraetfetp'] as const +export type Market = (typeof MARKETS)[number] + +export const inputParameters = new InputParameters( + { + isin: { + aliases: ['instrument', 'ISIN'], + required: true, + type: 'string', + description: 'The ISIN identifier of the instrument to query', + }, + market: { + aliases: ['stream'], + required: true, + type: 'string', + description: 'The market identifier of the stream to query', + options: [...MARKETS], + }, + }, + [ + { + market: 'md-xetraetfetp', + isin: 'IE00B53L3W79', + }, + ], +) + +interface LwbaLatestPriceResponse { + Result: number | null + Data: { + mid: number | null + bid: number | null + ask: number | null + latestPrice: number | null + quoteProviderIndicatedTimeUnixMs: number | null + tradeProviderIndicatedTimeUnixMs: number | null + } +} + +export type BaseEndpointTypes = { + Parameters: typeof inputParameters.definition + Response: LwbaLatestPriceResponse + Settings: typeof config.settings +} + +export const endpoint = new AdapterEndpoint({ + name: 'lwba', + aliases: [], + transport: wsTransport, + inputParameters, +}) diff --git a/packages/sources/deutsche-boerse/src/gen/client_pb.ts b/packages/sources/deutsche-boerse/src/gen/client_pb.ts new file mode 100644 index 0000000000..2f62a9ab8b --- /dev/null +++ b/packages/sources/deutsche-boerse/src/gen/client_pb.ts @@ -0,0 +1,210 @@ +// Date: 07.10.2023 +// Version: 001.000.006 + +// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated from file client.proto (package Client, syntax proto3) +/* eslint-disable */ + +import type { Message } from '@bufbuild/protobuf' +import type { GenEnum, GenFile, GenMessage } from '@bufbuild/protobuf/codegenv2' +import { enumDesc, fileDesc, messageDesc } from '@bufbuild/protobuf/codegenv2' +import type { Any } from '@bufbuild/protobuf/wkt' +import { file_google_protobuf_any } from '@bufbuild/protobuf/wkt' + +/** + * Describes the file client.proto. + */ +export const file_client: GenFile = + /*@__PURE__*/ + fileDesc( + 'CgxjbGllbnQucHJvdG8SBkNsaWVudCJ0CglTdWJzY3JpYmUSKAoGc3RyZWFtGAEgAygLMhguQ2xpZW50LlN1YnNjcmliZS5TdHJlYW0aPQoGU3RyZWFtEg4KBnN0cmVhbRgBIAEoCRIRCglzdGFydFRpbWUYAiABKAMSEAoIc3RhcnRTZXEYAyABKAQiHQoLVW5zdWJzY3JpYmUSDgoGc3RyZWFtGAEgAygJInsKB1JlcXVlc3QSDQoFZXZlbnQYASABKAkSEQoJcmVxdWVzdElkGAIgASgDEiQKCXN1YnNjcmliZRgDIAEoCzIRLkNsaWVudC5TdWJzY3JpYmUSKAoLdW5zdWJzY3JpYmUYBCABKAsyEy5DbGllbnQuVW5zdWJzY3JpYmUiPQoIUmVzcG9uc2USEQoJcmVxdWVzdElkGAEgASgDEh4KBnN0YXR1cxgCIAEoDjIOLkNsaWVudC5TdGF0dXMiUgoNU3RyZWFtTWVzc2FnZRIMCgRzdWJzGAEgASgJEgsKA3NlcRgCIAEoBBImCghtZXNzYWdlcxgDIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnkqRwoGU3RhdHVzEgYKAk9LEAASEAoMU0VSVkVSX0VSUk9SEAESEQoNQUNDRVNTX0RFTklFRBACEhAKDE5PVF9FTlRJVExFRBADYgZwcm90bzM', + [file_google_protobuf_any], + ) + +/** + * @generated from message Client.Subscribe + */ +export type Subscribe = Message<'Client.Subscribe'> & { + /** + * @generated from field: repeated Client.Subscribe.Stream stream = 1; + */ + stream: Subscribe_Stream[] +} + +/** + * Describes the message Client.Subscribe. + * Use `create(SubscribeSchema)` to create a new message. + */ +export const SubscribeSchema: GenMessage = /*@__PURE__*/ messageDesc(file_client, 0) + +/** + * @generated from message Client.Subscribe.Stream + */ +export type Subscribe_Stream = Message<'Client.Subscribe.Stream'> & { + /** + * @generated from field: string stream = 1; + */ + stream: string + + /** + * mutually exclusive to startSeq + * + * @generated from field: int64 startTime = 2; + */ + startTime: bigint + + /** + * mutually exclusive to startTime + * + * @generated from field: uint64 startSeq = 3; + */ + startSeq: bigint +} + +/** + * Describes the message Client.Subscribe.Stream. + * Use `create(Subscribe_StreamSchema)` to create a new message. + */ +export const Subscribe_StreamSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_client, 0, 0) + +/** + * @generated from message Client.Unsubscribe + */ +export type Unsubscribe = Message<'Client.Unsubscribe'> & { + /** + * @generated from field: repeated string stream = 1; + */ + stream: string[] +} + +/** + * Describes the message Client.Unsubscribe. + * Use `create(UnsubscribeSchema)` to create a new message. + */ +export const UnsubscribeSchema: GenMessage = /*@__PURE__*/ messageDesc(file_client, 1) + +/** + * @generated from message Client.Request + */ +export type Request = Message<'Client.Request'> & { + /** + * @generated from field: string event = 1; + */ + event: string + + /** + * @generated from field: int64 requestId = 2; + */ + requestId: bigint + + /** + * oneof data { + * + * @generated from field: Client.Subscribe subscribe = 3; + */ + subscribe?: Subscribe + + /** + * } + * + * @generated from field: Client.Unsubscribe unsubscribe = 4; + */ + unsubscribe?: Unsubscribe +} + +/** + * Describes the message Client.Request. + * Use `create(RequestSchema)` to create a new message. + */ +export const RequestSchema: GenMessage = /*@__PURE__*/ messageDesc(file_client, 2) + +/** + * one Response for each stream in Request + * + * @generated from message Client.Response + */ +export type Response = Message<'Client.Response'> & { + /** + * @generated from field: int64 requestId = 1; + */ + requestId: bigint + + /** + * @generated from field: Client.Status status = 2; + */ + status: Status +} + +/** + * Describes the message Client.Response. + * Use `create(ResponseSchema)` to create a new message. + */ +export const ResponseSchema: GenMessage = /*@__PURE__*/ messageDesc(file_client, 3) + +/** + * @generated from message Client.StreamMessage + */ +export type StreamMessage = Message<'Client.StreamMessage'> & { + /** + * protocol + * + * stream / topic subscription + * + * @generated from field: string subs = 1; + */ + subs: string + + /** + * message sequence number + * + * @generated from field: uint64 seq = 2; + */ + seq: bigint + + /** + * payload + * + * @generated from field: repeated google.protobuf.Any messages = 3; + */ + messages: Any[] +} + +/** + * Describes the message Client.StreamMessage. + * Use `create(StreamMessageSchema)` to create a new message. + */ +export const StreamMessageSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_client, 4) + +/** + * @generated from enum Client.Status + */ +export enum Status { + /** + * @generated from enum value: OK = 0; + */ + OK = 0, + + /** + * @generated from enum value: SERVER_ERROR = 1; + */ + SERVER_ERROR = 1, + + /** + * @generated from enum value: ACCESS_DENIED = 2; + */ + ACCESS_DENIED = 2, + + /** + * @generated from enum value: NOT_ENTITLED = 3; + */ + NOT_ENTITLED = 3, +} + +/** + * Describes the enum Client.Status. + */ +export const StatusSchema: GenEnum = /*@__PURE__*/ enumDesc(file_client, 0) diff --git a/packages/sources/deutsche-boerse/src/gen/md_cef_pb.ts b/packages/sources/deutsche-boerse/src/gen/md_cef_pb.ts new file mode 100644 index 0000000000..aec58afd3c --- /dev/null +++ b/packages/sources/deutsche-boerse/src/gen/md_cef_pb.ts @@ -0,0 +1,2352 @@ +// Date: 10.01.2025 +// Version: 001.000.009 + +// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated from file md_cef.proto (package dbag.cef, syntax proto3) +/* eslint-disable */ + +import type { Message } from '@bufbuild/protobuf' +import type { GenEnum, GenFile, GenMessage } from '@bufbuild/protobuf/codegenv2' +import { enumDesc, fileDesc, messageDesc } from '@bufbuild/protobuf/codegenv2' +import { file_google_protobuf_wrappers } from '@bufbuild/protobuf/wkt' + +/** + * Describes the file md_cef.proto. + */ +export const file_md_cef: GenFile = + /*@__PURE__*/ + fileDesc( + 'CgxtZF9jZWYucHJvdG8SCGRiYWcuY2VmIh8KB0RlY2ltYWwSCQoBbRgBIAEoAxIJCgFlGAIgASgFIjEKC0FwcGxTZXFDdHJsEg4KBkFwcGxJRBgBIAEoDRISCgpBcHBsU2VxTnVtGAIgASgEIrQPCgpJbnN0cnVtZW50Eg0KBU1rdElEGAEgASgJEgsKA1N5bRgCIAEoCRIKCgJJRBgDIAEoCRIyCgNTcmMYBCABKA4yJS5kYmFnLmNlZi5JbnN0cnVtZW50LlNlY3VyaXR5SURTb3VyY2USMQoGU2VjVHlwGAUgASgOMiEuZGJhZy5jZWYuSW5zdHJ1bWVudC5TZWN1cml0eVR5cGUSCwoDQ2N5GAYgASgJEg0KBUFsdElEGAcgASgJEjcKCEFsdElEU3JjGAggASgOMiUuZGJhZy5jZWYuSW5zdHJ1bWVudC5TZWN1cml0eUlEU291cmNlEg4KBk1rdFNlZxgJIAEoCRILCgNNTVkYCyABKAkSLQoIQ250ckRhdGUYDCABKAsyGy5nb29nbGUucHJvdG9idWYuSW50MzJWYWx1ZRIyCgJDdBgNIAEoCzImLmRiYWcuY2VmLkluc3RydW1lbnQuQ29udHJhY3RUeXBlVmFsdWUSIQoGU3Rya1B4GA4gASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIlCgpPcmlnU3Rya1B4GA8gASgLMhEuZGJhZy5jZWYuRGVjaW1hbBI0CgdQdXRDYWxsGBAgASgLMiMuZGJhZy5jZWYuSW5zdHJ1bWVudC5QdXRPckNhbGxWYWx1ZRIuCglDbnRyR2VuTnIYESABKAsyGy5nb29nbGUucHJvdG9idWYuSW50MzJWYWx1ZRI4CglTZXR0bE1ldGgYEiABKAsyJS5kYmFnLmNlZi5JbnN0cnVtZW50LlNldHRsTWV0aG9kVmFsdWUSOgoJRXhlclN0eWxlGBMgASgLMicuZGJhZy5jZWYuSW5zdHJ1bWVudC5FeGVyY2lzZVN0eWxlVmFsdWUSJAoJTWluUHhJbmNyGBUgASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIQCghUZW5vclZhbBgWIAEoCRI/CgdVcGRBY3RuGB4gASgLMi4uZGJhZy5jZWYuSW5zdHJ1bWVudC5TZWN1cml0eVVwZGF0ZUFjdGlvblZhbHVlEhQKDExhc3RVcGRhdGVUbRgfIAEoBBIpCgVFdm50cxggIAMoCzIaLmRiYWcuY2VmLkluc3RydW1lbnQuRXZlbnQabgoOUHV0T3JDYWxsVmFsdWUSPAoFVmFsdWUYASABKA4yLS5kYmFnLmNlZi5JbnN0cnVtZW50LlB1dE9yQ2FsbFZhbHVlLlB1dE9yQ2FsbCIeCglQdXRPckNhbGwSBwoDUFVUEAASCAoEQ0FMTBABGnEKEFNldHRsTWV0aG9kVmFsdWUSQAoFVmFsdWUYASABKA4yMS5kYmFnLmNlZi5JbnN0cnVtZW50LlNldHRsTWV0aG9kVmFsdWUuU2V0dGxNZXRob2QiGwoLU2V0dGxNZXRob2QSBQoBQxAAEgUKAVAQARp5ChJFeGVyY2lzZVN0eWxlVmFsdWUSRAoFVmFsdWUYASABKA4yNS5kYmFnLmNlZi5JbnN0cnVtZW50LkV4ZXJjaXNlU3R5bGVWYWx1ZS5FeGVyY2lzZVN0eWxlIh0KDUV4ZXJjaXNlU3R5bGUSBQoBRRAAEgUKAUEQARp1ChFDb250cmFjdFR5cGVWYWx1ZRJCCgVWYWx1ZRgBIAEoDjIzLmRiYWcuY2VmLkluc3RydW1lbnQuQ29udHJhY3RUeXBlVmFsdWUuQ29udHJhY3RUeXBlIhwKDENvbnRyYWN0VHlwZRIFCgFGEAASBQoBUxABGqgBChlTZWN1cml0eVVwZGF0ZUFjdGlvblZhbHVlElIKBVZhbHVlGAEgASgOMkMuZGJhZy5jZWYuSW5zdHJ1bWVudC5TZWN1cml0eVVwZGF0ZUFjdGlvblZhbHVlLlNlY3VyaXR5VXBkYXRlQWN0aW9uIjcKFFNlY3VyaXR5VXBkYXRlQWN0aW9uEgcKA05FVxAAEgoKBkRFTEVURRABEgoKBk1PRElGWRACGsYBCgVFdmVudBI2CghFdmVudFR5cBgBIAEoDjIkLmRiYWcuY2VmLkluc3RydW1lbnQuRXZlbnQuRXZlbnRUeXBlEgoKAkR0GAIgASgNInkKCUV2ZW50VHlwZRINCglVTkRFRklORUQQABIOCgpBQ1RJVkFUSU9OEAUSEAoMSU5BQ1RJVkFUSU9OEAYSHAoYTEFTVF9FTElHSUJMRV9UUkFERV9EQVRFEAcSHQoZRklSU1RfRUxJR0lCTEVfVFJBREVfREFURRAcIkAKEFNlY3VyaXR5SURTb3VyY2USCAoESVNJThAAEhMKD0VYQ0hBTkdFX1NZTUJPTBABEg0KCVNZTlRIRVRJQxACItYBCgxTZWN1cml0eVR5cGUSEwoPTk9fU0VDVVJJVFlUWVBFEAASBwoDRlVUEAESBwoDT1BUEAISCAoETUxFRxADEgkKBUlOREVYEAQSBwoDRVRDEAUSBwoDRVROEAYSBgoCQ1MQBxIICgRSRVBPEAgSCAoEQ0FTSBAJEgcKA0ZPUhAKEggKBEJPTkQQCxIGCgJNRhAMEgcKA0ZVThANEgcKA0lSUxAOEgYKAlNSEA8SBwoDV0FSEBASBwoDRVRGEBESCgoGRlhTV0FQEBISCQoFT1RIRVIQYyKwBwoJUXVvdGVTaWRlEh0KAlB4GAEgASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIdCgJTehgCIAEoCzIRLmRiYWcuY2VmLkRlY2ltYWwSLgoJTnVtT2ZPcmRzGAMgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSNgoITURRdGVUeXAYBCABKAsyJC5kYmFnLmNlZi5RdW90ZVNpZGUuTURRdW90ZVR5cGVWYWx1ZRIxCgNUeXAYBSABKAsyJC5kYmFnLmNlZi5RdW90ZVNpZGUuTURFbnRyeVR5cGVWYWx1ZRI2CgVRQ29uZBgGIAEoCzInLmRiYWcuY2VmLlF1b3RlU2lkZS5RdW90ZUNvbmRpdGlvblZhbHVlEiIKB0Z3ZFBudHMYByABKAsyES5kYmFnLmNlZi5EZWNpbWFsEgsKA1BpcBgIIAEoAxIzCgVIbFdybhgJIAEoCzIkLmRiYWcuY2VmLlF1b3RlU2lkZS5Ib2xpZGF5V2FyblZhbHVlGoEBChBNRFF1b3RlVHlwZVZhbHVlEj8KBVZhbHVlGAEgASgOMjAuZGJhZy5jZWYuUXVvdGVTaWRlLk1EUXVvdGVUeXBlVmFsdWUuTURRdW90ZVR5cGUiLAoLTURRdW90ZVR5cGUSDgoKSU5ESUNBVElWRRAAEg0KCVRSQURFQUJMRRABGogBChNRdW90ZUNvbmRpdGlvblZhbHVlEkUKBVZhbHVlGAEgASgOMjYuZGJhZy5jZWYuUXVvdGVTaWRlLlF1b3RlQ29uZGl0aW9uVmFsdWUuUXVvdGVDb25kaXRpb24iKgoOUXVvdGVDb25kaXRpb24SCAoERklSTRAAEg4KCklORElDQVRJVkUQARqYAQoQTURFbnRyeVR5cGVWYWx1ZRI/CgVWYWx1ZRgBIAEoDjIwLmRiYWcuY2VmLlF1b3RlU2lkZS5NREVudHJ5VHlwZVZhbHVlLk1ERW50cnlUeXBlIkMKC01ERW50cnlUeXBlEgcKA0JJRBAAEgkKBU9GRkVSEAESDgoKTUFSS0VUX0JJRBALEhAKDE1BUktFVF9PRkZFUhAMGoEBChBIb2xpZGF5V2FyblZhbHVlEj8KBVZhbHVlGAEgASgOMjAuZGJhZy5jZWYuUXVvdGVTaWRlLkhvbGlkYXlXYXJuVmFsdWUuSG9saWRheVdhcm4iLAoLSG9saWRheVdhcm4SDwoLTk9fSE9MSURBWVMQABIMCghIT0xJREFZUxABIrYnCgREYXRhEiAKA0JpZBgBIAEoCzITLmRiYWcuY2VmLlF1b3RlU2lkZRIiCgVPZmZlchgCIAEoCzITLmRiYWcuY2VmLlF1b3RlU2lkZRIsCgVQeFR5cBgDIAEoCzIdLmRiYWcuY2VmLkRhdGEuUHJpY2VUeXBlVmFsdWUSMgoGU3RhdHVzGAsgASgLMiIuZGJhZy5jZWYuRGF0YS5TZWN1cml0eVN0YXR1c1ZhbHVlEjMKBVNlc0lEGAwgASgLMiQuZGJhZy5jZWYuRGF0YS5UcmFkaW5nU2Vzc2lvbklEVmFsdWUSNwoGU2VzU3ViGA0gASgLMicuZGJhZy5jZWYuRGF0YS5UcmFkaW5nU2Vzc2lvblN1YklEVmFsdWUSLgoKRmFzdE1rdEluZBgOIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5Cb29sVmFsdWUSOwoIVHJkZ1N0YXQYDyABKAsyKS5kYmFnLmNlZi5EYXRhLlNlY3VyaXR5VHJhZGluZ1N0YXR1c1ZhbHVlEjQKB01rdENvbmQYECABKAsyIy5kYmFnLmNlZi5EYXRhLk1hcmtldENvbmRpdGlvblZhbHVlEjUKCVRlc1N0YXR1cxgRIAEoCzIiLmRiYWcuY2VmLkRhdGEuU2VjdXJpdHlTdGF0dXNWYWx1ZRI7CgpNa3RTZWdTdGF0GBIgASgLMicuZGJhZy5jZWYuRGF0YS5NYXJrZXRTZWdtZW50U3RhdHVzVmFsdWUSHQoCUHgYFSABKAsyES5kYmFnLmNlZi5EZWNpbWFsEh0KAlN6GBYgASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIrCgZUcmRUeXAYFyABKAsyGy5kYmFnLmNlZi5EYXRhLlRyZFR5cGVWYWx1ZRIxCgxOdW1PZkJ1eU9yZHMYGCABKAsyGy5nb29nbGUucHJvdG9idWYuSW50MzJWYWx1ZRIyCg1OdW1PZlNlbGxPcmRzGBkgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSMwoJTURPcmlnVHlwGBogASgLMiAuZGJhZy5jZWYuRGF0YS5NRE9yaWdpblR5cGVWYWx1ZRILCgNDY3kYGyABKAkSDAoETURJRBgcIAEoCRIOCgZNdGNoSUQYHSABKAkSMwoHVXBkdEFjdBgeIAEoCzIiLmRiYWcuY2VmLkRhdGEuTURVcGRhdGVBY3Rpb25WYWx1ZRIuCgdUcmRDb25kGB8gAygOMh0uZGJhZy5jZWYuRGF0YS5UcmFkZUNvbmRpdGlvbhIhCgRCaWRzGCkgAygLMhMuZGJhZy5jZWYuUXVvdGVTaWRlEiMKBk9mZmVycxgqIAMoCzITLmRiYWcuY2VmLlF1b3RlU2lkZRIgCgVTdGxQeBgzIAEoCzIRLmRiYWcuY2VmLkRlY2ltYWwSHgoDSW50GDQgASgLMhEuZGJhZy5jZWYuRGVjaW1hbBInCgxTZXR0bEN1cnJBbXQYNSABKAsyES5kYmFnLmNlZi5EZWNpbWFsEhAKCFNldHRsQ2N5GDYgASgJEg8KB1NldHRsRHQYNyABKAkSHwoEUGFQeBg9IAEoCzIRLmRiYWcuY2VmLkRlY2ltYWwSIQoGT3BlblB4GD4gASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIiCgdDbG9zZVB4GD8gASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIhCgZIaWdoUHgYQCABKAsyES5kYmFnLmNlZi5EZWNpbWFsEiAKBUxvd1B4GEEgASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIgCgVBdmdQeBhCIAEoCzIRLmRiYWcuY2VmLkRlY2ltYWwSIQoGVHJkVm9sGEMgASgLMhEuZGJhZy5jZWYuRGVjaW1hbBIeCgNUdHQYRCABKAsyES5kYmFnLmNlZi5EZWNpbWFsEisKBlRyZE51bRhFIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEi4KCVRyZE51bVRlcxhGIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEiwKBkNsc1RpbRhHIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZRIgCgVSZWZQeBhIIAEoCzIRLmRiYWcuY2VmLkRlY2ltYWwSKQoDUHhzGEkgAygLMhwuZGJhZy5jZWYuRGF0YS5NREVudHJ5UHJpY2VzEgsKA1ZhbBhRIAEoCRIKCgJUbRhjIAEoBBqSAgoTU2VjdXJpdHlTdGF0dXNWYWx1ZRJACgVWYWx1ZRgBIAEoDjIxLmRiYWcuY2VmLkRhdGEuU2VjdXJpdHlTdGF0dXNWYWx1ZS5TZWN1cml0eVN0YXR1cyK4AQoOU2VjdXJpdHlTdGF0dXMSDQoJVU5ERUZJTkVEEAASCgoGQUNUSVZFEAESDAoISU5BQ1RJVkUQAhILCgdFWFBJUkVEEAQSDAoIREVMSVNURUQQBRIPCgtLTk9DS0VEX09VVBAGEg0KCVNVU1BFTkRFRBAJEg0KCVBVQkxJU0hFRBAKEhQKEFBFTkRJTkdfREVMRVRJT04QCxIdChlLTk9DS0VEX09VVF9BTkRfU1VTUEVOREVEEAwa4AQKGlNlY3VyaXR5VHJhZGluZ1N0YXR1c1ZhbHVlEk4KBVZhbHVlGAEgASgOMj8uZGJhZy5jZWYuRGF0YS5TZWN1cml0eVRyYWRpbmdTdGF0dXNWYWx1ZS5TZWN1cml0eVRyYWRpbmdTdGF0dXMi8QMKFVNlY3VyaXR5VHJhZGluZ1N0YXR1cxINCglVTkRFRklORUQQABIRCg1PUEVOSU5HX0RFTEFZEAESDwoLVFJBRElOR0hBTFQQAhIKCgZSRVNVTUUQAxIdChlOT1RfVFJBREVEX09OX1RISVNfTUFSS0VUEBMSDwoLRkFTVF9NQVJLRVQQFxILCgZDTE9TRUQQyAESDwoKUkVTVFJJQ1RFRBDJARIJCgRCT09LEMoBEg8KCkNPTlRJTlVPVVMQywESEwoOT1BFTklOR0FVQ1RJT04QzAESGQoUT1BFTklOR0FVQ1RJT05GUkVFWkUQzQESFAoPSU5UUkFEQVlBVUNUSU9OEM4BEhoKFUlOVFJBREFZQVVDVElPTkZSRUVaRRDPARIaChVDSVJDVUlUQlJFQUtFUkFVQ1RJT04Q0AESIAobQ0lSQ1VJVEJSRUFLRVJBVUNUSU9ORlJFRVpFENEBEhMKDkNMT1NJTkdBVUNUSU9OENIBEhkKFENMT1NJTkdBVUNUSU9ORlJFRVpFENMBEg8KCklQT0FVQ1RJT04Q1AESFQoQSVBPQVVDVElPTkZSRUVaRRDVARIMCgdQUkVDQUxMENYBEgkKBENBTEwQ1wESCwoGRlJFRVpFENgBEhEKDFRSQURFQVRDTE9TRRDZARrcAQoVVHJhZGluZ1Nlc3Npb25JRFZhbHVlEkQKBVZhbHVlGAEgASgOMjUuZGJhZy5jZWYuRGF0YS5UcmFkaW5nU2Vzc2lvbklEVmFsdWUuVHJhZGluZ1Nlc3Npb25JRCJ9ChBUcmFkaW5nU2Vzc2lvbklEEg0KCVVOREVGSU5FRBAAEgcKA0RBWRABEgsKB0hBTEZEQVkQAhILCgdNT1JOSU5HEAMSDQoJQUZURVJOT09OEAQSCwoHRVZFTklORxAFEg4KCkFGVEVSSE9VUlMQBhILCgdIT0xJREFZEAcaxgIKGFRyYWRpbmdTZXNzaW9uU3ViSURWYWx1ZRJKCgVWYWx1ZRgBIAEoDjI7LmRiYWcuY2VmLkRhdGEuVHJhZGluZ1Nlc3Npb25TdWJJRFZhbHVlLlRyYWRpbmdTZXNzaW9uU3ViSUQi3QEKE1RyYWRpbmdTZXNzaW9uU3ViSUQSDQoJVU5ERUZJTkVEEAASDgoKUFJFVFJBRElORxABEg4KCkNPTlRJTlVPVVMQAxILCgdDTE9TSU5HEAQSDwoLUE9TVFRSQURJTkcQBRIcChhTQ0hFRFVMRURJTlRSQURBWUFVQ1RJT04QBhINCglRVUlFU0NFTlQQBxIOCgpBTllBVUNUSU9OEAgSGwoXQ09OVElOVU9VU0FVQ1RJT05JU1NVRVIQZxIfChtDT05USU5VT1VTQVVDVElPTlNQRUNJQUxJU1QQaBqYAQoUTWFya2V0Q29uZGl0aW9uVmFsdWUSQgoFVmFsdWUYASABKA4yMy5kYmFnLmNlZi5EYXRhLk1hcmtldENvbmRpdGlvblZhbHVlLk1hcmtldENvbmRpdGlvbiI8Cg9NYXJrZXRDb25kaXRpb24SCgoGTk9STUFMEAASDAoIU1RSRVNTRUQQARIPCgtFWENFUFRJT05BTBACGrYECgxUcmRUeXBlVmFsdWUSMgoFVmFsdWUYASABKA4yIy5kYmFnLmNlZi5EYXRhLlRyZFR5cGVWYWx1ZS5UcmRUeXBlIvEDCgdUcmRUeXBlEhAKDFJFR1VMQVJUUkFERRAAEg4KCkJMT0NLVFJBREUQARIHCgNFRlAQAhITCg9FWENIQU5HRUZPUlNXQVAQDBIdChlQT1JURk9MSU9DT01QUkVTU0lPTlRSQURFEDISBwoDT1RDEDYSGQoVRVhDSEFOR0VCQVNJU0ZBQ0lMSVRZEDcSDgoJVk9MQVRSQURFEOgHEhAKC0VGUEZJTlRSQURFEOkHEhkKFEVGUElOREVYRlVUVVJFU1RSQURFEOoHEhcKEkJMT0NLVFJBREVBVE1BUktFVBDsBxIkCh9YRVRSQUVVUkVYRU5MSUdIVFRSSUdHRVJFRFRSQURFEO4HEhQKD0JMT0NLUVRQSVBUUkFERRDvBxIXChJERUxUQVRSQURFQVRNQVJLRVQQ+QcSGAoTT1BFTklOR0FVQ1RJT05UUkFERRDMCBIZChRJTlRSQURBWUFVQ1RJT05UUkFERRDNCBIbChZWT0xBVElMSVRZQVVDVElPTlRSQURFEM4IEhgKE0NMT1NJTkdBVUNUSU9OVFJBREUQzwgSFgoRQ1JPU1NBVUNUSU9OVFJBREUQ0AgSFAoPSVBPQVVDVElPTlRSQURFENMIEh4KGUxJUVVJRElUWUlNUFJPVkVNRU5UQ1JPU1MQ1AgagwEKEU1ET3JpZ2luVHlwZVZhbHVlEjwKBVZhbHVlGAEgASgOMi0uZGJhZy5jZWYuRGF0YS5NRE9yaWdpblR5cGVWYWx1ZS5NRE9yaWdpblR5cGUiMAoMTURPcmlnaW5UeXBlEg0KCU1ET1RfQk9PSxAAEhEKDU1ET1RfT0ZGX0JPT0sQARqKAQoTTURVcGRhdGVBY3Rpb25WYWx1ZRJACgVWYWx1ZRgBIAEoDjIxLmRiYWcuY2VmLkRhdGEuTURVcGRhdGVBY3Rpb25WYWx1ZS5NRFVwZGF0ZUFjdGlvbiIxCg5NRFVwZGF0ZUFjdGlvbhIHCgNORVcQABIKCgZDSEFOR0UQARIKCgZERUxFVEUQAhrBAQoOUHJpY2VUeXBlVmFsdWUSNgoFVmFsdWUYASABKA4yJy5kYmFnLmNlZi5EYXRhLlByaWNlVHlwZVZhbHVlLlByaWNlVHlwZSJ3CglQcmljZVR5cGUSDQoJVU5ERUZJTkVEEAASDgoKUEVSQ0VOVEFHRRABEgwKCFBFUl9VTklUEAISCQoFWUlFTEQQCRIQCgxQUklDRV9TUFJFQUQQDBIPCgtOT1JNQUxfUkFURRAUEg8KC0JBU0lTX1BPSU5UEBYatQEKGE1hcmtldFNlZ21lbnRTdGF0dXNWYWx1ZRJKCgVWYWx1ZRgBIAEoDjI7LmRiYWcuY2VmLkRhdGEuTWFya2V0U2VnbWVudFN0YXR1c1ZhbHVlLk1hcmtldFNlZ21lbnRTdGF0dXMiTQoTTWFya2V0U2VnbWVudFN0YXR1cxINCglVTkRFRklORUQQABIKCgZBQ1RJVkUQARIMCghJTkFDVElWRRACEg0KCVBVQkxJU0hFRBADGo8DCg1NREVudHJ5UHJpY2VzEjUKA1R5cBgBIAEoDjIoLmRiYWcuY2VmLkRhdGEuTURFbnRyeVByaWNlcy5NREVudHJ5VHlwZRIdCgJQeBgCIAEoCzIRLmRiYWcuY2VmLkRlY2ltYWwSHQoCU3oYAyABKAsyES5kYmFnLmNlZi5EZWNpbWFsEgoKAlRtGAQgASgEEiwKBVB4VHlwGAUgASgLMh0uZGJhZy5jZWYuRGF0YS5QcmljZVR5cGVWYWx1ZSLOAQoLTURFbnRyeVR5cGUSDQoJVU5ERUZJTkVEEAASEQoNT1BFTklOR19QUklDRRABEhEKDUNMT1NJTkdfUFJJQ0UQAhIUChBTRVRUTEVNRU5UX1BSSUNFEAMSEQoNT1BFTl9JTlRFUkVTVBAEEhoKFkFVQ1RJT05fQ0xFQVJJTkdfUFJJQ0UQBRIaChZQUkVWSU9VU19DTE9TSU5HX1BSSUNFEAYSGgoWUFJJT1JfU0VUVExFTUVOVF9QUklDRRAHEg0KCU1JRF9QUklDRRAIInwKDlRyYWRlQ29uZGl0aW9uEgUKAVUQABIFCgFSEAESBgoCQUoQAhIGCgJBVxADEgYKAkFYEAQSBgoCQVkQBRIGCgJCRBAGEgYKAkJCEAcSBgoCQkMQCBIGCgJTQRAJEgYKAlRDEAoSBQoBaxALEgUKAWEQDBIGCgJYUhANIsMBCgpNYXJrZXREYXRhEjAKBk1zZ1R5cBgBIAEoDjIgLmRiYWcuY2VmLk1hcmtldERhdGEuTWVzc2FnZVR5cGUSIgoDU2VxGAIgASgLMhUuZGJhZy5jZWYuQXBwbFNlcUN0cmwSJQoHSW5zdHJtdBgDIAEoCzIULmRiYWcuY2VmLkluc3RydW1lbnQSGwoDRGF0GAQgASgLMg4uZGJhZy5jZWYuRGF0YSIbCgtNZXNzYWdlVHlwZRIFCgFYEAASBQoBVxABYgZwcm90bzM', + [file_google_protobuf_wrappers], + ) + +/** + * @generated from message dbag.cef.Decimal + */ +export type Decimal = Message<'dbag.cef.Decimal'> & { + /** + * Mantisssa + * + * @generated from field: int64 m = 1; + */ + m: bigint + + /** + * Exponent + * + * @generated from field: int32 e = 2; + */ + e: number +} + +/** + * Describes the message dbag.cef.Decimal. + * Use `create(DecimalSchema)` to create a new message. + */ +export const DecimalSchema: GenMessage = /*@__PURE__*/ messageDesc(file_md_cef, 0) + +/** + * @generated from message dbag.cef.ApplSeqCtrl + */ +export type ApplSeqCtrl = Message<'dbag.cef.ApplSeqCtrl'> & { + /** + * FIX 1180 - ApplID + * + * @generated from field: uint32 ApplID = 1; + */ + ApplID: number + + /** + * FIX 1181 - ApplSeqNum + * + * @generated from field: uint64 ApplSeqNum = 2; + */ + ApplSeqNum: bigint +} + +/** + * Describes the message dbag.cef.ApplSeqCtrl. + * Use `create(ApplSeqCtrlSchema)` to create a new message. + */ +export const ApplSeqCtrlSchema: GenMessage = /*@__PURE__*/ messageDesc(file_md_cef, 1) + +/** + * @generated from message dbag.cef.Instrument + */ +export type Instrument = Message<'dbag.cef.Instrument'> & { + /** + * FIX 1301 MarketID + * + * @generated from field: string MktID = 1; + */ + MktID: string + + /** + * FIX 55 - Symbol + * + * @generated from field: string Sym = 2; + */ + Sym: string + + /** + * FIX 48 - SecurityID + * + * @generated from field: string ID = 3; + */ + ID: string + + /** + * FIX 22 - SecurityIDSource + * + * @generated from field: dbag.cef.Instrument.SecurityIDSource Src = 4; + */ + Src: Instrument_SecurityIDSource + + /** + * FIX 167 - SecurityType + * + * @generated from field: dbag.cef.Instrument.SecurityType SecTyp = 5; + */ + SecTyp: Instrument_SecurityType + + /** + * FIX 15 - Currency + * + * @generated from field: string Ccy = 6; + */ + Ccy: string + + /** + * FIX 455 - SecurityAltID + * + * @generated from field: string AltID = 7; + */ + AltID: string + + /** + * FIX 456 - SecurityAltIDSource + * + * @generated from field: dbag.cef.Instrument.SecurityIDSource AltIDSrc = 8; + */ + AltIDSrc: Instrument_SecurityIDSource + + /** + * FIX 7703 - MarketSegment + * + * @generated from field: string MktSeg = 9; + */ + MktSeg: string + + /** + * FIX 200 - MaturityMonthYear + * + * @generated from field: string MMY = 11; + */ + MMY: string + + /** + * FIX T7 extension 30866 - ContractDate + * + * @generated from field: google.protobuf.Int32Value CntrDate = 12; + */ + CntrDate?: number + + /** + * FIX CEF extension - ContractType + * + * @generated from field: dbag.cef.Instrument.ContractTypeValue Ct = 13; + */ + Ct?: Instrument_ContractTypeValue + + /** + * FIX 202 StrikePrice + * + * @generated from field: dbag.cef.Decimal StrkPx = 14; + */ + StrkPx?: Decimal + + /** + * FIX 2578 - OrigStrikePrice + * + * @generated from field: dbag.cef.Decimal OrigStrkPx = 15; + */ + OrigStrkPx?: Decimal + + /** + * FIX 201 - PutOrCall + * + * @generated from field: dbag.cef.Instrument.PutOrCallValue PutCall = 16; + */ + PutCall?: Instrument_PutOrCallValue + + /** + * FIX T7 extension 25034 - ContractGenerationNumber + * + * @generated from field: google.protobuf.Int32Value CntrGenNr = 17; + */ + CntrGenNr?: number + + /** + * FIX 1193 - SettlMethod + * + * @generated from field: dbag.cef.Instrument.SettlMethodValue SettlMeth = 18; + */ + SettlMeth?: Instrument_SettlMethodValue + + /** + * FIX 1194 - ExerStyle + * + * @generated from field: dbag.cef.Instrument.ExerciseStyleValue ExerStyle = 19; + */ + ExerStyle?: Instrument_ExerciseStyleValue + + /** + * FIX 969 - MinPriceIncrement + * + * @generated from field: dbag.cef.Decimal MinPxIncr = 21; + */ + MinPxIncr?: Decimal + + /** + * FIX 6215 - TenorValue + * + * @generated from field: string TenorVal = 22; + */ + TenorVal: string + + /** + * FIX 980 - SecurityUpdateAction + * + * @generated from field: dbag.cef.Instrument.SecurityUpdateActionValue UpdActn = 30; + */ + UpdActn?: Instrument_SecurityUpdateActionValue + + /** + * FIX 779 - LastUpdateTime + * + * @generated from field: uint64 LastUpdateTm = 31; + */ + LastUpdateTm: bigint + + /** + * FIX EventGroup + * + * @generated from field: repeated dbag.cef.Instrument.Event Evnts = 32; + */ + Evnts: Instrument_Event[] +} + +/** + * Describes the message dbag.cef.Instrument. + * Use `create(InstrumentSchema)` to create a new message. + */ +export const InstrumentSchema: GenMessage = /*@__PURE__*/ messageDesc(file_md_cef, 2) + +/** + * @generated from message dbag.cef.Instrument.PutOrCallValue + */ +export type Instrument_PutOrCallValue = Message<'dbag.cef.Instrument.PutOrCallValue'> & { + /** + * @generated from field: dbag.cef.Instrument.PutOrCallValue.PutOrCall Value = 1; + */ + Value: Instrument_PutOrCallValue_PutOrCall +} + +/** + * Describes the message dbag.cef.Instrument.PutOrCallValue. + * Use `create(Instrument_PutOrCallValueSchema)` to create a new message. + */ +export const Instrument_PutOrCallValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 2, 0) + +/** + * @generated from enum dbag.cef.Instrument.PutOrCallValue.PutOrCall + */ +export enum Instrument_PutOrCallValue_PutOrCall { + /** + * FIX Put + * + * @generated from enum value: PUT = 0; + */ + PUT = 0, + + /** + * FIX Call + * + * @generated from enum value: CALL = 1; + */ + CALL = 1, +} + +/** + * Describes the enum dbag.cef.Instrument.PutOrCallValue.PutOrCall. + */ +export const Instrument_PutOrCallValue_PutOrCallSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 0, 0) + +/** + * @generated from message dbag.cef.Instrument.SettlMethodValue + */ +export type Instrument_SettlMethodValue = Message<'dbag.cef.Instrument.SettlMethodValue'> & { + /** + * @generated from field: dbag.cef.Instrument.SettlMethodValue.SettlMethod Value = 1; + */ + Value: Instrument_SettlMethodValue_SettlMethod +} + +/** + * Describes the message dbag.cef.Instrument.SettlMethodValue. + * Use `create(Instrument_SettlMethodValueSchema)` to create a new message. + */ +export const Instrument_SettlMethodValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 2, 1) + +/** + * @generated from enum dbag.cef.Instrument.SettlMethodValue.SettlMethod + */ +export enum Instrument_SettlMethodValue_SettlMethod { + /** + * Cash + * + * @generated from enum value: C = 0; + */ + C = 0, + + /** + * Physical + * + * @generated from enum value: P = 1; + */ + P = 1, +} + +/** + * Describes the enum dbag.cef.Instrument.SettlMethodValue.SettlMethod. + */ +export const Instrument_SettlMethodValue_SettlMethodSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 1, 0) + +/** + * @generated from message dbag.cef.Instrument.ExerciseStyleValue + */ +export type Instrument_ExerciseStyleValue = Message<'dbag.cef.Instrument.ExerciseStyleValue'> & { + /** + * @generated from field: dbag.cef.Instrument.ExerciseStyleValue.ExerciseStyle Value = 1; + */ + Value: Instrument_ExerciseStyleValue_ExerciseStyle +} + +/** + * Describes the message dbag.cef.Instrument.ExerciseStyleValue. + * Use `create(Instrument_ExerciseStyleValueSchema)` to create a new message. + */ +export const Instrument_ExerciseStyleValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 2, 2) + +/** + * @generated from enum dbag.cef.Instrument.ExerciseStyleValue.ExerciseStyle + */ +export enum Instrument_ExerciseStyleValue_ExerciseStyle { + /** + * European + * + * @generated from enum value: E = 0; + */ + E = 0, + + /** + * American + * + * @generated from enum value: A = 1; + */ + A = 1, +} + +/** + * Describes the enum dbag.cef.Instrument.ExerciseStyleValue.ExerciseStyle. + */ +export const Instrument_ExerciseStyleValue_ExerciseStyleSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 2, 0) + +/** + * @generated from message dbag.cef.Instrument.ContractTypeValue + */ +export type Instrument_ContractTypeValue = Message<'dbag.cef.Instrument.ContractTypeValue'> & { + /** + * @generated from field: dbag.cef.Instrument.ContractTypeValue.ContractType Value = 1; + */ + Value: Instrument_ContractTypeValue_ContractType +} + +/** + * Describes the message dbag.cef.Instrument.ContractTypeValue. + * Use `create(Instrument_ContractTypeValueSchema)` to create a new message. + */ +export const Instrument_ContractTypeValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 2, 3) + +/** + * @generated from enum dbag.cef.Instrument.ContractTypeValue.ContractType + */ +export enum Instrument_ContractTypeValue_ContractType { + /** + * Flexible + * + * @generated from enum value: F = 0; + */ + F = 0, + + /** + * Standard + * + * @generated from enum value: S = 1; + */ + S = 1, +} + +/** + * Describes the enum dbag.cef.Instrument.ContractTypeValue.ContractType. + */ +export const Instrument_ContractTypeValue_ContractTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 3, 0) + +/** + * @generated from message dbag.cef.Instrument.SecurityUpdateActionValue + */ +export type Instrument_SecurityUpdateActionValue = + Message<'dbag.cef.Instrument.SecurityUpdateActionValue'> & { + /** + * @generated from field: dbag.cef.Instrument.SecurityUpdateActionValue.SecurityUpdateAction Value = 1; + */ + Value: Instrument_SecurityUpdateActionValue_SecurityUpdateAction + } + +/** + * Describes the message dbag.cef.Instrument.SecurityUpdateActionValue. + * Use `create(Instrument_SecurityUpdateActionValueSchema)` to create a new message. + */ +export const Instrument_SecurityUpdateActionValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 2, 4) + +/** + * @generated from enum dbag.cef.Instrument.SecurityUpdateActionValue.SecurityUpdateAction + */ +export enum Instrument_SecurityUpdateActionValue_SecurityUpdateAction { + /** + * 'A' + * + * @generated from enum value: NEW = 0; + */ + NEW = 0, + + /** + * 'D' + * + * @generated from enum value: DELETE = 1; + */ + DELETE = 1, + + /** + * 'M' + * + * @generated from enum value: MODIFY = 2; + */ + MODIFY = 2, +} + +/** + * Describes the enum dbag.cef.Instrument.SecurityUpdateActionValue.SecurityUpdateAction. + */ +export const Instrument_SecurityUpdateActionValue_SecurityUpdateActionSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 4, 0) + +/** + * @generated from message dbag.cef.Instrument.Event + */ +export type Instrument_Event = Message<'dbag.cef.Instrument.Event'> & { + /** + * FIX 865 EventType + * + * @generated from field: dbag.cef.Instrument.Event.EventType EventTyp = 1; + */ + EventTyp: Instrument_Event_EventType + + /** + * FIX 866 EventDate + * + * @generated from field: uint32 Dt = 2; + */ + Dt: number +} + +/** + * Describes the message dbag.cef.Instrument.Event. + * Use `create(Instrument_EventSchema)` to create a new message. + */ +export const Instrument_EventSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 2, 5) + +/** + * @generated from enum dbag.cef.Instrument.Event.EventType + */ +export enum Instrument_Event_EventType { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: ACTIVATION = 5; + */ + ACTIVATION = 5, + + /** + * @generated from enum value: INACTIVATION = 6; + */ + INACTIVATION = 6, + + /** + * @generated from enum value: LAST_ELIGIBLE_TRADE_DATE = 7; + */ + LAST_ELIGIBLE_TRADE_DATE = 7, + + /** + * @generated from enum value: FIRST_ELIGIBLE_TRADE_DATE = 28; + */ + FIRST_ELIGIBLE_TRADE_DATE = 28, +} + +/** + * Describes the enum dbag.cef.Instrument.Event.EventType. + */ +export const Instrument_Event_EventTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 5, 0) + +/** + * @generated from enum dbag.cef.Instrument.SecurityIDSource + */ +export enum Instrument_SecurityIDSource { + /** + * @generated from enum value: ISIN = 0; + */ + ISIN = 0, + + /** + * @generated from enum value: EXCHANGE_SYMBOL = 1; + */ + EXCHANGE_SYMBOL = 1, + + /** + * @generated from enum value: SYNTHETIC = 2; + */ + SYNTHETIC = 2, +} + +/** + * Describes the enum dbag.cef.Instrument.SecurityIDSource. + */ +export const Instrument_SecurityIDSourceSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 0) + +/** + * @generated from enum dbag.cef.Instrument.SecurityType + */ +export enum Instrument_SecurityType { + /** + * None + * + * @generated from enum value: NO_SECURITYTYPE = 0; + */ + NO_SECURITYTYPE = 0, + + /** + * Future + * + * @generated from enum value: FUT = 1; + */ + FUT = 1, + + /** + * Option + * + * @generated from enum value: OPT = 2; + */ + OPT = 2, + + /** + * Multileg Instrument + * + * @generated from enum value: MLEG = 3; + */ + MLEG = 3, + + /** + * Index + * + * @generated from enum value: INDEX = 4; + */ + INDEX = 4, + + /** + * Exchange traded commodity + * + * @generated from enum value: ETC = 5; + */ + ETC = 5, + + /** + * Exchange traded note + * + * @generated from enum value: ETN = 6; + */ + ETN = 6, + + /** + * Common Stock + * + * @generated from enum value: CS = 7; + */ + CS = 7, + + /** + * Repurchase + * + * @generated from enum value: REPO = 8; + */ + REPO = 8, + + /** + * Repurchase + * + * @generated from enum value: CASH = 9; + */ + CASH = 9, + + /** + * Foreign Exchange Contract + * + * @generated from enum value: FOR = 10; + */ + FOR = 10, + + /** + * Bond + * + * @generated from enum value: BOND = 11; + */ + BOND = 11, + + /** + * Mutual Fund + * + * @generated from enum value: MF = 12; + */ + MF = 12, + + /** + * Investment Fund + * + * @generated from enum value: FUN = 13; + */ + FUN = 13, + + /** + * Interest Rate Swap + * + * @generated from enum value: IRS = 14; + */ + IRS = 14, + + /** + * Subscription Rights + * + * @generated from enum value: SR = 15; + */ + SR = 15, + + /** + * Warrant + * + * @generated from enum value: WAR = 16; + */ + WAR = 16, + + /** + * Exchange Traded Fund + * + * @generated from enum value: ETF = 17; + */ + ETF = 17, + + /** + * FX Swap + * + * @generated from enum value: FXSWAP = 18; + */ + FXSWAP = 18, + + /** + * Other + * + * @generated from enum value: OTHER = 99; + */ + OTHER = 99, +} + +/** + * Describes the enum dbag.cef.Instrument.SecurityType. + */ +export const Instrument_SecurityTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 2, 1) + +/** + * @generated from message dbag.cef.QuoteSide + */ +export type QuoteSide = Message<'dbag.cef.QuoteSide'> & { + /** + * FIX 270 - MDEntryPrice + * + * @generated from field: dbag.cef.Decimal Px = 1; + */ + Px?: Decimal + + /** + * FIX 271 - MDEntrySize + * + * @generated from field: dbag.cef.Decimal Sz = 2; + */ + Sz?: Decimal + + /** + * FIX 346 - NumberOfOrders + * + * @generated from field: google.protobuf.Int32Value NumOfOrds = 3; + */ + NumOfOrds?: number + + /** + * FIX 1070 - MDQuoteType + * + * @generated from field: dbag.cef.QuoteSide.MDQuoteTypeValue MDQteTyp = 4; + */ + MDQteTyp?: QuoteSide_MDQuoteTypeValue + + /** + * FIX 269 - MDEntryType + * + * @generated from field: dbag.cef.QuoteSide.MDEntryTypeValue Typ = 5; + */ + Typ?: QuoteSide_MDEntryTypeValue + + /** + * FIX 276 - QuoteCondition + * + * @generated from field: dbag.cef.QuoteSide.QuoteConditionValue QCond = 6; + */ + QCond?: QuoteSide_QuoteConditionValue + + /** + * FIX 5675 (360T) - ForwardPoints + * + * @generated from field: dbag.cef.Decimal FwdPnts = 7; + */ + FwdPnts?: Decimal + + /** + * FIX 5678 (360T) - Pip + * + * @generated from field: int64 Pip = 8; + */ + Pip: bigint + + /** + * FIX 5679 (360T) - HolidayWarn + * + * @generated from field: dbag.cef.QuoteSide.HolidayWarnValue HlWrn = 9; + */ + HlWrn?: QuoteSide_HolidayWarnValue +} + +/** + * Describes the message dbag.cef.QuoteSide. + * Use `create(QuoteSideSchema)` to create a new message. + */ +export const QuoteSideSchema: GenMessage = /*@__PURE__*/ messageDesc(file_md_cef, 3) + +/** + * @generated from message dbag.cef.QuoteSide.MDQuoteTypeValue + */ +export type QuoteSide_MDQuoteTypeValue = Message<'dbag.cef.QuoteSide.MDQuoteTypeValue'> & { + /** + * @generated from field: dbag.cef.QuoteSide.MDQuoteTypeValue.MDQuoteType Value = 1; + */ + Value: QuoteSide_MDQuoteTypeValue_MDQuoteType +} + +/** + * Describes the message dbag.cef.QuoteSide.MDQuoteTypeValue. + * Use `create(QuoteSide_MDQuoteTypeValueSchema)` to create a new message. + */ +export const QuoteSide_MDQuoteTypeValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 3, 0) + +/** + * @generated from enum dbag.cef.QuoteSide.MDQuoteTypeValue.MDQuoteType + */ +export enum QuoteSide_MDQuoteTypeValue_MDQuoteType { + /** + * @generated from enum value: INDICATIVE = 0; + */ + INDICATIVE = 0, + + /** + * @generated from enum value: TRADEABLE = 1; + */ + TRADEABLE = 1, +} + +/** + * Describes the enum dbag.cef.QuoteSide.MDQuoteTypeValue.MDQuoteType. + */ +export const QuoteSide_MDQuoteTypeValue_MDQuoteTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 3, 0, 0) + +/** + * @generated from message dbag.cef.QuoteSide.QuoteConditionValue + */ +export type QuoteSide_QuoteConditionValue = Message<'dbag.cef.QuoteSide.QuoteConditionValue'> & { + /** + * @generated from field: dbag.cef.QuoteSide.QuoteConditionValue.QuoteCondition Value = 1; + */ + Value: QuoteSide_QuoteConditionValue_QuoteCondition +} + +/** + * Describes the message dbag.cef.QuoteSide.QuoteConditionValue. + * Use `create(QuoteSide_QuoteConditionValueSchema)` to create a new message. + */ +export const QuoteSide_QuoteConditionValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 3, 1) + +/** + * FIX 276 + * + * @generated from enum dbag.cef.QuoteSide.QuoteConditionValue.QuoteCondition + */ +export enum QuoteSide_QuoteConditionValue_QuoteCondition { + /** + * @generated from enum value: FIRM = 0; + */ + FIRM = 0, + + /** + * @generated from enum value: INDICATIVE = 1; + */ + INDICATIVE = 1, +} + +/** + * Describes the enum dbag.cef.QuoteSide.QuoteConditionValue.QuoteCondition. + */ +export const QuoteSide_QuoteConditionValue_QuoteConditionSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 3, 1, 0) + +/** + * @generated from message dbag.cef.QuoteSide.MDEntryTypeValue + */ +export type QuoteSide_MDEntryTypeValue = Message<'dbag.cef.QuoteSide.MDEntryTypeValue'> & { + /** + * @generated from field: dbag.cef.QuoteSide.MDEntryTypeValue.MDEntryType Value = 1; + */ + Value: QuoteSide_MDEntryTypeValue_MDEntryType +} + +/** + * Describes the message dbag.cef.QuoteSide.MDEntryTypeValue. + * Use `create(QuoteSide_MDEntryTypeValueSchema)` to create a new message. + */ +export const QuoteSide_MDEntryTypeValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 3, 2) + +/** + * @generated from enum dbag.cef.QuoteSide.MDEntryTypeValue.MDEntryType + */ +export enum QuoteSide_MDEntryTypeValue_MDEntryType { + /** + * @generated from enum value: BID = 0; + */ + BID = 0, + + /** + * @generated from enum value: OFFER = 1; + */ + OFFER = 1, + + /** + * @generated from enum value: MARKET_BID = 11; + */ + MARKET_BID = 11, + + /** + * @generated from enum value: MARKET_OFFER = 12; + */ + MARKET_OFFER = 12, +} + +/** + * Describes the enum dbag.cef.QuoteSide.MDEntryTypeValue.MDEntryType. + */ +export const QuoteSide_MDEntryTypeValue_MDEntryTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 3, 2, 0) + +/** + * @generated from message dbag.cef.QuoteSide.HolidayWarnValue + */ +export type QuoteSide_HolidayWarnValue = Message<'dbag.cef.QuoteSide.HolidayWarnValue'> & { + /** + * @generated from field: dbag.cef.QuoteSide.HolidayWarnValue.HolidayWarn Value = 1; + */ + Value: QuoteSide_HolidayWarnValue_HolidayWarn +} + +/** + * Describes the message dbag.cef.QuoteSide.HolidayWarnValue. + * Use `create(QuoteSide_HolidayWarnValueSchema)` to create a new message. + */ +export const QuoteSide_HolidayWarnValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 3, 3) + +/** + * FIX 5679 (360T) + * + * @generated from enum dbag.cef.QuoteSide.HolidayWarnValue.HolidayWarn + */ +export enum QuoteSide_HolidayWarnValue_HolidayWarn { + /** + * @generated from enum value: NO_HOLIDAYS = 0; + */ + NO_HOLIDAYS = 0, + + /** + * @generated from enum value: HOLIDAYS = 1; + */ + HOLIDAYS = 1, +} + +/** + * Describes the enum dbag.cef.QuoteSide.HolidayWarnValue.HolidayWarn. + */ +export const QuoteSide_HolidayWarnValue_HolidayWarnSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 3, 3, 0) + +/** + * @generated from message dbag.cef.Data + */ +export type Data = Message<'dbag.cef.Data'> & { + /** + * Quote + * + * MDEntryType = 0 or MDEntryType = 'b' + * + * @generated from field: dbag.cef.QuoteSide Bid = 1; + */ + Bid?: QuoteSide + + /** + * MDEntryType = 1 or MDEntryType = 'c' + * + * @generated from field: dbag.cef.QuoteSide Offer = 2; + */ + Offer?: QuoteSide + + /** + * FIX 423 - PriceType + * + * @generated from field: dbag.cef.Data.PriceTypeValue PxTyp = 3; + */ + PxTyp?: Data_PriceTypeValue + + /** + * State Change + * + * FIX 965 - SecurityStatus + * + * @generated from field: dbag.cef.Data.SecurityStatusValue Status = 11; + */ + Status?: Data_SecurityStatusValue + + /** + * FIX 336 - TradingSessionID + * + * @generated from field: dbag.cef.Data.TradingSessionIDValue SesID = 12; + */ + SesID?: Data_TradingSessionIDValue + + /** + * FIX 625 - TradingSessionSubID + * + * @generated from field: dbag.cef.Data.TradingSessionSubIDValue SesSub = 13; + */ + SesSub?: Data_TradingSessionSubIDValue + + /** + * FIX 2447 - FastMktInd + * + * @generated from field: google.protobuf.BoolValue FastMktInd = 14; + */ + FastMktInd?: boolean + + /** + * FIX 326 - SecurityTradingStatus + * + * @generated from field: dbag.cef.Data.SecurityTradingStatusValue TrdgStat = 15; + */ + TrdgStat?: Data_SecurityTradingStatusValue + + /** + * FIX 2705 - MarketCondition + * + * @generated from field: dbag.cef.Data.MarketConditionValue MktCond = 16; + */ + MktCond?: Data_MarketConditionValue + + /** + * FIX 25045 - TESSecurityStatus + * + * @generated from field: dbag.cef.Data.SecurityStatusValue TesStatus = 17; + */ + TesStatus?: Data_SecurityStatusValue + + /** + * FIX 2542 - Market Segment Status + * + * @generated from field: dbag.cef.Data.MarketSegmentStatusValue MktSegStat = 18; + */ + MktSegStat?: Data_MarketSegmentStatusValue + + /** + * Trade + * + * FIX 270 - MDEntryPrice + * + * @generated from field: dbag.cef.Decimal Px = 21; + */ + Px?: Decimal + + /** + * FIX 271 - MDEntrySize + * + * @generated from field: dbag.cef.Decimal Sz = 22; + */ + Sz?: Decimal + + /** + * FIX 828 - TrDType + * + * @generated from field: dbag.cef.Data.TrdTypeValue TrdTyp = 23; + */ + TrdTyp?: Data_TrdTypeValue + + /** + * FIX 2449 - NumberOfBuyOrders + * + * @generated from field: google.protobuf.Int32Value NumOfBuyOrds = 24; + */ + NumOfBuyOrds?: number + + /** + * FIX 2450 - NumberOfSellOrders + * + * @generated from field: google.protobuf.Int32Value NumOfSellOrds = 25; + */ + NumOfSellOrds?: number + + /** + * FIX 1024 - MDOriginType + * + * @generated from field: dbag.cef.Data.MDOriginTypeValue MDOrigTyp = 26; + */ + MDOrigTyp?: Data_MDOriginTypeValue + + /** + * FIX 15 - Currency + * + * @generated from field: string Ccy = 27; + */ + Ccy: string + + /** + * FIX 278 - MDEntryID + * + * @generated from field: string MDID = 28; + */ + MDID: string + + /** + * FIX 880 - TrdMatchID (TVTIC - Trading Venue Transaction Identification Code) + * + * @generated from field: string MtchID = 29; + */ + MtchID: string + + /** + * FIX 279 - MDUpdateAction + * + * @generated from field: dbag.cef.Data.MDUpdateActionValue UpdtAct = 30; + */ + UpdtAct?: Data_MDUpdateActionValue + + /** + * FIX 277 - TradeCondition + * + * @generated from field: repeated dbag.cef.Data.TradeCondition TrdCond = 31; + */ + TrdCond: Data_TradeCondition[] + + /** + * Book + * + * MDEntryType = 0 + * + * @generated from field: repeated dbag.cef.QuoteSide Bids = 41; + */ + Bids: QuoteSide[] + + /** + * MDEntryType = 1 + * + * @generated from field: repeated dbag.cef.QuoteSide Offers = 42; + */ + Offers: QuoteSide[] + + /** + * Clearing + * + * FIX 270 FIX 269@6 - MDEntryPx + MDEntryType=6 (Settlement Price) + * + * @generated from field: dbag.cef.Decimal StlPx = 51; + */ + StlPx?: Decimal + + /** + * FIX 270 FIX 269@C - MDEntryPx + MDEntryType=C (Open Interest) + * + * @generated from field: dbag.cef.Decimal Int = 52; + */ + Int?: Decimal + + /** + * FIX 119 - Settlement Currency Amount / Nominal Amount + * + * @generated from field: dbag.cef.Decimal SettlCurrAmt = 53; + */ + SettlCurrAmt?: Decimal + + /** + * FIX 120 - Settlement Currency + * + * @generated from field: string SettlCcy = 54; + */ + SettlCcy: string + + /** + * FIX 64 - SettlementDate + * + * @generated from field: string SettlDt = 55; + */ + SettlDt: string + + /** + * Statistics & Others + * + * FIX - Potential Auction Price + * + * @generated from field: dbag.cef.Decimal PaPx = 61; + */ + PaPx?: Decimal + + /** + * FIX 270 & FIX 269@4 - MDEntryPx + MDEntryType=4 (Opening Price) + * + * @generated from field: dbag.cef.Decimal OpenPx = 62; + */ + OpenPx?: Decimal + + /** + * FIX 270 & FIX 269@5 - MDEntryPx + MDEntryType=5 (Closing Price) + * + * @generated from field: dbag.cef.Decimal ClosePx = 63; + */ + ClosePx?: Decimal + + /** + * FIX 332 - High Price + * + * @generated from field: dbag.cef.Decimal HighPx = 64; + */ + HighPx?: Decimal + + /** + * FIX 333 - Low Price + * + * @generated from field: dbag.cef.Decimal LowPx = 65; + */ + LowPx?: Decimal + + /** + * Average Price + * + * @generated from field: dbag.cef.Decimal AvgPx = 66; + */ + AvgPx?: Decimal + + /** + * FIX 1020 - Trade Volume + * + * @generated from field: dbag.cef.Decimal TrdVol = 67; + */ + TrdVol?: Decimal + + /** + * Total Turnover + * + * @generated from field: dbag.cef.Decimal Ttt = 68; + */ + Ttt?: Decimal + + /** + * FIX 2490 - Trade Number + * + * @generated from field: google.protobuf.Int32Value TrdNum = 69; + */ + TrdNum?: number + + /** + * Trade Number Tes + * + * @generated from field: google.protobuf.Int32Value TrdNumTes = 70; + */ + TrdNumTes?: number + + /** + * FIX 344 - Close Time + * + * @generated from field: google.protobuf.UInt64Value ClsTim = 71; + */ + ClsTim?: bigint + + /** + * FIX 270 FIX 269@2 FIX 271=0 - MDEntryPx + MDEntryType=2 (Reference Price) + * + * @generated from field: dbag.cef.Decimal RefPx = 72; + */ + RefPx?: Decimal + + /** + * FIX 269 & FIX 270 & FIX 271 + * + * @generated from field: repeated dbag.cef.Data.MDEntryPrices Pxs = 73; + */ + Pxs: Data_MDEntryPrices[] + + /** + * Reference + * + * FIX 234 - StipulationValue + * + * @generated from field: string Val = 81; + */ + Val: string + + /** + * Timestamp + * + * FIX 273 - MDEntryTime + * + * @generated from field: uint64 Tm = 99; + */ + Tm: bigint +} + +/** + * Describes the message dbag.cef.Data. + * Use `create(DataSchema)` to create a new message. + */ +export const DataSchema: GenMessage = /*@__PURE__*/ messageDesc(file_md_cef, 4) + +/** + * @generated from message dbag.cef.Data.SecurityStatusValue + */ +export type Data_SecurityStatusValue = Message<'dbag.cef.Data.SecurityStatusValue'> & { + /** + * @generated from field: dbag.cef.Data.SecurityStatusValue.SecurityStatus Value = 1; + */ + Value: Data_SecurityStatusValue_SecurityStatus +} + +/** + * Describes the message dbag.cef.Data.SecurityStatusValue. + * Use `create(Data_SecurityStatusValueSchema)` to create a new message. + */ +export const Data_SecurityStatusValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 0) + +/** + * @generated from enum dbag.cef.Data.SecurityStatusValue.SecurityStatus + */ +export enum Data_SecurityStatusValue_SecurityStatus { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: ACTIVE = 1; + */ + ACTIVE = 1, + + /** + * @generated from enum value: INACTIVE = 2; + */ + INACTIVE = 2, + + /** + * @generated from enum value: EXPIRED = 4; + */ + EXPIRED = 4, + + /** + * @generated from enum value: DELISTED = 5; + */ + DELISTED = 5, + + /** + * @generated from enum value: KNOCKED_OUT = 6; + */ + KNOCKED_OUT = 6, + + /** + * @generated from enum value: SUSPENDED = 9; + */ + SUSPENDED = 9, + + /** + * @generated from enum value: PUBLISHED = 10; + */ + PUBLISHED = 10, + + /** + * @generated from enum value: PENDING_DELETION = 11; + */ + PENDING_DELETION = 11, + + /** + * @generated from enum value: KNOCKED_OUT_AND_SUSPENDED = 12; + */ + KNOCKED_OUT_AND_SUSPENDED = 12, +} + +/** + * Describes the enum dbag.cef.Data.SecurityStatusValue.SecurityStatus. + */ +export const Data_SecurityStatusValue_SecurityStatusSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 0, 0) + +/** + * @generated from message dbag.cef.Data.SecurityTradingStatusValue + */ +export type Data_SecurityTradingStatusValue = + Message<'dbag.cef.Data.SecurityTradingStatusValue'> & { + /** + * @generated from field: dbag.cef.Data.SecurityTradingStatusValue.SecurityTradingStatus Value = 1; + */ + Value: Data_SecurityTradingStatusValue_SecurityTradingStatus + } + +/** + * Describes the message dbag.cef.Data.SecurityTradingStatusValue. + * Use `create(Data_SecurityTradingStatusValueSchema)` to create a new message. + */ +export const Data_SecurityTradingStatusValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 1) + +/** + * @generated from enum dbag.cef.Data.SecurityTradingStatusValue.SecurityTradingStatus + */ +export enum Data_SecurityTradingStatusValue_SecurityTradingStatus { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: OPENING_DELAY = 1; + */ + OPENING_DELAY = 1, + + /** + * @generated from enum value: TRADINGHALT = 2; + */ + TRADINGHALT = 2, + + /** + * @generated from enum value: RESUME = 3; + */ + RESUME = 3, + + /** + * @generated from enum value: NOT_TRADED_ON_THIS_MARKET = 19; + */ + NOT_TRADED_ON_THIS_MARKET = 19, + + /** + * @generated from enum value: FAST_MARKET = 23; + */ + FAST_MARKET = 23, + + /** + * @generated from enum value: CLOSED = 200; + */ + CLOSED = 200, + + /** + * @generated from enum value: RESTRICTED = 201; + */ + RESTRICTED = 201, + + /** + * @generated from enum value: BOOK = 202; + */ + BOOK = 202, + + /** + * @generated from enum value: CONTINUOUS = 203; + */ + CONTINUOUS = 203, + + /** + * @generated from enum value: OPENINGAUCTION = 204; + */ + OPENINGAUCTION = 204, + + /** + * @generated from enum value: OPENINGAUCTIONFREEZE = 205; + */ + OPENINGAUCTIONFREEZE = 205, + + /** + * @generated from enum value: INTRADAYAUCTION = 206; + */ + INTRADAYAUCTION = 206, + + /** + * @generated from enum value: INTRADAYAUCTIONFREEZE = 207; + */ + INTRADAYAUCTIONFREEZE = 207, + + /** + * @generated from enum value: CIRCUITBREAKERAUCTION = 208; + */ + CIRCUITBREAKERAUCTION = 208, + + /** + * @generated from enum value: CIRCUITBREAKERAUCTIONFREEZE = 209; + */ + CIRCUITBREAKERAUCTIONFREEZE = 209, + + /** + * @generated from enum value: CLOSINGAUCTION = 210; + */ + CLOSINGAUCTION = 210, + + /** + * @generated from enum value: CLOSINGAUCTIONFREEZE = 211; + */ + CLOSINGAUCTIONFREEZE = 211, + + /** + * @generated from enum value: IPOAUCTION = 212; + */ + IPOAUCTION = 212, + + /** + * @generated from enum value: IPOAUCTIONFREEZE = 213; + */ + IPOAUCTIONFREEZE = 213, + + /** + * @generated from enum value: PRECALL = 214; + */ + PRECALL = 214, + + /** + * @generated from enum value: CALL = 215; + */ + CALL = 215, + + /** + * @generated from enum value: FREEZE = 216; + */ + FREEZE = 216, + + /** + * @generated from enum value: TRADEATCLOSE = 217; + */ + TRADEATCLOSE = 217, +} + +/** + * Describes the enum dbag.cef.Data.SecurityTradingStatusValue.SecurityTradingStatus. + */ +export const Data_SecurityTradingStatusValue_SecurityTradingStatusSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 1, 0) + +/** + * @generated from message dbag.cef.Data.TradingSessionIDValue + */ +export type Data_TradingSessionIDValue = Message<'dbag.cef.Data.TradingSessionIDValue'> & { + /** + * @generated from field: dbag.cef.Data.TradingSessionIDValue.TradingSessionID Value = 1; + */ + Value: Data_TradingSessionIDValue_TradingSessionID +} + +/** + * Describes the message dbag.cef.Data.TradingSessionIDValue. + * Use `create(Data_TradingSessionIDValueSchema)` to create a new message. + */ +export const Data_TradingSessionIDValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 2) + +/** + * @generated from enum dbag.cef.Data.TradingSessionIDValue.TradingSessionID + */ +export enum Data_TradingSessionIDValue_TradingSessionID { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: DAY = 1; + */ + DAY = 1, + + /** + * @generated from enum value: HALFDAY = 2; + */ + HALFDAY = 2, + + /** + * @generated from enum value: MORNING = 3; + */ + MORNING = 3, + + /** + * @generated from enum value: AFTERNOON = 4; + */ + AFTERNOON = 4, + + /** + * @generated from enum value: EVENING = 5; + */ + EVENING = 5, + + /** + * @generated from enum value: AFTERHOURS = 6; + */ + AFTERHOURS = 6, + + /** + * @generated from enum value: HOLIDAY = 7; + */ + HOLIDAY = 7, +} + +/** + * Describes the enum dbag.cef.Data.TradingSessionIDValue.TradingSessionID. + */ +export const Data_TradingSessionIDValue_TradingSessionIDSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 2, 0) + +/** + * @generated from message dbag.cef.Data.TradingSessionSubIDValue + */ +export type Data_TradingSessionSubIDValue = Message<'dbag.cef.Data.TradingSessionSubIDValue'> & { + /** + * @generated from field: dbag.cef.Data.TradingSessionSubIDValue.TradingSessionSubID Value = 1; + */ + Value: Data_TradingSessionSubIDValue_TradingSessionSubID +} + +/** + * Describes the message dbag.cef.Data.TradingSessionSubIDValue. + * Use `create(Data_TradingSessionSubIDValueSchema)` to create a new message. + */ +export const Data_TradingSessionSubIDValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 3) + +/** + * @generated from enum dbag.cef.Data.TradingSessionSubIDValue.TradingSessionSubID + */ +export enum Data_TradingSessionSubIDValue_TradingSessionSubID { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: PRETRADING = 1; + */ + PRETRADING = 1, + + /** + * @generated from enum value: CONTINUOUS = 3; + */ + CONTINUOUS = 3, + + /** + * @generated from enum value: CLOSING = 4; + */ + CLOSING = 4, + + /** + * @generated from enum value: POSTTRADING = 5; + */ + POSTTRADING = 5, + + /** + * @generated from enum value: SCHEDULEDINTRADAYAUCTION = 6; + */ + SCHEDULEDINTRADAYAUCTION = 6, + + /** + * @generated from enum value: QUIESCENT = 7; + */ + QUIESCENT = 7, + + /** + * @generated from enum value: ANYAUCTION = 8; + */ + ANYAUCTION = 8, + + /** + * @generated from enum value: CONTINUOUSAUCTIONISSUER = 103; + */ + CONTINUOUSAUCTIONISSUER = 103, + + /** + * @generated from enum value: CONTINUOUSAUCTIONSPECIALIST = 104; + */ + CONTINUOUSAUCTIONSPECIALIST = 104, +} + +/** + * Describes the enum dbag.cef.Data.TradingSessionSubIDValue.TradingSessionSubID. + */ +export const Data_TradingSessionSubIDValue_TradingSessionSubIDSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 3, 0) + +/** + * @generated from message dbag.cef.Data.MarketConditionValue + */ +export type Data_MarketConditionValue = Message<'dbag.cef.Data.MarketConditionValue'> & { + /** + * @generated from field: dbag.cef.Data.MarketConditionValue.MarketCondition Value = 1; + */ + Value: Data_MarketConditionValue_MarketCondition +} + +/** + * Describes the message dbag.cef.Data.MarketConditionValue. + * Use `create(Data_MarketConditionValueSchema)` to create a new message. + */ +export const Data_MarketConditionValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 4) + +/** + * @generated from enum dbag.cef.Data.MarketConditionValue.MarketCondition + */ +export enum Data_MarketConditionValue_MarketCondition { + /** + * @generated from enum value: NORMAL = 0; + */ + NORMAL = 0, + + /** + * @generated from enum value: STRESSED = 1; + */ + STRESSED = 1, + + /** + * @generated from enum value: EXCEPTIONAL = 2; + */ + EXCEPTIONAL = 2, +} + +/** + * Describes the enum dbag.cef.Data.MarketConditionValue.MarketCondition. + */ +export const Data_MarketConditionValue_MarketConditionSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 4, 0) + +/** + * @generated from message dbag.cef.Data.TrdTypeValue + */ +export type Data_TrdTypeValue = Message<'dbag.cef.Data.TrdTypeValue'> & { + /** + * @generated from field: dbag.cef.Data.TrdTypeValue.TrdType Value = 1; + */ + Value: Data_TrdTypeValue_TrdType +} + +/** + * Describes the message dbag.cef.Data.TrdTypeValue. + * Use `create(Data_TrdTypeValueSchema)` to create a new message. + */ +export const Data_TrdTypeValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 5) + +/** + * @generated from enum dbag.cef.Data.TrdTypeValue.TrdType + */ +export enum Data_TrdTypeValue_TrdType { + /** + * @generated from enum value: REGULARTRADE = 0; + */ + REGULARTRADE = 0, + + /** + * @generated from enum value: BLOCKTRADE = 1; + */ + BLOCKTRADE = 1, + + /** + * @generated from enum value: EFP = 2; + */ + EFP = 2, + + /** + * @generated from enum value: EXCHANGEFORSWAP = 12; + */ + EXCHANGEFORSWAP = 12, + + /** + * @generated from enum value: PORTFOLIOCOMPRESSIONTRADE = 50; + */ + PORTFOLIOCOMPRESSIONTRADE = 50, + + /** + * @generated from enum value: OTC = 54; + */ + OTC = 54, + + /** + * @generated from enum value: EXCHANGEBASISFACILITY = 55; + */ + EXCHANGEBASISFACILITY = 55, + + /** + * @generated from enum value: VOLATRADE = 1000; + */ + VOLATRADE = 1000, + + /** + * @generated from enum value: EFPFINTRADE = 1001; + */ + EFPFINTRADE = 1001, + + /** + * @generated from enum value: EFPINDEXFUTURESTRADE = 1002; + */ + EFPINDEXFUTURESTRADE = 1002, + + /** + * @generated from enum value: BLOCKTRADEATMARKET = 1004; + */ + BLOCKTRADEATMARKET = 1004, + + /** + * @generated from enum value: XETRAEUREXENLIGHTTRIGGEREDTRADE = 1006; + */ + XETRAEUREXENLIGHTTRIGGEREDTRADE = 1006, + + /** + * @generated from enum value: BLOCKQTPIPTRADE = 1007; + */ + BLOCKQTPIPTRADE = 1007, + + /** + * @generated from enum value: DELTATRADEATMARKET = 1017; + */ + DELTATRADEATMARKET = 1017, + + /** + * @generated from enum value: OPENINGAUCTIONTRADE = 1100; + */ + OPENINGAUCTIONTRADE = 1100, + + /** + * @generated from enum value: INTRADAYAUCTIONTRADE = 1101; + */ + INTRADAYAUCTIONTRADE = 1101, + + /** + * @generated from enum value: VOLATILITYAUCTIONTRADE = 1102; + */ + VOLATILITYAUCTIONTRADE = 1102, + + /** + * @generated from enum value: CLOSINGAUCTIONTRADE = 1103; + */ + CLOSINGAUCTIONTRADE = 1103, + + /** + * @generated from enum value: CROSSAUCTIONTRADE = 1104; + */ + CROSSAUCTIONTRADE = 1104, + + /** + * @generated from enum value: IPOAUCTIONTRADE = 1107; + */ + IPOAUCTIONTRADE = 1107, + + /** + * @generated from enum value: LIQUIDITYIMPROVEMENTCROSS = 1108; + */ + LIQUIDITYIMPROVEMENTCROSS = 1108, +} + +/** + * Describes the enum dbag.cef.Data.TrdTypeValue.TrdType. + */ +export const Data_TrdTypeValue_TrdTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 5, 0) + +/** + * @generated from message dbag.cef.Data.MDOriginTypeValue + */ +export type Data_MDOriginTypeValue = Message<'dbag.cef.Data.MDOriginTypeValue'> & { + /** + * @generated from field: dbag.cef.Data.MDOriginTypeValue.MDOriginType Value = 1; + */ + Value: Data_MDOriginTypeValue_MDOriginType +} + +/** + * Describes the message dbag.cef.Data.MDOriginTypeValue. + * Use `create(Data_MDOriginTypeValueSchema)` to create a new message. + */ +export const Data_MDOriginTypeValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 6) + +/** + * @generated from enum dbag.cef.Data.MDOriginTypeValue.MDOriginType + */ +export enum Data_MDOriginTypeValue_MDOriginType { + /** + * @generated from enum value: MDOT_BOOK = 0; + */ + MDOT_BOOK = 0, + + /** + * @generated from enum value: MDOT_OFF_BOOK = 1; + */ + MDOT_OFF_BOOK = 1, +} + +/** + * Describes the enum dbag.cef.Data.MDOriginTypeValue.MDOriginType. + */ +export const Data_MDOriginTypeValue_MDOriginTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 6, 0) + +/** + * @generated from message dbag.cef.Data.MDUpdateActionValue + */ +export type Data_MDUpdateActionValue = Message<'dbag.cef.Data.MDUpdateActionValue'> & { + /** + * @generated from field: dbag.cef.Data.MDUpdateActionValue.MDUpdateAction Value = 1; + */ + Value: Data_MDUpdateActionValue_MDUpdateAction +} + +/** + * Describes the message dbag.cef.Data.MDUpdateActionValue. + * Use `create(Data_MDUpdateActionValueSchema)` to create a new message. + */ +export const Data_MDUpdateActionValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 7) + +/** + * @generated from enum dbag.cef.Data.MDUpdateActionValue.MDUpdateAction + */ +export enum Data_MDUpdateActionValue_MDUpdateAction { + /** + * @generated from enum value: NEW = 0; + */ + NEW = 0, + + /** + * @generated from enum value: CHANGE = 1; + */ + CHANGE = 1, + + /** + * @generated from enum value: DELETE = 2; + */ + DELETE = 2, +} + +/** + * Describes the enum dbag.cef.Data.MDUpdateActionValue.MDUpdateAction. + */ +export const Data_MDUpdateActionValue_MDUpdateActionSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 7, 0) + +/** + * @generated from message dbag.cef.Data.PriceTypeValue + */ +export type Data_PriceTypeValue = Message<'dbag.cef.Data.PriceTypeValue'> & { + /** + * @generated from field: dbag.cef.Data.PriceTypeValue.PriceType Value = 1; + */ + Value: Data_PriceTypeValue_PriceType +} + +/** + * Describes the message dbag.cef.Data.PriceTypeValue. + * Use `create(Data_PriceTypeValueSchema)` to create a new message. + */ +export const Data_PriceTypeValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 8) + +/** + * @generated from enum dbag.cef.Data.PriceTypeValue.PriceType + */ +export enum Data_PriceTypeValue_PriceType { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: PERCENTAGE = 1; + */ + PERCENTAGE = 1, + + /** + * @generated from enum value: PER_UNIT = 2; + */ + PER_UNIT = 2, + + /** + * @generated from enum value: YIELD = 9; + */ + YIELD = 9, + + /** + * @generated from enum value: PRICE_SPREAD = 12; + */ + PRICE_SPREAD = 12, + + /** + * @generated from enum value: NORMAL_RATE = 20; + */ + NORMAL_RATE = 20, + + /** + * @generated from enum value: BASIS_POINT = 22; + */ + BASIS_POINT = 22, +} + +/** + * Describes the enum dbag.cef.Data.PriceTypeValue.PriceType. + */ +export const Data_PriceTypeValue_PriceTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 8, 0) + +/** + * @generated from message dbag.cef.Data.MarketSegmentStatusValue + */ +export type Data_MarketSegmentStatusValue = Message<'dbag.cef.Data.MarketSegmentStatusValue'> & { + /** + * @generated from field: dbag.cef.Data.MarketSegmentStatusValue.MarketSegmentStatus Value = 1; + */ + Value: Data_MarketSegmentStatusValue_MarketSegmentStatus +} + +/** + * Describes the message dbag.cef.Data.MarketSegmentStatusValue. + * Use `create(Data_MarketSegmentStatusValueSchema)` to create a new message. + */ +export const Data_MarketSegmentStatusValueSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 9) + +/** + * @generated from enum dbag.cef.Data.MarketSegmentStatusValue.MarketSegmentStatus + */ +export enum Data_MarketSegmentStatusValue_MarketSegmentStatus { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * @generated from enum value: ACTIVE = 1; + */ + ACTIVE = 1, + + /** + * @generated from enum value: INACTIVE = 2; + */ + INACTIVE = 2, + + /** + * @generated from enum value: PUBLISHED = 3; + */ + PUBLISHED = 3, +} + +/** + * Describes the enum dbag.cef.Data.MarketSegmentStatusValue.MarketSegmentStatus. + */ +export const Data_MarketSegmentStatusValue_MarketSegmentStatusSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 9, 0) + +/** + * @generated from message dbag.cef.Data.MDEntryPrices + */ +export type Data_MDEntryPrices = Message<'dbag.cef.Data.MDEntryPrices'> & { + /** + * FIX 269 - MDEntryType + * + * @generated from field: dbag.cef.Data.MDEntryPrices.MDEntryType Typ = 1; + */ + Typ: Data_MDEntryPrices_MDEntryType + + /** + * FIX 270 - MDEntryPrice + * + * @generated from field: dbag.cef.Decimal Px = 2; + */ + Px?: Decimal + + /** + * FIX 271 - MDEntrySize + * + * @generated from field: dbag.cef.Decimal Sz = 3; + */ + Sz?: Decimal + + /** + * FIX 273 - MDEntryTime + * + * @generated from field: uint64 Tm = 4; + */ + Tm: bigint + + /** + * FIX 423 - PriceType + * + * @generated from field: dbag.cef.Data.PriceTypeValue PxTyp = 5; + */ + PxTyp?: Data_PriceTypeValue +} + +/** + * Describes the message dbag.cef.Data.MDEntryPrices. + * Use `create(Data_MDEntryPricesSchema)` to create a new message. + */ +export const Data_MDEntryPricesSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_md_cef, 4, 10) + +/** + * @generated from enum dbag.cef.Data.MDEntryPrices.MDEntryType + */ +export enum Data_MDEntryPrices_MDEntryType { + /** + * @generated from enum value: UNDEFINED = 0; + */ + UNDEFINED = 0, + + /** + * FIX '4' + * + * @generated from enum value: OPENING_PRICE = 1; + */ + OPENING_PRICE = 1, + + /** + * FIX '5' + * + * @generated from enum value: CLOSING_PRICE = 2; + */ + CLOSING_PRICE = 2, + + /** + * FIX '6' + * + * @generated from enum value: SETTLEMENT_PRICE = 3; + */ + SETTLEMENT_PRICE = 3, + + /** + * FIX 'C' + * + * @generated from enum value: OPEN_INTEREST = 4; + */ + OPEN_INTEREST = 4, + + /** + * FIX 'Q' + * + * @generated from enum value: AUCTION_CLEARING_PRICE = 5; + */ + AUCTION_CLEARING_PRICE = 5, + + /** + * FIX 'e' + * + * @generated from enum value: PREVIOUS_CLOSING_PRICE = 6; + */ + PREVIOUS_CLOSING_PRICE = 6, + + /** + * FIX 'M' + * + * @generated from enum value: PRIOR_SETTLEMENT_PRICE = 7; + */ + PRIOR_SETTLEMENT_PRICE = 7, + + /** + * FIX 'H' + * + * @generated from enum value: MID_PRICE = 8; + */ + MID_PRICE = 8, +} + +/** + * Describes the enum dbag.cef.Data.MDEntryPrices.MDEntryType. + */ +export const Data_MDEntryPrices_MDEntryTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 10, 0) + +/** + * @generated from enum dbag.cef.Data.TradeCondition + */ +export enum Data_TradeCondition { + /** + * FIX Exchange Last + * + * @generated from enum value: U = 0; + */ + U = 0, + + /** + * FIX Opening Price + * + * @generated from enum value: R = 1; + */ + R = 1, + + /** + * FIX Official Close Price + * + * @generated from enum value: AJ = 2; + */ + AJ = 2, + + /** + * FIX Last Auction Price + * + * @generated from enum value: AW = 3; + */ + AW = 3, + + /** + * FIX High Price + * + * @generated from enum value: AX = 4; + */ + AX = 4, + + /** + * FIX Low Price + * + * @generated from enum value: AY = 5; + */ + AY = 5, + + /** + * FIX Previous Closing Price + * + * @generated from enum value: BD = 6; + */ + BD = 6, + + /** + * FIX Midpoint Price //TODO cleanup this in T7 12.1 + * + * @generated from enum value: BB = 7; + */ + BB = 7, + + /** + * FIX Trading On Terms Of issue + * + * @generated from enum value: BC = 8; + */ + BC = 8, + + /** + * FIX Special Auction + * + * @generated from enum value: SA = 9; + */ + SA = 9, + + /** + * FIX Trade At Close + * + * @generated from enum value: TC = 10; + */ + TC = 10, + + /** + * FIX Out of Sequence + * + * @generated from enum value: k = 11; + */ + k = 11, + + /** + * FIX Volume Only + * + * @generated from enum value: a = 12; + */ + a = 12, + + /** + * Retail + * + * @generated from enum value: XR = 13; + */ + XR = 13, +} + +/** + * Describes the enum dbag.cef.Data.TradeCondition. + */ +export const Data_TradeConditionSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 4, 0) + +/** + * @generated from message dbag.cef.MarketData + */ +export type MarketData = Message<'dbag.cef.MarketData'> & { + /** + * FIX 35 - Message Type + * + * @generated from field: dbag.cef.MarketData.MessageType MsgTyp = 1; + */ + MsgTyp: MarketData_MessageType + + /** + * FIX: ApplicationSequenceControl + * + * @generated from field: dbag.cef.ApplSeqCtrl Seq = 2; + */ + Seq?: ApplSeqCtrl + + /** + * FIX: Instrument + * + * @generated from field: dbag.cef.Instrument Instrmt = 3; + */ + Instrmt?: Instrument + + /** + * @generated from field: dbag.cef.Data Dat = 4; + */ + Dat?: Data +} + +/** + * Describes the message dbag.cef.MarketData. + * Use `create(MarketDataSchema)` to create a new message. + */ +export const MarketDataSchema: GenMessage = /*@__PURE__*/ messageDesc(file_md_cef, 5) + +/** + * @generated from enum dbag.cef.MarketData.MessageType + */ +export enum MarketData_MessageType { + /** + * MarketDataIncrementalRefresh + * + * @generated from enum value: X = 0; + */ + X = 0, + + /** + * MarketDataSnapshotFullRefresh + * + * @generated from enum value: W = 1; + */ + W = 1, +} + +/** + * Describes the enum dbag.cef.MarketData.MessageType. + */ +export const MarketData_MessageTypeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_md_cef, 5, 0) diff --git a/packages/sources/deutsche-boerse/src/index.ts b/packages/sources/deutsche-boerse/src/index.ts new file mode 100644 index 0000000000..49f51bc0d0 --- /dev/null +++ b/packages/sources/deutsche-boerse/src/index.ts @@ -0,0 +1,13 @@ +import { expose, ServerInstance } from '@chainlink/external-adapter-framework' +import { Adapter } from '@chainlink/external-adapter-framework/adapter' +import { config } from './config' +import { lwba } from './endpoint' + +export const adapter = new Adapter({ + defaultEndpoint: lwba.name, + name: 'DEUTSCHE_BOERSE', + config, + endpoints: [lwba], +}) + +export const server = (): Promise => expose(adapter) diff --git a/packages/sources/deutsche-boerse/src/proto/client.proto b/packages/sources/deutsche-boerse/src/proto/client.proto new file mode 100644 index 0000000000..ecb7c24efb --- /dev/null +++ b/packages/sources/deutsche-boerse/src/proto/client.proto @@ -0,0 +1,60 @@ +// Source: https://github.com/Deutsche-Boerse/Cloud.Stream.Client/blob/main/proto/src/client.proto +// Date: 07.10.2023 +// Version: 001.000.006 + +syntax = "proto3"; + +import "google/protobuf/any.proto"; + +package Client; + +message Subscribe +{ + message Stream + { + string stream = 1; + int64 startTime = 2; // mutually exclusive to startSeq + uint64 startSeq = 3; // mutually exclusive to startTime + } + + repeated Stream stream = 1; +} + +message Unsubscribe +{ + repeated string stream = 1; +} + +message Request +{ + string event = 1; + int64 requestId = 2; + //oneof data { + Subscribe subscribe = 3; + Unsubscribe unsubscribe = 4; + //} +} + +enum Status { + OK = 0; + SERVER_ERROR = 1; + ACCESS_DENIED = 2; + NOT_ENTITLED = 3; +} + +//one Response for each stream in Request +message Response +{ + int64 requestId = 1; + Status status = 2; +} + +message StreamMessage +{ + // protocol + string subs = 1; // stream / topic subscription + uint64 seq = 2; // message sequence number + + // payload + repeated google.protobuf.Any messages = 3; +} diff --git a/packages/sources/deutsche-boerse/src/proto/md_cef.proto b/packages/sources/deutsche-boerse/src/proto/md_cef.proto new file mode 100644 index 0000000000..a51d4b6880 --- /dev/null +++ b/packages/sources/deutsche-boerse/src/proto/md_cef.proto @@ -0,0 +1,508 @@ +// Source: https://github.com/Deutsche-Boerse/Cloud.Stream.Client/blob/main/proto/src/md_cef.proto +// Date: 10.01.2025 +// Version: 001.000.009 + +syntax = "proto3"; + +import "google/protobuf/wrappers.proto"; + +package dbag.cef; + + +message Decimal +{ + int64 m = 1; // Mantisssa + int32 e = 2; // Exponent +} + +message ApplSeqCtrl +{ + uint32 ApplID = 1; // FIX 1180 - ApplID + uint64 ApplSeqNum = 2; // FIX 1181 - ApplSeqNum +} + +message Instrument +{ + enum SecurityIDSource // FIX 22 + { + ISIN = 0; + EXCHANGE_SYMBOL = 1; + SYNTHETIC = 2; + } + + message PutOrCallValue + { + enum PutOrCall // FIX 201 + { + PUT = 0; // FIX Put + CALL = 1; // FIX Call + } + + PutOrCall Value = 1; + } + + enum SecurityType // FIX 167 + { + NO_SECURITYTYPE = 0; // None + FUT = 1; // Future + OPT = 2; // Option + MLEG = 3; // Multileg Instrument + INDEX = 4; // Index + ETC = 5; // Exchange traded commodity + ETN = 6; // Exchange traded note + CS = 7; // Common Stock + REPO = 8; // Repurchase + CASH = 9; // Repurchase + FOR = 10; // Foreign Exchange Contract + BOND = 11; // Bond + MF = 12; // Mutual Fund + FUN = 13; // Investment Fund + IRS = 14; // Interest Rate Swap + SR = 15; // Subscription Rights + WAR = 16; // Warrant + ETF = 17; // Exchange Traded Fund + FXSWAP = 18; // FX Swap + OTHER = 99; // Other + } + + message SettlMethodValue + { + enum SettlMethod // FIX 1193 + { + C = 0; // Cash + P = 1; // Physical + } + + SettlMethod Value = 1; + } + + message ExerciseStyleValue + { + enum ExerciseStyle // FIX 1194 + { + E = 0; // European + A = 1; // American + } + + ExerciseStyle Value = 1; + } + + message ContractTypeValue + { + enum ContractType + { + F = 0; // Flexible + S = 1; // Standard + } + + ContractType Value = 1; + } + + message SecurityUpdateActionValue + { + enum SecurityUpdateAction // FIX 980 + { + NEW = 0; // 'A' + DELETE = 1; // 'D' + MODIFY = 2; // 'M' + } + + SecurityUpdateAction Value = 1; + } + + message Event + { + enum EventType + { + UNDEFINED = 0; + ACTIVATION = 5; + INACTIVATION = 6; + LAST_ELIGIBLE_TRADE_DATE = 7; + FIRST_ELIGIBLE_TRADE_DATE = 28; + } + + EventType EventTyp = 1; // FIX 865 EventType + uint32 Dt = 2; // FIX 866 EventDate + } + + string MktID = 1; // FIX 1301 MarketID + string Sym = 2; // FIX 55 - Symbol + string ID = 3; // FIX 48 - SecurityID + SecurityIDSource Src = 4; // FIX 22 - SecurityIDSource + SecurityType SecTyp = 5; // FIX 167 - SecurityType + string Ccy = 6; // FIX 15 - Currency + string AltID = 7; // FIX 455 - SecurityAltID + SecurityIDSource AltIDSrc = 8; // FIX 456 - SecurityAltIDSource + string MktSeg = 9; // FIX 7703 - MarketSegment + + string MMY = 11; // FIX 200 - MaturityMonthYear + google.protobuf.Int32Value CntrDate = 12; // FIX T7 extension 30866 - ContractDate + ContractTypeValue Ct = 13; // FIX CEF extension - ContractType + Decimal StrkPx = 14; // FIX 202 StrikePrice + Decimal OrigStrkPx = 15; // FIX 2578 - OrigStrikePrice + PutOrCallValue PutCall = 16; // FIX 201 - PutOrCall + google.protobuf.Int32Value CntrGenNr = 17; // FIX T7 extension 25034 - ContractGenerationNumber + SettlMethodValue SettlMeth = 18; // FIX 1193 - SettlMethod + ExerciseStyleValue ExerStyle = 19; // FIX 1194 - ExerStyle + + Decimal MinPxIncr = 21; // FIX 969 - MinPriceIncrement + string TenorVal = 22; // FIX 6215 - TenorValue + + SecurityUpdateActionValue UpdActn = 30; // FIX 980 - SecurityUpdateAction + uint64 LastUpdateTm = 31; // FIX 779 - LastUpdateTime + repeated Event Evnts = 32; // FIX EventGroup +} + +message QuoteSide +{ + message MDQuoteTypeValue { + enum MDQuoteType // FIX 1070 + { + INDICATIVE = 0; + TRADEABLE = 1; + } + + MDQuoteType Value = 1; + } + + message QuoteConditionValue { + enum QuoteCondition { // FIX 276 + FIRM = 0; + INDICATIVE = 1; + } + + QuoteCondition Value = 1; + } + + message MDEntryTypeValue { + enum MDEntryType // FIX 269 + { + BID = 0; + OFFER = 1; + MARKET_BID = 11; + MARKET_OFFER = 12; + } + + MDEntryType Value = 1; + } + + message HolidayWarnValue { + enum HolidayWarn { // FIX 5679 (360T) + NO_HOLIDAYS = 0; + HOLIDAYS = 1; + } + + HolidayWarn Value = 1; + } + + + Decimal Px = 1; // FIX 270 - MDEntryPrice + Decimal Sz = 2; // FIX 271 - MDEntrySize + google.protobuf.Int32Value NumOfOrds = 3; // FIX 346 - NumberOfOrders + MDQuoteTypeValue MDQteTyp = 4; // FIX 1070 - MDQuoteType + MDEntryTypeValue Typ = 5; // FIX 269 - MDEntryType + QuoteConditionValue QCond = 6; // FIX 276 - QuoteCondition + Decimal FwdPnts = 7; // FIX 5675 (360T) - ForwardPoints + int64 Pip = 8; // FIX 5678 (360T) - Pip + HolidayWarnValue HlWrn = 9; // FIX 5679 (360T) - HolidayWarn +} + +message Data +{ + message SecurityStatusValue + { + enum SecurityStatus // FIX 965 + { + UNDEFINED = 0; + ACTIVE = 1; + INACTIVE = 2; + EXPIRED = 4; + DELISTED = 5; + KNOCKED_OUT = 6; + SUSPENDED = 9; + PUBLISHED = 10; + PENDING_DELETION = 11; + KNOCKED_OUT_AND_SUSPENDED = 12; + } + + SecurityStatus Value = 1; + } + + message SecurityTradingStatusValue + { + enum SecurityTradingStatus // FIX 326 + { + UNDEFINED = 0; + OPENING_DELAY = 1; + TRADINGHALT = 2; + RESUME = 3; + NOT_TRADED_ON_THIS_MARKET = 19; + FAST_MARKET = 23; + CLOSED = 200; + RESTRICTED = 201; + BOOK = 202; + CONTINUOUS = 203; + OPENINGAUCTION = 204; + OPENINGAUCTIONFREEZE = 205; + INTRADAYAUCTION = 206; + INTRADAYAUCTIONFREEZE = 207; + CIRCUITBREAKERAUCTION = 208; + CIRCUITBREAKERAUCTIONFREEZE = 209; + CLOSINGAUCTION = 210; + CLOSINGAUCTIONFREEZE = 211; + IPOAUCTION = 212; + IPOAUCTIONFREEZE = 213; + PRECALL = 214; + CALL = 215; + FREEZE = 216; + TRADEATCLOSE = 217; + } + + SecurityTradingStatus Value = 1; + } + + message TradingSessionIDValue + { + enum TradingSessionID // FIX 336 + { + UNDEFINED = 0; + DAY = 1; + HALFDAY = 2; + MORNING = 3; + AFTERNOON = 4; + EVENING = 5; + AFTERHOURS = 6; + HOLIDAY = 7; + } + + TradingSessionID Value = 1; + } + + message TradingSessionSubIDValue + { + enum TradingSessionSubID // FIX 625 + { + UNDEFINED = 0; + PRETRADING = 1; + CONTINUOUS = 3; + CLOSING = 4; + POSTTRADING = 5; + SCHEDULEDINTRADAYAUCTION = 6; + QUIESCENT = 7; + ANYAUCTION = 8; + CONTINUOUSAUCTIONISSUER = 103; + CONTINUOUSAUCTIONSPECIALIST = 104; + } + + TradingSessionSubID Value = 1; + } + + message MarketConditionValue + { + enum MarketCondition + { + NORMAL = 0; + STRESSED = 1; + EXCEPTIONAL = 2; + } + + MarketCondition Value = 1; + } + + message TrdTypeValue + { + enum TrdType + { + REGULARTRADE = 0; + BLOCKTRADE = 1; + EFP = 2; + EXCHANGEFORSWAP = 12; + PORTFOLIOCOMPRESSIONTRADE = 50; + OTC = 54; + EXCHANGEBASISFACILITY = 55; + VOLATRADE = 1000; + EFPFINTRADE = 1001; + EFPINDEXFUTURESTRADE = 1002; + BLOCKTRADEATMARKET = 1004; + XETRAEUREXENLIGHTTRIGGEREDTRADE = 1006; + BLOCKQTPIPTRADE = 1007; + DELTATRADEATMARKET = 1017; + OPENINGAUCTIONTRADE = 1100; + INTRADAYAUCTIONTRADE = 1101; + VOLATILITYAUCTIONTRADE = 1102; + CLOSINGAUCTIONTRADE = 1103; + CROSSAUCTIONTRADE = 1104; + IPOAUCTIONTRADE = 1107; + LIQUIDITYIMPROVEMENTCROSS = 1108; + } + + TrdType Value = 1; + } + + message MDOriginTypeValue + { + enum MDOriginType // FIX 1024 + { + MDOT_BOOK = 0; + MDOT_OFF_BOOK = 1; + } + + MDOriginType Value = 1; + } + + message MDUpdateActionValue + { + enum MDUpdateAction // FIX 279 + { + NEW = 0; + CHANGE = 1; + DELETE = 2; + } + + MDUpdateAction Value = 1; + } + + enum TradeCondition // FIX 277 + { + U = 0; // FIX Exchange Last + R = 1; // FIX Opening Price + AJ = 2; // FIX Official Close Price + AW = 3; // FIX Last Auction Price + AX = 4; // FIX High Price + AY = 5; // FIX Low Price + BD = 6; // FIX Previous Closing Price + BB = 7; // FIX Midpoint Price //TODO cleanup this in T7 12.1 + BC = 8; // FIX Trading On Terms Of issue + SA = 9; // FIX Special Auction + TC = 10; // FIX Trade At Close + k = 11; // FIX Out of Sequence + a = 12; // FIX Volume Only + XR = 13; // Retail + } + + message PriceTypeValue + { + enum PriceType // FIX 423 + { + UNDEFINED = 0; + PERCENTAGE = 1; + PER_UNIT = 2; + YIELD = 9; + PRICE_SPREAD = 12; + NORMAL_RATE = 20; + BASIS_POINT = 22; + } + + PriceType Value = 1; + } + + message MarketSegmentStatusValue + { + enum MarketSegmentStatus // FIX 2542 + { + UNDEFINED = 0; + ACTIVE = 1; + INACTIVE = 2; + PUBLISHED = 3; + } + + MarketSegmentStatus Value = 1; + } + + message MDEntryPrices + { + enum MDEntryType + { + UNDEFINED = 0; + OPENING_PRICE = 1; // FIX '4' + CLOSING_PRICE = 2; // FIX '5' + SETTLEMENT_PRICE = 3; // FIX '6' + OPEN_INTEREST = 4; // FIX 'C' + AUCTION_CLEARING_PRICE = 5; // FIX 'Q' + PREVIOUS_CLOSING_PRICE = 6; // FIX 'e' + PRIOR_SETTLEMENT_PRICE = 7; // FIX 'M' + MID_PRICE = 8; // FIX 'H' + } + + MDEntryType Typ = 1; // FIX 269 - MDEntryType + Decimal Px = 2; // FIX 270 - MDEntryPrice + Decimal Sz = 3; // FIX 271 - MDEntrySize + uint64 Tm = 4; // FIX 273 - MDEntryTime + PriceTypeValue PxTyp = 5; // FIX 423 - PriceType + } + + + // Quote + QuoteSide Bid = 1; // MDEntryType = 0 or MDEntryType = 'b' + QuoteSide Offer = 2; // MDEntryType = 1 or MDEntryType = 'c' + PriceTypeValue PxTyp = 3; // FIX 423 - PriceType + + // State Change + SecurityStatusValue Status = 11; // FIX 965 - SecurityStatus + TradingSessionIDValue SesID = 12; // FIX 336 - TradingSessionID + TradingSessionSubIDValue SesSub = 13; // FIX 625 - TradingSessionSubID + google.protobuf.BoolValue FastMktInd = 14; // FIX 2447 - FastMktInd + SecurityTradingStatusValue TrdgStat = 15; // FIX 326 - SecurityTradingStatus + MarketConditionValue MktCond = 16; // FIX 2705 - MarketCondition + SecurityStatusValue TesStatus = 17; // FIX 25045 - TESSecurityStatus + MarketSegmentStatusValue MktSegStat = 18; // FIX 2542 - Market Segment Status + + // Trade + Decimal Px = 21; // FIX 270 - MDEntryPrice + Decimal Sz = 22; // FIX 271 - MDEntrySize + TrdTypeValue TrdTyp = 23; // FIX 828 - TrDType + google.protobuf.Int32Value NumOfBuyOrds = 24; // FIX 2449 - NumberOfBuyOrders + google.protobuf.Int32Value NumOfSellOrds = 25; // FIX 2450 - NumberOfSellOrders + MDOriginTypeValue MDOrigTyp = 26; // FIX 1024 - MDOriginType + string Ccy = 27; // FIX 15 - Currency + string MDID = 28; // FIX 278 - MDEntryID + string MtchID = 29; // FIX 880 - TrdMatchID (TVTIC - Trading Venue Transaction Identification Code) + MDUpdateActionValue UpdtAct = 30; // FIX 279 - MDUpdateAction + repeated TradeCondition TrdCond = 31; // FIX 277 - TradeCondition + + // Book + repeated QuoteSide Bids = 41; // MDEntryType = 0 + repeated QuoteSide Offers = 42; // MDEntryType = 1 + + // Clearing + Decimal StlPx = 51; // FIX 270 FIX 269@6 - MDEntryPx + MDEntryType=6 (Settlement Price) + Decimal Int = 52; // FIX 270 FIX 269@C - MDEntryPx + MDEntryType=C (Open Interest) + Decimal SettlCurrAmt = 53; // FIX 119 - Settlement Currency Amount / Nominal Amount + string SettlCcy = 54; // FIX 120 - Settlement Currency + string SettlDt = 55; // FIX 64 - SettlementDate + + // Statistics & Others + Decimal PaPx = 61; // FIX - Potential Auction Price + Decimal OpenPx = 62; // FIX 270 & FIX 269@4 - MDEntryPx + MDEntryType=4 (Opening Price) + Decimal ClosePx = 63; // FIX 270 & FIX 269@5 - MDEntryPx + MDEntryType=5 (Closing Price) + Decimal HighPx = 64; // FIX 332 - High Price + Decimal LowPx = 65; // FIX 333 - Low Price + Decimal AvgPx = 66; // Average Price + Decimal TrdVol = 67; // FIX 1020 - Trade Volume + Decimal Ttt = 68; // Total Turnover + google.protobuf.Int32Value TrdNum = 69; // FIX 2490 - Trade Number + google.protobuf.Int32Value TrdNumTes = 70; // Trade Number Tes + google.protobuf.UInt64Value ClsTim = 71; // FIX 344 - Close Time + Decimal RefPx = 72; // FIX 270 FIX 269@2 FIX 271=0 - MDEntryPx + MDEntryType=2 (Reference Price) + repeated MDEntryPrices Pxs = 73; // FIX 269 & FIX 270 & FIX 271 + + // Reference + string Val = 81; // FIX 234 - StipulationValue + + // Timestamp + uint64 Tm = 99; // FIX 273 - MDEntryTime +} + +message MarketData +{ + enum MessageType // FIX 35 + { + X = 0; // MarketDataIncrementalRefresh + W = 1; // MarketDataSnapshotFullRefresh + } + + MessageType MsgTyp = 1; // FIX 35 - Message Type + ApplSeqCtrl Seq = 2; // FIX: ApplicationSequenceControl + Instrument Instrmt = 3; // FIX: Instrument + Data Dat = 4; +} diff --git a/packages/sources/deutsche-boerse/src/transport/instrument-quote-cache.ts b/packages/sources/deutsche-boerse/src/transport/instrument-quote-cache.ts new file mode 100644 index 0000000000..551eede4eb --- /dev/null +++ b/packages/sources/deutsche-boerse/src/transport/instrument-quote-cache.ts @@ -0,0 +1,49 @@ +import Decimal from 'decimal.js' + +export type Quote = { + bid?: number + ask?: number + mid?: number + latestPrice?: number + quoteProviderTimeUnixMs?: number + tradeProviderTimeUnixMs?: number +} + +export class InstrumentQuoteCache { + private readonly map = new Map() + + activate(isin: string) { + if (!this.map.has(isin)) this.map.set(isin, {}) + } + deactivate(isin: string) { + this.map.delete(isin) + } + has(isin: string): boolean { + return this.map.has(isin) + } + get(isin: string): Quote | undefined { + return this.map.get(isin) + } + addQuote(isin: string, bid: number, ask: number, providerTime: number) { + const quote = this.get(isin) + if (!quote) { + throw new Error(`Cannot add quote for inactive ISIN ${isin}`) + } + const mid = new Decimal(bid).plus(ask).div(2) + quote.bid = bid + quote.ask = ask + quote.mid = mid.toNumber() + quote.quoteProviderTimeUnixMs = providerTime + } + addTrade(isin: string, lastPrice: number, providerTime: number) { + const quote = this.get(isin) + if (!quote) { + throw new Error(`Cannot add trade for inactive ISIN ${isin}`) + } + quote.latestPrice = lastPrice + quote.tradeProviderTimeUnixMs = providerTime + } + isEmpty(): boolean { + return this.map.size === 0 + } +} diff --git a/packages/sources/deutsche-boerse/src/transport/lwba.ts b/packages/sources/deutsche-boerse/src/transport/lwba.ts new file mode 100644 index 0000000000..668bf68dcc --- /dev/null +++ b/packages/sources/deutsche-boerse/src/transport/lwba.ts @@ -0,0 +1,238 @@ +import { create, fromBinary, toBinary } from '@bufbuild/protobuf' +import { makeLogger } from '@chainlink/external-adapter-framework/util' +import { BaseEndpointTypes, Market, MARKETS } from '../endpoint/lwba' +import { + RequestSchema, + StreamMessageSchema, + SubscribeSchema, + UnsubscribeSchema, + type StreamMessage, +} from '../gen/client_pb' +import { MarketDataSchema, type MarketData } from '../gen/md_cef_pb' +import { InstrumentQuoteCache } from './instrument-quote-cache' +import { + decimalToNumber, + isSingleQuoteFrame, + isSingleTradeFrame, + parseIsin, + pickProviderTime, +} from './proto-utils' +import { ProtobufWsTransport } from './protobuf-wstransport' + +export type WsTransportTypes = BaseEndpointTypes & { + Provider: { + WsMessage: Buffer + } +} + +const logger = makeLogger('DeutscheBoerseTransport') + +export function createLwbaWsTransport() { + const cache = new InstrumentQuoteCache() + + return new ProtobufWsTransport({ + url: (context) => `${context.adapterSettings.WS_API_ENDPOINT}/stream?format=proto`, + options: async (context) => ({ + headers: { 'X-API-Key': context.adapterSettings.API_KEY }, + followRedirects: true, + }), + handlers: { + open: () => { + logger.info('LWBA websocket connection established') + }, + error: (errorEvent) => { + logger.error({ errorEvent }, 'LWBA websocket error') + }, + close: (closeEvent) => { + const code = (closeEvent as any)?.code + const reason = (closeEvent as any)?.reason + const wasClean = (closeEvent as any)?.wasClean + logger.info({ code, reason, wasClean }, 'LWBA websocket closed') + }, + message(buf) { + logger.debug( + { + payloadType: Buffer.isBuffer(buf) ? 'buffer' : typeof buf, + byteLength: Buffer.isBuffer(buf) ? buf.byteLength : undefined, + }, + 'LWBA websocket message received', + ) + + const sm = decodeStreamMessage(buf) + if (!sm) return [] + + const decoded = decodeSingleMarketData(sm) + if (!decoded) return [] + + const { market, md } = decoded + const result = processMarketData(md, cache) + if (!result) return [] + + const { isin, providerTime } = result + const quote = cache.get(isin) + if (quote == null) { + logger.error({ isin, market }, 'Quote missing from cache after processing frame') + return [] + } + if (quote.mid == null && quote.latestPrice == null) { + logger.error( + { isin, market }, + 'Neither mid nor latestPrice present after processing frame', + ) + throw new Error('Neither mid nor latest price present after processing frame') + } + + return [ + { + params: { isin, market }, + response: { + result: null, + data: { + mid: quote.mid ?? null, + bid: quote.bid ?? null, + ask: quote.ask ?? null, + latestPrice: quote.latestPrice ?? null, + quoteProviderIndicatedTimeUnixMs: quote.quoteProviderTimeUnixMs ?? null, + tradeProviderIndicatedTimeUnixMs: quote.tradeProviderTimeUnixMs ?? null, + }, + timestamps: { providerIndicatedTimeUnixMs: providerTime }, + }, + }, + ] + }, + }, + builders: { + subscribeMessage: (p: { market: string; isin: string }) => { + if (cache.isEmpty()) { + cache.activate(p.isin) + const req = create(RequestSchema, { + event: 'subscribe', + requestId: BigInt(Date.now()), + subscribe: create(SubscribeSchema, { + stream: [{ stream: p.market }], + }), + }) + logger.info( + { isin: p.isin, market: p.market }, + 'Building initial subscribe request (first instrument activates stream)', + ) + return toBinary(RequestSchema, req) + } + cache.activate(p.isin) + logger.debug( + { isin: p.isin, market: p.market }, + 'Instrument activated; stream already subscribed, no outbound subscribe message sent', + ) + return undefined + }, + + unsubscribeMessage: (p: { market: string; isin: string }) => { + cache.deactivate(p.isin) + if (cache.isEmpty()) { + const req = create(RequestSchema, { + event: 'unsubscribe', + requestId: BigInt(Date.now()), + unsubscribe: create(UnsubscribeSchema, { stream: [p.market] }), + }) + logger.info( + { isin: p.isin, market: p.market }, + 'All instruments deactivated; building unsubscribe request', + ) + return toBinary(RequestSchema, req) + } + logger.debug( + { isin: p.isin, market: p.market }, + 'Instrument deactivated; other instruments still active, no outbound unsubscribe sent', + ) + return undefined + }, + }, + }) +} + +// --- helpers ----------------------------------------------------------------- +function decodeStreamMessage(buf: Buffer): StreamMessage | null { + try { + return fromBinary(StreamMessageSchema, buf) + } catch (err) { + logger.error({ err }, 'Failed to decode Client.StreamMessage from binary') + return null + } +} + +function processMarketData( + md: MarketData, + cache: InstrumentQuoteCache, +): { + isin: string + providerTime: number +} | null { + const isin = parseIsin(md) + const dat: any = (md as any)?.Dat ?? {} + + if (!isin) { + logger.warn({ md }, 'Could not parse ISIN from MarketData.Instrmt.Sym') + return null + } + + const quote = cache.get(isin) + if (!quote) { + logger.debug({ isin }, 'Ignoring message for inactive instrument (not in cache)') + return null + } + + const providerTime = pickProviderTime(dat) + + if (isSingleTradeFrame(dat)) { + const latestPrice = decimalToNumber(dat.Px) + cache.addTrade(isin, latestPrice, providerTime) + logger.debug( + { isin, latestPrice, providerTimeUnixMs: providerTime }, + 'Processed single trade frame', + ) + return { isin, providerTime } + } + + if (isSingleQuoteFrame(dat)) { + const bidPx = decimalToNumber(dat!.Bid!.Px) + const askPx = decimalToNumber(dat!.Offer!.Px) + cache.addQuote(isin, bidPx, askPx, providerTime) + logger.debug( + { isin, bid: bidPx, ask: askPx, mid: (bidPx + askPx) / 2, providerTimeUnixMs: providerTime }, + 'Processed single quote frame', + ) + return { isin, providerTime } + } + + logger.debug({ isin, keys: Object.keys(dat ?? {}) }, 'Ignoring unsupported market data frame') + return null +} + +function decodeSingleMarketData(sm: StreamMessage): { market: Market; md: MarketData } | undefined { + const msgs = sm.messages ?? [] + if (msgs.length !== 1) { + logger.warn({ count: msgs.length }, 'Expected exactly one message in StreamMessage') + return + } + const subs = sm.subs ?? '' + let market + if (isMarket(subs)) { + market = subs + } else { + logger.error({ subs }, 'Unsupported market/stream identifier in StreamMessage.subs') + return + } + const anyMsg = msgs[0] + try { + const md = fromBinary(MarketDataSchema, anyMsg.value) + return { market, md } + } catch (err) { + logger.error({ err }, 'Failed to decode MarketData from StreamMessage') + return + } +} + +function isMarket(x: string): x is Market { + return (MARKETS as readonly string[]).includes(x) +} +export const wsTransport = createLwbaWsTransport() diff --git a/packages/sources/deutsche-boerse/src/transport/proto-utils.ts b/packages/sources/deutsche-boerse/src/transport/proto-utils.ts new file mode 100644 index 0000000000..30e5121a39 --- /dev/null +++ b/packages/sources/deutsche-boerse/src/transport/proto-utils.ts @@ -0,0 +1,54 @@ +import Decimal from 'decimal.js' +import type { + Data as DataProto, + Decimal as DecimalProto, + MarketData as MarketDataProto, +} from '../gen/md_cef_pb' +const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER) + +export function decimalToNumber(decimal?: DecimalProto): number { + if (!decimal || decimal.m === undefined || decimal.e === undefined) { + throw new Error('Invalid price') + } + + const { m: mantissa, e: exponent } = decimal + + // Safety: converting a bigint > Number.MAX_SAFE_INTEGER loses precision. + if (mantissa > MAX_SAFE || mantissa < -MAX_SAFE) { + throw new Error(`Invalid price due to potential overflow, mantissa: ${mantissa.toString()}`) + } + + return new Decimal(mantissa.toString()).times(Decimal.pow(10, exponent)).toNumber() +} + +export function convertNsToMs(t?: bigint): number { + if (t == null) { + throw new Error('Invalid timestamp') + } + return Math.floor(Number(t) / 1e6) +} + +export function parseIsin(md: MarketDataProto): string | undefined { + const instr = md.Instrmt + if (!instr) return + const sym = instr.Sym + return (typeof sym === 'string' && sym) || undefined +} + +export function pickProviderTime(dat: DataProto): number { + return convertNsToMs(dat?.Tm) +} + +export function isDecimalPrice(x?: DecimalProto): boolean { + return !!x && (typeof x.m === 'bigint' || typeof x.m === 'number') && typeof x.e === 'number' +} + +// true if this frame is exactly a "single trade price" +export function isSingleTradeFrame(dat?: DataProto): boolean { + return isDecimalPrice(dat?.Px) +} + +// true if this frame carries only a single best bid/offer (not multui-level) +export function isSingleQuoteFrame(dat?: DataProto): boolean { + return isDecimalPrice(dat?.Bid?.Px) && isDecimalPrice(dat?.Offer?.Px) +} diff --git a/packages/sources/deutsche-boerse/src/transport/protobuf-wstransport.ts b/packages/sources/deutsche-boerse/src/transport/protobuf-wstransport.ts new file mode 100644 index 0000000000..e187bdd786 --- /dev/null +++ b/packages/sources/deutsche-boerse/src/transport/protobuf-wstransport.ts @@ -0,0 +1,63 @@ +import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' +import { + WebSocketTransport, + type WebsocketTransportGenerics, +} from '@chainlink/external-adapter-framework/transports' +import WebSocket from 'ws' + +export class ProtobufWsTransport< + T extends WebsocketTransportGenerics, +> extends WebSocketTransport { + private toRawData(payload: unknown): Buffer | null { + // Handle undefined/null payloads gracefully + if (payload === undefined || payload === null) { + return null + } + if (Buffer.isBuffer(payload)) { + return payload + } + if (payload instanceof ArrayBuffer) { + return Buffer.from(new Uint8Array(payload)) + } + if (ArrayBuffer.isView(payload)) { + const v = payload as ArrayBufferView + return Buffer.from(v.buffer, v.byteOffset, v.byteLength) + } + if (typeof payload === 'string') { + return Buffer.from(payload, 'utf8') + } + return Buffer.from(JSON.stringify(payload), 'utf8') + } + + async sendMessages( + _context: EndpointContext, + subscribes: unknown[], + unsubscribes: unknown[], + ): Promise { + ;[...subscribes, ...unsubscribes] + .map((m) => this.toRawData(m)) + .filter((m): m is Buffer => m !== null) + .forEach((m) => this.wsConnection?.send(m)) + } + + deserializeMessage(data: WebSocket.Data): T['Provider']['WsMessage'] { + if (Array.isArray(data) && data.every(Buffer.isBuffer)) { + return Buffer.concat(data as Buffer[]) as unknown as T['Provider']['WsMessage'] + } + if (Buffer.isBuffer(data)) { + return data as unknown as T['Provider']['WsMessage'] + } + if (data instanceof ArrayBuffer) { + return Buffer.from(new Uint8Array(data)) as unknown as T['Provider']['WsMessage'] + } + if (ArrayBuffer.isView(data)) { + const v = data as ArrayBufferView + return Buffer.from( + v.buffer, + v.byteOffset, + v.byteLength, + ) as unknown as T['Provider']['WsMessage'] + } + return data as unknown as T['Provider']['WsMessage'] + } +} diff --git a/packages/sources/deutsche-boerse/test-payload.json b/packages/sources/deutsche-boerse/test-payload.json new file mode 100644 index 0000000000..3de6e3c161 --- /dev/null +++ b/packages/sources/deutsche-boerse/test-payload.json @@ -0,0 +1,6 @@ +{ + "requests": [{ + "isin": "IE00B53L3W79", + "market": "md-xetraetfetp", + }] +} diff --git a/packages/sources/deutsche-boerse/test/integration/__snapshots__/adapter.test.ts.snap b/packages/sources/deutsche-boerse/test/integration/__snapshots__/adapter.test.ts.snap new file mode 100644 index 0000000000..7c9f0c7c4f --- /dev/null +++ b/packages/sources/deutsche-boerse/test/integration/__snapshots__/adapter.test.ts.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`websocket lwba endpoint returns success and exposes quote/trade fields 1`] = ` +{ + "data": { + "ask": 101, + "bid": 100, + "latestPrice": 100.1, + "mid": 100.5, + "quoteProviderIndicatedTimeUnixMs": 5, + "tradeProviderIndicatedTimeUnixMs": 6, + }, + "result": null, + "statusCode": 200, + "timestamps": { + "providerDataReceivedUnixMs": 1018, + "providerDataStreamEstablishedUnixMs": 1010, + "providerIndicatedTimeUnixMs": 6, + }, +} +`; diff --git a/packages/sources/deutsche-boerse/test/integration/adapter.test.ts b/packages/sources/deutsche-boerse/test/integration/adapter.test.ts new file mode 100644 index 0000000000..7a49ff59ba --- /dev/null +++ b/packages/sources/deutsche-boerse/test/integration/adapter.test.ts @@ -0,0 +1,73 @@ +import { WebSocketClassProvider } from '@chainlink/external-adapter-framework/transports' +import { + mockWebSocketProvider, + MockWebsocketServer, + setEnvVariables, + TestAdapter, +} from '@chainlink/external-adapter-framework/util/testing-utils' +import FakeTimers from '@sinonjs/fake-timers' +import { mockWebsocketServer, STREAM, TEST_ISIN } from './fixtures' + +describe('websocket', () => { + let mockWsServer: MockWebsocketServer | undefined + let testAdapter: TestAdapter + const wsBase = 'ws://localhost:9090' + const wsFull = `${wsBase}/stream?format=proto` + let oldEnv: NodeJS.ProcessEnv + + const dataLwba = { + isin: TEST_ISIN, + market: STREAM, + } + + beforeAll(async () => { + oldEnv = { ...process.env } + process.env.WS_API_ENDPOINT = wsBase + process.env.API_KEY = 'fake-api-key' + + mockWebSocketProvider(WebSocketClassProvider) + mockWsServer = mockWebsocketServer(wsFull) + + const { adapter } = await import('./../../src') + testAdapter = await TestAdapter.startWithMockedCache(adapter, { + clock: FakeTimers.install(), + testAdapter: {} as TestAdapter, + }) + + await testAdapter.request(dataLwba) + await testAdapter.waitForCache() + }) + + afterAll(async () => { + setEnvVariables(oldEnv) + mockWsServer?.close() + testAdapter.clock?.uninstall() + await testAdapter.api.close() + }) + + describe('lwba endpoint', () => { + it('returns success and exposes quote/trade fields', async () => { + const response = await testAdapter.request(dataLwba) + const body = response.json() + + expect(response.statusCode).toBe(200) + expect(body.statusCode).toBe(200) + expect(body).toHaveProperty('data') + const d = body.data + expect(d).toHaveProperty('bid') + expect(d).toHaveProperty('ask') + expect(d).toHaveProperty('mid') + expect(d).toHaveProperty('latestPrice') + expect(d).toHaveProperty('quoteProviderIndicatedTimeUnixMs') + expect(d).toHaveProperty('tradeProviderIndicatedTimeUnixMs') + const numOrNull = (v: unknown) => v === null || typeof v === 'number' + expect(numOrNull(d.bid)).toBe(true) + expect(numOrNull(d.ask)).toBe(true) + expect(numOrNull(d.mid)).toBe(true) + expect(numOrNull(d.latestPrice)).toBe(true) + expect(numOrNull(d.quoteProviderIndicatedTimeUnixMs)).toBe(true) + expect(numOrNull(d.tradeProviderIndicatedTimeUnixMs)).toBe(true) + expect(body).toMatchSnapshot() + }) + }) +}) diff --git a/packages/sources/deutsche-boerse/test/integration/fixtures.ts b/packages/sources/deutsche-boerse/test/integration/fixtures.ts new file mode 100644 index 0000000000..86cd697021 --- /dev/null +++ b/packages/sources/deutsche-boerse/test/integration/fixtures.ts @@ -0,0 +1,67 @@ +// test/integration/fixtures.ts +import { create, toBinary } from '@bufbuild/protobuf' +import { MockWebsocketServer } from '@chainlink/external-adapter-framework/util/testing-utils' +// ⬅️ don't rely on Any.pack for tests; just set {typeUrl, value} +import { + Status as ClientStatus, + ResponseSchema, + StreamMessageSchema, +} from '../../src/gen/client_pb' +import { DataSchema, DecimalSchema, MarketDataSchema } from '../../src/gen/md_cef_pb' + +export const STREAM = 'md-xetraetfetp' +export const TEST_ISIN = 'IE00B53L3W79' + +const dec = (m: bigint, e: number) => create(DecimalSchema, { m, e }) + +const u8 = (schema: any, value: any): Uint8Array => toBinary(schema, value) +const toAB = (u: Uint8Array): ArrayBuffer => + u.buffer.slice(u.byteOffset, u.byteOffset + u.byteLength) + +const frame = (typeUrl: string, payload: Uint8Array, seq: bigint): Uint8Array => + u8( + StreamMessageSchema, + create(StreamMessageSchema, { + subs: STREAM, + seq, + messages: [{ typeUrl, value: payload } as any], + }), + ) + +const ack = (requestId: bigint, seq: bigint): Uint8Array => + frame( + 'type.googleapis.com/Client.Response', + u8(ResponseSchema, create(ResponseSchema, { requestId, status: ClientStatus.OK })), + seq, + ) + +const quoteFrame = (seq: bigint): Uint8Array => { + const dat = create(DataSchema, { + Bid: { Px: dec(10000n, -2) }, // 100.00 + Offer: { Px: dec(10100n, -2) }, // 101.00 + Tm: 5_000_000n, // 5 ms + } as any) + const md = create(MarketDataSchema, { Instrmt: { Sym: TEST_ISIN }, Dat: dat } as any) + return frame('type.googleapis.com/dbag.cef.MarketData', u8(MarketDataSchema, md), seq) +} + +const tradeFrame = (seq: bigint): Uint8Array => { + const dat = create(DataSchema, { Px: dec(10010n, -2), Tm: 6_000_000n } as any) + const md = create(MarketDataSchema, { Instrmt: { Sym: TEST_ISIN }, Dat: dat } as any) + return frame('type.googleapis.com/dbag.cef.MarketData', u8(MarketDataSchema, md), seq) +} + +export const mockWebsocketServer = (FULL_URL: string): MockWebsocketServer => { + const server = new MockWebsocketServer(FULL_URL, { mock: false }) + server.on('connection', (socket) => { + // Send subscribe ACK as binary + socket.send(toAB(ack(123456789n, 1n))) + + // After client sends anything, stream quote + trade frames + socket.on('message', () => { + socket.send(toAB(quoteFrame(2n))) + socket.send(toAB(tradeFrame(3n))) + }) + }) + return server +} diff --git a/packages/sources/deutsche-boerse/test/unit/instrument-quote-cache.test.ts b/packages/sources/deutsche-boerse/test/unit/instrument-quote-cache.test.ts new file mode 100644 index 0000000000..2b7395d4d0 --- /dev/null +++ b/packages/sources/deutsche-boerse/test/unit/instrument-quote-cache.test.ts @@ -0,0 +1,93 @@ +import { InstrumentQuoteCache } from '../../src/transport/instrument-quote-cache' + +describe('InstrumentQuoteCache', () => { + const ISIN = 'IE00B53L3W79' + const ISIN2 = 'US0000000001' + test('activate/deactivate/has/isEmpty/get', () => { + const cache = new InstrumentQuoteCache() + expect(cache.isEmpty()).toBe(true) + cache.activate(ISIN) + expect(cache.has(ISIN)).toBe(true) + expect(cache.get(ISIN)).toEqual({}) + expect(cache.isEmpty()).toBe(false) + cache.deactivate(ISIN) + expect(cache.has(ISIN)).toBe(false) + expect(cache.isEmpty()).toBe(true) + }) + + test('addQuote sets bid/ask/mid and quote time', () => { + const cache = new InstrumentQuoteCache() + cache.activate(ISIN) + + cache.addQuote(ISIN, 100, 102, 1234) + const q = cache.get(ISIN) + expect(q?.bid).toBe(100) + expect(q?.ask).toBe(102) + expect(q?.mid).toBe(101) + expect(q?.quoteProviderTimeUnixMs).toBe(1234) + }) + + test('addTrade sets latestPrice and trade time', () => { + const cache = new InstrumentQuoteCache() + cache.activate(ISIN) + + cache.addTrade(ISIN, 99.5, 2222) + const q = cache.get(ISIN) + + expect(q?.latestPrice).toBe(99.5) + expect(q?.tradeProviderTimeUnixMs).toBe(2222) + }) + test('addQuote without activate throws', () => { + const cache = new InstrumentQuoteCache() + expect(() => cache.addQuote(ISIN, 100, 102, 1234)).toThrow(/inactive isin/i) + }) + + test('addTrade without activate throws', () => { + const cache = new InstrumentQuoteCache() + expect(() => cache.addTrade(ISIN, 99.5, 2222)).toThrow(/inactive isin/i) + }) + test('deactivate then attempt to add -> throws', () => { + const cache = new InstrumentQuoteCache() + cache.activate(ISIN) + cache.deactivate(ISIN) + expect(() => cache.addQuote(ISIN, 1, 2, 3)).toThrow(/inactive isin/i) + expect(() => cache.addTrade(ISIN, 1, 3)).toThrow(/inactive isin/i) + }) + test('mid is computed correctly for equal sides and edge values', () => { + const cache = new InstrumentQuoteCache() + cache.activate(ISIN) + cache.addQuote(ISIN, 0, 0, 123) + const q = cache.get(ISIN)! + expect(q.bid).toBe(0) + expect(q.ask).toBe(0) + expect(q.mid).toBe(0) + expect(q.quoteProviderTimeUnixMs).toBe(123) + }) + + test('multiple instruments lifecycle', () => { + const cache = new InstrumentQuoteCache() + cache.activate(ISIN) + cache.activate(ISIN2) + expect(cache.has(ISIN)).toBe(true) + expect(cache.has(ISIN2)).toBe(true) + expect(cache.isEmpty()).toBe(false) + + cache.addQuote(ISIN, 100, 101, 10) + cache.addTrade(ISIN2, 55, 20) + + const q1 = cache.get(ISIN)! + const q2 = cache.get(ISIN2)! + + expect(q1.mid).toBe(100.5) + expect(q1.quoteProviderTimeUnixMs).toBe(10) + expect(q2.latestPrice).toBe(55) + expect(q2.tradeProviderTimeUnixMs).toBe(20) + + cache.deactivate(ISIN) + expect(cache.has(ISIN)).toBe(false) + expect(cache.isEmpty()).toBe(false) + + cache.deactivate(ISIN2) + expect(cache.isEmpty()).toBe(true) + }) +}) diff --git a/packages/sources/deutsche-boerse/test/unit/lwba.test.ts b/packages/sources/deutsche-boerse/test/unit/lwba.test.ts new file mode 100644 index 0000000000..c47a81858b --- /dev/null +++ b/packages/sources/deutsche-boerse/test/unit/lwba.test.ts @@ -0,0 +1,111 @@ +import { create, toBinary, type MessageInitShape } from '@bufbuild/protobuf' +import { anyPack, type Any } from '@bufbuild/protobuf/wkt' +import { LoggerFactoryProvider } from '@chainlink/external-adapter-framework/util' +import { StreamMessageSchema } from '../../src/gen/client_pb' +import { + DataSchema, + DecimalSchema, + MarketDataSchema, + type Decimal, + type MarketData, +} from '../../src/gen/md_cef_pb' +import { createLwbaWsTransport } from '../../src/transport/lwba' + +LoggerFactoryProvider.set() + +const dec = (m: bigint, e: number): Decimal => create(DecimalSchema, { m, e }) + +type MarketDataInit = MessageInitShape + +const MARKET = 'md-xetraetfetp' as const + +function makeStreamBuffer(md: MarketData | MarketDataInit): Buffer { + const mdMsg = create(MarketDataSchema, md as MarketDataInit) + const anyMsg: Any = anyPack(MarketDataSchema, mdMsg) + const sm = create(StreamMessageSchema, { + subs: MARKET, // include market/stream on the frame + messages: [anyMsg], // exactly one Any payload + }) + return Buffer.from(toBinary(StreamMessageSchema, sm)) +} + +describe('LWBA transport (more integration cases)', () => { + const ISIN = 'IE00B53L3W79' + const OTHER = 'US0000000001' + + test('message for non-activated instrument returns []', () => { + const t = createLwbaWsTransport() as any + const md = create(MarketDataSchema, { + Instrmt: { Sym: ISIN }, + Dat: create(DataSchema, { + Bid: { Px: dec(10000n, -2) }, + Offer: { Px: dec(10100n, -2) }, + Tm: 1_000_000n, + } as any), + } as any) + const out = t.config.handlers.message(makeStreamBuffer(md), {} as any) + expect(out).toEqual([]) + }) + + test('subscribe builder: first subscribe returns frame, subsequent subscribes return undefined', () => { + const t = createLwbaWsTransport() as any + const first = t.config.builders.subscribeMessage({ market: MARKET, isin: ISIN }) + const second = t.config.builders.subscribeMessage({ market: MARKET, isin: OTHER }) + + expect(first).toBeInstanceOf(Uint8Array) + expect(second).toBeUndefined() + }) + + test('unsubscribe builder: removing last returns frame, otherwise undefined', () => { + const t = createLwbaWsTransport() as any + t.config.builders.subscribeMessage({ market: MARKET, isin: ISIN }) + t.config.builders.subscribeMessage({ market: MARKET, isin: OTHER }) + + const removeOne = t.config.builders.unsubscribeMessage({ market: MARKET, isin: OTHER }) + expect(removeOne).toBeUndefined() + + const removeLast = t.config.builders.unsubscribeMessage({ market: MARKET, isin: ISIN }) + expect(removeLast).toBeInstanceOf(Uint8Array) + }) + + test('missing ISIN: handler returns []', () => { + const t = createLwbaWsTransport() as any + t.config.builders.subscribeMessage({ market: MARKET, isin: ISIN }) + + const md = create(MarketDataSchema, { + Dat: create(DataSchema, { Px: dec(100n, 0), Tm: 1_000_000n } as any), + } as any) + + const out = t.config.handlers.message(makeStreamBuffer(md), {} as any) + expect(out).toEqual([]) + }) + + test('quote then trade: response reflects cached fields and timestamps', () => { + const t = createLwbaWsTransport() as any + t.config.builders.subscribeMessage({ market: MARKET, isin: ISIN }) + + // Quote + const quoteDat = create(DataSchema, { + Bid: { Px: dec(10000n, -2) }, + Offer: { Px: dec(10100n, -2) }, + Tm: 5_000_000n, + } as any) + const quoteMd = create(MarketDataSchema, { Instrmt: { Sym: ISIN }, Dat: quoteDat } as any) + const quoteRes = t.config.handlers.message(makeStreamBuffer(quoteMd), {} as any) + const [qEntry] = quoteRes + expect(qEntry.response.data.bid).toBe(100) + expect(qEntry.response.data.ask).toBe(101) + expect(qEntry.response.data.mid).toBe(100.5) + expect(qEntry.response.data.quoteProviderIndicatedTimeUnixMs).toBe(5) + expect(qEntry.response.data.tradeProviderIndicatedTimeUnixMs).toBeNull() + + // Trade + const tradeDat = create(DataSchema, { Px: dec(9999n, -2), Tm: 6_000_000n } as any) + const tradeMd = create(MarketDataSchema, { Instrmt: { Sym: ISIN }, Dat: tradeDat } as any) + const tradeRes = t.config.handlers.message(makeStreamBuffer(tradeMd), {} as any) + const [tEntry] = tradeRes + expect(tEntry.response.data.latestPrice).toBe(99.99) + expect(tEntry.response.data.quoteProviderIndicatedTimeUnixMs).toBe(5) + expect(tEntry.response.data.tradeProviderIndicatedTimeUnixMs).toBe(6) + }) +}) diff --git a/packages/sources/deutsche-boerse/test/unit/proto-utils.test.ts b/packages/sources/deutsche-boerse/test/unit/proto-utils.test.ts new file mode 100644 index 0000000000..e9ca765595 --- /dev/null +++ b/packages/sources/deutsche-boerse/test/unit/proto-utils.test.ts @@ -0,0 +1,69 @@ +import { create } from '@bufbuild/protobuf' +import { + DataSchema, + DecimalSchema, + MarketDataSchema, + type Data, + type Decimal, + type MarketData, +} from '../../src/gen/md_cef_pb' +import { + convertNsToMs, + decimalToNumber, + isSingleQuoteFrame, + isSingleTradeFrame, + parseIsin, + pickProviderTime, +} from '../../src/transport/proto-utils' + +describe('proto-utils', () => { + const dec = (m: bigint, e: number): Decimal => create(DecimalSchema, { m, e }) + + test('decimalToNumber – basic fractional', () => { + expect(decimalToNumber(dec(123n, -2))).toBeCloseTo(1.23) + }) + + test('decimalToNumber – integer scaling', () => { + expect(decimalToNumber(dec(42n, 0))).toBe(42) + expect(decimalToNumber(dec(42n, 1))).toBe(420) + }) + + test('decimalToNumber – mantissa overflow throws', () => { + const tooBig = BigInt(Number.MAX_SAFE_INTEGER) + 1n + expect(() => decimalToNumber(dec(tooBig, 0))).toThrow(/overflow/i) + }) + + test('convertNsToMs', () => { + expect(convertNsToMs(2_000_000n)).toBe(2) + expect(convertNsToMs(1_999_999n)).toBe(1) + }) + + test('getIsin (uses Instrmt.Sym)', () => { + const md: MarketData = create(MarketDataSchema, { + Instrmt: { Sym: 'IE00B53L3W79' as string }, + } as any) + expect(parseIsin(md)).toBe('IE00B53L3W79') + }) + + test('pickProviderTime', () => { + const dat: Data = create(DataSchema, { Tm: 5_000_000n } as any) + expect(pickProviderTime(dat)).toBe(5) + }) + + test('isSingleTradeFrame', () => { + const datWithTrade: Data = create(DataSchema, { Px: dec(100n, -2) } as any) + const datNoTrade: Data = create(DataSchema, {} as any) + expect(isSingleTradeFrame(datWithTrade)).toBe(true) + expect(isSingleTradeFrame(datNoTrade)).toBe(false) + }) + + test('isSingleQuoteFrame', () => { + const datWithQuote: Data = create(DataSchema, { + Bid: { Px: dec(10000n, -2) }, + Offer: { Px: dec(10050n, -2) }, + } as any) + const datMissing: Data = create(DataSchema, { Bid: {} } as any) + expect(isSingleQuoteFrame(datWithQuote)).toBe(true) + expect(isSingleQuoteFrame(datMissing)).toBe(false) + }) +}) diff --git a/packages/sources/deutsche-boerse/test/unit/protobuf-wstransport.test.ts b/packages/sources/deutsche-boerse/test/unit/protobuf-wstransport.test.ts new file mode 100644 index 0000000000..f9a797a337 --- /dev/null +++ b/packages/sources/deutsche-boerse/test/unit/protobuf-wstransport.test.ts @@ -0,0 +1,34 @@ +import type { WebsocketTransportGenerics } from '@chainlink/external-adapter-framework/transports' +import { ProtobufWsTransport } from '../../src/transport/protobuf-wstransport' + +type Dummy = WebsocketTransportGenerics & { Provider: { WsMessage: Buffer } } + +describe('ProtobufWsTransport helpers', () => { + const t = new ProtobufWsTransport({} as any) + + test('deserializeMessage handles Buffer', () => { + const src = Buffer.from([1, 2, 3]) + expect(t.deserializeMessage(src)).toBeInstanceOf(Buffer) + }) + + test('deserializeMessage handles ArrayBuffer', () => { + const ab = new Uint8Array([4, 5, 6]).buffer + const out = t.deserializeMessage(ab) + expect(Buffer.isBuffer(out)).toBe(true) + expect((out as Buffer).equals(Buffer.from([4, 5, 6]))).toBe(true) + }) + + test('deserializeMessage handles ArrayBufferView', () => { + const u8 = new Uint8Array([7, 8, 9]) + const out = t.deserializeMessage(u8) + expect((out as Buffer).equals(Buffer.from([7, 8, 9]))).toBe(true) + }) + + test('toRawData private: coerces inputs to Buffer', () => { + const anyT = t as any + expect(Buffer.isBuffer(anyT.toRawData(Buffer.from('x')))).toBe(true) + expect(Buffer.isBuffer(anyT.toRawData(new Uint8Array([1, 2])))).toBe(true) + expect(Buffer.isBuffer(anyT.toRawData('hi'))).toBe(true) + expect(Buffer.isBuffer(anyT.toRawData({ a: 1 }))).toBe(true) + }) +}) diff --git a/packages/sources/deutsche-boerse/tsconfig.json b/packages/sources/deutsche-boerse/tsconfig.json new file mode 100644 index 0000000000..f59363fd76 --- /dev/null +++ b/packages/sources/deutsche-boerse/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*", "src/**/*.json"], + "exclude": ["dist", "**/*.spec.ts", "**/*.test.ts"] +} diff --git a/packages/sources/deutsche-boerse/tsconfig.test.json b/packages/sources/deutsche-boerse/tsconfig.test.json new file mode 100755 index 0000000000..e3de28cb5c --- /dev/null +++ b/packages/sources/deutsche-boerse/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*", "**/test", "src/**/*.json"], + "compilerOptions": { + "noEmit": true + } +} diff --git a/packages/tsconfig.json b/packages/tsconfig.json index 88b8edc15a..1e943d1927 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -299,6 +299,9 @@ { "path": "./sources/deribit" }, + { + "path": "./sources/deutsche-boerse" + }, { "path": "./sources/dlc-btc-por" }, diff --git a/packages/tsconfig.test.json b/packages/tsconfig.test.json index c79724964e..2a44cfb2db 100644 --- a/packages/tsconfig.test.json +++ b/packages/tsconfig.test.json @@ -299,6 +299,9 @@ { "path": "./sources/deribit/tsconfig.test.json" }, + { + "path": "./sources/deutsche-boerse/tsconfig.test.json" + }, { "path": "./sources/dlc-btc-por/tsconfig.test.json" }, diff --git a/yarn.lock b/yarn.lock index dd2f22d0f7..f49d727886 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2337,6 +2337,96 @@ __metadata: languageName: node linkType: hard +"@bufbuild/buf-darwin-arm64@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-darwin-arm64@npm:1.57.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@bufbuild/buf-darwin-x64@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-darwin-x64@npm:1.57.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@bufbuild/buf-linux-aarch64@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-linux-aarch64@npm:1.57.0" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@bufbuild/buf-linux-armv7@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-linux-armv7@npm:1.57.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@bufbuild/buf-linux-x64@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-linux-x64@npm:1.57.0" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@bufbuild/buf-win32-arm64@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-win32-arm64@npm:1.57.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@bufbuild/buf-win32-x64@npm:1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf-win32-x64@npm:1.57.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@bufbuild/buf@npm:^1.57.0": + version: 1.57.0 + resolution: "@bufbuild/buf@npm:1.57.0" + dependencies: + "@bufbuild/buf-darwin-arm64": "npm:1.57.0" + "@bufbuild/buf-darwin-x64": "npm:1.57.0" + "@bufbuild/buf-linux-aarch64": "npm:1.57.0" + "@bufbuild/buf-linux-armv7": "npm:1.57.0" + "@bufbuild/buf-linux-x64": "npm:1.57.0" + "@bufbuild/buf-win32-arm64": "npm:1.57.0" + "@bufbuild/buf-win32-x64": "npm:1.57.0" + dependenciesMeta: + "@bufbuild/buf-darwin-arm64": + optional: true + "@bufbuild/buf-darwin-x64": + optional: true + "@bufbuild/buf-linux-aarch64": + optional: true + "@bufbuild/buf-linux-armv7": + optional: true + "@bufbuild/buf-linux-x64": + optional: true + "@bufbuild/buf-win32-arm64": + optional: true + "@bufbuild/buf-win32-x64": + optional: true + bin: + buf: bin/buf + protoc-gen-buf-breaking: bin/protoc-gen-buf-breaking + protoc-gen-buf-lint: bin/protoc-gen-buf-lint + checksum: 10/3870772d7363943e14b66cb86830dbc8df45ada72af74fb8a1b0aceef55906a01289e1d8883ff4a71488c22898f544fb108e58c860f91f056ca7055535352040 + languageName: node + linkType: hard + +"@bufbuild/protobuf@npm:^2.7.0": + version: 2.7.0 + resolution: "@bufbuild/protobuf@npm:2.7.0" + checksum: 10/3610b8da210a903cdce0824653710cf2bcd5801ba8f90714e018fc9c19a52123c10dbed246c49ea9502a06411f16acc8f0d22918eee04c32054aad0b861c249b + languageName: node + linkType: hard + "@cardano-ogmios/client@npm:^5.0.0": version: 5.6.0 resolution: "@cardano-ogmios/client@npm:5.6.0" @@ -3452,6 +3542,26 @@ __metadata: languageName: unknown linkType: soft +"@chainlink/deutsche-boerse-adapter@workspace:packages/sources/deutsche-boerse": + version: 0.0.0-use.local + resolution: "@chainlink/deutsche-boerse-adapter@workspace:packages/sources/deutsche-boerse" + dependencies: + "@bufbuild/buf": "npm:^1.57.0" + "@bufbuild/protobuf": "npm:^2.7.0" + "@chainlink/external-adapter-framework": "npm:2.7.0" + "@sinonjs/fake-timers": "npm:9.1.2" + "@types/jest": "npm:^29.5.14" + "@types/node": "npm:22.14.1" + "@types/sinonjs__fake-timers": "npm:8.1.5" + "@types/ws": "npm:^8" + decimal.js: "npm:10.5.0" + nock: "npm:13.5.6" + tslib: "npm:2.4.1" + typescript: "npm:5.8.3" + ws: "npm:^8.18.3" + languageName: unknown + linkType: soft + "@chainlink/dlc-btc-por-adapter@workspace:packages/sources/dlc-btc-por": version: 0.0.0-use.local resolution: "@chainlink/dlc-btc-por-adapter@workspace:packages/sources/dlc-btc-por" @@ -13663,6 +13773,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8": + version: 8.18.1 + resolution: "@types/ws@npm:8.18.1" + dependencies: + "@types/node": "npm:*" + checksum: 10/1ce05e3174dcacf28dae0e9b854ef1c9a12da44c7ed73617ab6897c5cbe4fccbb155a20be5508ae9a7dde2f83bd80f5cf3baa386b934fc4b40889ec963e94f3a + languageName: node + linkType: hard + "@types/ws@npm:^8.2.2": version: 8.5.13 resolution: "@types/ws@npm:8.5.13" @@ -17290,7 +17409,7 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.5.0": +"decimal.js@npm:10.5.0, decimal.js@npm:^10.5.0": version: 10.5.0 resolution: "decimal.js@npm:10.5.0" checksum: 10/714d49cf2f2207b268221795ede330e51452b7c451a0c02a770837d2d4faed47d603a729c2aa1d952eb6c4102d999e91c9b952c1aa016db3c5cba9fc8bf4cda2 @@ -33540,7 +33659,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.18.3": +"ws@npm:8.18.3, ws@npm:^8.18.3": version: 8.18.3 resolution: "ws@npm:8.18.3" peerDependencies: