diff --git a/apps/vendor-deepcoin/api-extractor.json b/apps/vendor-deepcoin/api-extractor.json new file mode 100644 index 000000000..62f4fd324 --- /dev/null +++ b/apps/vendor-deepcoin/api-extractor.json @@ -0,0 +1,411 @@ +/** + * Config file for API Extractor. For more info, please visit: https://api-extractor.com + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for + * standard settings to be shared across multiple projects. + * + * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains + * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be + * resolved using NodeJS require(). + * + * SUPPORTED TOKENS: none + * DEFAULT VALUE: "" + */ + // "extends": "./shared/api-extractor-base.json" + // "extends": "my-package/include/api-extractor-base.json" + + /** + * Determines the "" token that can be used with other config file settings. The project folder + * typically contains the tsconfig.json and package.json config files, but the path is user-defined. + * + * The path is resolved relative to the folder of the config file that contains the setting. + * + * The default value for "projectFolder" is the token "", which means the folder is determined by traversing + * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder + * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error + * will be reported. + * + * SUPPORTED TOKENS: + * DEFAULT VALUE: "" + */ + // "projectFolder": "..", + + /** + * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor + * analyzes the symbols exported by this module. + * + * The file extension must be ".d.ts" and not ".ts". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + */ + "mainEntryPointFilePath": "/lib/index.d.ts", + + /** + * A list of NPM package names whose exports should be treated as part of this package. + * + * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", + * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part + * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly + * imports library2. To avoid this, we can specify: + * + * "bundledPackages": [ "library2" ], + * + * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been + * local files for library1. + */ + "bundledPackages": [], + + /** + * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files + * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. + * To use the OS's default newline kind, specify "os". + * + * DEFAULT VALUE: "crlf" + */ + // "newlineKind": "crlf", + + /** + * Set to true when invoking API Extractor's test harness. When `testMode` is true, the `toolVersion` field in the + * .api.json file is assigned an empty string to prevent spurious diffs in output files tracked for tests. + * + * DEFAULT VALUE: "false" + */ + // "testMode": false, + + /** + * Specifies how API Extractor sorts members of an enum when generating the .api.json file. By default, the output + * files will be sorted alphabetically, which is "by-name". To keep the ordering in the source code, specify + * "preserve". + * + * DEFAULT VALUE: "by-name" + */ + // "enumMemberOrder": "by-name", + + /** + * Determines how the TypeScript compiler engine will be invoked by API Extractor. + */ + "compiler": { + /** + * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * Note: This setting will be ignored if "overrideTsconfig" is used. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/tsconfig.json" + */ + // "tsconfigFilePath": "/tsconfig.json", + /** + * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. + * The object must conform to the TypeScript tsconfig schema: + * + * http://json.schemastore.org/tsconfig + * + * If omitted, then the tsconfig.json file will be read from the "projectFolder". + * + * DEFAULT VALUE: no overrideTsconfig section + */ + // "overrideTsconfig": { + // . . . + // } + /** + * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended + * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when + * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses + * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. + * + * DEFAULT VALUE: false + */ + // "skipLibCheck": true, + }, + + /** + * Configures how the API report file (*.api.md) will be generated. + */ + "apiReport": { + /** + * (REQUIRED) Whether to generate an API report. + */ + "enabled": true + + /** + * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce + * a full file path. + * + * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". + * + * SUPPORTED TOKENS: , + * DEFAULT VALUE: ".api.md" + */ + // "reportFileName": ".api.md", + + /** + * Specifies the folder where the API report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, + * e.g. for an API review. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/" + */ + // "reportFolder": "/temp/", + + /** + * Specifies the folder where the temporary report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * After the temporary file is written to disk, it is compared with the file in the "reportFolder". + * If they are different, a production build will fail. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/" + */ + // "reportTempFolder": "/temp/", + + /** + * Whether "forgotten exports" should be included in the API report file. Forgotten exports are declarations + * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to + * learn more. + * + * DEFAULT VALUE: "false" + */ + // "includeForgottenExports": false + }, + + /** + * Configures how the doc model file (*.api.json) will be generated. + */ + "docModel": { + /** + * (REQUIRED) Whether to generate a doc model file. + */ + "enabled": true + + /** + * The output path for the doc model file. The file extension should be ".api.json". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/.api.json" + */ + // "apiJsonFilePath": "/temp/.api.json", + + /** + * Whether "forgotten exports" should be included in the doc model file. Forgotten exports are declarations + * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to + * learn more. + * + * DEFAULT VALUE: "false" + */ + // "includeForgottenExports": false + }, + + /** + * Configures how the .d.ts rollup file will be generated. + */ + "dtsRollup": { + /** + * (REQUIRED) Whether to generate the .d.ts rollup file. + */ + "enabled": true + + /** + * Specifies the output path for a .d.ts rollup file to be generated without any trimming. + * This file will include all declarations that are exported by the main entry point. + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/dist/.d.ts" + */ + // "untrimmedFilePath": "/dist/.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release. + * This file will include only declarations that are marked as "@public", "@beta", or "@alpha". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "alphaTrimmedFilePath": "/dist/-alpha.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. + * This file will include only declarations that are marked as "@public" or "@beta". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "betaTrimmedFilePath": "/dist/-beta.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. + * This file will include only declarations that are marked as "@public". + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "publicTrimmedFilePath": "/dist/-public.d.ts", + + /** + * When a declaration is trimmed, by default it will be replaced by a code comment such as + * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the + * declaration completely. + * + * DEFAULT VALUE: false + */ + // "omitTrimmingComments": true + }, + + /** + * Configures how the tsdoc-metadata.json file will be generated. + */ + "tsdocMetadata": { + /** + * Whether to generate the tsdoc-metadata.json file. + * + * DEFAULT VALUE: true + */ + // "enabled": true, + /** + * Specifies where the TSDoc metadata file should be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", + * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup + * falls back to "tsdoc-metadata.json" in the package folder. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" + }, + + /** + * Configures how API Extractor reports error and warning messages produced during analysis. + * + * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. + */ + "messages": { + /** + * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing + * the input .d.ts files. + * + * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "compilerMessageReporting": { + /** + * Configures the default routing for messages that don't match an explicit rule in this table. + */ + "default": { + /** + * Specifies whether the message should be written to the the tool's output log. Note that + * the "addToApiReportFile" property may supersede this option. + * + * Possible values: "error", "warning", "none" + * + * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail + * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes + * the "--local" option), the warning is displayed but the build will not fail. + * + * DEFAULT VALUE: "warning" + */ + "logLevel": "warning" + + /** + * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), + * then the message will be written inside that file; otherwise, the message is instead logged according to + * the "logLevel" option. + * + * DEFAULT VALUE: false + */ + // "addToApiReportFile": false + } + + // "TS2551": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by API Extractor during its analysis. + * + * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" + * + * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings + */ + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "ae-extra-release-tag": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by the TSDoc parser when analyzing code comments. + * + * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "tsdoc-link-tag-unescaped-text": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + } + } +} diff --git a/apps/vendor-deepcoin/build/Dockerfile b/apps/vendor-deepcoin/build/Dockerfile new file mode 100644 index 000000000..66f79f72f --- /dev/null +++ b/apps/vendor-deepcoin/build/Dockerfile @@ -0,0 +1,25 @@ +# syntax = docker/dockerfile:1.4 +FROM node:18.17.0-bullseye-slim + +LABEL maintainer="Siyuan Wang " + +# https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#handling-kernel-signals +ARG TINI_VERSION=v0.19.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini +RUN chmod a+x /tini +ENTRYPOINT ["/tini", "--"] + +ENV NODE_ENV=production + +USER node + +WORKDIR /app + +COPY --chown=node:node ./out/app-vendor-deepcoin-out /app + +RUN node create-links.js create + +WORKDIR /app/apps/vendor-deepcoin + +# USER nobody +CMD ["node", "./lib/index.js"] \ No newline at end of file diff --git a/apps/vendor-deepcoin/config/jest.config.json b/apps/vendor-deepcoin/config/jest.config.json new file mode 100644 index 000000000..4bb17bde3 --- /dev/null +++ b/apps/vendor-deepcoin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/vendor-deepcoin/config/rig.json b/apps/vendor-deepcoin/config/rig.json new file mode 100644 index 000000000..f6c7b5537 --- /dev/null +++ b/apps/vendor-deepcoin/config/rig.json @@ -0,0 +1,18 @@ +// The "rig.json" file directs tools to look for their config files in an external package. +// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "@rushstack/heft-node-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/apps/vendor-deepcoin/config/typescript.json b/apps/vendor-deepcoin/config/typescript.json new file mode 100644 index 000000000..854907e8a --- /dev/null +++ b/apps/vendor-deepcoin/config/typescript.json @@ -0,0 +1,87 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/typescript.schema.json", + + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for standard + * settings to be shared across multiple projects. + */ + // "extends": "base-project/config/typescript.json", + + /** + * Can be set to "copy" or "hardlink". If set to "copy", copy files from cache. + * If set to "hardlink", files will be hardlinked to the cache location. + * This option is useful when producing a tarball of build output as TAR files don't + * handle these hardlinks correctly. "hardlink" is the default behavior. + */ + // "copyFromCacheMode": "copy", + + /** + * If provided, emit these module kinds in addition to the modules specified in the tsconfig. + * Note that this option only applies to the main tsconfig.json configuration. + */ + "additionalModuleKindsToEmit": [ + { + "moduleKind": "esnext", + "outFolderName": "dist" + } + // { + // /** + // * (Required) Must be one of "commonjs", "amd", "umd", "system", "es2015", "esnext" + // */ + // "moduleKind": "amd", + // + // /** + // * (Required) The name of the folder where the output will be written. + // */ + // "outFolderName": "lib-amd" + // } + ], + + /** + * Specifies the intermediary folder that tests will use. Because Jest uses the + * Node.js runtime to execute tests, the module format must be CommonJS. + * + * The default value is "lib". + */ + // "emitFolderNameForTests": "lib-commonjs", + + /** + * If set to "true", the TSlint task will not be invoked. + */ + // "disableTslint": true, + + /** + * Set this to change the maximum number of file handles that will be opened concurrently for writing. + * The default is 50. + */ + // "maxWriteParallelism": 50, + + /** + * Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example + * so that these files can be resolved by import statements. + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + // "fileExtensions": [ + // ".json", ".css" + // ], + /** + * Glob patterns that should be explicitly included. + */ + // "includeGlobs": [ + // "some/path/*.js" + // ], + /** + * Glob patterns that should be explicitly excluded. This takes precedence over globs listed + * in "includeGlobs" and files that match the file extensions provided in "fileExtensions". + */ + // "excludeGlobs": [ + // "some/path/*.css" + // ] + } +} diff --git a/apps/vendor-deepcoin/etc/vendor-deepcoin.api.md b/apps/vendor-deepcoin/etc/vendor-deepcoin.api.md new file mode 100644 index 000000000..0e90358b5 --- /dev/null +++ b/apps/vendor-deepcoin/etc/vendor-deepcoin.api.md @@ -0,0 +1,9 @@ +## API Report File for "@yuants/vendor-deepcoin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// (No @packageDocumentation comment for this package) + +``` diff --git a/apps/vendor-deepcoin/package.json b/apps/vendor-deepcoin/package.json new file mode 100644 index 000000000..b247eb448 --- /dev/null +++ b/apps/vendor-deepcoin/package.json @@ -0,0 +1,44 @@ +{ + "name": "@yuants/vendor-deepcoin", + "version": "0.0.0", + "homepage": "https://github.com/No-Trade-No-Life/Yuan/tree/main/apps/vendor-deepcoin", + "main": "lib/index.js", + "module": "dist/index.js", + "files": [ + "dist", + "lib", + "temp" + ], + "scripts": { + "build": "heft test --clean && api-extractor run --local && yuan-toolkit post-build" + }, + "dependencies": { + "@types/json-schema": "~7.0.11", + "@yuants/data-model": "workspace:*", + "@yuants/kernel": "workspace:*", + "@yuants/protocol": "workspace:*", + "@yuants/utils": "workspace:*", + "ajv": "~8.12.0", + "ajv-formats": "~2.1.1", + "rxjs": "~7.5.6", + "ws": "~8.16.0" + }, + "devDependencies": { + "@microsoft/api-extractor": "~7.30.0", + "@rushstack/heft": "~0.47.5", + "@rushstack/heft-jest-plugin": "~0.3.30", + "@rushstack/heft-node-rig": "~1.10.7", + "@types/heft-jest": "1.0.3", + "@types/json-schema": "~7.0.11", + "@types/node": "18", + "@yuants/extension": "workspace:*", + "@yuants/tool-kit": "workspace:*", + "json-schema": "~0.4.0", + "typescript": "~4.7.4", + "@types/ws": "~8.5.10" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + } +} diff --git a/apps/vendor-deepcoin/src/extension.ts b/apps/vendor-deepcoin/src/extension.ts new file mode 100644 index 000000000..5f0c8e6ad --- /dev/null +++ b/apps/vendor-deepcoin/src/extension.ts @@ -0,0 +1,99 @@ +import { IExtensionContext, makeDockerEnvs, makeK8sEnvs } from '@yuants/extension'; +export default (context: IExtensionContext) => { + context.registerDeployProvider({ + make_json_schema: () => ({ + type: 'object', + properties: { + env: { + type: 'object', + required: ['HOST_URL'], + properties: { + HOST_URL: { + type: 'string', + title: '主机地址', + }, + }, + }, + }, + }), + make_docker_compose_file: async (ctx, envCtx) => { + return { + [`crysto-api`.replace(/\s/g, '')]: { + image: `registry.ap-southeast-1.aliyuncs.com/ntnl-y/vendor-deepcoin-api:${ + ctx.version ?? envCtx.version + }`, + restart: 'always', + environment: makeDockerEnvs(ctx.env), + }, + }; + }, + make_k8s_resource_objects: async (ctx, envCtx) => { + const entry = ctx.env?.ENTRY!; + const manifest_key = ctx.key; + return { + deployment: { + apiVersion: 'apps/v1', + kind: 'Deployment', + metadata: { + labels: { + 'y.ntnl.io/version': ctx.version ?? envCtx.version, + 'y.ntnl.io/component': 'crysto-api', + 'y.ntnl.io/manifest-key': manifest_key, + }, + name: `crysto-api-${manifest_key}`.replace(/\s/g, '').replace(/\./g, '').toLocaleLowerCase(), + namespace: 'yuan', + }, + spec: { + replicas: 1, + selector: { + matchLabels: { + 'y.ntnl.io/component': 'crysto-api', + 'y.ntnl.io/manifest-key': manifest_key, + }, + }, + template: { + metadata: { + labels: { + 'y.ntnl.io/version': ctx.version ?? envCtx.version, + 'y.ntnl.io/component': 'crysto-api', + 'y.ntnl.io/manifest-key': manifest_key, + }, + }, + spec: { + containers: [ + { + command: ['./node_modules/.bin/ts-node'], + args: [`src/${entry}`], + env: makeK8sEnvs(ctx.env), + image: `registry.ap-southeast-1.aliyuncs.com/ntnl-y/vendor-deepcoin-api:${ + ctx.version ?? envCtx.version + }`, + // TODO: remove this after CI is ready + imagePullPolicy: 'Always', + name: 'crysto-api', + resources: { + limits: { + cpu: ctx.cpu?.max ?? '500m', + memory: ctx.memory?.max ?? '256Mi', + }, + requests: { + cpu: ctx.cpu?.min ?? '100m', + memory: ctx.memory?.min ?? '128Mi', + }, + }, + }, + ], + hostname: 'crysto-api', + imagePullSecrets: [ + { + name: 'pull-secret', + }, + ], + }, + }, + }, + }, + }; + }, + }); +}; diff --git a/apps/vendor-deepcoin/src/index.ts b/apps/vendor-deepcoin/src/index.ts new file mode 100644 index 000000000..8e1fb4327 --- /dev/null +++ b/apps/vendor-deepcoin/src/index.ts @@ -0,0 +1,100 @@ +import { ITick, UUID, formatTime } from '@yuants/data-model'; +import { Terminal } from '@yuants/protocol'; +import { Subject, filter, fromEvent, interval, map, mergeMap, tap } from 'rxjs'; +import { MessageEvent, WebSocket } from 'ws'; + +// API Doc: https://www.deepcoin.com/zh/docs#WebSocket-public-address +const ws = new WebSocket('wss://stream.deepcoin.com/public/ws'); + +const datasource_id = 'DeepCoin'; +const terminal = new Terminal(process.env.HOST_URL!, { + terminal_id: `DeepCoinAPI/${UUID()}`, + name: 'DeepCoin API', +}); + +const tick$ = new Subject(); + +// TODO +// const products$ = defer(() => +// fetch( +// `https://api.deepcoin.com/deepcoin/market/instruments?instType=SWAP` +// ).then((v) => v.json()) +// ).pipe( +// // +// mergeAll(), +// map( +// (v: any): IProduct => ({ +// datasource_id, +// product_id: `${v.baseCcy}${v.quoteCcy}`, +// name: v.InstId, +// base_currency: v.baseCcy, +// quote_currency: v.quoteCcy, +// price_step: v.tickSz, +// // volume_step: v.ctVal, +// // value_scale: +// }) +// ), +// shareReplay(1) +// ); + +interval(5000).subscribe(() => { + ws.send('ping'); +}); + +fromEvent(ws, 'message') + .pipe( + map((e) => e.data.toString()), + // tap((x) => { + // console.info(formatTime(Date.now()), "RX", x); + // }), + filter((x) => x !== 'pong'), + map((x) => JSON.parse(x)), + filter((v) => v.action === 'PushMarketDataOverView' && !!v.result), + // map deepcoin tick to ITick + mergeMap((v) => v.result), + map((v: any): ITick => { + return { + datasource_id, + product_id: v.data.InstrumentID, + //NOTE: rawTick.UpdateMilliSecond should be the millisecond part of rawTick.UpdateTime + // yet it's not documented and always be 132 in my test. + updated_at: v.data.UpdateTime * 1000, + price: v.data.LastPrice, + // volume: v.data.Volume, + ask: v.data.AskPrice1, + bid: v.data.BidPrice1, + interest_rate_for_long: -v.data.PositionFeeRate, + interest_rate_for_short: v.data.PositionFeeRate, + }; + }), + ) + .subscribe(tick$); + +let LocalNo = 0; + +fromEvent(ws, 'close').subscribe(() => { + console.info(formatTime(Date.now()), 'WS Closed, Exiting...'); + process.exit(0); +}); + +terminal.provideTicks(datasource_id, (product_id) => { + console.info(formatTime(Date.now()), 'Subscribing', product_id); + ws.send( + JSON.stringify({ + SendTopicAction: { + Action: '1', + FilterValue: `DeepCoin_${product_id}`, + LocalNo: LocalNo++, + ResumeNo: -1, + TopicID: '7', + }, + }), + ); + return tick$.pipe( + // + filter((v) => v.product_id === product_id), + tap((x) => { + console.info(formatTime(Date.now()), 'Tick', JSON.stringify(x)); + }), + ); +}); diff --git a/apps/vendor-deepcoin/tsconfig.json b/apps/vendor-deepcoin/tsconfig.json new file mode 100644 index 000000000..22f94ca28 --- /dev/null +++ b/apps/vendor-deepcoin/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "types": ["heft-jest", "node"] + } +} diff --git a/common/config/rush/deploy.json b/common/config/rush/deploy.json index e5cc180db..629feb5a7 100644 --- a/common/config/rush/deploy.json +++ b/common/config/rush/deploy.json @@ -29,6 +29,7 @@ "@yuants/app-general-data-source", "@yuants/app-general-realtime-data-source", "@yuants/app-trade-copier", + "@yuants/vendor-deepcoin", "@yuants/vendor-ctp" ], /** diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 7e7fd805e..e0be34103 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -508,6 +508,51 @@ importers: '@yuants/tool-kit': link:../../tools/toolkit typescript: 4.7.4 + ../../apps/vendor-deepcoin: + specifiers: + '@microsoft/api-extractor': ~7.30.0 + '@rushstack/heft': ~0.47.5 + '@rushstack/heft-jest-plugin': ~0.3.30 + '@rushstack/heft-node-rig': ~1.10.7 + '@types/heft-jest': 1.0.3 + '@types/json-schema': ~7.0.11 + '@types/node': '18' + '@types/ws': ~8.5.10 + '@yuants/data-model': workspace:* + '@yuants/extension': workspace:* + '@yuants/kernel': workspace:* + '@yuants/protocol': workspace:* + '@yuants/tool-kit': workspace:* + '@yuants/utils': workspace:* + ajv: ~8.12.0 + ajv-formats: ~2.1.1 + json-schema: ~0.4.0 + rxjs: ~7.5.6 + typescript: ~4.7.4 + ws: ~8.16.0 + dependencies: + '@types/json-schema': 7.0.15 + '@yuants/data-model': link:../../libraries/data-model + '@yuants/kernel': link:../../libraries/kernel + '@yuants/protocol': link:../../libraries/protocol + '@yuants/utils': link:../../libraries/utils + ajv: 8.12.0 + ajv-formats: 2.1.1 + rxjs: 7.5.7 + ws: 8.16.0 + devDependencies: + '@microsoft/api-extractor': 7.30.1 + '@rushstack/heft': 0.47.11 + '@rushstack/heft-jest-plugin': 0.3.45_@rushstack+heft@0.47.11 + '@rushstack/heft-node-rig': 1.10.13_@rushstack+heft@0.47.11 + '@types/heft-jest': 1.0.3 + '@types/node': 18.17.12 + '@types/ws': 8.5.10 + '@yuants/extension': link:../../libraries/extension + '@yuants/tool-kit': link:../../tools/toolkit + json-schema: 0.4.0 + typescript: 4.7.4 + ../../libraries/agent: specifiers: '@microsoft/api-extractor': ~7.30.0 @@ -1560,7 +1605,6 @@ packages: /@babel/helper-validator-identifier/7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-identifier/7.22.5: resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} @@ -1598,7 +1642,7 @@ packages: resolution: {integrity: sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 @@ -6191,7 +6235,6 @@ packages: /@types/json-schema/7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true /@types/jsonfile/6.1.1: resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} @@ -6462,6 +6505,12 @@ packages: '@types/webidl-conversions': 7.0.0 dev: false + /@types/ws/8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 18.17.12 + dev: true + /@types/ws/8.5.5: resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} dependencies: @@ -19091,6 +19140,19 @@ packages: optional: true dev: false + /ws/8.16.0: + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /ws/8.8.1: resolution: {integrity: sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==} engines: {node: '>=10.0.0'} diff --git a/rush.json b/rush.json index f0842b47b..a0cf52f90 100644 --- a/rush.json +++ b/rush.json @@ -535,6 +535,11 @@ "projectFolder": "apps/vendor-ctp", "shouldPublish": true }, + { + "packageName": "@yuants/vendor-deepcoin", + "projectFolder": "apps/vendor-deepcoin", + "shouldPublish": true + }, { "packageName": "@yuants/ui-web", "projectFolder": "ui/web" diff --git a/tools/toolkit/src/features/buildDependencyHash.ts b/tools/toolkit/src/features/buildDependencyHash.ts index ea12db76f..0eb388ca5 100644 --- a/tools/toolkit/src/features/buildDependencyHash.ts +++ b/tools/toolkit/src/features/buildDependencyHash.ts @@ -8,9 +8,15 @@ export const buildDependencyHash = async () => { const packageJson = await fs.readJson(path.resolve(process.cwd(), 'package.json')); const packageName = packageJson.name; - const rushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ - startingFolder: process.cwd(), - }); + let rushConfiguration: rushLib.RushConfiguration; + try { + rushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ + startingFolder: process.cwd(), + }); + } catch (e) { + console.error(new Date(), `rush.json not found`); + process.exit(1); + } const thisProject = rushConfiguration.projectsByName.get(packageName); if (!thisProject) {