@yuants/app-virtual-exchange 0.18.11 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/credential.js +25 -18
- package/dist/credential.js.map +1 -1
- package/dist/general.js.map +1 -1
- package/dist/series-collector/interest-ledger.js +143 -0
- package/dist/series-collector/interest-ledger.js.map +1 -0
- package/dist/series-collector/patch-interest-rate.js +2 -23
- package/dist/series-collector/patch-interest-rate.js.map +1 -1
- package/dist/series-collector/patch-ohlc.js +2 -23
- package/dist/series-collector/patch-ohlc.js.map +1 -1
- package/dist/series-collector/setup.js +4 -12
- package/dist/series-collector/setup.js.map +1 -1
- package/dist/series-collector/sql-helpers.js +27 -0
- package/dist/series-collector/sql-helpers.js.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/lib/credential.d.ts +14 -4
- package/lib/credential.d.ts.map +1 -1
- package/lib/credential.js +27 -19
- package/lib/credential.js.map +1 -1
- package/lib/general.js.map +1 -1
- package/lib/series-collector/interest-ledger.d.ts +16 -0
- package/lib/series-collector/interest-ledger.d.ts.map +1 -0
- package/lib/series-collector/interest-ledger.js +152 -0
- package/lib/series-collector/interest-ledger.js.map +1 -0
- package/lib/series-collector/patch-interest-rate.d.ts.map +1 -1
- package/lib/series-collector/patch-interest-rate.js +2 -23
- package/lib/series-collector/patch-interest-rate.js.map +1 -1
- package/lib/series-collector/patch-ohlc.d.ts.map +1 -1
- package/lib/series-collector/patch-ohlc.js +2 -23
- package/lib/series-collector/patch-ohlc.js.map +1 -1
- package/lib/series-collector/setup.js +4 -12
- package/lib/series-collector/setup.js.map +1 -1
- package/lib/series-collector/sql-helpers.d.ts +6 -0
- package/lib/series-collector/sql-helpers.d.ts.map +1 -1
- package/lib/series-collector/sql-helpers.js +31 -1
- package/lib/series-collector/sql-helpers.js.map +1 -1
- package/lib/types.d.ts +5 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/package.json +5 -5
- package/temp/build/typescript/ts_KjrfbUqK.json +1 -1
- package/temp/test/jest/haste-map-76b16e3ab892e2fd05068740b7223d57-a6c52f003baf5bf33cffc52364f3bd7a-4ce9ff2cd20d69bbaecd1543c7e32e02 +0 -0
- package/temp/test/jest/perf-cache-76b16e3ab892e2fd05068740b7223d57-da39a3ee5e6b4b0d3255bfef95601890 +1 -1
package/dist/credential.js
CHANGED
|
@@ -22,6 +22,31 @@ const secretSignToCredentialIdCache = createCache(async (sign) => {
|
|
|
22
22
|
const credential = JSON.parse(new TextDecoder().decode(decrypted));
|
|
23
23
|
return credential;
|
|
24
24
|
});
|
|
25
|
+
export const allCredentials$ = defer(() => terminal.client.requestForResponseData('VEX/ListExchangeCredential', {})).pipe(repeat({ delay: 10000 }), retry({ delay: 5000 }), shareReplay(1));
|
|
26
|
+
export const mapCredentialIdToCredentials$ = allCredentials$.pipe(map((x) => Map.groupBy(x, (item) => item.credentialId || '')), shareReplay(1));
|
|
27
|
+
export const validCredentials$ = allCredentials$.pipe(map((x) => {
|
|
28
|
+
const map = new Map();
|
|
29
|
+
if (!x)
|
|
30
|
+
return map;
|
|
31
|
+
for (const xx of x) {
|
|
32
|
+
if (xx.credentialId && xx.credential) {
|
|
33
|
+
map.set(xx.credentialId, xx.credential);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return map;
|
|
37
|
+
}), shareReplay(1));
|
|
38
|
+
export const validCredentialTypes$ = validCredentials$.pipe(map((credentials) => {
|
|
39
|
+
const types = new Set();
|
|
40
|
+
credentials.forEach((credential) => {
|
|
41
|
+
types.add(credential.type);
|
|
42
|
+
});
|
|
43
|
+
return Array.from(types);
|
|
44
|
+
}));
|
|
45
|
+
export const getCredentialByCredentialId = async (credentialId) => {
|
|
46
|
+
const credentials = (await firstValueFrom(mapCredentialIdToCredentials$)).get(credentialId);
|
|
47
|
+
const theCredential = credentials === null || credentials === void 0 ? void 0 : credentials[0].credential;
|
|
48
|
+
return theCredential;
|
|
49
|
+
};
|
|
25
50
|
/**
|
|
26
51
|
* 根据 credential 信息解析出对应的 credential ID
|
|
27
52
|
* 此处可以做缓存,因为同一个 credential 永远对应同一个 credential ID,可以节约后续 SQL 查询的开销
|
|
@@ -78,24 +103,6 @@ terminal.server.provideService('VEX/ListCredentials', {}, async () => {
|
|
|
78
103
|
const credentials = await firstValueFrom(validCredentials$);
|
|
79
104
|
return { res: { code: 0, message: 'OK', data: [...credentials.keys()] } };
|
|
80
105
|
});
|
|
81
|
-
export const validCredentials$ = defer(() => listAllCredentials()).pipe(map((x) => {
|
|
82
|
-
const map = new Map();
|
|
83
|
-
if (!x)
|
|
84
|
-
return map;
|
|
85
|
-
for (const xx of x) {
|
|
86
|
-
if (xx.credentialId && xx.credential) {
|
|
87
|
-
map.set(xx.credentialId, xx.credential);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return map;
|
|
91
|
-
}), repeat({ delay: 10000 }), retry({ delay: 5000 }), shareReplay(1));
|
|
92
|
-
export const validCredentialTypes$ = validCredentials$.pipe(map((credentials) => {
|
|
93
|
-
const types = new Set();
|
|
94
|
-
credentials.forEach((credential) => {
|
|
95
|
-
types.add(credential.type);
|
|
96
|
-
});
|
|
97
|
-
return Array.from(types);
|
|
98
|
-
}));
|
|
99
106
|
/**
|
|
100
107
|
* 根据 secret sign 解析出对应的 credential 以及 credential ID
|
|
101
108
|
* @param sign - secret sign
|
package/dist/credential.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCache } from '@yuants/cache';\nimport { getCredentialId } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { ISecret, listSecrets, readSecret, writeSecret } from '@yuants/secret';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { newError } from '@yuants/utils';\nimport { defer, firstValueFrom, map, repeat, retry, shareReplay } from 'rxjs';\n\nexport interface IExchangeCredential {\n type: string;\n payload: any;\n}\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst credentialReader = process.env.NODE_UNIT_PUBLIC_KEY || terminal.keyPair.public_key;\n\n/**\n * 根据 secret sign 解析出对应的 exchange credential\n * 此处可以做缓存,因为同一个 secret sign 对应的 credential 信息永远不会变化,可以节约解密和后续 SQL 查询的开销\n * 得到 credential 后,此 credential 不一定是有效的,因为可能凭证信息已经过期或被撤销\n */\nconst secretSignToCredentialIdCache = createCache(async (sign: string) => {\n const sql = `SELECT * FROM secret WHERE sign = ${escapeSQL(sign)} LIMIT 1;`;\n const res = await requestSQL<ISecret[]>(terminal, sql);\n if (res.length === 0) throw newError('SECRET_NOT_FOUND', { sign });\n const secret = res[0];\n const decrypted = await readSecret(terminal, secret);\n const credential = JSON.parse(new TextDecoder().decode(decrypted)) as IExchangeCredential;\n return credential;\n});\n\n/**\n * 根据 credential 信息解析出对应的 credential ID\n * 此处可以做缓存,因为同一个 credential 永远对应同一个 credential ID,可以节约后续 SQL 查询的开销\n * 但是需要注意的是,credential ID 可能会因为凭证被撤销而失效,但是可以在下游调用其他服务时感知到,因此可以永久缓存\n */\nconst credentialIdCache = createCache(async (credentialKey: string) => {\n const credential = JSON.parse(credentialKey) as IExchangeCredential;\n const res = await getCredentialId(terminal, credential);\n return res.data;\n});\n\nconst listAllCredentials = async () => {\n const secrets = await listSecrets(terminal, {\n reader: credentialReader,\n tags: { type: 'exchange_credential' },\n });\n\n const results = await Promise.allSettled(secrets.map((secret) => getCredentialBySecretId(secret.sign)));\n return results.map(\n (\n result,\n index,\n ): {\n sign: string;\n credential: IExchangeCredential | null;\n credentialId: string | null;\n error: any;\n } => {\n if (result.status === 'fulfilled') {\n return {\n sign: secrets[index].sign,\n credential: result.value.credential,\n credentialId: result.value.credentialId,\n error: null,\n };\n } else {\n return {\n sign: secrets[index].sign,\n credential: null,\n credentialId: null,\n error: `${result.reason}`,\n };\n }\n },\n );\n};\n\nterminal.server.provideService<IExchangeCredential, ISecret>(\n 'VEX/RegisterExchangeCredential',\n {\n type: 'object',\n required: ['type', 'payload'],\n properties: {\n type: { type: 'string' },\n payload: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = msg.req;\n const secretData = new TextEncoder().encode(JSON.stringify(credential));\n const secret = await writeSecret(terminal, credentialReader, { type: 'exchange_credential' }, secretData);\n return { res: { code: 0, message: 'OK', data: secret } };\n },\n);\n\n// For Debugging Purpose\nterminal.server.provideService('VEX/ListExchangeCredential', {}, async () => {\n return { res: { code: 0, message: 'OK', data: await listAllCredentials() } };\n});\n\nterminal.server.provideService<void, string[]>('VEX/ListCredentials', {}, async () => {\n const credentials = await firstValueFrom(validCredentials$);\n return { res: { code: 0, message: 'OK', data: [...credentials.keys()] } };\n});\n\nexport const validCredentials$ = defer(() => listAllCredentials()).pipe(\n map((x) => {\n const map = new Map<string, IExchangeCredential>();\n if (!x) return map;\n for (const xx of x) {\n if (xx.credentialId && xx.credential) {\n map.set(xx.credentialId, xx.credential);\n }\n }\n return map;\n }),\n repeat({ delay: 10000 }),\n retry({ delay: 5000 }),\n shareReplay(1),\n);\n\nexport const validCredentialTypes$ = validCredentials$.pipe(\n map((credentials) => {\n const types = new Set<string>();\n credentials.forEach((credential) => {\n types.add(credential.type);\n });\n return Array.from(types);\n }),\n);\n\n/**\n * 根据 secret sign 解析出对应的 credential 以及 credential ID\n * @param sign - secret sign\n * @returns 解析得到的 credential 以及对应的 credential ID\n * @throws 如果无法解析出对应的 credential 或 credential ID,则抛出异常\n *\n * 不依赖 List Credential 服务,可以及时感知凭证的新增和变更\n */\nexport const getCredentialBySecretId = async (sign: string) => {\n const credential = await secretSignToCredentialIdCache.query(sign);\n if (!credential) throw newError('CREDENTIAL_NOT_RESOLVED', { sign });\n const credentialId = await credentialIdCache.query(JSON.stringify(credential));\n if (!credentialId) throw newError('CREDENTIAL_ID_NOT_RESOLVED', { sign });\n return { sign, credential, credentialId };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCache } from '@yuants/cache';\nimport { getCredentialId } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { ISecret, listSecrets, readSecret, writeSecret } from '@yuants/secret';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { newError } from '@yuants/utils';\nimport { defer, firstValueFrom, map, repeat, retry, shareReplay } from 'rxjs';\nimport { IExchangeCredential } from './types';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst credentialReader = process.env.NODE_UNIT_PUBLIC_KEY || terminal.keyPair.public_key;\n\n/**\n * 根据 secret sign 解析出对应的 exchange credential\n * 此处可以做缓存,因为同一个 secret sign 对应的 credential 信息永远不会变化,可以节约解密和后续 SQL 查询的开销\n * 得到 credential 后,此 credential 不一定是有效的,因为可能凭证信息已经过期或被撤销\n */\nconst secretSignToCredentialIdCache = createCache(async (sign: string) => {\n const sql = `SELECT * FROM secret WHERE sign = ${escapeSQL(sign)} LIMIT 1;`;\n const res = await requestSQL<ISecret[]>(terminal, sql);\n if (res.length === 0) throw newError('SECRET_NOT_FOUND', { sign });\n const secret = res[0];\n const decrypted = await readSecret(terminal, secret);\n const credential = JSON.parse(new TextDecoder().decode(decrypted)) as IExchangeCredential;\n return credential;\n});\n\nexport const allCredentials$ = defer(() =>\n terminal.client.requestForResponseData<{}, Awaited<ReturnType<typeof listAllCredentials>>>(\n 'VEX/ListExchangeCredential',\n {},\n ),\n).pipe(repeat({ delay: 10000 }), retry({ delay: 5000 }), shareReplay(1));\n\nexport const mapCredentialIdToCredentials$ = allCredentials$.pipe(\n map((x) => Map.groupBy(x, (item) => item.credentialId || '')),\n shareReplay(1),\n);\n\nexport const validCredentials$ = allCredentials$.pipe(\n map((x) => {\n const map = new Map<string, IExchangeCredential>();\n if (!x) return map;\n for (const xx of x) {\n if (xx.credentialId && xx.credential) {\n map.set(xx.credentialId, xx.credential);\n }\n }\n return map;\n }),\n shareReplay(1),\n);\n\nexport const validCredentialTypes$ = validCredentials$.pipe(\n map((credentials) => {\n const types = new Set<string>();\n credentials.forEach((credential) => {\n types.add(credential.type);\n });\n return Array.from(types);\n }),\n);\n\nexport const getCredentialByCredentialId = async (credentialId: string) => {\n const credentials = (await firstValueFrom(mapCredentialIdToCredentials$)).get(credentialId);\n const theCredential = credentials?.[0].credential;\n return theCredential;\n};\n\n/**\n * 根据 credential 信息解析出对应的 credential ID\n * 此处可以做缓存,因为同一个 credential 永远对应同一个 credential ID,可以节约后续 SQL 查询的开销\n * 但是需要注意的是,credential ID 可能会因为凭证被撤销而失效,但是可以在下游调用其他服务时感知到,因此可以永久缓存\n */\nconst credentialIdCache = createCache(async (credentialKey: string) => {\n const credential = JSON.parse(credentialKey) as IExchangeCredential;\n const res = await getCredentialId(terminal, credential);\n return res.data;\n});\n\nconst listAllCredentials = async () => {\n const secrets = await listSecrets(terminal, {\n reader: credentialReader,\n tags: { type: 'exchange_credential' },\n });\n\n const results = await Promise.allSettled(secrets.map((secret) => getCredentialBySecretId(secret.sign)));\n return results.map(\n (\n result,\n index,\n ): {\n sign: string;\n credential: IExchangeCredential | null;\n credentialId: string | null;\n error: any;\n } => {\n if (result.status === 'fulfilled') {\n return {\n sign: secrets[index].sign,\n credential: result.value.credential,\n credentialId: result.value.credentialId,\n error: null,\n };\n } else {\n return {\n sign: secrets[index].sign,\n credential: null,\n credentialId: null,\n error: `${result.reason}`,\n };\n }\n },\n );\n};\n\nterminal.server.provideService<IExchangeCredential, ISecret>(\n 'VEX/RegisterExchangeCredential',\n {\n type: 'object',\n required: ['type', 'payload'],\n properties: {\n type: { type: 'string' },\n payload: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = msg.req;\n const secretData = new TextEncoder().encode(JSON.stringify(credential));\n const secret = await writeSecret(terminal, credentialReader, { type: 'exchange_credential' }, secretData);\n return { res: { code: 0, message: 'OK', data: secret } };\n },\n);\n\n// For Debugging Purpose\nterminal.server.provideService('VEX/ListExchangeCredential', {}, async () => {\n return { res: { code: 0, message: 'OK', data: await listAllCredentials() } };\n});\n\nterminal.server.provideService<void, string[]>('VEX/ListCredentials', {}, async () => {\n const credentials = await firstValueFrom(validCredentials$);\n return { res: { code: 0, message: 'OK', data: [...credentials.keys()] } };\n});\n\n/**\n * 根据 secret sign 解析出对应的 credential 以及 credential ID\n * @param sign - secret sign\n * @returns 解析得到的 credential 以及对应的 credential ID\n * @throws 如果无法解析出对应的 credential 或 credential ID,则抛出异常\n *\n * 不依赖 List Credential 服务,可以及时感知凭证的新增和变更\n */\nexport const getCredentialBySecretId = async (sign: string) => {\n const credential = await secretSignToCredentialIdCache.query(sign);\n if (!credential) throw newError('CREDENTIAL_NOT_RESOLVED', { sign });\n const credentialId = await credentialIdCache.query(JSON.stringify(credential));\n if (!credentialId) throw newError('CREDENTIAL_ID_NOT_RESOLVED', { sign });\n return { sign, credential, credentialId };\n};\n"]}
|
package/dist/general.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"general.js","sourceRoot":"","sources":["../src/general.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"general.js","sourceRoot":"","sources":["../src/general.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,kBAAkB,EAClB;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,WAAW,CAAC;IACvB,UAAU,EAAE;QACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC/B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpF,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnD,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACxB,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;IAC3C,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;AAC9D,CAAC,CACF,CAAC;AAEF,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,eAAe,EACf;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,WAAW,CAAC;IACvB,UAAU,EAAE;QACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC/B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACjF,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC;IACxB,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACvB,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;IAC7C,CAAC,CAAC,CAAC;IACH,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;AAC3D,CAAC,CACF,CAAC;AAEF,mBAAmB;AACnB,cAAc;AACd,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,iBAAiB,EACjB;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;IAChC,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC9B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,cAAc;AACd,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,iBAAiB,EACjB;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;IAChC,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC9B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,cAAc;AACd,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,iBAAiB,EACjB;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;IAChC,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC9B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,gBAAgB;AAChB,QAAQ,CAAC,MAAM,CAAC,cAAc,CAQ5B,mBAAmB,EACnB;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,WAAW,CAAC;IACvB,UAAU,EAAE;QACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC9B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,OAAO;QACL,GAAG,EAAE;YACH,IAAI,EAAE,CAAC;YACP,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,UAAU;SACjB;KACF,CAAC;AACJ,CAAC,CACF,CAAC","sourcesContent":["import { IPosition } from '@yuants/data-account';\nimport { IOrder } from '@yuants/data-order';\nimport { cancelOrder, getOrders, getPositions, modifyOrder, submitOrder } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { getCredentialBySecretId } from './credential';\nimport { polyfillOrders, polyfillPosition } from './position';\nimport { IExchangeCredential } from './types';\n\nconst terminal = Terminal.fromNodeEnv();\n\nterminal.server.provideService<{ secret_id: string; product_id?: string }, IPosition[]>(\n 'VEX/GetPositions',\n {\n type: 'object',\n required: ['secret_id'],\n properties: {\n secret_id: { type: 'string' },\n product_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = await getCredentialBySecretId(msg.req.secret_id);\n const res = await getPositions(terminal, credential.credential, msg.req.product_id);\n if (!res.data) return { res };\n const positions = await polyfillPosition(res.data);\n positions.forEach((pos) => {\n pos.account_id = credential.credentialId;\n });\n return { res: { code: 0, message: 'OK', data: positions } };\n },\n);\n\nterminal.server.provideService<{ secret_id: string; product_id?: string }, IOrder[]>(\n 'VEX/GetOrders',\n {\n type: 'object',\n required: ['secret_id'],\n properties: {\n secret_id: { type: 'string' },\n product_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = await getCredentialBySecretId(msg.req.secret_id);\n const res = await getOrders(terminal, credential.credential, msg.req.product_id);\n if (!res.data) return { res };\n const orders = res.data;\n orders.forEach((order) => {\n order.account_id = credential.credentialId;\n });\n await polyfillOrders(orders);\n return { res: { code: 0, message: 'OK', data: orders } };\n },\n);\n\n// 10. Proxy Orders\n// SubmitOrder\nterminal.server.provideService<{ order: IOrder; secret_id: string }, { order_id: string }>(\n 'VEX/SubmitOrder',\n {\n type: 'object',\n required: ['order', 'secret_id'],\n properties: {\n order: { type: 'object' },\n secret_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = await getCredentialBySecretId(msg.req.secret_id);\n const [order] = await polyfillOrders([msg.req.order]);\n const res = await submitOrder(terminal, credential.credential, order);\n return { res };\n },\n);\n\n// ModifyOrder\nterminal.server.provideService<{ order: IOrder; secret_id: string }, void>(\n 'VEX/ModifyOrder',\n {\n type: 'object',\n required: ['order', 'secret_id'],\n properties: {\n order: { type: 'object' },\n secret_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = await getCredentialBySecretId(msg.req.secret_id);\n const [order] = await polyfillOrders([msg.req.order]);\n const res = await modifyOrder(terminal, credential.credential, order);\n return { res };\n },\n);\n\n// CancelOrder\nterminal.server.provideService<{ order: IOrder; secret_id: string }, void>(\n 'VEX/CancelOrder',\n {\n type: 'object',\n required: ['order', 'secret_id'],\n properties: {\n order: { type: 'object' },\n secret_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = await getCredentialBySecretId(msg.req.secret_id);\n const [order] = await polyfillOrders([msg.req.order]);\n const res = await cancelOrder(terminal, credential.credential, order);\n return { res };\n },\n);\n\n// GetCredential\nterminal.server.provideService<\n { secret_id: string },\n {\n sign: string;\n credential: IExchangeCredential;\n credentialId: string;\n }\n>(\n 'VEX/GetCredential',\n {\n type: 'object',\n required: ['secret_id'],\n properties: {\n secret_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = await getCredentialBySecretId(msg.req.secret_id);\n return {\n res: {\n code: 0,\n message: 'OK',\n data: credential,\n },\n };\n },\n);\n"]}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Terminal } from '@yuants/protocol';
|
|
2
|
+
import { decodePath, encodePath, formatTime, newError } from '@yuants/utils';
|
|
3
|
+
import { getCredentialByCredentialId } from '../credential';
|
|
4
|
+
import { findBackwardTaskFirstStartTime, findForwardTaskLastEndTime, findPatchGap } from './sql-helpers';
|
|
5
|
+
const parseInterestLedgerServiceMetadataFromSchema = (schema) => {
|
|
6
|
+
//
|
|
7
|
+
return {
|
|
8
|
+
type: schema.properties.credential.properties.type.const,
|
|
9
|
+
direction: schema.properties.direction.const,
|
|
10
|
+
ledgerTypes: schema.properties.ledger_type.enum,
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
const terminal = Terminal.fromNodeEnv();
|
|
14
|
+
export const listInterestLedgerSeriesIds = async () => {
|
|
15
|
+
// List All Credentials from VEX
|
|
16
|
+
const credentials = await terminal.client.requestForResponseData('VEX/ListExchangeCredential', {});
|
|
17
|
+
const series_ids = new Map();
|
|
18
|
+
for (const terminalInfo of terminal.terminalInfos) {
|
|
19
|
+
for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {
|
|
20
|
+
if (serviceInfo.method !== 'IngestInterestLedger')
|
|
21
|
+
continue;
|
|
22
|
+
try {
|
|
23
|
+
const meta = parseInterestLedgerServiceMetadataFromSchema(serviceInfo.schema);
|
|
24
|
+
for (const credential of credentials) {
|
|
25
|
+
if (!credential.credentialId)
|
|
26
|
+
continue;
|
|
27
|
+
if (credential.credential.type !== meta.type)
|
|
28
|
+
continue;
|
|
29
|
+
for (const ledgerType of meta.ledgerTypes) {
|
|
30
|
+
const series_id = encodeInterestLedgerSeriesId(credential.credentialId, ledgerType);
|
|
31
|
+
series_ids.set(series_id, meta.direction);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return series_ids;
|
|
40
|
+
};
|
|
41
|
+
export const encodeInterestLedgerSeriesId = (account_id, ledger_type) => encodePath(...decodePath(account_id), ledger_type);
|
|
42
|
+
export const decodeInterestLedgerSeriesId = (series_id) => {
|
|
43
|
+
const parts = decodePath(series_id);
|
|
44
|
+
const account_id = encodePath(...parts.slice(0, -1));
|
|
45
|
+
const ledger_type = parts[parts.length - 1];
|
|
46
|
+
return { account_id, ledger_type };
|
|
47
|
+
};
|
|
48
|
+
const ingestCounter = terminal.metrics
|
|
49
|
+
.counter('series_collector_ingest_count', '')
|
|
50
|
+
.labels({ terminal_id: terminal.terminal_id, type: 'interest_ledger' });
|
|
51
|
+
export const handleIngestInterestLedgerForward = async (series_id, direction, signal) => {
|
|
52
|
+
var _a, _b, _c, _d;
|
|
53
|
+
const { account_id, ledger_type } = decodeInterestLedgerSeriesId(series_id);
|
|
54
|
+
const credential = await getCredentialByCredentialId(account_id);
|
|
55
|
+
if (!credential)
|
|
56
|
+
throw newError('CREDENTIAL_NOT_FOUND_WHEN_HANDLING_INGEST', { account_id });
|
|
57
|
+
let req;
|
|
58
|
+
if (direction === 'forward') {
|
|
59
|
+
const endTime = await findForwardTaskLastEndTime(terminal, series_id, 'account_interest_ledger');
|
|
60
|
+
const time = endTime ? new Date(endTime).getTime() : 0;
|
|
61
|
+
req = {
|
|
62
|
+
account_id,
|
|
63
|
+
direction,
|
|
64
|
+
time,
|
|
65
|
+
ledger_type,
|
|
66
|
+
credential,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
req = {
|
|
71
|
+
account_id,
|
|
72
|
+
direction,
|
|
73
|
+
time: Date.now(),
|
|
74
|
+
ledger_type,
|
|
75
|
+
credential,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const res = await terminal.client.requestForResponseData('IngestInterestLedger', req);
|
|
79
|
+
ingestCounter.labels({ task: 'forward' }).inc(res.wrote_count || 0);
|
|
80
|
+
console.info(formatTime(Date.now()), '[SeriesCollector][InterestLedger][Forward]', 'Result', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
|
|
81
|
+
};
|
|
82
|
+
export const handleIngestInterestLedgerBackward = async (series_id, direction) => {
|
|
83
|
+
var _a, _b, _c, _d;
|
|
84
|
+
const { account_id, ledger_type } = decodeInterestLedgerSeriesId(series_id);
|
|
85
|
+
const credential = await getCredentialByCredentialId(account_id);
|
|
86
|
+
if (!credential)
|
|
87
|
+
throw newError('CREDENTIAL_NOT_FOUND_WHEN_HANDLING_INGEST', { account_id });
|
|
88
|
+
let req;
|
|
89
|
+
if (direction === 'backward') {
|
|
90
|
+
const startTime = await findBackwardTaskFirstStartTime(terminal, series_id, 'account_interest_ledger');
|
|
91
|
+
const time = startTime ? new Date(startTime).getTime() : Date.now();
|
|
92
|
+
req = {
|
|
93
|
+
account_id,
|
|
94
|
+
direction,
|
|
95
|
+
time,
|
|
96
|
+
ledger_type,
|
|
97
|
+
credential,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// do backward using forward request with time = 0
|
|
102
|
+
req = {
|
|
103
|
+
account_id,
|
|
104
|
+
direction,
|
|
105
|
+
time: 0,
|
|
106
|
+
ledger_type,
|
|
107
|
+
credential,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const res = await terminal.client.requestForResponseData('IngestInterestLedger', req);
|
|
111
|
+
ingestCounter.labels({ task: 'backward' }).inc(res.wrote_count || 0);
|
|
112
|
+
console.info(formatTime(Date.now()), '[SeriesCollector][InterestLedger][Backward]', 'Result', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
|
|
113
|
+
};
|
|
114
|
+
export const handleIngestInterestLedgerPatch = async (series_id, direction, signal) => {
|
|
115
|
+
var _a, _b, _c, _d;
|
|
116
|
+
const { account_id, ledger_type } = decodeInterestLedgerSeriesId(series_id);
|
|
117
|
+
const credential = await getCredentialByCredentialId(account_id);
|
|
118
|
+
if (!credential)
|
|
119
|
+
throw newError('CREDENTIAL_NOT_FOUND_WHEN_HANDLING_INGEST', { account_id });
|
|
120
|
+
const patch = await findPatchGap(terminal, 'account_interest_ledger', series_id);
|
|
121
|
+
if (!patch)
|
|
122
|
+
return; // no gap
|
|
123
|
+
const time = direction === 'forward'
|
|
124
|
+
? new Date(patch.gap_start_time).getTime()
|
|
125
|
+
: new Date(patch.gap_end_time).getTime();
|
|
126
|
+
const req = {
|
|
127
|
+
account_id,
|
|
128
|
+
direction,
|
|
129
|
+
time,
|
|
130
|
+
ledger_type,
|
|
131
|
+
credential,
|
|
132
|
+
};
|
|
133
|
+
const res = await terminal.client.requestForResponseData('IngestInterestLedger', req);
|
|
134
|
+
ingestCounter.labels({ task: 'patch' }).inc(res.wrote_count || 0);
|
|
135
|
+
console.info(formatTime(Date.now()), '[SeriesCollector][InterestLedger][Patch]', 'Result', `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime((_b = (_a = res.range) === null || _a === void 0 ? void 0 : _a.start_time) !== null && _b !== void 0 ? _b : NaN)}, end_time=${formatTime((_d = (_c = res.range) === null || _c === void 0 ? void 0 : _c.end_time) !== null && _d !== void 0 ? _d : NaN)}`);
|
|
136
|
+
};
|
|
137
|
+
export const InterestLedger = {
|
|
138
|
+
list: listInterestLedgerSeriesIds,
|
|
139
|
+
forward: handleIngestInterestLedgerForward,
|
|
140
|
+
backward: handleIngestInterestLedgerBackward,
|
|
141
|
+
patch: handleIngestInterestLedgerPatch,
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=interest-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interest-ledger.js","sourceRoot":"","sources":["../../src/series-collector/interest-ledger.ts"],"names":[],"mappings":"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","sourcesContent":["import { ISeriesIngestResult } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { decodePath, encodePath, formatTime, newError } from '@yuants/utils';\nimport { getCredentialByCredentialId } from '../credential';\nimport { IExchangeCredential } from '../types';\nimport { findBackwardTaskFirstStartTime, findForwardTaskLastEndTime, findPatchGap } from './sql-helpers';\n\nconst parseInterestLedgerServiceMetadataFromSchema = (\n schema: any,\n): { type: string; direction: 'backward' | 'forward'; ledgerTypes: string[] } => {\n //\n return {\n type: schema.properties.credential.properties.type.const,\n direction: schema.properties.direction.const,\n ledgerTypes: schema.properties.ledger_type.enum,\n };\n};\n\nconst terminal = Terminal.fromNodeEnv();\n\nexport const listInterestLedgerSeriesIds = async () => {\n // List All Credentials from VEX\n const credentials = await terminal.client.requestForResponseData<\n {},\n Array<{ sign: string; credential: IExchangeCredential; credentialId?: string }>\n >('VEX/ListExchangeCredential', {});\n\n const series_ids = new Map<string, 'forward' | 'backward'>();\n\n for (const terminalInfo of terminal.terminalInfos) {\n for (const serviceInfo of Object.values(terminalInfo.serviceInfo || {})) {\n if (serviceInfo.method !== 'IngestInterestLedger') continue;\n try {\n const meta = parseInterestLedgerServiceMetadataFromSchema(serviceInfo.schema);\n\n for (const credential of credentials) {\n if (!credential.credentialId) continue;\n if (credential.credential.type !== meta.type) continue;\n\n for (const ledgerType of meta.ledgerTypes) {\n const series_id = encodeInterestLedgerSeriesId(credential.credentialId, ledgerType);\n series_ids.set(series_id, meta.direction);\n }\n }\n } finally {\n }\n }\n }\n\n return series_ids;\n};\n\nexport const encodeInterestLedgerSeriesId = (account_id: string, ledger_type: string) =>\n encodePath(...decodePath(account_id), ledger_type);\n\nexport const decodeInterestLedgerSeriesId = (series_id: string) => {\n const parts = decodePath(series_id);\n const account_id = encodePath(...parts.slice(0, -1));\n const ledger_type = parts[parts.length - 1];\n return { account_id, ledger_type };\n};\n\ninterface IIngestInterestLedgerRequest {\n account_id: string;\n direction: 'forward' | 'backward';\n time: number;\n ledger_type: string;\n credential: IExchangeCredential;\n}\n\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'interest_ledger' });\n\nexport const handleIngestInterestLedgerForward = async (\n series_id: string,\n direction: 'forward' | 'backward',\n signal: AbortSignal,\n) => {\n const { account_id, ledger_type } = decodeInterestLedgerSeriesId(series_id);\n\n const credential = await getCredentialByCredentialId(account_id);\n if (!credential) throw newError('CREDENTIAL_NOT_FOUND_WHEN_HANDLING_INGEST', { account_id });\n\n let req: IIngestInterestLedgerRequest;\n\n if (direction === 'forward') {\n const endTime = await findForwardTaskLastEndTime(terminal, series_id, 'account_interest_ledger');\n const time = endTime ? new Date(endTime).getTime() : 0;\n req = {\n account_id,\n direction,\n time,\n ledger_type,\n credential,\n };\n } else {\n req = {\n account_id,\n direction,\n time: Date.now(),\n ledger_type,\n credential,\n };\n }\n\n const res = await terminal.client.requestForResponseData<IIngestInterestLedgerRequest, ISeriesIngestResult>(\n 'IngestInterestLedger',\n req,\n );\n\n ingestCounter.labels({ task: 'forward' }).inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestLedger][Forward]',\n 'Result',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n\nexport const handleIngestInterestLedgerBackward = async (\n series_id: string,\n direction: 'forward' | 'backward',\n) => {\n const { account_id, ledger_type } = decodeInterestLedgerSeriesId(series_id);\n\n const credential = await getCredentialByCredentialId(account_id);\n if (!credential) throw newError('CREDENTIAL_NOT_FOUND_WHEN_HANDLING_INGEST', { account_id });\n\n let req: IIngestInterestLedgerRequest;\n\n if (direction === 'backward') {\n const startTime = await findBackwardTaskFirstStartTime(terminal, series_id, 'account_interest_ledger');\n const time = startTime ? new Date(startTime).getTime() : Date.now();\n req = {\n account_id,\n direction,\n time,\n ledger_type,\n credential,\n };\n } else {\n // do backward using forward request with time = 0\n req = {\n account_id,\n direction,\n time: 0,\n ledger_type,\n credential,\n };\n }\n\n const res = await terminal.client.requestForResponseData<IIngestInterestLedgerRequest, ISeriesIngestResult>(\n 'IngestInterestLedger',\n req,\n );\n\n ingestCounter.labels({ task: 'backward' }).inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestLedger][Backward]',\n 'Result',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n\nexport const handleIngestInterestLedgerPatch = async (\n series_id: string,\n direction: 'forward' | 'backward',\n signal: AbortSignal,\n) => {\n const { account_id, ledger_type } = decodeInterestLedgerSeriesId(series_id);\n\n const credential = await getCredentialByCredentialId(account_id);\n if (!credential) throw newError('CREDENTIAL_NOT_FOUND_WHEN_HANDLING_INGEST', { account_id });\n\n const patch = await findPatchGap(terminal, 'account_interest_ledger', series_id);\n\n if (!patch) return; // no gap\n const time =\n direction === 'forward'\n ? new Date(patch.gap_start_time).getTime()\n : new Date(patch.gap_end_time).getTime();\n const req: IIngestInterestLedgerRequest = {\n account_id,\n direction,\n time,\n ledger_type,\n credential,\n };\n\n const res = await terminal.client.requestForResponseData<IIngestInterestLedgerRequest, ISeriesIngestResult>(\n 'IngestInterestLedger',\n req,\n );\n\n ingestCounter.labels({ task: 'patch' }).inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestLedger][Patch]',\n 'Result',\n `series_id=${series_id}, ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n\nexport const InterestLedger = {\n list: listInterestLedgerSeriesIds,\n forward: handleIngestInterestLedgerForward,\n backward: handleIngestInterestLedgerBackward,\n patch: handleIngestInterestLedgerPatch,\n};\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Terminal } from '@yuants/protocol';
|
|
2
|
-
import { escapeSQL, requestSQL } from '@yuants/sql';
|
|
3
2
|
import { formatTime } from '@yuants/utils';
|
|
3
|
+
import { findPatchGap } from './sql-helpers';
|
|
4
4
|
const terminal = Terminal.fromNodeEnv();
|
|
5
5
|
const ingestCounter = terminal.metrics
|
|
6
6
|
.counter('series_collector_ingest_count', '')
|
|
@@ -8,28 +8,7 @@ const ingestCounter = terminal.metrics
|
|
|
8
8
|
// Patch 任务:查找数据缺口并进行补齐
|
|
9
9
|
export const handleInterestRatePatch = async (product_id, direction, signal) => {
|
|
10
10
|
var _a, _b, _c, _d;
|
|
11
|
-
const
|
|
12
|
-
WITH reversed_ranges AS (
|
|
13
|
-
SELECT
|
|
14
|
-
start_time,
|
|
15
|
-
end_time,
|
|
16
|
-
LEAD(end_time) OVER (
|
|
17
|
-
PARTITION BY table_name, series_id
|
|
18
|
-
ORDER BY start_time DESC
|
|
19
|
-
) AS next_end_time -- 注意:倒序时 LEAD 是前一个区间
|
|
20
|
-
FROM series_data_range
|
|
21
|
-
WHERE table_name = 'interest_rate'
|
|
22
|
-
AND series_id = ${escapeSQL(product_id)}
|
|
23
|
-
)
|
|
24
|
-
SELECT
|
|
25
|
-
next_end_time AS gap_start_time, -- 前一个区间的结束时间
|
|
26
|
-
start_time AS gap_end_time -- 当前区间的开始时间
|
|
27
|
-
FROM reversed_ranges
|
|
28
|
-
WHERE next_end_time IS NOT NULL
|
|
29
|
-
AND start_time > next_end_time -- 有空缺
|
|
30
|
-
ORDER BY start_time DESC -- 从最新开始
|
|
31
|
-
LIMIT 1;
|
|
32
|
-
`);
|
|
11
|
+
const record = await findPatchGap(terminal, 'interest_rate', product_id);
|
|
33
12
|
// no gap
|
|
34
13
|
if (!record)
|
|
35
14
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch-interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/patch-interest-rate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"patch-interest-rate.js","sourceRoot":"","sources":["../../src/series-collector/patch-interest-rate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO;KACnC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;KAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AAEzF,uBAAuB;AACvB,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAC1C,UAAkB,EAClB,SAAiC,EACjC,MAAmB,EACnB,EAAE;;IACF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;IAEzE,SAAS;IACT,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC;IAE3D,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,wCAAwC,EACxC,SAAS,EACT,UAAU,UAAU,UAAU,UAAU,CAAC,YAAY,CAAC,QAAQ,UAAU,CAAC,UAAU,CAAC,EAAE,CACvF,CAAC;IAEF,IAAI,GAA+B,CAAC;IAEpC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,gBAAgB;QAChB,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,SAAkB;YAC7B,IAAI,EAAE,YAAY;SACnB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,iBAAiB;QACjB,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,UAAmB;YAC9B,IAAI,EAAE,UAAU;SACjB,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,wCAAwC,EACxC,UAAU,EACV,cAAc,EACd,aAAa,GAAG,CAAC,SAAS,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAC3D,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,oBAAoB,EACpB,GAAG,CACJ,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,wCAAwC,EACxC,UAAU,EACV,qBAAqB,EACrB,kBAAkB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CACzD,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { IIngestInterestRateRequest, ISeriesIngestResult } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { formatTime } from '@yuants/utils';\nimport { findPatchGap } from './sql-helpers';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'interest_rate', task: 'forward' });\n\n// Patch 任务:查找数据缺口并进行补齐\nexport const handleInterestRatePatch = async (\n product_id: string,\n direction: 'forward' | 'backward',\n signal: AbortSignal,\n) => {\n const record = await findPatchGap(terminal, 'interest_rate', product_id);\n\n // no gap\n if (!record) return;\n\n const gapStartTime = new Date(record.gap_start_time).getTime();\n const gapEndTime = new Date(record.gap_end_time).getTime();\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Patch]',\n 'FindGap',\n `series=${product_id}, from=${formatTime(gapStartTime)}, to=${formatTime(gapEndTime)}`,\n );\n\n let req: IIngestInterestRateRequest;\n\n if (direction === 'forward') {\n // forward patch\n req = {\n product_id: product_id,\n direction: 'forward' as const,\n time: gapStartTime,\n };\n } else {\n // backward patch\n req = {\n product_id: product_id,\n direction: 'backward' as const,\n time: gapEndTime,\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Patch]',\n product_id,\n 'PatchRequest',\n `direction=${req.direction}, time=${formatTime(req.time)}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestInterestRateRequest, ISeriesIngestResult>(\n 'IngestInterestRate',\n req,\n );\n\n ingestCounter.inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][InterestRate][Patch]',\n product_id,\n 'PatchBackwardResult',\n `ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { decodeOHLCSeriesId } from '@yuants/data-ohlc';
|
|
2
2
|
import { Terminal } from '@yuants/protocol';
|
|
3
|
-
import { escapeSQL, requestSQL } from '@yuants/sql';
|
|
4
3
|
import { formatTime } from '@yuants/utils';
|
|
4
|
+
import { findPatchGap } from './sql-helpers';
|
|
5
5
|
const terminal = Terminal.fromNodeEnv();
|
|
6
6
|
const ingestCounter = terminal.metrics
|
|
7
7
|
.counter('series_collector_ingest_count', '')
|
|
@@ -9,28 +9,7 @@ const ingestCounter = terminal.metrics
|
|
|
9
9
|
// Patch 任务:查找数据缺口并进行补齐
|
|
10
10
|
export const handleIngestOHLCPatch = async (series_id, direction, signal) => {
|
|
11
11
|
var _a, _b, _c, _d;
|
|
12
|
-
const
|
|
13
|
-
WITH reversed_ranges AS (
|
|
14
|
-
SELECT
|
|
15
|
-
start_time,
|
|
16
|
-
end_time,
|
|
17
|
-
LEAD(end_time) OVER (
|
|
18
|
-
PARTITION BY table_name, series_id
|
|
19
|
-
ORDER BY start_time DESC
|
|
20
|
-
) AS next_end_time -- 注意:倒序时 LEAD 是前一个区间
|
|
21
|
-
FROM series_data_range
|
|
22
|
-
WHERE table_name = 'ohlc_v2'
|
|
23
|
-
AND series_id = ${escapeSQL(series_id)}
|
|
24
|
-
)
|
|
25
|
-
SELECT
|
|
26
|
-
next_end_time AS gap_start_time, -- 前一个区间的结束时间
|
|
27
|
-
start_time AS gap_end_time -- 当前区间的开始时间
|
|
28
|
-
FROM reversed_ranges
|
|
29
|
-
WHERE next_end_time IS NOT NULL
|
|
30
|
-
AND start_time > next_end_time -- 有空缺
|
|
31
|
-
ORDER BY start_time DESC -- 从最新开始
|
|
32
|
-
LIMIT 1;
|
|
33
|
-
`);
|
|
12
|
+
const record = await findPatchGap(terminal, 'ohlc_v2', series_id);
|
|
34
13
|
// no gap
|
|
35
14
|
if (!record)
|
|
36
15
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch-ohlc.js","sourceRoot":"","sources":["../../src/series-collector/patch-ohlc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"patch-ohlc.js","sourceRoot":"","sources":["../../src/series-collector/patch-ohlc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO;KACnC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;KAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AAEhF,uBAAuB;AACvB,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EACxC,SAAiB,EACjB,SAAiC,EACjC,MAAmB,EACnB,EAAE;;IACF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAElE,SAAS;IACT,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC;IAE3D,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,gCAAgC,EAChC,SAAS,EACT,UAAU,SAAS,UAAU,UAAU,CAAC,YAAY,CAAC,QAAQ,UAAU,CAAC,UAAU,CAAC,EAAE,CACtF,CAAC;IAEF,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAE/D,IAAI,GAAuB,CAAC;IAE5B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,gBAAgB;QAChB,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,QAAQ;YACR,SAAS,EAAE,SAAkB;YAC7B,IAAI,EAAE,YAAY;SACnB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,iBAAiB;QACjB,GAAG,GAAG;YACJ,UAAU,EAAE,UAAU;YACtB,QAAQ;YACR,SAAS,EAAE,UAAmB;YAC9B,IAAI,EAAE,UAAU;SACjB,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,gCAAgC,EAChC,SAAS,EACT,cAAc,EACd,aAAa,GAAG,CAAC,SAAS,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAC3D,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CACtD,YAAY,EACZ,GAAG,CACJ,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,IAAI,CACV,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EACtB,gCAAgC,EAChC,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GAAG,CAAC,WAAW,gBAAgB,UAAU,CACzD,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,UAAU,mCAAI,GAAG,CAC7B,cAAc,UAAU,CAAC,MAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,mCAAI,GAAG,CAAC,EAAE,CACxD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { decodeOHLCSeriesId } from '@yuants/data-ohlc';\nimport { IIngestOHLCRequest, ISeriesIngestResult } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { formatTime } from '@yuants/utils';\nimport { findPatchGap } from './sql-helpers';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst ingestCounter = terminal.metrics\n .counter('series_collector_ingest_count', '')\n .labels({ terminal_id: terminal.terminal_id, type: 'ohlc', task: 'forward' });\n\n// Patch 任务:查找数据缺口并进行补齐\nexport const handleIngestOHLCPatch = async (\n series_id: string,\n direction: 'forward' | 'backward',\n signal: AbortSignal,\n) => {\n const record = await findPatchGap(terminal, 'ohlc_v2', series_id);\n\n // no gap\n if (!record) return;\n\n const gapStartTime = new Date(record.gap_start_time).getTime();\n const gapEndTime = new Date(record.gap_end_time).getTime();\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Patch]',\n 'FindGap',\n `series=${series_id}, from=${formatTime(gapStartTime)}, to=${formatTime(gapEndTime)}`,\n );\n\n const { product_id, duration } = decodeOHLCSeriesId(series_id);\n\n let req: IIngestOHLCRequest;\n\n if (direction === 'forward') {\n // forward patch\n req = {\n product_id: product_id,\n duration,\n direction: 'forward' as const,\n time: gapStartTime,\n };\n } else {\n // backward patch\n req = {\n product_id: product_id,\n duration,\n direction: 'backward' as const,\n time: gapEndTime,\n };\n }\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Patch]',\n series_id,\n 'PatchRequest',\n `direction=${req.direction}, time=${formatTime(req.time)}`,\n );\n\n const res = await terminal.client.requestForResponseData<IIngestOHLCRequest, ISeriesIngestResult>(\n 'IngestOHLC',\n req,\n );\n\n ingestCounter.inc(res.wrote_count || 0);\n\n console.info(\n formatTime(Date.now()),\n '[SeriesCollector][OHLC][Patch]',\n series_id,\n 'PatchBackwardResult',\n `ingested_count=${res.wrote_count}, start_time=${formatTime(\n res.range?.start_time ?? NaN,\n )}, end_time=${formatTime(res.range?.end_time ?? NaN)}`,\n );\n};\n"]}
|
|
@@ -4,6 +4,7 @@ import { handleIngestOHLCBackward } from './backwards-ohlc';
|
|
|
4
4
|
import { listInterestRateSeriesIds, listOHLCSeriesIds } from './discovery';
|
|
5
5
|
import { handleIngestInterestRateForward } from './forwards-interest-rate';
|
|
6
6
|
import { handleIngestOHLCForward } from './forwards-ohlc';
|
|
7
|
+
import { InterestLedger } from './interest-ledger';
|
|
7
8
|
import { handleInterestRatePatch } from './patch-interest-rate';
|
|
8
9
|
import { handleIngestOHLCPatch } from './patch-ohlc';
|
|
9
10
|
const api = {
|
|
@@ -19,11 +20,12 @@ const api = {
|
|
|
19
20
|
backward: handleIngestInterestRateBackward,
|
|
20
21
|
patch: handleInterestRatePatch,
|
|
21
22
|
},
|
|
23
|
+
InterestLedger,
|
|
22
24
|
};
|
|
23
25
|
(async () => {
|
|
24
26
|
const abortController = new AbortController();
|
|
25
27
|
const signal = abortController.signal;
|
|
26
|
-
for (const type of ['OHLC', 'InterestRate']) {
|
|
28
|
+
for (const type of ['OHLC', 'InterestRate', 'InterestLedger']) {
|
|
27
29
|
const list = api[type].list;
|
|
28
30
|
for (const task of ['forward', 'backward', 'patch']) {
|
|
29
31
|
const handler = api[type][task];
|
|
@@ -32,17 +34,7 @@ const api = {
|
|
|
32
34
|
await tokenBucket(`${type}:${task}`).acquire(1, signal);
|
|
33
35
|
try {
|
|
34
36
|
const tasks = await list();
|
|
35
|
-
|
|
36
|
-
const groups = new Map();
|
|
37
|
-
for (const item of tasks) {
|
|
38
|
-
const [datasource_id] = decodePath(item[0]);
|
|
39
|
-
let items = groups.get(datasource_id);
|
|
40
|
-
if (!items) {
|
|
41
|
-
items = [];
|
|
42
|
-
groups.set(datasource_id, items);
|
|
43
|
-
}
|
|
44
|
-
items.push(item);
|
|
45
|
-
}
|
|
37
|
+
const groups = Map.groupBy(tasks, (item) => decodePath(item[0])[0]);
|
|
46
38
|
await Promise.all(Array.from(groups.entries()).map(async ([datasource_id, tasks]) => {
|
|
47
39
|
for (const [series_id, direction] of tasks) {
|
|
48
40
|
await tokenBucket(`${type}:${task}:${datasource_id}`).acquire(1, signal);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/series-collector/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,GAAG,GAAG;IACV,IAAI,EAAE;QACJ,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,uBAAuB;QAChC,QAAQ,EAAE,wBAAwB;QAClC,KAAK,EAAE,qBAAqB;KAC7B;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,yBAAyB;QAC/B,OAAO,EAAE,+BAA+B;QACxC,QAAQ,EAAE,gCAAgC;QAC1C,KAAK,EAAE,uBAAuB;KAC/B;
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/series-collector/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import { decodePath, formatTime, tokenBucket } from '@yuants/utils';\nimport { handleIngestInterestRateBackward } from './backwards-interest-rate';\nimport { handleIngestOHLCBackward } from './backwards-ohlc';\nimport { listInterestRateSeriesIds, listOHLCSeriesIds } from './discovery';\nimport { handleIngestInterestRateForward } from './forwards-interest-rate';\nimport { handleIngestOHLCForward } from './forwards-ohlc';\nimport { InterestLedger } from './interest-ledger';\nimport { handleInterestRatePatch } from './patch-interest-rate';\nimport { handleIngestOHLCPatch } from './patch-ohlc';\n\nconst api = {\n OHLC: {\n list: listOHLCSeriesIds,\n forward: handleIngestOHLCForward,\n backward: handleIngestOHLCBackward,\n patch: handleIngestOHLCPatch,\n },\n InterestRate: {\n list: listInterestRateSeriesIds,\n forward: handleIngestInterestRateForward,\n backward: handleIngestInterestRateBackward,\n patch: handleInterestRatePatch,\n },\n InterestLedger,\n};\n\n(async () => {\n const abortController = new AbortController();\n const signal = abortController.signal;\n for (const type of ['OHLC', 'InterestRate', 'InterestLedger'] as const) {\n const list = api[type].list;\n for (const task of ['forward', 'backward', 'patch'] as const) {\n const handler = api[type][task];\n (async () => {\n while (true) {\n await tokenBucket(`${type}:${task}`).acquire(1, signal);\n try {\n const tasks = await list();\n\n const groups = Map.groupBy(tasks, (item) => decodePath(item[0])[0]);\n\n await Promise.all(\n Array.from(groups.entries()).map(async ([datasource_id, tasks]) => {\n for (const [series_id, direction] of tasks) {\n await tokenBucket(`${type}:${task}:${datasource_id}`).acquire(1, signal);\n await handler(series_id, direction, signal).catch((err) => {\n console.info(\n formatTime(Date.now()),\n `[SeriesCollector][${type}][${task}]`,\n series_id,\n 'Error',\n err,\n );\n });\n }\n }),\n );\n } catch (e) {}\n }\n })();\n }\n }\n})();\n"]}
|
|
@@ -8,4 +8,31 @@ import { escapeSQL, requestSQL } from '@yuants/sql';
|
|
|
8
8
|
export const findInterestRateEndTimeForward = (terminal, product_id) => requestSQL(terminal, `select end_time from series_data_range where series_id = ${escapeSQL(product_id)} and table_name = 'interest_rate' order by end_time desc limit 1`).then((records) => { var _a; return (_a = records === null || records === void 0 ? void 0 : records[0]) === null || _a === void 0 ? void 0 : _a.end_time; });
|
|
9
9
|
export const findInterestRateStartTimeBackward = (terminal, product_id) => requestSQL(terminal, `select start_time from series_data_range where series_id = ${escapeSQL(product_id)} and table_name = 'interest_rate' order by start_time asc limit 1`).then((records) => { var _a; return (_a = records === null || records === void 0 ? void 0 : records[0]) === null || _a === void 0 ? void 0 : _a.start_time; });
|
|
10
10
|
export const findOHLCEndTimeForward = (terminal, series_id) => requestSQL(terminal, `select end_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = 'ohlc_v2' order by end_time desc limit 1`).then((records) => { var _a; return (_a = records === null || records === void 0 ? void 0 : records[0]) === null || _a === void 0 ? void 0 : _a.end_time; });
|
|
11
|
+
export const findForwardTaskLastEndTime = (terminal, series_id, table_name) => requestSQL(terminal, `select end_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = ${escapeSQL(table_name)} order by end_time desc limit 1`).then((records) => { var _a; return (_a = records === null || records === void 0 ? void 0 : records[0]) === null || _a === void 0 ? void 0 : _a.end_time; });
|
|
12
|
+
export const findBackwardTaskFirstStartTime = (terminal, series_id, table_name) => requestSQL(terminal, `select start_time from series_data_range where series_id = ${escapeSQL(series_id)} and table_name = ${escapeSQL(table_name)} order by start_time asc limit 1`).then((records) => { var _a; return (_a = records === null || records === void 0 ? void 0 : records[0]) === null || _a === void 0 ? void 0 : _a.start_time; });
|
|
13
|
+
export const findPatchGap = async (terminal, table_name, series_id) => {
|
|
14
|
+
const [record] = await requestSQL(terminal, `
|
|
15
|
+
WITH reversed_ranges AS (
|
|
16
|
+
SELECT
|
|
17
|
+
start_time,
|
|
18
|
+
end_time,
|
|
19
|
+
LEAD(end_time) OVER (
|
|
20
|
+
PARTITION BY table_name, series_id
|
|
21
|
+
ORDER BY start_time DESC
|
|
22
|
+
) AS next_end_time -- 注意:倒序时 LEAD 是前一个区间
|
|
23
|
+
FROM series_data_range
|
|
24
|
+
WHERE table_name = ${escapeSQL(table_name)}
|
|
25
|
+
AND series_id = ${escapeSQL(series_id)}
|
|
26
|
+
)
|
|
27
|
+
SELECT
|
|
28
|
+
next_end_time AS gap_start_time, -- 前一个区间的结束时间
|
|
29
|
+
start_time AS gap_end_time -- 当前区间的开始时间
|
|
30
|
+
FROM reversed_ranges
|
|
31
|
+
WHERE next_end_time IS NOT NULL
|
|
32
|
+
AND start_time > next_end_time -- 有空缺
|
|
33
|
+
ORDER BY start_time DESC -- 从最新开始
|
|
34
|
+
LIMIT 1;
|
|
35
|
+
`);
|
|
36
|
+
return record;
|
|
37
|
+
};
|
|
11
38
|
//# sourceMappingURL=sql-helpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-helpers.js","sourceRoot":"","sources":["../../src/series-collector/sql-helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,QAAkB,EAAE,UAAkB,EAAE,EAAE,CACvF,UAAU,CAKR,QAAQ,EACR,4DAA4D,SAAS,CACnE,UAAU,CACX,kEAAkE,CACpE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,QAAQ,CAAA,EAAA,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,QAAkB,EAAE,UAAkB,EAAE,EAAE,CAC1F,UAAU,CAKR,QAAQ,EACR,8DAA8D,SAAS,CACrE,UAAU,CACX,mEAAmE,CACrE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,UAAU,CAAA,EAAA,CAAC,CAAC;AAEhD,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAAkB,EAAE,SAAiB,EAAE,EAAE,CAC9E,UAAU,CAKR,QAAQ,EACR,4DAA4D,SAAS,CACnE,SAAS,CACV,4DAA4D,CAC9D,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,QAAQ,CAAA,EAAA,CAAC,CAAC","sourcesContent":["import { Terminal } from '@yuants/protocol';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\n\n/**\n * 查找某个利率品种系列ID的最新结束时间(for forward task)\n * @param terminal\n * @param product_id\n * @returns\n */\nexport const findInterestRateEndTimeForward = (terminal: Terminal, product_id: string) =>\n requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n product_id,\n )} and table_name = 'interest_rate' order by end_time desc limit 1`,\n ).then((records) => records?.[0]?.end_time);\n\nexport const findInterestRateStartTimeBackward = (terminal: Terminal, product_id: string) =>\n requestSQL<\n {\n start_time: string;\n }[]\n >(\n terminal,\n `select start_time from series_data_range where series_id = ${escapeSQL(\n product_id,\n )} and table_name = 'interest_rate' order by start_time asc limit 1`,\n ).then((records) => records?.[0]?.start_time);\n\nexport const findOHLCEndTimeForward = (terminal: Terminal, series_id: string) =>\n requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = 'ohlc_v2' order by end_time desc limit 1`,\n ).then((records) => records?.[0]?.end_time);\n"]}
|
|
1
|
+
{"version":3,"file":"sql-helpers.js","sourceRoot":"","sources":["../../src/series-collector/sql-helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,QAAkB,EAAE,UAAkB,EAAE,EAAE,CACvF,UAAU,CAKR,QAAQ,EACR,4DAA4D,SAAS,CACnE,UAAU,CACX,kEAAkE,CACpE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,QAAQ,CAAA,EAAA,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,QAAkB,EAAE,UAAkB,EAAE,EAAE,CAC1F,UAAU,CAKR,QAAQ,EACR,8DAA8D,SAAS,CACrE,UAAU,CACX,mEAAmE,CACrE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,UAAU,CAAA,EAAA,CAAC,CAAC;AAEhD,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAAkB,EAAE,SAAiB,EAAE,EAAE,CAC9E,UAAU,CAKR,QAAQ,EACR,4DAA4D,SAAS,CACnE,SAAS,CACV,4DAA4D,CAC9D,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,QAAQ,CAAA,EAAA,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,QAAkB,EAAE,SAAiB,EAAE,UAAkB,EAAE,EAAE,CACtG,UAAU,CAKR,QAAQ,EACR,4DAA4D,SAAS,CACnE,SAAS,CACV,qBAAqB,SAAS,CAAC,UAAU,CAAC,iCAAiC,CAC7E,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,QAAQ,CAAA,EAAA,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,QAAkB,EAAE,SAAiB,EAAE,UAAkB,EAAE,EAAE,CAC1G,UAAU,CAKR,QAAQ,EACR,8DAA8D,SAAS,CACrE,SAAS,CACV,qBAAqB,SAAS,CAAC,UAAU,CAAC,kCAAkC,CAC9E,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,WAAC,OAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,0CAAE,UAAU,CAAA,EAAA,CAAC,CAAC;AAEhD,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,QAAkB,EAClB,UAAkB,EAClB,SAAiB,EAOjB,EAAE;IACF,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,UAAU,CAC/B,QAAQ,EACR;;;;;;;;;;yBAUqB,SAAS,CAAC,UAAU,CAAC;wBACtB,SAAS,CAAC,SAAS,CAAC;;;;;;;;;;KAUvC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC","sourcesContent":["import { Terminal } from '@yuants/protocol';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\n\n/**\n * 查找某个利率品种系列ID的最新结束时间(for forward task)\n * @param terminal\n * @param product_id\n * @returns\n */\nexport const findInterestRateEndTimeForward = (terminal: Terminal, product_id: string) =>\n requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n product_id,\n )} and table_name = 'interest_rate' order by end_time desc limit 1`,\n ).then((records) => records?.[0]?.end_time);\n\nexport const findInterestRateStartTimeBackward = (terminal: Terminal, product_id: string) =>\n requestSQL<\n {\n start_time: string;\n }[]\n >(\n terminal,\n `select start_time from series_data_range where series_id = ${escapeSQL(\n product_id,\n )} and table_name = 'interest_rate' order by start_time asc limit 1`,\n ).then((records) => records?.[0]?.start_time);\n\nexport const findOHLCEndTimeForward = (terminal: Terminal, series_id: string) =>\n requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = 'ohlc_v2' order by end_time desc limit 1`,\n ).then((records) => records?.[0]?.end_time);\n\nexport const findForwardTaskLastEndTime = (terminal: Terminal, series_id: string, table_name: string) =>\n requestSQL<\n {\n end_time: string;\n }[]\n >(\n terminal,\n `select end_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = ${escapeSQL(table_name)} order by end_time desc limit 1`,\n ).then((records) => records?.[0]?.end_time);\n\nexport const findBackwardTaskFirstStartTime = (terminal: Terminal, series_id: string, table_name: string) =>\n requestSQL<\n {\n start_time: string;\n }[]\n >(\n terminal,\n `select start_time from series_data_range where series_id = ${escapeSQL(\n series_id,\n )} and table_name = ${escapeSQL(table_name)} order by start_time asc limit 1`,\n ).then((records) => records?.[0]?.start_time);\n\nexport const findPatchGap = async (\n terminal: Terminal,\n table_name: string,\n series_id: string,\n): Promise<\n | {\n gap_start_time: string;\n gap_end_time: string;\n }\n | undefined\n> => {\n const [record] = await requestSQL<{ gap_start_time: string; gap_end_time: string }[]>(\n terminal,\n `\nWITH reversed_ranges AS (\n SELECT \n start_time,\n end_time,\n LEAD(end_time) OVER (\n PARTITION BY table_name, series_id \n ORDER BY start_time DESC\n ) AS next_end_time -- 注意:倒序时 LEAD 是前一个区间\n FROM series_data_range\n WHERE table_name = ${escapeSQL(table_name)} \n AND series_id = ${escapeSQL(series_id)}\n)\nSELECT \n next_end_time AS gap_start_time, -- 前一个区间的结束时间\n start_time AS gap_end_time -- 当前区间的开始时间\nFROM reversed_ranges\nWHERE next_end_time IS NOT NULL \n AND start_time > next_end_time -- 有空缺\nORDER BY start_time DESC -- 从最新开始\nLIMIT 1;\n `,\n );\n\n return record;\n};\n"]}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface IExchangeCredential {\n type: string;\n payload: any;\n}\n"]}
|
package/lib/credential.d.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { IExchangeCredential } from './types';
|
|
2
|
+
export declare const allCredentials$: import("rxjs").Observable<{
|
|
3
|
+
sign: string;
|
|
4
|
+
credential: IExchangeCredential | null;
|
|
5
|
+
credentialId: string | null;
|
|
6
|
+
error: any;
|
|
7
|
+
}[]>;
|
|
8
|
+
export declare const mapCredentialIdToCredentials$: import("rxjs").Observable<Map<string, {
|
|
9
|
+
sign: string;
|
|
10
|
+
credential: IExchangeCredential | null;
|
|
11
|
+
credentialId: string | null;
|
|
12
|
+
error: any;
|
|
13
|
+
}[]>>;
|
|
5
14
|
export declare const validCredentials$: import("rxjs").Observable<Map<string, IExchangeCredential>>;
|
|
6
15
|
export declare const validCredentialTypes$: import("rxjs").Observable<string[]>;
|
|
16
|
+
export declare const getCredentialByCredentialId: (credentialId: string) => Promise<IExchangeCredential | null | undefined>;
|
|
7
17
|
/**
|
|
8
18
|
* 根据 secret sign 解析出对应的 credential 以及 credential ID
|
|
9
19
|
* @param sign - secret sign
|