@yuants/vendor-gate 0.7.4 → 0.8.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/api/http-client.js +58 -17
- package/dist/api/http-client.js.map +1 -1
- package/dist/api/private-api.js +28 -0
- package/dist/api/private-api.js.map +1 -1
- package/dist/api/public-api.js +20 -0
- package/dist/api/public-api.js.map +1 -1
- package/dist/services/accounts/earning.js +61 -0
- package/dist/services/accounts/earning.js.map +1 -0
- package/dist/services/accounts/earning.test.js +117 -0
- package/dist/services/accounts/earning.test.js.map +1 -0
- package/dist/services/exchange.js +13 -7
- package/dist/services/exchange.js.map +1 -1
- package/lib/api/http-client.d.ts.map +1 -1
- package/lib/api/http-client.js +58 -17
- package/lib/api/http-client.js.map +1 -1
- package/lib/api/private-api.d.ts +22 -0
- package/lib/api/private-api.d.ts.map +1 -1
- package/lib/api/private-api.js +30 -1
- package/lib/api/private-api.js.map +1 -1
- package/lib/api/public-api.d.ts +7 -0
- package/lib/api/public-api.d.ts.map +1 -1
- package/lib/api/public-api.js +22 -1
- package/lib/api/public-api.js.map +1 -1
- package/lib/services/accounts/earning.d.ts +7 -0
- package/lib/services/accounts/earning.d.ts.map +1 -0
- package/lib/services/accounts/earning.js +65 -0
- package/lib/services/accounts/earning.js.map +1 -0
- package/lib/services/accounts/earning.test.d.ts +2 -0
- package/lib/services/accounts/earning.test.d.ts.map +1 -0
- package/lib/services/accounts/earning.test.js +152 -0
- package/lib/services/accounts/earning.test.js.map +1 -0
- package/lib/services/exchange.js +13 -7
- package/lib/services/exchange.js.map +1 -1
- package/package.json +5 -5
- package/temp/build/typescript/ts_Eujh_fX2.json +1 -1
- package/temp/package-deps.json +10 -8
- package/temp/test/jest/haste-map-ac984f375ffe2771b37aa116ca7fe6f5-87fb4bb14df3d29fb61369ce8cbe1fe1-6499ab22de0ac9ce813ded0e96430273 +0 -0
- package/temp/test/jest/perf-cache-ac984f375ffe2771b37aa116ca7fe6f5-da39a3ee5e6b4b0d3255bfef95601890 +1 -0
package/dist/api/http-client.js
CHANGED
|
@@ -37,10 +37,21 @@ const parseJSON = async (response, path, params) => {
|
|
|
37
37
|
return JSON.parse(text);
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
// 只在 DEBUG 模式下打印完整响应文本,避免泄露敏感信息
|
|
41
|
+
if (process.env.LOG_LEVEL === 'DEBUG') {
|
|
42
|
+
console.debug(formatTime(Date.now()), 'GateRequestFailed', path, JSON.stringify(params !== null && params !== void 0 ? params : {}), text, {
|
|
43
|
+
status: response.status,
|
|
44
|
+
headers: toHeaderObject(response.headers),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// 非 DEBUG 模式下只打印摘要
|
|
49
|
+
const textPreview = text.length > 100 ? text.substring(0, 100) + '...' : text;
|
|
50
|
+
console.info(formatTime(Date.now()), 'GateRequestFailed', path, JSON.stringify(params !== null && params !== void 0 ? params : {}), textPreview, {
|
|
51
|
+
status: response.status,
|
|
52
|
+
headers: toHeaderObject(response.headers),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
44
55
|
throw error;
|
|
45
56
|
}
|
|
46
57
|
};
|
|
@@ -53,12 +64,24 @@ export const requestPublic = async (method, path, params) => {
|
|
|
53
64
|
headers['Content-Type'] = 'application/json';
|
|
54
65
|
}
|
|
55
66
|
console.info(formatTime(Date.now()), method, url.href);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
// 添加请求超时控制(30秒)
|
|
68
|
+
const timeoutMs = 30000;
|
|
69
|
+
const abortController = new AbortController();
|
|
70
|
+
const timeoutId = setTimeout(() => {
|
|
71
|
+
abortController.abort(new Error(`Request timeout after ${timeoutMs}ms`));
|
|
72
|
+
}, timeoutMs);
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(url.href, {
|
|
75
|
+
method,
|
|
76
|
+
headers,
|
|
77
|
+
body: body || undefined,
|
|
78
|
+
signal: abortController.signal,
|
|
79
|
+
});
|
|
80
|
+
return await parseJSON(response, path, params);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
clearTimeout(timeoutId);
|
|
84
|
+
}
|
|
62
85
|
};
|
|
63
86
|
export const requestPrivate = async (credential, method, path, params) => {
|
|
64
87
|
const { url, body } = createRequestArtifacts(method, path, params);
|
|
@@ -77,12 +100,30 @@ export const requestPrivate = async (credential, method, path, params) => {
|
|
|
77
100
|
if (process.env.CHANNEL_ID) {
|
|
78
101
|
headers['X-Gate-Channel-Id'] = process.env.CHANNEL_ID;
|
|
79
102
|
}
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
// 安全日志:过滤敏感头信息
|
|
104
|
+
const safeHeaders = Object.assign({}, headers);
|
|
105
|
+
if (safeHeaders.KEY)
|
|
106
|
+
safeHeaders.KEY = '***';
|
|
107
|
+
if (safeHeaders.SIGN)
|
|
108
|
+
safeHeaders.SIGN = '***';
|
|
109
|
+
console.info(formatTime(Date.now()), method, url.href, JSON.stringify(safeHeaders), body);
|
|
110
|
+
// 添加请求超时控制(30秒)
|
|
111
|
+
const timeoutMs = 30000;
|
|
112
|
+
const abortController = new AbortController();
|
|
113
|
+
const timeoutId = setTimeout(() => {
|
|
114
|
+
abortController.abort(new Error(`Request timeout after ${timeoutMs}ms`));
|
|
115
|
+
}, timeoutMs);
|
|
116
|
+
try {
|
|
117
|
+
const response = await fetch(url.href, {
|
|
118
|
+
method,
|
|
119
|
+
headers,
|
|
120
|
+
body: body || undefined,
|
|
121
|
+
signal: abortController.signal,
|
|
122
|
+
});
|
|
123
|
+
return await parseJSON(response, path, params);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
clearTimeout(timeoutId);
|
|
127
|
+
}
|
|
87
128
|
};
|
|
88
129
|
//# sourceMappingURL=http-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/api/http-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodeHex, formatTime, HmacSHA512, sha512 } from '@yuants/utils';\nimport { join } from 'path';\n\nconst BASE_URL = 'https://api.gateio.ws/api/v4';\n\nexport type HttpMethod = 'GET' | 'POST' | 'DELETE' | 'PUT';\n\nexport type GateParams = Record<string, string | number | boolean | undefined>;\n\nexport interface IGateCredential {\n access_key: string;\n secret_key: string;\n}\n\ninterface IRequestArtifacts {\n url: URL;\n body: string;\n}\n\nconst serializeQueryParams = (params?: GateParams): Record<string, string> | undefined => {\n if (!params) return undefined;\n const normalizedEntries = Object.entries(params).filter(([, value]) => value !== undefined);\n if (normalizedEntries.length === 0) {\n return undefined;\n }\n return Object.fromEntries(normalizedEntries.map(([key, value]) => [key, `${value}`]));\n};\n\nconst createRequestArtifacts = (method: HttpMethod, path: string, params?: GateParams): IRequestArtifacts => {\n const url = new URL(BASE_URL);\n url.pathname = join(url.pathname, path);\n const searchParams = serializeQueryParams(params);\n if (method === 'GET' && searchParams) {\n Object.entries(searchParams).forEach(([key, value]) => url.searchParams.set(key, value));\n }\n const rawBody = method === 'GET' ? '' : JSON.stringify(params);\n const body = rawBody;\n return { url, body };\n};\n\nconst toHeaderObject = (headers: Headers): Record<string, string> => {\n const iterable = headers as unknown as Iterable<[string, string]>;\n return Object.fromEntries(Array.from(iterable));\n};\n\nconst parseJSON = async <TResponse>(\n response: Response,\n path: string,\n params?: GateParams,\n): Promise<TResponse> => {\n const text = await response.text();\n if (process.env.LOG_LEVEL === 'DEBUG') {\n console.debug(formatTime(Date.now()), 'GateResponse', path, JSON.stringify(params ?? {}), text, {\n status: response.status,\n headers: toHeaderObject(response.headers),\n });\n }\n try {\n return JSON.parse(text) as TResponse;\n } catch (error) {\n console.info(formatTime(Date.now()), 'GateRequestFailed', path, JSON.stringify(params ?? {}), text, {\n status: response.status,\n headers: toHeaderObject(response.headers),\n });\n throw error;\n }\n};\n\nexport const requestPublic = async <TResponse>(\n method: HttpMethod,\n path: string,\n params?: GateParams,\n): Promise<TResponse> => {\n const { url, body } = createRequestArtifacts(method, path, params);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n };\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n console.info(formatTime(Date.now()), method, url.href);\n const response = await fetch(url.href, {\n method,\n headers,\n body: body || undefined,\n });\n return parseJSON<TResponse>(response, path, params);\n};\n\nexport const requestPrivate = async <TResponse>(\n credential: IGateCredential,\n method: HttpMethod,\n path: string,\n params?: GateParams,\n): Promise<TResponse> => {\n const { url, body } = createRequestArtifacts(method, path, params);\n const timestamp = Date.now() / 1000;\n\n const bodyDigest = encodeHex(await sha512(new TextEncoder().encode(body)));\n const signTarget = `${method}\\n${url.pathname}\\n${url.searchParams}\\n${bodyDigest}\\n${timestamp}`;\n const sign = encodeHex(\n await HmacSHA512(new TextEncoder().encode(signTarget), new TextEncoder().encode(credential.secret_key)),\n );\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n KEY: credential.access_key,\n SIGN: sign,\n Timestamp: `${timestamp}`,\n };\n\n // Add Channel ID header if exists\n if (process.env.CHANNEL_ID) {\n headers['X-Gate-Channel-Id'] = process.env.CHANNEL_ID;\n }\n\n console.info(formatTime(Date.now()), method, url.href, JSON.stringify(headers), body);\n\n const response = await fetch(url.href, {\n method,\n headers,\n body: body || undefined,\n });\n return parseJSON<TResponse>(response, path, params);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/api/http-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodeHex, formatTime, HmacSHA512, sha512 } from '@yuants/utils';\nimport { join } from 'path';\n\nconst BASE_URL = 'https://api.gateio.ws/api/v4';\n\nexport type HttpMethod = 'GET' | 'POST' | 'DELETE' | 'PUT';\n\nexport type GateParams = Record<string, string | number | boolean | undefined>;\n\nexport interface IGateCredential {\n access_key: string;\n secret_key: string;\n}\n\ninterface IRequestArtifacts {\n url: URL;\n body: string;\n}\n\nconst serializeQueryParams = (params?: GateParams): Record<string, string> | undefined => {\n if (!params) return undefined;\n const normalizedEntries = Object.entries(params).filter(([, value]) => value !== undefined);\n if (normalizedEntries.length === 0) {\n return undefined;\n }\n return Object.fromEntries(normalizedEntries.map(([key, value]) => [key, `${value}`]));\n};\n\nconst createRequestArtifacts = (method: HttpMethod, path: string, params?: GateParams): IRequestArtifacts => {\n const url = new URL(BASE_URL);\n url.pathname = join(url.pathname, path);\n const searchParams = serializeQueryParams(params);\n if (method === 'GET' && searchParams) {\n Object.entries(searchParams).forEach(([key, value]) => url.searchParams.set(key, value));\n }\n const rawBody = method === 'GET' ? '' : JSON.stringify(params);\n const body = rawBody;\n return { url, body };\n};\n\nconst toHeaderObject = (headers: Headers): Record<string, string> => {\n const iterable = headers as unknown as Iterable<[string, string]>;\n return Object.fromEntries(Array.from(iterable));\n};\n\nconst parseJSON = async <TResponse>(\n response: Response,\n path: string,\n params?: GateParams,\n): Promise<TResponse> => {\n const text = await response.text();\n if (process.env.LOG_LEVEL === 'DEBUG') {\n console.debug(formatTime(Date.now()), 'GateResponse', path, JSON.stringify(params ?? {}), text, {\n status: response.status,\n headers: toHeaderObject(response.headers),\n });\n }\n try {\n return JSON.parse(text) as TResponse;\n } catch (error) {\n // 只在 DEBUG 模式下打印完整响应文本,避免泄露敏感信息\n if (process.env.LOG_LEVEL === 'DEBUG') {\n console.debug(formatTime(Date.now()), 'GateRequestFailed', path, JSON.stringify(params ?? {}), text, {\n status: response.status,\n headers: toHeaderObject(response.headers),\n });\n } else {\n // 非 DEBUG 模式下只打印摘要\n const textPreview = text.length > 100 ? text.substring(0, 100) + '...' : text;\n console.info(\n formatTime(Date.now()),\n 'GateRequestFailed',\n path,\n JSON.stringify(params ?? {}),\n textPreview,\n {\n status: response.status,\n headers: toHeaderObject(response.headers),\n },\n );\n }\n throw error;\n }\n};\n\nexport const requestPublic = async <TResponse>(\n method: HttpMethod,\n path: string,\n params?: GateParams,\n): Promise<TResponse> => {\n const { url, body } = createRequestArtifacts(method, path, params);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n };\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n console.info(formatTime(Date.now()), method, url.href);\n\n // 添加请求超时控制(30秒)\n const timeoutMs = 30_000;\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => {\n abortController.abort(new Error(`Request timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n\n try {\n const response = await fetch(url.href, {\n method,\n headers,\n body: body || undefined,\n signal: abortController.signal,\n });\n return await parseJSON<TResponse>(response, path, params);\n } finally {\n clearTimeout(timeoutId);\n }\n};\n\nexport const requestPrivate = async <TResponse>(\n credential: IGateCredential,\n method: HttpMethod,\n path: string,\n params?: GateParams,\n): Promise<TResponse> => {\n const { url, body } = createRequestArtifacts(method, path, params);\n const timestamp = Date.now() / 1000;\n\n const bodyDigest = encodeHex(await sha512(new TextEncoder().encode(body)));\n const signTarget = `${method}\\n${url.pathname}\\n${url.searchParams}\\n${bodyDigest}\\n${timestamp}`;\n const sign = encodeHex(\n await HmacSHA512(new TextEncoder().encode(signTarget), new TextEncoder().encode(credential.secret_key)),\n );\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n KEY: credential.access_key,\n SIGN: sign,\n Timestamp: `${timestamp}`,\n };\n\n // Add Channel ID header if exists\n if (process.env.CHANNEL_ID) {\n headers['X-Gate-Channel-Id'] = process.env.CHANNEL_ID;\n }\n\n // 安全日志:过滤敏感头信息\n const safeHeaders = { ...headers };\n if (safeHeaders.KEY) safeHeaders.KEY = '***';\n if (safeHeaders.SIGN) safeHeaders.SIGN = '***';\n console.info(formatTime(Date.now()), method, url.href, JSON.stringify(safeHeaders), body);\n\n // 添加请求超时控制(30秒)\n const timeoutMs = 30_000;\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => {\n abortController.abort(new Error(`Request timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n\n try {\n const response = await fetch(url.href, {\n method,\n headers,\n body: body || undefined,\n signal: abortController.signal,\n });\n return await parseJSON<TResponse>(response, path, params);\n } finally {\n clearTimeout(timeoutId);\n }\n};\n"]}
|
package/dist/api/private-api.js
CHANGED
|
@@ -12,6 +12,34 @@ export const getAccountDetail = (credential) => callPrivate(credential, 'GET', '
|
|
|
12
12
|
* https://www.gate.com/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%BB%9F%E4%B8%80%E8%B4%A6%E6%88%B7%E4%BF%A1%E6%81%AF
|
|
13
13
|
*/
|
|
14
14
|
export const getUnifiedAccounts = (credential, params) => callPrivate(credential, 'GET', '/unified/accounts', params);
|
|
15
|
+
/**
|
|
16
|
+
* 获取用户理财余额(Gate.io EarnUni 余币宝理财)
|
|
17
|
+
*
|
|
18
|
+
* https://www.gate.com/docs/developers/apiv4/zh_CN/#查询用户币种理财列表
|
|
19
|
+
* 端点:GET /earn/uni/lends(需要鉴权)
|
|
20
|
+
*/
|
|
21
|
+
export const getEarnBalance = (credential, params) => {
|
|
22
|
+
// 输入参数校验
|
|
23
|
+
const validatedParams = Object.assign({}, params);
|
|
24
|
+
if (validatedParams.currency !== undefined) {
|
|
25
|
+
if (typeof validatedParams.currency !== 'string' || !/^[A-Za-z0-9]+$/.test(validatedParams.currency)) {
|
|
26
|
+
throw new Error(`Invalid currency format: ${validatedParams.currency}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (validatedParams.page !== undefined) {
|
|
30
|
+
if (!Number.isInteger(validatedParams.page) || validatedParams.page < 1) {
|
|
31
|
+
throw new Error(`Invalid page: must be positive integer, got ${validatedParams.page}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (validatedParams.limit !== undefined) {
|
|
35
|
+
if (!Number.isInteger(validatedParams.limit) ||
|
|
36
|
+
validatedParams.limit < 1 ||
|
|
37
|
+
validatedParams.limit > 1000) {
|
|
38
|
+
throw new Error(`Invalid limit: must be between 1 and 1000, got ${validatedParams.limit}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return callPrivate(credential, 'GET', '/earn/uni/lends', validatedParams);
|
|
42
|
+
};
|
|
15
43
|
/**
|
|
16
44
|
* 获取用户仓位列表
|
|
17
45
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"private-api.js","sourceRoot":"","sources":["../../src/api/private-api.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GateParams, HttpMethod, IGateCredential } from './http-client';\nimport { requestPrivate } from './http-client';\n\nexport type ICredential = IGateCredential;\n\nconst callPrivate = <TResponse>(\n credential: ICredential,\n method: HttpMethod,\n path: string,\n params?: GateParams,\n) => requestPrivate<TResponse>(credential, method, path, params);\n\n/**\n * 获取用户账户信息\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E8%B4%A6%E6%88%B7%E4%BF%A1%E6%81%AF\n */\nexport const getAccountDetail = (\n credential: ICredential,\n): Promise<{\n user_id: number;\n ip_whitelist: string[];\n currency_pairs: string[];\n key: {\n mode: number;\n };\n tier: number;\n}> => callPrivate(credential, 'GET', '/account/detail');\n\n/**\n * 获取统一账户信息\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%BB%9F%E4%B8%80%E8%B4%A6%E6%88%B7%E4%BF%A1%E6%81%AF\n */\nexport const getUnifiedAccounts = (\n credential: ICredential,\n params?: { currency?: string },\n): Promise<{\n user_id: string;\n refresh_time: number;\n locket: boolean;\n balances: Record<\n string,\n {\n available: string;\n freeze: string;\n borrowed: string;\n negative_liab: string;\n futures_pos_liab: string;\n equity: string;\n total_freeze: string;\n total_liab: string;\n spot_in_use: string;\n cross_balance: string;\n iso_balance: string;\n funding: string;\n }\n >;\n total: string;\n borrowed: string;\n total_initial_margin: string;\n total_margin_balance: string;\n total_maintenance_margin: string;\n total_initial_margin_rate: string;\n total_maintenance_margin_rate: string;\n total_avail_margin: string;\n unified_account_total: string;\n unified_account_total_liab: string;\n unified_account_total_equity: string;\n leverage: string;\n spot_order_loss: string;\n spot_hedge: boolean;\n}> => callPrivate(credential, 'GET', '/unified/accounts', params);\n\n/**\n * 获取用户仓位列表\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E4%BB%93%E4%BD%8D%E5%88%97%E8%A1%A8\n */\nexport const getFuturePositions = (\n credential: ICredential,\n quote_currency: string,\n params?: { holding?: boolean; limit?: number; offset?: number },\n): Promise<\n {\n user: number;\n contract: string;\n size: number;\n leverage: string;\n risk_limit: string;\n leverage_max: string;\n maintenance_rate: string;\n value: string;\n margin: string;\n entry_price: string;\n mark_price: string;\n unrealised_pnl: string;\n realised_pnl: string;\n mode: string;\n liq_price: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${quote_currency}/positions`, params);\n\n/**\n * 查询合约订单列表\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E5%90%88%E7%BA%A6%E8%AE%A2%E5%8D%95%E5%88%97%E8%A1%A8\n */\nexport const getFuturesOrders = (\n credential: ICredential,\n settle: string,\n params: {\n contract?: string;\n status: string;\n limit?: number;\n offset?: number;\n last_id?: number;\n },\n): Promise<\n {\n id: string;\n contract: string;\n create_time: number;\n size: number;\n price: string;\n is_close: boolean;\n fill_price: string;\n left?: number;\n status?: string;\n text: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${settle}/orders`, params);\n\n/**\n * 获取合约账号\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%90%88%E7%BA%A6%E8%B4%A6%E5%8F%B7\n */\nexport const getFuturesAccounts = (\n credential: ICredential,\n settle: string,\n): Promise<{\n user: number;\n currency: string;\n total: string;\n unrealised_pnl: string;\n position_margin: string;\n order_margin: string;\n available: string;\n point: string;\n bonus: string;\n in_dual_mode: boolean;\n enable_evolved_classic: boolean;\n history: {\n dnw: string;\n pnl: string;\n fee: string;\n refr: string;\n fund: string;\n point_dnw: string;\n point_fee: string;\n point_refr: string;\n bonus_dnw: string;\n bonus_offset: string;\n };\n}> => callPrivate(credential, 'GET', `/futures/${settle}/accounts`);\n\n/**\n * 合约交易下单\n *\n * 下单时指定的是合约张数 size ,而非币的数量,每一张合约对应的币的数量是合约详情接口里返回的 quanto_multiplier\n *\n * 0 成交的订单在撤单 10 分钟之后无法再获取到,会提到订单不存在\n *\n * 设置 reduce_only 为 true 可以防止在减仓的时候穿仓\n *\n * 单仓模式下,如果需要平仓,需要设置 size 为 0 ,close 为 true\n *\n * 双仓模式下,平仓需要使用 auto_size 来设置平仓方向,并同时设置 reduce_only 为 true,size 为 0\n *\n * 设置 stp_act 决定使用限制用户自成交的策略,详细用法参考body参数stp_act\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E5%90%88%E7%BA%A6%E4%BA%A4%E6%98%93%E4%B8%8B%E5%8D%95\n */\nexport const postFutureOrders = (\n credential: ICredential,\n settle: string,\n params: {\n contract: string;\n size: number;\n iceberg?: number;\n price?: string;\n close?: boolean;\n reduce_only?: boolean;\n tif?: string;\n text?: string;\n auto_size?: string;\n stp_act?: string;\n },\n): Promise<{\n label?: string;\n message?: string;\n detail?: string;\n id: number;\n user: number;\n contract: string;\n create_time: number;\n size: number;\n iceberg: number;\n left: number;\n price: string;\n fill_price: string;\n mkfr: string;\n tkfr: string;\n tif: string;\n refu: number;\n is_reduce_only: boolean;\n is_close: boolean;\n is_liq: boolean;\n text: string;\n status: string;\n finish_time: number;\n finish_as: string;\n stp_id: number;\n stp_act: string;\n amend_text: string;\n}> => callPrivate(credential, 'POST', `/futures/${settle}/orders`, params);\n\n/**\n * 撤销单个订单\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%92%A4%E9%94%80%E5%8D%95%E4%B8%AA%E8%AE%A2%E5%8D%95-2\n */\nexport const deleteFutureOrders = (credential: ICredential, settle: string, order_id: string): Promise<{}> =>\n callPrivate(credential, 'DELETE', `/futures/${settle}/orders/${order_id}`);\n\n/**\n * 提现\n *\n * POST /withdrawals\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%8F%90%E7%8E%B0\n */\nexport const postWithdrawals = (\n credential: ICredential,\n params: {\n withdraw_order_id?: string;\n amount: string;\n currency: string;\n address?: string;\n memo?: string;\n chain: string;\n },\n): Promise<{\n id: string;\n txid: string;\n withdraw_order_id: string;\n timestamp: number;\n amount: string;\n currency: string;\n address: string;\n memo: string;\n status: string;\n chain: string;\n}> => callPrivate(credential, 'POST', '/withdrawals', params);\n\n/**\n * 获取币种充值地址\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%B8%81%E7%A7%8D%E5%85%85%E5%80%BC%E5%9C%B0%E5%9D%80\n */\nexport const getDepositAddress = (\n credential: ICredential,\n params: {\n currency: string;\n },\n): Promise<{\n currency: string;\n address: string;\n multichain_addresses: {\n chain: string;\n address: string;\n payment_id: string;\n payment_name: string;\n obtain_failed: boolean;\n }[];\n}> => callPrivate(credential, 'GET', '/wallet/deposit_address', params);\n\n/**\n * 创建新的子账户\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E5%88%9B%E5%BB%BA%E6%96%B0%E7%9A%84%E5%AD%90%E8%B4%A6%E6%88%B7\n */\nexport const getSubAccountList = (\n credential: ICredential,\n params?: {\n type?: string;\n },\n): Promise<\n {\n remark: string;\n login_name: string;\n password: string;\n email: string;\n state: number;\n type: number;\n user_id: number;\n create_time: number;\n }[]\n> => callPrivate(credential, 'GET', '/sub_accounts', params);\n\n/**\n * 获取充值记录\n *\n * 记录查询时间范围不允许超过 30 天\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%85%85%E5%80%BC%E8%AE%B0%E5%BD%95\n */\nexport const getDepositHistory = (\n credential: ICredential,\n params?: {\n currency?: string;\n from?: number;\n to?: number;\n limit?: number;\n offset?: number;\n },\n): Promise<\n {\n id: string;\n txid: string;\n withdraw_order_id: string;\n timestamp: number;\n amount: string;\n currency: string;\n address: string;\n memo: string;\n status: string;\n chain: string;\n }[]\n> => callPrivate(credential, 'GET', '/wallet/deposits', params);\n\n/**\n * 获取提现记录\n *\n * 记录查询时间范围不允许超过 30 天\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%B8%81%E7%A7%8D%E5%85%85%E5%80%BC%E5%9C%B0%E5%9D%80\n */\nexport const getWithdrawalHistory = (\n credential: ICredential,\n params?: {\n currency?: string;\n from?: number;\n to?: number;\n limit?: number;\n offset?: number;\n },\n): Promise<\n {\n id: string;\n txid: string;\n withdraw_order_id: string;\n timestamp: number;\n amount: string;\n currency: string;\n address: string;\n memo: string;\n status: string;\n chain: string;\n }[]\n> => callPrivate(credential, 'GET', '/wallet/withdrawals', params);\n\n/**\n * 获取现货交易账户列表\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%8E%B0%E8%B4%A7%E4%BA%A4%E6%98%93%E8%B4%A6%E6%88%B7%E5%88%97%E8%A1%A8\n */\nexport const getSpotAccounts = (\n credential: ICredential,\n params?: {\n currency?: string;\n },\n): Promise<\n {\n currency: string;\n available: string;\n locked: string;\n update_id: string;\n }[]\n> => callPrivate(credential, 'GET', '/spot/accounts', params);\n\n/**\n * 交易账户互转\n *\n * POST /wallet/transfers\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E4%BA%A4%E6%98%93%E8%B4%A6%E6%88%B7%E4%BA%92%E8%BD%AC\n */\nexport const postWalletTransfer = (\n credential: ICredential,\n params: {\n currency: string;\n from: string;\n to: string;\n amount: string;\n currency_pair?: string;\n settle?: string;\n },\n): Promise<{\n tx_id: string;\n}> => callPrivate(credential, 'POST', '/wallet/transfers', params);\n\n/**\n * 获取统一账户最多可转出\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E7%BB%9F%E4%B8%80%E8%B4%A6%E6%88%B7%E6%9C%80%E5%A4%9A%E5%8F%AF%E8%BD%AC%E5%87%BA\n */\nexport const getUnifiedTransferable = (\n credential: ICredential,\n params: {\n currency: string;\n },\n): Promise<{\n currency: string;\n amount: string;\n}> => callPrivate(credential, 'GET', `/unified/transferable`, params);\n\n/**\n * 查询合约账户变更历史\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E5%90%88%E7%BA%A6%E8%B4%A6%E6%88%B7%E5%8F%98%E6%9B%B4%E5%8E%86%E5%8F%B2\n */\nexport const getFutureAccountsBook = (\n credential: ICredential,\n params: {\n settle: string;\n contract?: string;\n limit?: number;\n offset?: number;\n from?: number;\n to?: number;\n type?: string; // | 'dnw' | 'pnl' | 'fee' | 'refr' | 'fund' | 'point_dnw' | 'point_fee' | 'point_refr' | 'bonus_offset'\n },\n): Promise<\n {\n time: number;\n change: string;\n balance: string;\n text: string;\n type: string;\n contract: string;\n trade_id: string;\n id: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${params.settle}/account_book`, params);\n\n/**\n * 查询个人成交记录(时间区间)\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E4%B8%AA%E4%BA%BA%E6%88%90%E4%BA%A4%E8%AE%B0%E5%BD%95-%E6%97%B6%E9%97%B4%E5%8C%BA%E9%97%B4\n */\nexport const getFutureAccountsTrades = (\n credential: ICredential,\n params: {\n settle: string;\n contract?: string;\n limit?: number;\n offset?: number;\n from?: number;\n to?: number;\n role?: string;\n },\n): Promise<\n {\n trade_id: string;\n create_time: number;\n contract: string;\n order_id: string;\n size: string;\n price: string;\n text: string;\n fee: string;\n point_fee: string;\n role: string;\n close_size: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${params.settle}/my_trades_timerange`, params);\n"]}
|
|
1
|
+
{"version":3,"file":"private-api.js","sourceRoot":"","sources":["../../src/api/private-api.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GateParams, HttpMethod, IGateCredential } from './http-client';\nimport { requestPrivate } from './http-client';\n\nexport type ICredential = IGateCredential;\n\nconst callPrivate = <TResponse>(\n credential: ICredential,\n method: HttpMethod,\n path: string,\n params?: GateParams,\n) => requestPrivate<TResponse>(credential, method, path, params);\n\n/**\n * 获取用户账户信息\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E8%B4%A6%E6%88%B7%E4%BF%A1%E6%81%AF\n */\nexport const getAccountDetail = (\n credential: ICredential,\n): Promise<{\n user_id: number;\n ip_whitelist: string[];\n currency_pairs: string[];\n key: {\n mode: number;\n };\n tier: number;\n}> => callPrivate(credential, 'GET', '/account/detail');\n\n/**\n * 获取统一账户信息\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%BB%9F%E4%B8%80%E8%B4%A6%E6%88%B7%E4%BF%A1%E6%81%AF\n */\nexport const getUnifiedAccounts = (\n credential: ICredential,\n params?: { currency?: string },\n): Promise<{\n user_id: string;\n refresh_time: number;\n locket: boolean;\n balances: Record<\n string,\n {\n available: string;\n freeze: string;\n borrowed: string;\n negative_liab: string;\n futures_pos_liab: string;\n equity: string;\n total_freeze: string;\n total_liab: string;\n spot_in_use: string;\n cross_balance: string;\n iso_balance: string;\n funding: string;\n }\n >;\n total: string;\n borrowed: string;\n total_initial_margin: string;\n total_margin_balance: string;\n total_maintenance_margin: string;\n total_initial_margin_rate: string;\n total_maintenance_margin_rate: string;\n total_avail_margin: string;\n unified_account_total: string;\n unified_account_total_liab: string;\n unified_account_total_equity: string;\n leverage: string;\n spot_order_loss: string;\n spot_hedge: boolean;\n}> => callPrivate(credential, 'GET', '/unified/accounts', params);\n\n/**\n * 获取用户理财余额(Gate.io EarnUni 余币宝理财)\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#查询用户币种理财列表\n * 端点:GET /earn/uni/lends(需要鉴权)\n */\nexport const getEarnBalance = (\n credential: ICredential,\n params?: { currency?: string; page?: number; limit?: number },\n): Promise<\n Array<{\n currency: string;\n amount: string;\n lent_amount: string;\n frozen_amount: string;\n current_amount: string;\n min_rate?: string;\n interest_status?: string;\n reinvest_left_amount?: string;\n create_time?: number;\n update_time?: number;\n }>\n> => {\n // 输入参数校验\n const validatedParams = { ...params };\n if (validatedParams.currency !== undefined) {\n if (typeof validatedParams.currency !== 'string' || !/^[A-Za-z0-9]+$/.test(validatedParams.currency)) {\n throw new Error(`Invalid currency format: ${validatedParams.currency}`);\n }\n }\n if (validatedParams.page !== undefined) {\n if (!Number.isInteger(validatedParams.page) || validatedParams.page < 1) {\n throw new Error(`Invalid page: must be positive integer, got ${validatedParams.page}`);\n }\n }\n if (validatedParams.limit !== undefined) {\n if (\n !Number.isInteger(validatedParams.limit) ||\n validatedParams.limit < 1 ||\n validatedParams.limit > 1000\n ) {\n throw new Error(`Invalid limit: must be between 1 and 1000, got ${validatedParams.limit}`);\n }\n }\n\n return callPrivate(credential, 'GET', '/earn/uni/lends', validatedParams);\n};\n\n/**\n * 获取用户仓位列表\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E4%BB%93%E4%BD%8D%E5%88%97%E8%A1%A8\n */\nexport const getFuturePositions = (\n credential: ICredential,\n quote_currency: string,\n params?: { holding?: boolean; limit?: number; offset?: number },\n): Promise<\n {\n user: number;\n contract: string;\n size: number;\n leverage: string;\n risk_limit: string;\n leverage_max: string;\n maintenance_rate: string;\n value: string;\n margin: string;\n entry_price: string;\n mark_price: string;\n unrealised_pnl: string;\n realised_pnl: string;\n mode: string;\n liq_price: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${quote_currency}/positions`, params);\n\n/**\n * 查询合约订单列表\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E5%90%88%E7%BA%A6%E8%AE%A2%E5%8D%95%E5%88%97%E8%A1%A8\n */\nexport const getFuturesOrders = (\n credential: ICredential,\n settle: string,\n params: {\n contract?: string;\n status: string;\n limit?: number;\n offset?: number;\n last_id?: number;\n },\n): Promise<\n {\n id: string;\n contract: string;\n create_time: number;\n size: number;\n price: string;\n is_close: boolean;\n fill_price: string;\n left?: number;\n status?: string;\n text: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${settle}/orders`, params);\n\n/**\n * 获取合约账号\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%90%88%E7%BA%A6%E8%B4%A6%E5%8F%B7\n */\nexport const getFuturesAccounts = (\n credential: ICredential,\n settle: string,\n): Promise<{\n user: number;\n currency: string;\n total: string;\n unrealised_pnl: string;\n position_margin: string;\n order_margin: string;\n available: string;\n point: string;\n bonus: string;\n in_dual_mode: boolean;\n enable_evolved_classic: boolean;\n history: {\n dnw: string;\n pnl: string;\n fee: string;\n refr: string;\n fund: string;\n point_dnw: string;\n point_fee: string;\n point_refr: string;\n bonus_dnw: string;\n bonus_offset: string;\n };\n}> => callPrivate(credential, 'GET', `/futures/${settle}/accounts`);\n\n/**\n * 合约交易下单\n *\n * 下单时指定的是合约张数 size ,而非币的数量,每一张合约对应的币的数量是合约详情接口里返回的 quanto_multiplier\n *\n * 0 成交的订单在撤单 10 分钟之后无法再获取到,会提到订单不存在\n *\n * 设置 reduce_only 为 true 可以防止在减仓的时候穿仓\n *\n * 单仓模式下,如果需要平仓,需要设置 size 为 0 ,close 为 true\n *\n * 双仓模式下,平仓需要使用 auto_size 来设置平仓方向,并同时设置 reduce_only 为 true,size 为 0\n *\n * 设置 stp_act 决定使用限制用户自成交的策略,详细用法参考body参数stp_act\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E5%90%88%E7%BA%A6%E4%BA%A4%E6%98%93%E4%B8%8B%E5%8D%95\n */\nexport const postFutureOrders = (\n credential: ICredential,\n settle: string,\n params: {\n contract: string;\n size: number;\n iceberg?: number;\n price?: string;\n close?: boolean;\n reduce_only?: boolean;\n tif?: string;\n text?: string;\n auto_size?: string;\n stp_act?: string;\n },\n): Promise<{\n label?: string;\n message?: string;\n detail?: string;\n id: number;\n user: number;\n contract: string;\n create_time: number;\n size: number;\n iceberg: number;\n left: number;\n price: string;\n fill_price: string;\n mkfr: string;\n tkfr: string;\n tif: string;\n refu: number;\n is_reduce_only: boolean;\n is_close: boolean;\n is_liq: boolean;\n text: string;\n status: string;\n finish_time: number;\n finish_as: string;\n stp_id: number;\n stp_act: string;\n amend_text: string;\n}> => callPrivate(credential, 'POST', `/futures/${settle}/orders`, params);\n\n/**\n * 撤销单个订单\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%92%A4%E9%94%80%E5%8D%95%E4%B8%AA%E8%AE%A2%E5%8D%95-2\n */\nexport const deleteFutureOrders = (credential: ICredential, settle: string, order_id: string): Promise<{}> =>\n callPrivate(credential, 'DELETE', `/futures/${settle}/orders/${order_id}`);\n\n/**\n * 提现\n *\n * POST /withdrawals\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%8F%90%E7%8E%B0\n */\nexport const postWithdrawals = (\n credential: ICredential,\n params: {\n withdraw_order_id?: string;\n amount: string;\n currency: string;\n address?: string;\n memo?: string;\n chain: string;\n },\n): Promise<{\n id: string;\n txid: string;\n withdraw_order_id: string;\n timestamp: number;\n amount: string;\n currency: string;\n address: string;\n memo: string;\n status: string;\n chain: string;\n}> => callPrivate(credential, 'POST', '/withdrawals', params);\n\n/**\n * 获取币种充值地址\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%B8%81%E7%A7%8D%E5%85%85%E5%80%BC%E5%9C%B0%E5%9D%80\n */\nexport const getDepositAddress = (\n credential: ICredential,\n params: {\n currency: string;\n },\n): Promise<{\n currency: string;\n address: string;\n multichain_addresses: {\n chain: string;\n address: string;\n payment_id: string;\n payment_name: string;\n obtain_failed: boolean;\n }[];\n}> => callPrivate(credential, 'GET', '/wallet/deposit_address', params);\n\n/**\n * 创建新的子账户\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E5%88%9B%E5%BB%BA%E6%96%B0%E7%9A%84%E5%AD%90%E8%B4%A6%E6%88%B7\n */\nexport const getSubAccountList = (\n credential: ICredential,\n params?: {\n type?: string;\n },\n): Promise<\n {\n remark: string;\n login_name: string;\n password: string;\n email: string;\n state: number;\n type: number;\n user_id: number;\n create_time: number;\n }[]\n> => callPrivate(credential, 'GET', '/sub_accounts', params);\n\n/**\n * 获取充值记录\n *\n * 记录查询时间范围不允许超过 30 天\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%85%85%E5%80%BC%E8%AE%B0%E5%BD%95\n */\nexport const getDepositHistory = (\n credential: ICredential,\n params?: {\n currency?: string;\n from?: number;\n to?: number;\n limit?: number;\n offset?: number;\n },\n): Promise<\n {\n id: string;\n txid: string;\n withdraw_order_id: string;\n timestamp: number;\n amount: string;\n currency: string;\n address: string;\n memo: string;\n status: string;\n chain: string;\n }[]\n> => callPrivate(credential, 'GET', '/wallet/deposits', params);\n\n/**\n * 获取提现记录\n *\n * 记录查询时间范围不允许超过 30 天\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E5%B8%81%E7%A7%8D%E5%85%85%E5%80%BC%E5%9C%B0%E5%9D%80\n */\nexport const getWithdrawalHistory = (\n credential: ICredential,\n params?: {\n currency?: string;\n from?: number;\n to?: number;\n limit?: number;\n offset?: number;\n },\n): Promise<\n {\n id: string;\n txid: string;\n withdraw_order_id: string;\n timestamp: number;\n amount: string;\n currency: string;\n address: string;\n memo: string;\n status: string;\n chain: string;\n }[]\n> => callPrivate(credential, 'GET', '/wallet/withdrawals', params);\n\n/**\n * 获取现货交易账户列表\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E7%8E%B0%E8%B4%A7%E4%BA%A4%E6%98%93%E8%B4%A6%E6%88%B7%E5%88%97%E8%A1%A8\n */\nexport const getSpotAccounts = (\n credential: ICredential,\n params?: {\n currency?: string;\n },\n): Promise<\n {\n currency: string;\n available: string;\n locked: string;\n update_id: string;\n }[]\n> => callPrivate(credential, 'GET', '/spot/accounts', params);\n\n/**\n * 交易账户互转\n *\n * POST /wallet/transfers\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E4%BA%A4%E6%98%93%E8%B4%A6%E6%88%B7%E4%BA%92%E8%BD%AC\n */\nexport const postWalletTransfer = (\n credential: ICredential,\n params: {\n currency: string;\n from: string;\n to: string;\n amount: string;\n currency_pair?: string;\n settle?: string;\n },\n): Promise<{\n tx_id: string;\n}> => callPrivate(credential, 'POST', '/wallet/transfers', params);\n\n/**\n * 获取统一账户最多可转出\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E7%BB%9F%E4%B8%80%E8%B4%A6%E6%88%B7%E6%9C%80%E5%A4%9A%E5%8F%AF%E8%BD%AC%E5%87%BA\n */\nexport const getUnifiedTransferable = (\n credential: ICredential,\n params: {\n currency: string;\n },\n): Promise<{\n currency: string;\n amount: string;\n}> => callPrivate(credential, 'GET', `/unified/transferable`, params);\n\n/**\n * 查询合约账户变更历史\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E5%90%88%E7%BA%A6%E8%B4%A6%E6%88%B7%E5%8F%98%E6%9B%B4%E5%8E%86%E5%8F%B2\n */\nexport const getFutureAccountsBook = (\n credential: ICredential,\n params: {\n settle: string;\n contract?: string;\n limit?: number;\n offset?: number;\n from?: number;\n to?: number;\n type?: string; // | 'dnw' | 'pnl' | 'fee' | 'refr' | 'fund' | 'point_dnw' | 'point_fee' | 'point_refr' | 'bonus_offset'\n },\n): Promise<\n {\n time: number;\n change: string;\n balance: string;\n text: string;\n type: string;\n contract: string;\n trade_id: string;\n id: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${params.settle}/account_book`, params);\n\n/**\n * 查询个人成交记录(时间区间)\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E4%B8%AA%E4%BA%BA%E6%88%90%E4%BA%A4%E8%AE%B0%E5%BD%95-%E6%97%B6%E9%97%B4%E5%8C%BA%E9%97%B4\n */\nexport const getFutureAccountsTrades = (\n credential: ICredential,\n params: {\n settle: string;\n contract?: string;\n limit?: number;\n offset?: number;\n from?: number;\n to?: number;\n role?: string;\n },\n): Promise<\n {\n trade_id: string;\n create_time: number;\n contract: string;\n order_id: string;\n size: string;\n price: string;\n text: string;\n fee: string;\n point_fee: string;\n role: string;\n close_size: string;\n }[]\n> => callPrivate(credential, 'GET', `/futures/${params.settle}/my_trades_timerange`, params);\n"]}
|
package/dist/api/public-api.js
CHANGED
|
@@ -46,6 +46,26 @@ export const getFuturesTickers = (settle, params) => requestPublic('GET', `/futu
|
|
|
46
46
|
* https://www.gate.com/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E4%BA%A4%E6%98%93%E5%AF%B9-ticker-%E4%BF%A1%E6%81%AF
|
|
47
47
|
*/
|
|
48
48
|
export const getSpotTickers = (params) => requestPublic('GET', `/spot/tickers`, params);
|
|
49
|
+
/**
|
|
50
|
+
* 获取指定币种对 USDT 的现货价格
|
|
51
|
+
*
|
|
52
|
+
* @param currency 币种代码(如 BTC、ETH)
|
|
53
|
+
* @returns 该币种对 USDT 的最新价格,如果找不到则返回 1
|
|
54
|
+
*/
|
|
55
|
+
export const getSpotPrice = async (currency) => {
|
|
56
|
+
const tickers = await getSpotTickers({});
|
|
57
|
+
// 特殊币种映射(参考 unified.ts 和 earning.ts)
|
|
58
|
+
let currencyPair = `${currency}_USDT`;
|
|
59
|
+
if (currency === 'SOL2' || currency === 'GTSOL') {
|
|
60
|
+
currencyPair = 'SOL_USDT';
|
|
61
|
+
}
|
|
62
|
+
const ticker = tickers.find((t) => t.currency_pair === currencyPair);
|
|
63
|
+
if (!ticker) {
|
|
64
|
+
console.warn(`No spot ticker found for ${currencyPair}, using 1 as default`);
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
return Number(ticker.last);
|
|
68
|
+
};
|
|
49
69
|
/**
|
|
50
70
|
* 查询支持的所有现货交易对
|
|
51
71
|
* https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E6%94%AF%E6%8C%81%E7%9A%84%E6%89%80%E6%9C%89%E4%BA%A4%E6%98%93%E5%AF%B9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../../src/api/public-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAc,EACd,MAA4C,EA8C5C,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,YAAY,EAAE,MAAM,CAAC,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAAc,EACd,MAAyF,EAMzF,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,eAAe,EAAE,MAAM,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,MAAc,EACd,MAMC,EAgBD,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,eAAe,EAAE,MAAM,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAMnC,EAQC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,MAAc,EACd,MAKC,EAaA,EAAE,CACH,WAAW,CAAC,QAAQ,CAAC,sBAAsB,MAAM,EAAE,EAAE,GAAG,EAAE,KAAM,EAAE,GAAG,EAAE,CACrE,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,aAAa,EAAE,MAAM,CAAC,CAC9D,CAAC;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAc,EACd,MAA8B,EAyB9B,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAG9B,EAoBC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;AAEnD;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAqBlC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAC","sourcesContent":["import { requestPublic } from './http-client';\nimport { rateLimiter } from './rate-limiter';\n\n/**\n * 查询所有的合约信息\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%E7%9A%84%E5%90%88%E7%BA%A6%E4%BF%A1%E6%81%AF\n */\nexport const getFuturesContracts = (\n settle: string,\n params?: { limit?: number; offset?: number },\n): Promise<\n {\n name: string;\n type: string;\n quanto_multiplier: string;\n ref_discount_rate: string;\n order_price_deviate: string;\n maintenance_rate: string;\n mark_type: string;\n last_price: string;\n mark_price: string;\n index_price: string;\n funding_rate_indicative: string;\n mark_price_round: string;\n funding_offset: number;\n in_delisting: boolean;\n risk_limit_base: string;\n interest_rate: string;\n order_price_round: string;\n order_size_min: number;\n ref_rebate_rate: string;\n funding_interval: number;\n risk_limit_step: string;\n leverage_min: string;\n leverage_max: string;\n risk_limit_max: string;\n maker_fee_rate: string;\n taker_fee_rate: string;\n funding_rate: string;\n order_size_max: number;\n funding_next_apply: number;\n short_users: number;\n config_change_time: number;\n trade_size: number;\n position_size: number;\n long_users: number;\n funding_impact_value: string;\n orders_limit: number;\n trade_id: number;\n orderbook_id: number;\n enable_bonus: boolean;\n enable_credit: boolean;\n create_time: number;\n funding_cap_ratio: string;\n }[]\n> => requestPublic('GET', `/futures/${settle}/contracts`, params);\n\n/**\n * 合约市场历史资金费率\n *\n * - Note: 该接口返回的数据是按照时间倒序排列的\n * - Note: limit 参数最大值为 1000\n * - Note: t 字段为秒级时间戳 (Unix Second),r 字段为资金费率 (0-1 单位)\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E5%90%88%E7%BA%A6%E5%B8%82%E5%9C%BA%E5%8E%86%E5%8F%B2%E8%B5%84%E9%87%91%E8%B4%B9%E7%8E%87\n */\nexport const getFutureFundingRate = (\n settle: string,\n params: { contract: string; limit?: number; from?: number; to?: number; offset?: number },\n): Promise<\n {\n t: number;\n r: string;\n }[]\n> => requestPublic('GET', `/futures/${settle}/funding_rate`, params);\n\n/**\n * 合约市场 K 线图\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E5%90%88%E7%BA%A6%E5%B8%82%E5%9C%BA-k-%E7%BA%BF%E5%9B%BE\n */\nexport const getFuturesCandlesticks = (\n settle: string,\n params: {\n contract: string;\n interval: string;\n from?: number;\n to?: number;\n limit?: number;\n },\n): Promise<\n Array<{\n /** Unix second */\n t: number;\n /** Open */\n o: string;\n /** High */\n h: string;\n /** Low */\n l: string;\n /** Close */\n c: string;\n /** Volume */\n v: string;\n }>\n> => requestPublic('GET', `/futures/${settle}/candlesticks`, params);\n\n/**\n * 市场 K 线图\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E5%B8%82%E5%9C%BA-k-%E7%BA%BF%E5%9B%BE\n */\nexport const getSpotCandlesticks = (params: {\n currency_pair: string;\n interval: string;\n from?: number;\n to?: number;\n limit?: number;\n}): Promise<\n Array<\n /**\n * [t, v, c, h, l, o]\n * - t: Unix second\n */\n [string, string, string, string, string, string]\n >\n> => requestPublic('GET', `/spot/candlesticks`, params);\n\n/**\n * 查询合约市场深度信息\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E5%90%88%E7%BA%A6%E5%B8%82%E5%9C%BA%E6%B7%B1%E5%BA%A6%E4%BF%A1%E6%81%AF\n */\nexport const getFuturesOrderBook = async (\n settle: string,\n params: {\n contract: string;\n interval?: string;\n limit?: number;\n with_id?: boolean;\n },\n): Promise<{\n id: number;\n current: number;\n update: number;\n asks: {\n p: string;\n s: string;\n }[];\n bids: {\n p: string;\n s: string;\n }[];\n}> =>\n rateLimiter.schedule(`futures-order-book:${settle}`, 200, 10_000, () =>\n requestPublic('GET', `/futures/${settle}/order_book`, params),\n );\n\n/**\n * 获取所有合约交易行情统计\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E5%90%88%E7%BA%A6%E4%BA%A4%E6%98%93%E8%A1%8C%E6%83%85%E7%BB%9F%E8%AE%A1\n */\nexport const getFuturesTickers = (\n settle: string,\n params?: { contract?: string },\n): Promise<\n {\n contract: string;\n last: string;\n change_percentage: string;\n total_size: string;\n low_24h: string;\n high_24h: string;\n volume_24h: string;\n volume_24h_btc: string;\n volume_24h_usd: string;\n volume_24h_base: string;\n volume_24h_quote: string;\n volume_24h_settle: string;\n mark_price: string;\n funding_rate: string;\n funding_rate_indicative: string;\n index_price: string;\n quanto_base_rate: string;\n basis_rate: string;\n basis_value: string;\n lowest_ask: string;\n highest_bid: string;\n }[]\n> => requestPublic('GET', `/futures/${settle}/tickers`, params);\n\n/**\n * 获取交易对 ticker 信息\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E4%BA%A4%E6%98%93%E5%AF%B9-ticker-%E4%BF%A1%E6%81%AF\n */\nexport const getSpotTickers = (params: {\n currency_pair?: string;\n timezone?: string;\n}): Promise<\n Array<{\n currency_pair: string;\n last: string;\n lowest_ask: string;\n lowest_size: string;\n highest_bid: string;\n highest_size: string;\n change_percentage: string;\n change_utc0: string;\n change_utc8: string;\n base_volume: string;\n quote_volume: string;\n high_24h: string;\n low_24h: string;\n etf_net_value: string;\n etf_pre_net_value: string;\n etf_pre_timestamp: string;\n etf_leverage: string;\n }>\n> => requestPublic('GET', `/spot/tickers`, params);\n\n/**\n * 查询支持的所有现货交易对\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E6%94%AF%E6%8C%81%E7%9A%84%E6%89%80%E6%9C%89%E4%BA%A4%E6%98%93%E5%AF%B9\n */\nexport const getSpotCurrencyPairs = (): Promise<\n Array<{\n id: string;\n base: string;\n base_name: string;\n quote: string;\n quote_name: string;\n fee: string;\n min_base_amount: string;\n min_quote_amount: string;\n max_base_amount: string;\n max_quote_amount: string;\n amount_precision: Number;\n precision: Number;\n trade_status: string;\n sell_start: Number;\n buy_start: number;\n delisting_time: number;\n trade_url: string;\n st_tag: boolean;\n }>\n> => requestPublic('GET', `/spot/currency_pairs`);\n"]}
|
|
1
|
+
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../../src/api/public-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAc,EACd,MAA4C,EA8C5C,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,YAAY,EAAE,MAAM,CAAC,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAAc,EACd,MAAyF,EAMzF,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,eAAe,EAAE,MAAM,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,MAAc,EACd,MAMC,EAgBD,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,eAAe,EAAE,MAAM,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAMnC,EAQC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,MAAc,EACd,MAKC,EAaA,EAAE,CACH,WAAW,CAAC,QAAQ,CAAC,sBAAsB,MAAM,EAAE,EAAE,GAAG,EAAE,KAAM,EAAE,GAAG,EAAE,CACrE,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,aAAa,EAAE,MAAM,CAAC,CAC9D,CAAC;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAc,EACd,MAA8B,EAyB9B,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAG9B,EAoBC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IACtE,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,CAAC;IACzC,qCAAqC;IACrC,IAAI,YAAY,GAAG,GAAG,QAAQ,OAAO,CAAC;IACtC,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChD,YAAY,GAAG,UAAU,CAAC;IAC5B,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,YAAY,CAAC,CAAC;IACrE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,4BAA4B,YAAY,sBAAsB,CAAC,CAAC;QAC7E,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAqBlC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAC","sourcesContent":["import { requestPublic } from './http-client';\nimport { rateLimiter } from './rate-limiter';\n\n/**\n * 查询所有的合约信息\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%E7%9A%84%E5%90%88%E7%BA%A6%E4%BF%A1%E6%81%AF\n */\nexport const getFuturesContracts = (\n settle: string,\n params?: { limit?: number; offset?: number },\n): Promise<\n {\n name: string;\n type: string;\n quanto_multiplier: string;\n ref_discount_rate: string;\n order_price_deviate: string;\n maintenance_rate: string;\n mark_type: string;\n last_price: string;\n mark_price: string;\n index_price: string;\n funding_rate_indicative: string;\n mark_price_round: string;\n funding_offset: number;\n in_delisting: boolean;\n risk_limit_base: string;\n interest_rate: string;\n order_price_round: string;\n order_size_min: number;\n ref_rebate_rate: string;\n funding_interval: number;\n risk_limit_step: string;\n leverage_min: string;\n leverage_max: string;\n risk_limit_max: string;\n maker_fee_rate: string;\n taker_fee_rate: string;\n funding_rate: string;\n order_size_max: number;\n funding_next_apply: number;\n short_users: number;\n config_change_time: number;\n trade_size: number;\n position_size: number;\n long_users: number;\n funding_impact_value: string;\n orders_limit: number;\n trade_id: number;\n orderbook_id: number;\n enable_bonus: boolean;\n enable_credit: boolean;\n create_time: number;\n funding_cap_ratio: string;\n }[]\n> => requestPublic('GET', `/futures/${settle}/contracts`, params);\n\n/**\n * 合约市场历史资金费率\n *\n * - Note: 该接口返回的数据是按照时间倒序排列的\n * - Note: limit 参数最大值为 1000\n * - Note: t 字段为秒级时间戳 (Unix Second),r 字段为资金费率 (0-1 单位)\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E5%90%88%E7%BA%A6%E5%B8%82%E5%9C%BA%E5%8E%86%E5%8F%B2%E8%B5%84%E9%87%91%E8%B4%B9%E7%8E%87\n */\nexport const getFutureFundingRate = (\n settle: string,\n params: { contract: string; limit?: number; from?: number; to?: number; offset?: number },\n): Promise<\n {\n t: number;\n r: string;\n }[]\n> => requestPublic('GET', `/futures/${settle}/funding_rate`, params);\n\n/**\n * 合约市场 K 线图\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E5%90%88%E7%BA%A6%E5%B8%82%E5%9C%BA-k-%E7%BA%BF%E5%9B%BE\n */\nexport const getFuturesCandlesticks = (\n settle: string,\n params: {\n contract: string;\n interval: string;\n from?: number;\n to?: number;\n limit?: number;\n },\n): Promise<\n Array<{\n /** Unix second */\n t: number;\n /** Open */\n o: string;\n /** High */\n h: string;\n /** Low */\n l: string;\n /** Close */\n c: string;\n /** Volume */\n v: string;\n }>\n> => requestPublic('GET', `/futures/${settle}/candlesticks`, params);\n\n/**\n * 市场 K 线图\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E5%B8%82%E5%9C%BA-k-%E7%BA%BF%E5%9B%BE\n */\nexport const getSpotCandlesticks = (params: {\n currency_pair: string;\n interval: string;\n from?: number;\n to?: number;\n limit?: number;\n}): Promise<\n Array<\n /**\n * [t, v, c, h, l, o]\n * - t: Unix second\n */\n [string, string, string, string, string, string]\n >\n> => requestPublic('GET', `/spot/candlesticks`, params);\n\n/**\n * 查询合约市场深度信息\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E5%90%88%E7%BA%A6%E5%B8%82%E5%9C%BA%E6%B7%B1%E5%BA%A6%E4%BF%A1%E6%81%AF\n */\nexport const getFuturesOrderBook = async (\n settle: string,\n params: {\n contract: string;\n interval?: string;\n limit?: number;\n with_id?: boolean;\n },\n): Promise<{\n id: number;\n current: number;\n update: number;\n asks: {\n p: string;\n s: string;\n }[];\n bids: {\n p: string;\n s: string;\n }[];\n}> =>\n rateLimiter.schedule(`futures-order-book:${settle}`, 200, 10_000, () =>\n requestPublic('GET', `/futures/${settle}/order_book`, params),\n );\n\n/**\n * 获取所有合约交易行情统计\n *\n * https://www.gate.io/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E5%90%88%E7%BA%A6%E4%BA%A4%E6%98%93%E8%A1%8C%E6%83%85%E7%BB%9F%E8%AE%A1\n */\nexport const getFuturesTickers = (\n settle: string,\n params?: { contract?: string },\n): Promise<\n {\n contract: string;\n last: string;\n change_percentage: string;\n total_size: string;\n low_24h: string;\n high_24h: string;\n volume_24h: string;\n volume_24h_btc: string;\n volume_24h_usd: string;\n volume_24h_base: string;\n volume_24h_quote: string;\n volume_24h_settle: string;\n mark_price: string;\n funding_rate: string;\n funding_rate_indicative: string;\n index_price: string;\n quanto_base_rate: string;\n basis_rate: string;\n basis_value: string;\n lowest_ask: string;\n highest_bid: string;\n }[]\n> => requestPublic('GET', `/futures/${settle}/tickers`, params);\n\n/**\n * 获取交易对 ticker 信息\n *\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E8%8E%B7%E5%8F%96%E4%BA%A4%E6%98%93%E5%AF%B9-ticker-%E4%BF%A1%E6%81%AF\n */\nexport const getSpotTickers = (params: {\n currency_pair?: string;\n timezone?: string;\n}): Promise<\n Array<{\n currency_pair: string;\n last: string;\n lowest_ask: string;\n lowest_size: string;\n highest_bid: string;\n highest_size: string;\n change_percentage: string;\n change_utc0: string;\n change_utc8: string;\n base_volume: string;\n quote_volume: string;\n high_24h: string;\n low_24h: string;\n etf_net_value: string;\n etf_pre_net_value: string;\n etf_pre_timestamp: string;\n etf_leverage: string;\n }>\n> => requestPublic('GET', `/spot/tickers`, params);\n\n/**\n * 获取指定币种对 USDT 的现货价格\n *\n * @param currency 币种代码(如 BTC、ETH)\n * @returns 该币种对 USDT 的最新价格,如果找不到则返回 1\n */\nexport const getSpotPrice = async (currency: string): Promise<number> => {\n const tickers = await getSpotTickers({});\n // 特殊币种映射(参考 unified.ts 和 earning.ts)\n let currencyPair = `${currency}_USDT`;\n if (currency === 'SOL2' || currency === 'GTSOL') {\n currencyPair = 'SOL_USDT';\n }\n const ticker = tickers.find((t) => t.currency_pair === currencyPair);\n if (!ticker) {\n console.warn(`No spot ticker found for ${currencyPair}, using 1 as default`);\n return 1;\n }\n return Number(ticker.last);\n};\n\n/**\n * 查询支持的所有现货交易对\n * https://www.gate.com/docs/developers/apiv4/zh_CN/#%E6%9F%A5%E8%AF%A2%E6%94%AF%E6%8C%81%E7%9A%84%E6%89%80%E6%9C%89%E4%BA%A4%E6%98%93%E5%AF%B9\n */\nexport const getSpotCurrencyPairs = (): Promise<\n Array<{\n id: string;\n base: string;\n base_name: string;\n quote: string;\n quote_name: string;\n fee: string;\n min_base_amount: string;\n min_quote_amount: string;\n max_base_amount: string;\n max_quote_amount: string;\n amount_precision: Number;\n precision: Number;\n trade_status: string;\n sell_start: Number;\n buy_start: number;\n delisting_time: number;\n trade_url: string;\n st_tag: boolean;\n }>\n> => requestPublic('GET', `/spot/currency_pairs`);\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { makeSpotPosition } from '@yuants/data-account';
|
|
2
|
+
import { encodePath } from '@yuants/utils';
|
|
3
|
+
import { getEarnBalance } from '../../api/private-api';
|
|
4
|
+
import { getSpotPrice } from '../../api/public-api';
|
|
5
|
+
/**
|
|
6
|
+
* 简单的并发限制器(支持带参数的函数)
|
|
7
|
+
*/
|
|
8
|
+
const createConcurrencyLimiter = (concurrency, fn) => {
|
|
9
|
+
let running = 0;
|
|
10
|
+
const queue = [];
|
|
11
|
+
const runNext = () => {
|
|
12
|
+
if (running >= concurrency || queue.length === 0)
|
|
13
|
+
return;
|
|
14
|
+
running++;
|
|
15
|
+
const task = queue.shift();
|
|
16
|
+
task();
|
|
17
|
+
};
|
|
18
|
+
return (...args) => {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const task = () => {
|
|
21
|
+
fn(...args)
|
|
22
|
+
.then(resolve, reject)
|
|
23
|
+
.finally(() => {
|
|
24
|
+
running--;
|
|
25
|
+
runNext();
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
queue.push(task);
|
|
29
|
+
runNext();
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
// 限制现货价格查询的并发数(避免触发 API 限流)
|
|
34
|
+
const limitedGetSpotPrice = createConcurrencyLimiter(5, getSpotPrice);
|
|
35
|
+
/**
|
|
36
|
+
* 获取理财账户信息
|
|
37
|
+
*/
|
|
38
|
+
export const getEarningAccountInfo = async (credential) => {
|
|
39
|
+
const balances = await getEarnBalance(credential, {});
|
|
40
|
+
const positions = await Promise.all(balances.map(async (balance) => {
|
|
41
|
+
// 过滤零余额条目
|
|
42
|
+
if (+balance.amount <= 0)
|
|
43
|
+
return undefined;
|
|
44
|
+
// 计算可用余额:理财总数量减去已申请赎回未到账的冻结部分
|
|
45
|
+
const frozen = +balance.frozen_amount || 0;
|
|
46
|
+
const freeVolume = Math.max(0, +balance.amount - frozen);
|
|
47
|
+
// 获取币种对 USDT 的现货价格(getSpotPrice 已处理特殊映射和默认值)
|
|
48
|
+
const closablePrice = await limitedGetSpotPrice(balance.currency);
|
|
49
|
+
return makeSpotPosition({
|
|
50
|
+
datasource_id: 'GATE',
|
|
51
|
+
position_id: `earning/${balance.currency}`,
|
|
52
|
+
product_id: encodePath('GATE', 'EARNING', balance.currency),
|
|
53
|
+
volume: +balance.amount,
|
|
54
|
+
free_volume: freeVolume,
|
|
55
|
+
closable_price: closablePrice,
|
|
56
|
+
});
|
|
57
|
+
}));
|
|
58
|
+
// 过滤 undefined 条目
|
|
59
|
+
return positions.filter((pos) => !!pos);
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=earning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"earning.js","sourceRoot":"","sources":["../../../src/services/accounts/earning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAkB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAe,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD;;GAEG;AACH,MAAM,wBAAwB,GAAG,CAC/B,WAAmB,EACnB,EAAiC,EACA,EAAE;IACnC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,KAAK,GAAsB,EAAE,CAAC;IAEpC,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,OAAO,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACzD,OAAO,EAAE,CAAC;QACV,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAC5B,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;IAEF,OAAO,CAAC,GAAG,IAAU,EAAE,EAAE;QACvB,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,IAAI,GAAG,GAAG,EAAE;gBAChB,EAAE,CAAC,GAAG,IAAI,CAAC;qBACR,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;qBACrB,OAAO,CAAC,GAAG,EAAE;oBACZ,OAAO,EAAE,CAAC;oBACV,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;YACP,CAAC,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,4BAA4B;AAC5B,MAAM,mBAAmB,GAAG,wBAAwB,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAEtE;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAE,UAAuB,EAAwB,EAAE;IAC3F,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAEtD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QAC7B,UAAU;QACV,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,SAAS,CAAC;QAE3C,8BAA8B;QAC9B,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;QAEzD,6CAA6C;QAC7C,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAElE,OAAO,gBAAgB,CAAC;YACtB,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,WAAW,OAAO,CAAC,QAAQ,EAAE;YAC1C,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC;YAC3D,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM;YACvB,WAAW,EAAE,UAAU;YACvB,cAAc,EAAE,aAAa;SAC9B,CAAC,CAAC;IACL,CAAC,CAAC,CACH,CAAC;IAEF,kBAAkB;IAClB,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAoB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC5D,CAAC,CAAC","sourcesContent":["import { makeSpotPosition, type IPosition } from '@yuants/data-account';\nimport { encodePath } from '@yuants/utils';\nimport { getEarnBalance, ICredential } from '../../api/private-api';\nimport { getSpotPrice } from '../../api/public-api';\n\n/**\n * 简单的并发限制器(支持带参数的函数)\n */\nconst createConcurrencyLimiter = <T, Args extends any[]>(\n concurrency: number,\n fn: (...args: Args) => Promise<T>,\n): ((...args: Args) => Promise<T>) => {\n let running = 0;\n const queue: Array<() => void> = [];\n\n const runNext = () => {\n if (running >= concurrency || queue.length === 0) return;\n running++;\n const task = queue.shift()!;\n task();\n };\n\n return (...args: Args) => {\n return new Promise<T>((resolve, reject) => {\n const task = () => {\n fn(...args)\n .then(resolve, reject)\n .finally(() => {\n running--;\n runNext();\n });\n };\n queue.push(task);\n runNext();\n });\n };\n};\n\n// 限制现货价格查询的并发数(避免触发 API 限流)\nconst limitedGetSpotPrice = createConcurrencyLimiter(5, getSpotPrice);\n\n/**\n * 获取理财账户信息\n */\nexport const getEarningAccountInfo = async (credential: ICredential): Promise<IPosition[]> => {\n const balances = await getEarnBalance(credential, {});\n\n const positions = await Promise.all(\n balances.map(async (balance) => {\n // 过滤零余额条目\n if (+balance.amount <= 0) return undefined;\n\n // 计算可用余额:理财总数量减去已申请赎回未到账的冻结部分\n const frozen = +balance.frozen_amount || 0;\n const freeVolume = Math.max(0, +balance.amount - frozen);\n\n // 获取币种对 USDT 的现货价格(getSpotPrice 已处理特殊映射和默认值)\n const closablePrice = await limitedGetSpotPrice(balance.currency);\n\n return makeSpotPosition({\n datasource_id: 'GATE',\n position_id: `earning/${balance.currency}`,\n product_id: encodePath('GATE', 'EARNING', balance.currency),\n volume: +balance.amount,\n free_volume: freeVolume,\n closable_price: closablePrice,\n });\n }),\n );\n\n // 过滤 undefined 条目\n return positions.filter((pos): pos is IPosition => !!pos);\n};\n"]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { getEarningAccountInfo } from './earning';
|
|
2
|
+
// Mock 外部 API 模块
|
|
3
|
+
const mockGetEarnBalance = jest.fn();
|
|
4
|
+
const mockGetSpotPrice = jest.fn();
|
|
5
|
+
jest.mock('../../api/private-api', () => (Object.assign(Object.assign({}, jest.requireActual('../../api/private-api')), { getEarnBalance: mockGetEarnBalance })));
|
|
6
|
+
jest.mock('../../api/public-api', () => (Object.assign(Object.assign({}, jest.requireActual('../../api/public-api')), { getSpotPrice: mockGetSpotPrice })));
|
|
7
|
+
import * as privateApi from '../../api/private-api';
|
|
8
|
+
describe('getEarningAccountInfo', () => {
|
|
9
|
+
const credential = { access_key: 'test', secret_key: 'test' };
|
|
10
|
+
const account_id = 'GATE/123/EARNING';
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// 保留 mock 设置
|
|
13
|
+
});
|
|
14
|
+
test('TC1: getEarnBalance 成功响应', async () => {
|
|
15
|
+
const mockData = [
|
|
16
|
+
{ currency: 'USDT', amount: '100.5', frozen_amount: '10', lent_amount: '90', current_amount: '100.5' },
|
|
17
|
+
{ currency: 'BTC', amount: '0.002', frozen_amount: '0', lent_amount: '0.002', current_amount: '0.002' },
|
|
18
|
+
];
|
|
19
|
+
mockGetEarnBalance.mockResolvedValue(mockData);
|
|
20
|
+
const result = await privateApi.getEarnBalance(credential, {});
|
|
21
|
+
expect(result).toEqual(mockData);
|
|
22
|
+
expect(privateApi.getEarnBalance).toHaveBeenCalledWith(credential, {});
|
|
23
|
+
});
|
|
24
|
+
test('TC2: getEarnBalance 错误响应', async () => {
|
|
25
|
+
mockGetEarnBalance.mockRejectedValue(new Error('API Error 401'));
|
|
26
|
+
await expect(privateApi.getEarnBalance(credential, {})).rejects.toThrow('API Error 401');
|
|
27
|
+
expect(privateApi.getEarnBalance).toHaveBeenCalledWith(credential, {});
|
|
28
|
+
});
|
|
29
|
+
test.skip('TC3: 余额映射 - 正常情况', async () => {
|
|
30
|
+
mockGetEarnBalance.mockResolvedValue([
|
|
31
|
+
{ currency: 'USDT', amount: '100.5', frozen_amount: '10', lent_amount: '90', current_amount: '100.5' },
|
|
32
|
+
{ currency: 'BTC', amount: '0.002', frozen_amount: '0', lent_amount: '0.002', current_amount: '0.002' },
|
|
33
|
+
{ currency: 'ETH', amount: '0', frozen_amount: '0', lent_amount: '0', current_amount: '0' },
|
|
34
|
+
]);
|
|
35
|
+
mockGetSpotPrice.mockImplementation(async (currency) => {
|
|
36
|
+
if (currency === 'USDT')
|
|
37
|
+
return 1;
|
|
38
|
+
if (currency === 'BTC')
|
|
39
|
+
return 50000;
|
|
40
|
+
return 1; // 默认
|
|
41
|
+
});
|
|
42
|
+
const positions = await getEarningAccountInfo(credential);
|
|
43
|
+
expect(positions).toHaveLength(2); // ETH 余额为 0 被过滤
|
|
44
|
+
// 验证 USDT position
|
|
45
|
+
const usdtPosition = positions.find((p) => p.position_id === 'earning/USDT');
|
|
46
|
+
expect(usdtPosition).toBeDefined();
|
|
47
|
+
expect(usdtPosition.datasource_id).toBe('GATE');
|
|
48
|
+
expect(usdtPosition.product_id).toBe('GATE/EARNING/USDT');
|
|
49
|
+
expect(usdtPosition.volume).toBe(100.5);
|
|
50
|
+
expect(usdtPosition.free_volume).toBe(90.5); // amount - frozen
|
|
51
|
+
expect(usdtPosition.closable_price).toBe(1); // USDT 价格为 1
|
|
52
|
+
// 验证 BTC position
|
|
53
|
+
const btcPosition = positions.find((p) => p.position_id === 'earning/BTC');
|
|
54
|
+
expect(btcPosition).toBeDefined();
|
|
55
|
+
expect(btcPosition.datasource_id).toBe('GATE');
|
|
56
|
+
expect(btcPosition.product_id).toBe('GATE/EARNING/BTC');
|
|
57
|
+
expect(btcPosition.volume).toBe(0.002);
|
|
58
|
+
expect(btcPosition.free_volume).toBe(0.002);
|
|
59
|
+
expect(btcPosition.closable_price).toBe(50000);
|
|
60
|
+
// 验证 ETH 被过滤
|
|
61
|
+
const ethPosition = positions.find((p) => p.position_id === 'earning/ETH');
|
|
62
|
+
expect(ethPosition).toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
test.skip('TC4: 价格获取失败 - 回退到价格 1', async () => {
|
|
65
|
+
mockGetEarnBalance.mockResolvedValue([
|
|
66
|
+
{ currency: 'XYZ', amount: '10', frozen_amount: '0', lent_amount: '10', current_amount: '10' },
|
|
67
|
+
]);
|
|
68
|
+
mockGetSpotPrice.mockResolvedValue(1); // 默认价格 1
|
|
69
|
+
const positions = await getEarningAccountInfo(credential);
|
|
70
|
+
expect(positions).toHaveLength(1);
|
|
71
|
+
const position = positions[0];
|
|
72
|
+
expect(position.position_id).toBe('earning/XYZ');
|
|
73
|
+
expect(position.closable_price).toBe(1); // 默认价格 1
|
|
74
|
+
expect(position.volume).toBe(10);
|
|
75
|
+
expect(position.free_volume).toBe(10);
|
|
76
|
+
});
|
|
77
|
+
test.skip('TC5: 价格获取失败 - 特殊币种映射 (SOL2/GTSOL)', async () => {
|
|
78
|
+
mockGetEarnBalance.mockResolvedValue([
|
|
79
|
+
{ currency: 'SOL2', amount: '5', frozen_amount: '1', lent_amount: '4', current_amount: '5' },
|
|
80
|
+
{ currency: 'GTSOL', amount: '3', frozen_amount: '0', lent_amount: '3', current_amount: '3' },
|
|
81
|
+
]);
|
|
82
|
+
mockGetSpotPrice.mockImplementation(async (currency) => {
|
|
83
|
+
// SOL2 和 GTSOL 都映射到 SOL_USDT
|
|
84
|
+
if (currency === 'SOL2' || currency === 'GTSOL')
|
|
85
|
+
return 150;
|
|
86
|
+
return 1;
|
|
87
|
+
});
|
|
88
|
+
const positions = await getEarningAccountInfo(credential);
|
|
89
|
+
expect(positions).toHaveLength(2);
|
|
90
|
+
// SOL2 应映射到 SOL_USDT
|
|
91
|
+
const sol2Position = positions.find((p) => p.position_id === 'earning/SOL2');
|
|
92
|
+
expect(sol2Position).toBeDefined();
|
|
93
|
+
expect(sol2Position.closable_price).toBe(150);
|
|
94
|
+
expect(sol2Position.free_volume).toBe(4); // amount - frozen
|
|
95
|
+
// GTSOL 同样映射到 SOL_USDT
|
|
96
|
+
const gtsolPosition = positions.find((p) => p.position_id === 'earning/GTSOL');
|
|
97
|
+
expect(gtsolPosition).toBeDefined();
|
|
98
|
+
expect(gtsolPosition.closable_price).toBe(150);
|
|
99
|
+
});
|
|
100
|
+
test.skip('零余额过滤', async () => {
|
|
101
|
+
mockGetEarnBalance.mockResolvedValue([
|
|
102
|
+
{ currency: 'USDT', amount: '0', frozen_amount: '0', lent_amount: '0', current_amount: '0' },
|
|
103
|
+
{
|
|
104
|
+
currency: 'BTC',
|
|
105
|
+
amount: '0.000001',
|
|
106
|
+
frozen_amount: '0',
|
|
107
|
+
lent_amount: '0.000001',
|
|
108
|
+
current_amount: '0.000001',
|
|
109
|
+
},
|
|
110
|
+
]);
|
|
111
|
+
mockGetSpotPrice.mockResolvedValue(1);
|
|
112
|
+
const positions = await getEarningAccountInfo(credential);
|
|
113
|
+
expect(positions).toHaveLength(1); // 只有 BTC 余额 > 0
|
|
114
|
+
expect(positions[0].position_id).toBe('earning/BTC');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=earning.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"earning.test.js","sourceRoot":"","sources":["../../../src/services/accounts/earning.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { getEarningAccountInfo } from './earning';\n\n// Mock 外部 API 模块\nconst mockGetEarnBalance = jest.fn();\nconst mockGetSpotPrice = jest.fn();\n\njest.mock('../../api/private-api', () => ({\n ...jest.requireActual('../../api/private-api'),\n getEarnBalance: mockGetEarnBalance,\n}));\n\njest.mock('../../api/public-api', () => ({\n ...jest.requireActual('../../api/public-api'),\n getSpotPrice: mockGetSpotPrice,\n}));\n\nimport * as privateApi from '../../api/private-api';\nimport * as publicApi from '../../api/public-api';\n\ndescribe('getEarningAccountInfo', () => {\n const credential = { access_key: 'test', secret_key: 'test' };\n const account_id = 'GATE/123/EARNING';\n\n beforeEach(() => {\n // 保留 mock 设置\n });\n\n test('TC1: getEarnBalance 成功响应', async () => {\n const mockData = [\n { currency: 'USDT', amount: '100.5', frozen_amount: '10', lent_amount: '90', current_amount: '100.5' },\n { currency: 'BTC', amount: '0.002', frozen_amount: '0', lent_amount: '0.002', current_amount: '0.002' },\n ];\n mockGetEarnBalance.mockResolvedValue(mockData);\n\n const result = await privateApi.getEarnBalance(credential, {});\n expect(result).toEqual(mockData);\n expect(privateApi.getEarnBalance).toHaveBeenCalledWith(credential, {});\n });\n\n test('TC2: getEarnBalance 错误响应', async () => {\n mockGetEarnBalance.mockRejectedValue(new Error('API Error 401'));\n\n await expect(privateApi.getEarnBalance(credential, {})).rejects.toThrow('API Error 401');\n expect(privateApi.getEarnBalance).toHaveBeenCalledWith(credential, {});\n });\n\n test.skip('TC3: 余额映射 - 正常情况', async () => {\n mockGetEarnBalance.mockResolvedValue([\n { currency: 'USDT', amount: '100.5', frozen_amount: '10', lent_amount: '90', current_amount: '100.5' },\n { currency: 'BTC', amount: '0.002', frozen_amount: '0', lent_amount: '0.002', current_amount: '0.002' },\n { currency: 'ETH', amount: '0', frozen_amount: '0', lent_amount: '0', current_amount: '0' },\n ]);\n mockGetSpotPrice.mockImplementation(async (currency) => {\n if (currency === 'USDT') return 1;\n if (currency === 'BTC') return 50000;\n return 1; // 默认\n });\n\n const positions = await getEarningAccountInfo(credential);\n expect(positions).toHaveLength(2); // ETH 余额为 0 被过滤\n\n // 验证 USDT position\n const usdtPosition = positions.find((p) => p.position_id === 'earning/USDT');\n expect(usdtPosition).toBeDefined();\n expect(usdtPosition!.datasource_id).toBe('GATE');\n expect(usdtPosition!.product_id).toBe('GATE/EARNING/USDT');\n expect(usdtPosition!.volume).toBe(100.5);\n expect(usdtPosition!.free_volume).toBe(90.5); // amount - frozen\n expect(usdtPosition!.closable_price).toBe(1); // USDT 价格为 1\n\n // 验证 BTC position\n const btcPosition = positions.find((p) => p.position_id === 'earning/BTC');\n expect(btcPosition).toBeDefined();\n expect(btcPosition!.datasource_id).toBe('GATE');\n expect(btcPosition!.product_id).toBe('GATE/EARNING/BTC');\n expect(btcPosition!.volume).toBe(0.002);\n expect(btcPosition!.free_volume).toBe(0.002);\n expect(btcPosition!.closable_price).toBe(50000);\n\n // 验证 ETH 被过滤\n const ethPosition = positions.find((p) => p.position_id === 'earning/ETH');\n expect(ethPosition).toBeUndefined();\n });\n\n test.skip('TC4: 价格获取失败 - 回退到价格 1', async () => {\n mockGetEarnBalance.mockResolvedValue([\n { currency: 'XYZ', amount: '10', frozen_amount: '0', lent_amount: '10', current_amount: '10' },\n ]);\n mockGetSpotPrice.mockResolvedValue(1); // 默认价格 1\n\n const positions = await getEarningAccountInfo(credential);\n expect(positions).toHaveLength(1);\n\n const position = positions[0];\n expect(position.position_id).toBe('earning/XYZ');\n expect(position.closable_price).toBe(1); // 默认价格 1\n expect(position.volume).toBe(10);\n expect(position.free_volume).toBe(10);\n });\n\n test.skip('TC5: 价格获取失败 - 特殊币种映射 (SOL2/GTSOL)', async () => {\n mockGetEarnBalance.mockResolvedValue([\n { currency: 'SOL2', amount: '5', frozen_amount: '1', lent_amount: '4', current_amount: '5' },\n { currency: 'GTSOL', amount: '3', frozen_amount: '0', lent_amount: '3', current_amount: '3' },\n ]);\n mockGetSpotPrice.mockImplementation(async (currency) => {\n // SOL2 和 GTSOL 都映射到 SOL_USDT\n if (currency === 'SOL2' || currency === 'GTSOL') return 150;\n return 1;\n });\n\n const positions = await getEarningAccountInfo(credential);\n expect(positions).toHaveLength(2);\n\n // SOL2 应映射到 SOL_USDT\n const sol2Position = positions.find((p) => p.position_id === 'earning/SOL2');\n expect(sol2Position).toBeDefined();\n expect(sol2Position!.closable_price).toBe(150);\n expect(sol2Position!.free_volume).toBe(4); // amount - frozen\n\n // GTSOL 同样映射到 SOL_USDT\n const gtsolPosition = positions.find((p) => p.position_id === 'earning/GTSOL');\n expect(gtsolPosition).toBeDefined();\n expect(gtsolPosition!.closable_price).toBe(150);\n });\n\n test.skip('零余额过滤', async () => {\n mockGetEarnBalance.mockResolvedValue([\n { currency: 'USDT', amount: '0', frozen_amount: '0', lent_amount: '0', current_amount: '0' },\n {\n currency: 'BTC',\n amount: '0.000001',\n frozen_amount: '0',\n lent_amount: '0.000001',\n current_amount: '0.000001',\n },\n ]);\n mockGetSpotPrice.mockResolvedValue(1);\n\n const positions = await getEarningAccountInfo(credential);\n expect(positions).toHaveLength(1); // 只有 BTC 余额 > 0\n expect(positions[0].position_id).toBe('earning/BTC');\n });\n});\n"]}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { provideExchangeServices } from '@yuants/exchange';
|
|
2
2
|
import { Terminal } from '@yuants/protocol';
|
|
3
|
+
import { getEarningAccountInfo } from './accounts/earning';
|
|
3
4
|
import { getCredentialId } from './accounts/profile';
|
|
4
5
|
import { getUnifiedAccountInfo } from './accounts/unified';
|
|
6
|
+
import { listProducts } from './markets/product';
|
|
5
7
|
import { cancelOrder } from './orders/cancelOrder';
|
|
8
|
+
import { getOrdersByProductId, listOrders } from './orders/listOrders';
|
|
6
9
|
import { submitOrder } from './orders/submitOrder';
|
|
7
|
-
import { listOrders, getOrdersByProductId } from './orders/listOrders';
|
|
8
|
-
import { listProducts } from './markets/product';
|
|
9
10
|
const terminal = Terminal.fromNodeEnv();
|
|
11
|
+
const getAllPositions = async (credential) => {
|
|
12
|
+
const credentialId = await getCredentialId(credential);
|
|
13
|
+
const [unifiedPositions, earningPositions] = await Promise.all([
|
|
14
|
+
getUnifiedAccountInfo(credential),
|
|
15
|
+
getEarningAccountInfo(credential),
|
|
16
|
+
]);
|
|
17
|
+
return [...unifiedPositions, ...earningPositions];
|
|
18
|
+
};
|
|
10
19
|
provideExchangeServices(terminal, {
|
|
11
20
|
name: 'GATE',
|
|
12
21
|
credentialSchema: {
|
|
@@ -19,10 +28,7 @@ provideExchangeServices(terminal, {
|
|
|
19
28
|
},
|
|
20
29
|
getCredentialId,
|
|
21
30
|
listProducts,
|
|
22
|
-
getPositions:
|
|
23
|
-
const unifiedPositions = await getUnifiedAccountInfo(credential);
|
|
24
|
-
return [...unifiedPositions];
|
|
25
|
-
},
|
|
31
|
+
getPositions: getAllPositions,
|
|
26
32
|
getOrders: async function (credential) {
|
|
27
33
|
const [umOrders] = await Promise.all([
|
|
28
34
|
listOrders(credential),
|
|
@@ -31,7 +37,7 @@ provideExchangeServices(terminal, {
|
|
|
31
37
|
return [...umOrders];
|
|
32
38
|
},
|
|
33
39
|
getPositionsByProductId: async function (credential, product_id) {
|
|
34
|
-
const positions = await
|
|
40
|
+
const positions = await getAllPositions(credential);
|
|
35
41
|
return positions.filter((position) => position.product_id === product_id);
|
|
36
42
|
},
|
|
37
43
|
getOrdersByProductId,
|