@tigeropenapi/tigeropen 0.1.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.
Files changed (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/dist/cjs/client/api-request.js +26 -0
  4. package/dist/cjs/client/api-response.js +18 -0
  5. package/dist/cjs/client/errors.js +51 -0
  6. package/dist/cjs/client/http-client.js +149 -0
  7. package/dist/cjs/client/index.js +19 -0
  8. package/dist/cjs/client/retry.js +54 -0
  9. package/dist/cjs/config/client-config.js +114 -0
  10. package/dist/cjs/config/config-parser.js +142 -0
  11. package/dist/cjs/config/domain.js +97 -0
  12. package/dist/cjs/config/index.js +14 -0
  13. package/dist/cjs/config/token-manager.js +116 -0
  14. package/dist/cjs/index.js +21 -0
  15. package/dist/cjs/logger/index.js +20 -0
  16. package/dist/cjs/logger/logger.js +68 -0
  17. package/dist/cjs/model/contract-helpers.js +38 -0
  18. package/dist/cjs/model/contract.js +6 -0
  19. package/dist/cjs/model/enums.js +110 -0
  20. package/dist/cjs/model/order-helpers.js +104 -0
  21. package/dist/cjs/model/order.js +6 -0
  22. package/dist/cjs/model/position.js +6 -0
  23. package/dist/cjs/push/callbacks.js +2 -0
  24. package/dist/cjs/push/index.js +25 -0
  25. package/dist/cjs/push/push-client.js +423 -0
  26. package/dist/cjs/push/push-message.js +83 -0
  27. package/dist/cjs/quote/index.js +8 -0
  28. package/dist/cjs/quote/quote-client.js +110 -0
  29. package/dist/cjs/signer/index.js +12 -0
  30. package/dist/cjs/signer/sign-content.js +19 -0
  31. package/dist/cjs/signer/signer.js +93 -0
  32. package/dist/cjs/trade/index.js +8 -0
  33. package/dist/cjs/trade/trade-client.js +99 -0
  34. package/dist/esm/client/api-request.js +23 -0
  35. package/dist/esm/client/api-response.js +15 -0
  36. package/dist/esm/client/errors.js +46 -0
  37. package/dist/esm/client/http-client.js +145 -0
  38. package/dist/esm/client/index.js +8 -0
  39. package/dist/esm/client/retry.js +48 -0
  40. package/dist/esm/config/client-config.js +111 -0
  41. package/dist/esm/config/config-parser.js +105 -0
  42. package/dist/esm/config/domain.js +93 -0
  43. package/dist/esm/config/index.js +6 -0
  44. package/dist/esm/config/token-manager.js +112 -0
  45. package/dist/esm/index.js +18 -0
  46. package/dist/esm/logger/index.js +4 -0
  47. package/dist/esm/logger/logger.js +61 -0
  48. package/dist/esm/model/contract-helpers.js +29 -0
  49. package/dist/esm/model/contract.js +5 -0
  50. package/dist/esm/model/enums.js +107 -0
  51. package/dist/esm/model/order-helpers.js +93 -0
  52. package/dist/esm/model/order.js +5 -0
  53. package/dist/esm/model/position.js +5 -0
  54. package/dist/esm/push/callbacks.js +1 -0
  55. package/dist/esm/push/index.js +6 -0
  56. package/dist/esm/push/push-client.js +419 -0
  57. package/dist/esm/push/push-message.js +77 -0
  58. package/dist/esm/quote/index.js +4 -0
  59. package/dist/esm/quote/quote-client.js +106 -0
  60. package/dist/esm/signer/index.js +5 -0
  61. package/dist/esm/signer/sign-content.js +16 -0
  62. package/dist/esm/signer/signer.js +88 -0
  63. package/dist/esm/trade/index.js +4 -0
  64. package/dist/esm/trade/trade-client.js +95 -0
  65. package/dist/types/client/api-request.d.ts +18 -0
  66. package/dist/types/client/api-response.d.ts +16 -0
  67. package/dist/types/client/errors.d.ts +19 -0
  68. package/dist/types/client/http-client.d.ts +45 -0
  69. package/dist/types/client/index.d.ts +8 -0
  70. package/dist/types/client/retry.d.ts +37 -0
  71. package/dist/types/config/client-config.d.ts +43 -0
  72. package/dist/types/config/config-parser.d.ts +16 -0
  73. package/dist/types/config/domain.d.ts +18 -0
  74. package/dist/types/config/index.d.ts +7 -0
  75. package/dist/types/config/token-manager.d.ts +38 -0
  76. package/dist/types/index.d.ts +18 -0
  77. package/dist/types/logger/index.d.ts +4 -0
  78. package/dist/types/logger/logger.d.ts +42 -0
  79. package/dist/types/model/contract-helpers.d.ts +18 -0
  80. package/dist/types/model/contract.d.ts +60 -0
  81. package/dist/types/model/enums.d.ts +97 -0
  82. package/dist/types/model/order-helpers.d.ts +22 -0
  83. package/dist/types/model/order.d.ts +95 -0
  84. package/dist/types/model/position.d.ts +39 -0
  85. package/dist/types/push/callbacks.d.ts +57 -0
  86. package/dist/types/push/index.d.ts +7 -0
  87. package/dist/types/push/push-client.d.ts +139 -0
  88. package/dist/types/push/push-message.d.ts +167 -0
  89. package/dist/types/quote/index.d.ts +4 -0
  90. package/dist/types/quote/quote-client.d.ts +58 -0
  91. package/dist/types/signer/index.d.ts +5 -0
  92. package/dist/types/signer/sign-content.d.ts +13 -0
  93. package/dist/types/signer/signer.d.ts +36 -0
  94. package/dist/types/trade/index.d.ts +4 -0
  95. package/dist/types/trade/trade-client.d.ts +48 -0
  96. package/package.json +54 -0
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createClientConfig = createClientConfig;
4
+ /**
5
+ * ClientConfig - 客户端配置管理
6
+ *
7
+ * 聚合所有配置参数,支持:
8
+ * - 代码直接设置
9
+ * - 从 properties 配置文件加载
10
+ * - 环境变量覆盖
11
+ *
12
+ * 优先级:环境变量 > 代码设置(含配置文件) > 默认值
13
+ */
14
+ const fs_1 = require("fs");
15
+ const config_parser_1 = require("./config-parser");
16
+ const domain_1 = require("./domain");
17
+ /** 默认值 */
18
+ const DEFAULT_LANGUAGE = 'zh_CN';
19
+ const DEFAULT_TIMEOUT = 15;
20
+ const DEFAULT_SERVER_URL = 'https://openapi.tigerfintech.com/gateway';
21
+ const SANDBOX_SERVER_URL = 'https://openapi-sandbox.tigerfintech.com/gateway';
22
+ /** 环境变量名 */
23
+ const ENV_TIGER_ID = 'TIGEROPEN_TIGER_ID';
24
+ const ENV_PRIVATE_KEY = 'TIGEROPEN_PRIVATE_KEY';
25
+ const ENV_ACCOUNT = 'TIGEROPEN_ACCOUNT';
26
+ /**
27
+ * 创建客户端配置。
28
+ *
29
+ * 优先级:环境变量 > 代码设置(含配置文件) > 默认值。
30
+ * 必填字段 tigerId 和 privateKey 为空时抛出错误。
31
+ *
32
+ * @param options - 配置选项
33
+ * @returns 完整的客户端配置对象
34
+ * @throws tigerId 或 privateKey 为空时抛出错误
35
+ */
36
+ function createClientConfig(options) {
37
+ // 从配置文件加载(如果指定了路径)
38
+ let fileProps = {};
39
+ if (options.propertiesFilePath) {
40
+ try {
41
+ const content = (0, fs_1.readFileSync)(options.propertiesFilePath, 'utf-8');
42
+ fileProps = (0, config_parser_1.parsePropertiesString)(content);
43
+ }
44
+ catch {
45
+ // 文件加载失败时静默跳过,后续校验会捕获必填字段缺失
46
+ }
47
+ }
48
+ // 从配置文件提取值(代码设置优先于配置文件)
49
+ let tigerId = options.tigerId || fileProps['tiger_id'] || '';
50
+ let privateKey = options.privateKey || resolvePrivateKey(fileProps) || '';
51
+ let account = options.account || fileProps['account'] || '';
52
+ const license = options.license || fileProps['license'];
53
+ const language = options.language || fileProps['language'] || DEFAULT_LANGUAGE;
54
+ const timezone = options.timezone || fileProps['timezone'];
55
+ // 环境变量覆盖(最高优先级)
56
+ const envTigerId = process.env[ENV_TIGER_ID];
57
+ const envPrivateKey = process.env[ENV_PRIVATE_KEY];
58
+ const envAccount = process.env[ENV_ACCOUNT];
59
+ if (envTigerId) {
60
+ tigerId = envTigerId;
61
+ }
62
+ if (envPrivateKey) {
63
+ privateKey = envPrivateKey;
64
+ }
65
+ if (envAccount) {
66
+ account = envAccount;
67
+ }
68
+ // 校验必填字段
69
+ if (!tigerId) {
70
+ throw new Error(`tigerId 不能为空,请通过 options.tigerId 或环境变量 ${ENV_TIGER_ID} 设置`);
71
+ }
72
+ if (!privateKey) {
73
+ throw new Error(`privateKey 不能为空,请通过 options.privateKey 或环境变量 ${ENV_PRIVATE_KEY} 设置`);
74
+ }
75
+ // 确定服务器 URL:sandbox > 动态域名 > 默认
76
+ const sandboxDebug = options.sandboxDebug ?? false;
77
+ const enableDynamicDomain = options.enableDynamicDomain ?? true;
78
+ let serverUrl;
79
+ if (sandboxDebug) {
80
+ serverUrl = SANDBOX_SERVER_URL;
81
+ }
82
+ else if (options.serverUrl) {
83
+ serverUrl = options.serverUrl;
84
+ }
85
+ else {
86
+ // 尝试动态域名获取
87
+ let dynamicUrl = '';
88
+ if (enableDynamicDomain) {
89
+ const domainConf = (0, domain_1.queryDomains)(license);
90
+ dynamicUrl = (0, domain_1.resolveDynamicServerUrl)(domainConf, license);
91
+ }
92
+ serverUrl = dynamicUrl || DEFAULT_SERVER_URL;
93
+ }
94
+ return {
95
+ tigerId,
96
+ privateKey,
97
+ account,
98
+ license,
99
+ language,
100
+ timezone,
101
+ timeout: options.timeout ?? DEFAULT_TIMEOUT,
102
+ sandboxDebug,
103
+ token: options.token,
104
+ tokenRefreshDuration: options.tokenRefreshDuration,
105
+ serverUrl,
106
+ };
107
+ }
108
+ /**
109
+ * 从 properties 键值对中解析私钥。
110
+ * 优先级:private_key > private_key_pk8 > private_key_pk1
111
+ */
112
+ function resolvePrivateKey(props) {
113
+ return props['private_key'] || props['private_key_pk8'] || props['private_key_pk1'] || '';
114
+ }
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parsePropertiesFile = parsePropertiesFile;
37
+ exports.parsePropertiesString = parsePropertiesString;
38
+ /**
39
+ * ConfigParser - Java properties 格式配置文件解析器
40
+ *
41
+ * 支持:
42
+ * - key=value 键值对解析
43
+ * - \ 续行(多行值)
44
+ * - # 和 ! 注释行
45
+ * - 空行忽略
46
+ */
47
+ const fs = __importStar(require("fs/promises"));
48
+ /**
49
+ * 解析 Java properties 格式的配置文件。
50
+ * 异步读取文件内容后调用 parsePropertiesString 解析。
51
+ *
52
+ * @param filePath - 配置文件路径
53
+ * @returns 键值对映射
54
+ * @throws 文件不存在或读取失败时抛出错误
55
+ */
56
+ async function parsePropertiesFile(filePath) {
57
+ const content = await fs.readFile(filePath, 'utf-8');
58
+ return parsePropertiesString(content);
59
+ }
60
+ /**
61
+ * 解析 Java properties 格式的字符串内容。
62
+ *
63
+ * @param content - properties 格式的字符串
64
+ * @returns 键值对映射
65
+ */
66
+ function parsePropertiesString(content) {
67
+ const props = {};
68
+ const lines = content.split('\n');
69
+ let currentLine = '';
70
+ let continuation = false;
71
+ for (const rawLine of lines) {
72
+ if (continuation) {
73
+ // 续行:去除前导空格后拼接
74
+ const trimmedLeft = rawLine.replace(/^[ \t]+/, '');
75
+ if (trimmedLeft.endsWith('\\')) {
76
+ currentLine += trimmedLeft.slice(0, -1);
77
+ continue;
78
+ }
79
+ currentLine += trimmedLeft;
80
+ continuation = false;
81
+ }
82
+ else {
83
+ const trimmed = rawLine.trim();
84
+ // 跳过空行
85
+ if (trimmed === '') {
86
+ continue;
87
+ }
88
+ // 跳过注释行
89
+ if (trimmed.startsWith('#') || trimmed.startsWith('!')) {
90
+ continue;
91
+ }
92
+ // 检查续行
93
+ if (trimmed.endsWith('\\')) {
94
+ currentLine = trimmed.slice(0, -1);
95
+ continuation = true;
96
+ continue;
97
+ }
98
+ currentLine = trimmed;
99
+ }
100
+ // 解析键值对
101
+ const result = parseKeyValue(currentLine);
102
+ if (result) {
103
+ props[result[0]] = result[1];
104
+ }
105
+ currentLine = '';
106
+ }
107
+ // 处理最后一行是续行但文件结束的情况
108
+ if (continuation && currentLine !== '') {
109
+ const result = parseKeyValue(currentLine);
110
+ if (result) {
111
+ props[result[0]] = result[1];
112
+ }
113
+ }
114
+ return props;
115
+ }
116
+ /**
117
+ * 解析单行键值对,支持 = 和 : 分隔符。
118
+ * 值中可以包含 = 或 :,只按第一个分隔符拆分。
119
+ *
120
+ * @param line - 待解析的行
121
+ * @returns [key, value] 元组,或 null(无效行)
122
+ */
123
+ function parseKeyValue(line) {
124
+ const eqIdx = line.indexOf('=');
125
+ const colonIdx = line.indexOf(':');
126
+ let sepIdx = -1;
127
+ if (eqIdx >= 0 && colonIdx >= 0) {
128
+ sepIdx = Math.min(eqIdx, colonIdx);
129
+ }
130
+ else if (eqIdx >= 0) {
131
+ sepIdx = eqIdx;
132
+ }
133
+ else if (colonIdx >= 0) {
134
+ sepIdx = colonIdx;
135
+ }
136
+ if (sepIdx < 0) {
137
+ return null;
138
+ }
139
+ const key = line.slice(0, sepIdx).trim();
140
+ const value = line.slice(sepIdx + 1).trim();
141
+ return key ? [key, value] : null;
142
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /**
3
+ * 动态域名获取模块
4
+ *
5
+ * 从域名花园获取动态域名配置,用于 SDK 初始化时自动选择最优服务器地址。
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.queryDomains = queryDomains;
9
+ exports.resolveDynamicServerUrl = resolveDynamicServerUrl;
10
+ /** 域名花园地址 */
11
+ const DOMAIN_GARDEN_ADDRESS = 'https://cg.play-analytics.com';
12
+ /** 动态域名查询超时(毫秒) */
13
+ const DOMAIN_QUERY_TIMEOUT = 1000;
14
+ /** TBUS 牌照标识 */
15
+ const LICENSE_TBUS = 'TBUS';
16
+ /** COMMON 域名 key */
17
+ const DOMAIN_KEY_COMMON = 'COMMON';
18
+ /** gateway 后缀 */
19
+ const GATEWAY_SUFFIX = '/gateway';
20
+ /**
21
+ * 从域名花园获取动态域名配置。
22
+ * 失败时返回空对象(静默回退)。
23
+ *
24
+ * @param license - 牌照类型(如 "TBNZ")
25
+ * @returns 域名配置 map(key → URL)
26
+ */
27
+ function queryDomains(license) {
28
+ try {
29
+ let url = DOMAIN_GARDEN_ADDRESS;
30
+ if (license === LICENSE_TBUS) {
31
+ url += '?appName=tradeup';
32
+ }
33
+ // 使用同步 XMLHttpRequest(SDK 初始化时调用,非每次请求)
34
+ // Node.js 环境下使用 child_process 同步 HTTP 请求
35
+ const result = syncHttpGet(url, DOMAIN_QUERY_TIMEOUT);
36
+ if (!result)
37
+ return {};
38
+ const parsed = JSON.parse(result);
39
+ const items = parsed?.items;
40
+ if (!Array.isArray(items) || items.length === 0)
41
+ return {};
42
+ const conf = items[0]?.openapi;
43
+ if (!conf || typeof conf !== 'object')
44
+ return {};
45
+ return conf;
46
+ }
47
+ catch {
48
+ return {};
49
+ }
50
+ }
51
+ /**
52
+ * 根据动态域名配置和 license 解析服务器地址。
53
+ * 返回空字符串表示无法解析(应使用默认地址)。
54
+ */
55
+ function resolveDynamicServerUrl(domainConf, license) {
56
+ if (!domainConf || Object.keys(domainConf).length === 0) {
57
+ return '';
58
+ }
59
+ const key = license || DOMAIN_KEY_COMMON;
60
+ if (typeof domainConf[key] === 'string') {
61
+ return domainConf[key] + GATEWAY_SUFFIX;
62
+ }
63
+ // 回退到 COMMON
64
+ if (typeof domainConf[DOMAIN_KEY_COMMON] === 'string') {
65
+ return domainConf[DOMAIN_KEY_COMMON] + GATEWAY_SUFFIX;
66
+ }
67
+ return '';
68
+ }
69
+ /**
70
+ * 同步 HTTP GET 请求(Node.js 环境)。
71
+ * 使用 child_process.execSync 实现同步请求,超时快速失败。
72
+ */
73
+ function syncHttpGet(url, timeoutMs) {
74
+ try {
75
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
76
+ const { execSync } = require('child_process');
77
+ const script = `
78
+ const http = require('${url.startsWith('https') ? 'https' : 'http'}');
79
+ const req = http.get('${url}', { timeout: ${timeoutMs} }, (res) => {
80
+ let data = '';
81
+ res.on('data', (chunk) => data += chunk);
82
+ res.on('end', () => process.stdout.write(data));
83
+ });
84
+ req.on('error', () => process.exit(1));
85
+ req.on('timeout', () => { req.destroy(); process.exit(1); });
86
+ `;
87
+ const result = execSync(`node -e "${script.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, {
88
+ timeout: timeoutMs + 500, // 额外 500ms 给进程启动
89
+ encoding: 'utf-8',
90
+ stdio: ['pipe', 'pipe', 'pipe'],
91
+ });
92
+ return result || null;
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveDynamicServerUrl = exports.queryDomains = exports.createClientConfig = exports.parsePropertiesString = exports.parsePropertiesFile = void 0;
4
+ /**
5
+ * 配置层导出
6
+ */
7
+ var config_parser_1 = require("./config-parser");
8
+ Object.defineProperty(exports, "parsePropertiesFile", { enumerable: true, get: function () { return config_parser_1.parsePropertiesFile; } });
9
+ Object.defineProperty(exports, "parsePropertiesString", { enumerable: true, get: function () { return config_parser_1.parsePropertiesString; } });
10
+ var client_config_1 = require("./client-config");
11
+ Object.defineProperty(exports, "createClientConfig", { enumerable: true, get: function () { return client_config_1.createClientConfig; } });
12
+ var domain_1 = require("./domain");
13
+ Object.defineProperty(exports, "queryDomains", { enumerable: true, get: function () { return domain_1.queryDomains; } });
14
+ Object.defineProperty(exports, "resolveDynamicServerUrl", { enumerable: true, get: function () { return domain_1.resolveDynamicServerUrl; } });
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TokenManager = void 0;
4
+ /**
5
+ * TokenManager - Token 管理器
6
+ *
7
+ * 从 tiger_openapi_token.properties 文件加载 Token,
8
+ * 支持后台定期刷新,更新内存和文件中的 Token。
9
+ */
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const config_parser_1 = require("./config-parser");
13
+ /** 默认 Token 文件名 */
14
+ const DEFAULT_TOKEN_FILE = 'tiger_openapi_token.properties';
15
+ /** 默认刷新间隔(毫秒):24 小时 */
16
+ const DEFAULT_REFRESH_INTERVAL = 24 * 60 * 60 * 1000;
17
+ /**
18
+ * Token 管理器
19
+ */
20
+ class TokenManager {
21
+ constructor(options) {
22
+ this.token = '';
23
+ this.timer = null;
24
+ this.filePath = options?.filePath ?? DEFAULT_TOKEN_FILE;
25
+ this.refreshInterval = options?.refreshInterval ?? DEFAULT_REFRESH_INTERVAL;
26
+ let dur = options?.refreshDuration ?? 0;
27
+ if (dur > 0 && dur < 30) {
28
+ dur = 30;
29
+ }
30
+ this.refreshDuration = dur;
31
+ }
32
+ /** 从 properties 文件加载 Token */
33
+ loadToken() {
34
+ const content = (0, fs_1.readFileSync)(this.filePath, 'utf-8');
35
+ const props = (0, config_parser_1.parsePropertiesString)(content);
36
+ const token = props['token'];
37
+ if (!token) {
38
+ throw new Error('Token 文件中未找到 token 字段');
39
+ }
40
+ this.token = token;
41
+ return token;
42
+ }
43
+ /** 获取当前 Token */
44
+ getToken() {
45
+ return this.token;
46
+ }
47
+ /** 设置 Token 并更新文件 */
48
+ setToken(token) {
49
+ this.token = token;
50
+ this.saveTokenToFile(token);
51
+ }
52
+ /** 将 Token 保存到 properties 文件 */
53
+ saveTokenToFile(token) {
54
+ const dir = (0, path_1.dirname)(this.filePath);
55
+ if (dir && dir !== '.') {
56
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
57
+ }
58
+ (0, fs_1.writeFileSync)(this.filePath, `token=${token}\n`, 'utf-8');
59
+ }
60
+ /**
61
+ * 判断 Token 是否需要刷新。
62
+ * 解码 base64 token,提取前 27 字符中的 gen_ts,
63
+ * 当 (当前时间秒 - gen_ts/1000) > refreshDuration 时返回 true。
64
+ */
65
+ shouldTokenRefresh() {
66
+ if (!this.token || this.refreshDuration === 0) {
67
+ return false;
68
+ }
69
+ try {
70
+ const decoded = Buffer.from(this.token, 'base64');
71
+ if (decoded.length < 27) {
72
+ return false;
73
+ }
74
+ const header = decoded.subarray(0, 27).toString('utf-8');
75
+ const parts = header.split(',');
76
+ if (parts.length < 2) {
77
+ return false;
78
+ }
79
+ const genTs = parseInt(parts[0].trim(), 10);
80
+ if (isNaN(genTs)) {
81
+ return false;
82
+ }
83
+ return (Math.floor(Date.now() / 1000) - Math.floor(genTs / 1000)) > this.refreshDuration;
84
+ }
85
+ catch {
86
+ return false;
87
+ }
88
+ }
89
+ /** 启动后台定期刷新 */
90
+ startAutoRefresh(refreshFn) {
91
+ this.stopAutoRefresh();
92
+ this.timer = setInterval(async () => {
93
+ try {
94
+ // 先检查是否需要刷新
95
+ if (!this.shouldTokenRefresh()) {
96
+ return;
97
+ }
98
+ const newToken = await refreshFn();
99
+ if (newToken) {
100
+ this.setToken(newToken);
101
+ }
102
+ }
103
+ catch {
104
+ // 刷新失败时静默跳过
105
+ }
106
+ }, this.refreshInterval);
107
+ }
108
+ /** 停止后台刷新 */
109
+ stopAutoRefresh() {
110
+ if (this.timer) {
111
+ clearInterval(this.timer);
112
+ this.timer = null;
113
+ }
114
+ }
115
+ }
116
+ exports.TokenManager = TokenManager;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * 老虎证券 OpenAPI TypeScript SDK
4
+ *
5
+ * 本 SDK 提供行情查询、交易下单、账户管理和实时推送等功能,
6
+ * 与 Python SDK 保持功能对等,遵循 TypeScript 最佳实践。
7
+ *
8
+ * 分层架构:
9
+ * - 模型层(model):Contract、Order、Position 等数据模型和枚举
10
+ * - 配置层(config):ClientConfig、ConfigParser
11
+ * - 认证层(signer):RSA 签名
12
+ * - 传输层(client):HttpClient、重试策略
13
+ * - 业务层(quote/trade):QuoteClient、TradeClient
14
+ * - 推送层(push):PushClient
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.VERSION = void 0;
20
+ /** SDK 版本号 */
21
+ exports.VERSION = '0.1.0';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * 日志模块导出
19
+ */
20
+ __exportStar(require("./logger"), exports);
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Logger - 日志接口和默认实现
4
+ *
5
+ * 定义 Logger 接口,支持注入自定义 logger 对象。
6
+ * 默认实现使用 console 输出。
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.NopLogger = exports.DefaultLogger = exports.LogLevel = void 0;
10
+ exports.setDefaultLogger = setDefaultLogger;
11
+ exports.getDefaultLogger = getDefaultLogger;
12
+ /** 日志级别 */
13
+ var LogLevel;
14
+ (function (LogLevel) {
15
+ LogLevel[LogLevel["Debug"] = 0] = "Debug";
16
+ LogLevel[LogLevel["Info"] = 1] = "Info";
17
+ LogLevel[LogLevel["Warn"] = 2] = "Warn";
18
+ LogLevel[LogLevel["Error"] = 3] = "Error";
19
+ })(LogLevel || (exports.LogLevel = LogLevel = {}));
20
+ /** 默认日志实现,使用 console 输出 */
21
+ class DefaultLogger {
22
+ constructor() {
23
+ this.level = LogLevel.Info;
24
+ }
25
+ setLevel(level) {
26
+ this.level = level;
27
+ }
28
+ debug(msg, ...args) {
29
+ if (this.level <= LogLevel.Debug) {
30
+ console.debug(`[tigeropen] [DEBUG] ${msg}`, ...args);
31
+ }
32
+ }
33
+ info(msg, ...args) {
34
+ if (this.level <= LogLevel.Info) {
35
+ console.info(`[tigeropen] [INFO] ${msg}`, ...args);
36
+ }
37
+ }
38
+ warn(msg, ...args) {
39
+ if (this.level <= LogLevel.Warn) {
40
+ console.warn(`[tigeropen] [WARN] ${msg}`, ...args);
41
+ }
42
+ }
43
+ error(msg, ...args) {
44
+ if (this.level <= LogLevel.Error) {
45
+ console.error(`[tigeropen] [ERROR] ${msg}`, ...args);
46
+ }
47
+ }
48
+ }
49
+ exports.DefaultLogger = DefaultLogger;
50
+ /** 空日志实现,不输出任何内容 */
51
+ class NopLogger {
52
+ debug() { }
53
+ info() { }
54
+ warn() { }
55
+ error() { }
56
+ setLevel() { }
57
+ }
58
+ exports.NopLogger = NopLogger;
59
+ /** 全局默认 logger */
60
+ let defaultLogger = new DefaultLogger();
61
+ /** 设置全局默认 logger */
62
+ function setDefaultLogger(logger) {
63
+ defaultLogger = logger;
64
+ }
65
+ /** 获取全局默认 logger */
66
+ function getDefaultLogger() {
67
+ return defaultLogger;
68
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stockContract = stockContract;
4
+ exports.optionContract = optionContract;
5
+ exports.optionContractBySymbol = optionContractBySymbol;
6
+ exports.futureContract = futureContract;
7
+ exports.cashContract = cashContract;
8
+ exports.fundContract = fundContract;
9
+ exports.warrantContract = warrantContract;
10
+ const enums_1 = require("./enums");
11
+ /** 构造股票合约 */
12
+ function stockContract(symbol, currency) {
13
+ return { symbol, secType: enums_1.SecurityType.STK, currency };
14
+ }
15
+ /** 通过 identifier 构造期权合约 */
16
+ function optionContract(identifier) {
17
+ return { symbol: '', secType: enums_1.SecurityType.OPT, identifier };
18
+ }
19
+ /** 通过各字段构造期权合约 */
20
+ function optionContractBySymbol(symbol, expiry, strike, right, currency) {
21
+ return { symbol, secType: enums_1.SecurityType.OPT, expiry, strike, right, currency };
22
+ }
23
+ /** 构造期货合约 */
24
+ function futureContract(symbol, currency, expiry) {
25
+ return { symbol, secType: enums_1.SecurityType.FUT, currency, expiry };
26
+ }
27
+ /** 构造外汇合约 */
28
+ function cashContract(symbol) {
29
+ return { symbol, secType: enums_1.SecurityType.CASH };
30
+ }
31
+ /** 构造基金合约 */
32
+ function fundContract(symbol, currency) {
33
+ return { symbol, secType: enums_1.SecurityType.FUND, currency };
34
+ }
35
+ /** 构造窝轮合约 */
36
+ function warrantContract(symbol, currency, expiry, strike, right) {
37
+ return { symbol, secType: enums_1.SecurityType.WAR, currency, expiry, strike, right };
38
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Contract 合约接口
4
+ * 字段名 camelCase 与 API JSON 天然一致,不改名、不加封装层
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });