@yuants/vendor-huobi 0.13.1 → 0.14.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 (61) hide show
  1. package/dist/account-actions-with-credentials.js +30 -0
  2. package/dist/account-actions-with-credentials.js.map +1 -0
  3. package/dist/account-info.js +13 -173
  4. package/dist/account-info.js.map +1 -1
  5. package/dist/accounts/list.js +8 -0
  6. package/dist/accounts/list.js.map +1 -0
  7. package/dist/accounts/spot.js +20 -0
  8. package/dist/accounts/spot.js.map +1 -0
  9. package/dist/accounts/super-margin.js +74 -0
  10. package/dist/accounts/super-margin.js.map +1 -0
  11. package/dist/accounts/swap.js +87 -0
  12. package/dist/accounts/swap.js.map +1 -0
  13. package/dist/api/private-api.js +0 -8
  14. package/dist/api/private-api.js.map +1 -1
  15. package/dist/index.js +5 -4
  16. package/dist/index.js.map +1 -1
  17. package/dist/orders/submitOrder.js +3 -2
  18. package/dist/orders/submitOrder.js.map +1 -1
  19. package/dist/uid.js +0 -1
  20. package/dist/uid.js.map +1 -1
  21. package/lib/account-actions-with-credentials.d.ts +2 -0
  22. package/lib/account-actions-with-credentials.d.ts.map +1 -0
  23. package/lib/account-actions-with-credentials.js +32 -0
  24. package/lib/account-actions-with-credentials.js.map +1 -0
  25. package/lib/account-info.d.ts +1 -1
  26. package/lib/account-info.d.ts.map +1 -1
  27. package/lib/account-info.js +11 -171
  28. package/lib/account-info.js.map +1 -1
  29. package/lib/accounts/list.d.ts +4 -0
  30. package/lib/accounts/list.d.ts.map +1 -0
  31. package/lib/accounts/list.js +12 -0
  32. package/lib/accounts/list.js.map +1 -0
  33. package/lib/accounts/spot.d.ts +4 -0
  34. package/lib/accounts/spot.d.ts.map +1 -0
  35. package/lib/accounts/spot.js +24 -0
  36. package/lib/accounts/spot.js.map +1 -0
  37. package/lib/accounts/super-margin.d.ts +7 -0
  38. package/lib/accounts/super-margin.d.ts.map +1 -0
  39. package/lib/accounts/super-margin.js +78 -0
  40. package/lib/accounts/super-margin.js.map +1 -0
  41. package/lib/accounts/swap.d.ts +4 -0
  42. package/lib/accounts/swap.d.ts.map +1 -0
  43. package/lib/accounts/swap.js +91 -0
  44. package/lib/accounts/swap.js.map +1 -0
  45. package/lib/api/private-api.d.ts +0 -13
  46. package/lib/api/private-api.d.ts.map +1 -1
  47. package/lib/api/private-api.js +1 -10
  48. package/lib/api/private-api.js.map +1 -1
  49. package/lib/index.d.ts +1 -0
  50. package/lib/index.d.ts.map +1 -1
  51. package/lib/index.js +4 -3
  52. package/lib/index.js.map +1 -1
  53. package/lib/orders/submitOrder.d.ts.map +1 -1
  54. package/lib/orders/submitOrder.js +2 -1
  55. package/lib/orders/submitOrder.js.map +1 -1
  56. package/lib/uid.d.ts +0 -1
  57. package/lib/uid.d.ts.map +1 -1
  58. package/lib/uid.js +0 -1
  59. package/lib/uid.js.map +1 -1
  60. package/package.json +2 -2
  61. package/temp/package-deps.json +14 -9
@@ -0,0 +1,30 @@
1
+ import { provideAccountActionsWithCredential } from '@yuants/data-account';
2
+ import { Terminal } from '@yuants/protocol';
3
+ import { listAccounts } from './accounts/list';
4
+ import { getSpotAccountInfo } from './accounts/spot';
5
+ import { getSuperMarginAccountInfo } from './accounts/super-margin';
6
+ import { getSwapAccountInfo } from './accounts/swap';
7
+ import { getAccountIds } from './uid';
8
+ provideAccountActionsWithCredential(Terminal.fromNodeEnv(), 'HTX', {
9
+ type: 'object',
10
+ required: ['access_key', 'secret_key'],
11
+ properties: {
12
+ access_key: { type: 'string' },
13
+ secret_key: { type: 'string' },
14
+ },
15
+ }, {
16
+ listAccounts: listAccounts,
17
+ getAccountInfo: async (credential, account_id) => {
18
+ const accounts = await getAccountIds(JSON.stringify(credential));
19
+ switch (account_id) {
20
+ case accounts.spot:
21
+ return getSpotAccountInfo(credential, account_id);
22
+ case accounts.superMargin:
23
+ return getSuperMarginAccountInfo(credential, account_id);
24
+ case accounts.swap:
25
+ return getSwapAccountInfo(credential, account_id);
26
+ }
27
+ throw new Error(`Unsupported account_id: ${account_id}`);
28
+ },
29
+ });
30
+ //# sourceMappingURL=account-actions-with-credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-actions-with-credentials.js","sourceRoot":"","sources":["../src/account-actions-with-credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,mCAAmC,CACjC,QAAQ,CAAC,WAAW,EAAE,EACtB,KAAK,EACL;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IACtC,UAAU,EAAE;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC/B;CACF,EACD;IACE,YAAY,EAAE,YAAY;IAC1B,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE;QAC/C,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QACjE,QAAQ,UAAU,EAAE;YAClB,KAAK,QAAQ,CAAC,IAAI;gBAChB,OAAO,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACpD,KAAK,QAAQ,CAAC,WAAW;gBACvB,OAAO,yBAAyB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAC3D,KAAK,QAAQ,CAAC,IAAI;gBAChB,OAAO,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;SACrD;QACD,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,EAAE,CAAC,CAAC;IAC3D,CAAC;CACF,CACF,CAAC","sourcesContent":["import { provideAccountActionsWithCredential } from '@yuants/data-account';\nimport { Terminal } from '@yuants/protocol';\nimport { listAccounts } from './accounts/list';\nimport { getSpotAccountInfo } from './accounts/spot';\nimport { getSuperMarginAccountInfo } from './accounts/super-margin';\nimport { getSwapAccountInfo } from './accounts/swap';\nimport { getAccountIds } from './uid';\n\nprovideAccountActionsWithCredential(\n Terminal.fromNodeEnv(),\n 'HTX',\n {\n type: 'object',\n required: ['access_key', 'secret_key'],\n properties: {\n access_key: { type: 'string' },\n secret_key: { type: 'string' },\n },\n },\n {\n listAccounts: listAccounts,\n getAccountInfo: async (credential, account_id) => {\n const accounts = await getAccountIds(JSON.stringify(credential));\n switch (account_id) {\n case accounts.spot:\n return getSpotAccountInfo(credential, account_id);\n case accounts.superMargin:\n return getSuperMarginAccountInfo(credential, account_id);\n case accounts.swap:\n return getSwapAccountInfo(credential, account_id);\n }\n throw new Error(`Unsupported account_id: ${account_id}`);\n },\n },\n);\n"]}
@@ -1,96 +1,18 @@
1
1
  import { provideAccountInfoService } from '@yuants/data-account';
2
2
  import { formatTime } from '@yuants/utils';
3
- import { defer, distinct, filter, first, firstValueFrom, from, map, mergeMap, repeat, retry, shareReplay, tap, timeout, toArray, } from 'rxjs';
3
+ import { defer, distinct, filter, from, map, mergeMap, repeat, retry, shareReplay, tap, toArray } from 'rxjs';
4
+ import { getSpotAccountInfo } from './accounts/spot';
5
+ import { getSuperMarginAccountInfo } from './accounts/super-margin';
6
+ import { getSwapAccountInfo } from './accounts/swap';
4
7
  import { client } from './api';
5
- import { getSpotAccountBalance, getSpotTick, getSwapCrossPositionInfo, getUnifiedAccountInfo, } from './api/private-api';
6
- import { swapProductService } from './product';
8
+ import { getSpotAccountBalance } from './api/private-api';
7
9
  /**
8
10
  * 提供 SWAP 账户信息服务
9
11
  */
10
12
  export const provideSwapAccountInfoService = (terminal, accountId, credential) => {
11
- provideAccountInfoService(terminal, accountId, async () => {
12
- // balance
13
- const balance = await getUnifiedAccountInfo(credential);
14
- if (!balance.data) {
15
- throw new Error('Failed to get unified account info');
16
- }
17
- const balanceData = balance.data.find((v) => v.margin_asset === 'USDT');
18
- if (!balanceData) {
19
- throw new Error('No USDT balance found in unified account');
20
- }
21
- const equity = balanceData.margin_balance;
22
- const free = balanceData.withdraw_available;
23
- // positions
24
- const positionsRes = await getSwapCrossPositionInfo(credential);
25
- const mapProductIdToPerpetualProduct = await firstValueFrom(swapProductService.mapProductIdToProduct$);
26
- const positions = (positionsRes.data || []).map((v) => {
27
- const product_id = v.contract_code;
28
- const theProduct = mapProductIdToPerpetualProduct === null || mapProductIdToPerpetualProduct === void 0 ? void 0 : mapProductIdToPerpetualProduct.get(product_id);
29
- const valuation = v.volume * v.last_price * ((theProduct === null || theProduct === void 0 ? void 0 : theProduct.value_scale) || 1);
30
- return {
31
- position_id: `${v.contract_code}/${v.contract_type}/${v.direction}/${v.margin_mode}`,
32
- datasource_id: 'HUOBI-SWAP',
33
- product_id,
34
- direction: v.direction === 'buy' ? 'LONG' : 'SHORT',
35
- volume: v.volume,
36
- free_volume: v.available,
37
- position_price: v.cost_hold,
38
- closable_price: v.last_price,
39
- floating_profit: v.profit_unreal,
40
- valuation,
41
- };
42
- });
43
- // orders
44
- // const orders: IOrder[] = [];
45
- // let page_index = 1;
46
- // const page_size = 50;
47
- // while (true) {
48
- // const ordersRes = await client.getSwapOpenOrders({ page_index, page_size });
49
- // if (!ordersRes.data?.orders || ordersRes.data.orders.length === 0) {
50
- // break;
51
- // }
52
- // const pageOrders: IOrder[] = ordersRes.data.orders.map((v): IOrder => {
53
- // return {
54
- // order_id: v.order_id_str,
55
- // account_id: SWAP_ACCOUNT_ID,
56
- // product_id: v.contract_code,
57
- // order_type: ['lightning'].includes(v.order_price_type)
58
- // ? 'MARKET'
59
- // : ['limit', 'opponent', 'post_only', 'optimal_5', 'optimal_10', 'optimal_20'].includes(
60
- // v.order_price_type,
61
- // )
62
- // ? 'LIMIT'
63
- // : ['fok'].includes(v.order_price_type)
64
- // ? 'FOK'
65
- // : v.order_price_type.includes('ioc')
66
- // ? 'IOC'
67
- // : 'STOP', // unreachable code
68
- // order_direction:
69
- // v.direction === 'open'
70
- // ? v.offset === 'buy'
71
- // ? 'OPEN_LONG'
72
- // : 'OPEN_SHORT'
73
- // : v.offset === 'buy'
74
- // ? 'CLOSE_SHORT'
75
- // : 'CLOSE_LONG',
76
- // volume: v.volume,
77
- // submit_at: v.created_at,
78
- // price: v.price,
79
- // traded_volume: v.trade_volume,
80
- // };
81
- // });
82
- // orders.push(...pageOrders);
83
- // page_index++;
84
- // }
85
- return {
86
- money: {
87
- currency: 'USDT',
88
- equity,
89
- free,
90
- },
91
- positions,
92
- };
93
- }, { auto_refresh_interval: 1000 });
13
+ provideAccountInfoService(terminal, accountId, async () => getSwapAccountInfo(credential, accountId), {
14
+ auto_refresh_interval: 1000,
15
+ });
94
16
  };
95
17
  /**
96
18
  * 获取超级保证金账户余额流
@@ -139,97 +61,15 @@ export const setupSuperMarginWebSocketSubscriptions = (superMarginAccountBalance
139
61
  export const provideSuperMarginAccountInfoService = (terminal, accountId, credential, superMarginAccountUid, subscriptions) => {
140
62
  const superMarginAccountBalance$ = getSuperMarginAccountBalance$(credential, superMarginAccountUid);
141
63
  setupSuperMarginWebSocketSubscriptions(superMarginAccountBalance$, subscriptions);
142
- provideAccountInfoService(terminal, accountId, async () => {
143
- var _a;
144
- // get account balance
145
- const accountBalance = await getSpotAccountBalance(credential, superMarginAccountUid);
146
- const balanceList = ((_a = accountBalance.data) === null || _a === void 0 ? void 0 : _a.list) || [];
147
- // calculate usdt balance
148
- const usdtBalance = balanceList
149
- .filter((v) => v.currency === 'usdt')
150
- .reduce((acc, cur) => acc + +cur.balance, 0);
151
- // get positions (non-usdt currencies)
152
- const positions = [];
153
- const nonUsdtCurrencies = balanceList
154
- .filter((v) => v.currency !== 'usdt')
155
- .reduce((acc, cur) => {
156
- const existing = acc.find((item) => item.currency === cur.currency);
157
- if (existing) {
158
- existing.balance += +cur.balance;
159
- }
160
- else {
161
- acc.push({ currency: cur.currency, balance: +cur.balance });
162
- }
163
- return acc;
164
- }, []);
165
- // get prices and create positions
166
- for (const currencyData of nonUsdtCurrencies) {
167
- if (currencyData.balance > 0) {
168
- try {
169
- // get current price from websocket or fallback to REST API
170
- let price;
171
- try {
172
- const tickPrice = await firstValueFrom(client.spot_ws.input$.pipe(
173
- //
174
- first((v) => { var _a, _b; return ((_a = v.ch) === null || _a === void 0 ? void 0 : _a.includes('ticker')) && ((_b = v.ch) === null || _b === void 0 ? void 0 : _b.includes(currencyData.currency)) && v.tick; }), map((v) => v.tick.bid), timeout(5000), tap({
175
- error: (e) => {
176
- subscriptions.clear();
177
- },
178
- })));
179
- price = tickPrice;
180
- }
181
- catch (_b) {
182
- // fallback to REST API
183
- const tickerRes = await getSpotTick(credential, { symbol: `${currencyData.currency}usdt` });
184
- price = tickerRes.tick.close;
185
- }
186
- positions.push({
187
- position_id: `${currencyData.currency}/usdt/spot`,
188
- product_id: `${currencyData.currency}usdt`,
189
- direction: 'LONG',
190
- volume: currencyData.balance,
191
- free_volume: currencyData.balance,
192
- position_price: price,
193
- closable_price: price,
194
- floating_profit: 0,
195
- valuation: currencyData.balance * price,
196
- });
197
- }
198
- catch (error) {
199
- console.warn(formatTime(Date.now()), `Failed to get price for ${currencyData.currency}:`, error);
200
- }
201
- }
202
- }
203
- // calculate equity
204
- const equity = positions.reduce((acc, cur) => acc + cur.closable_price * cur.volume, 0) + usdtBalance;
205
- return {
206
- money: {
207
- currency: 'USDT',
208
- equity,
209
- free: equity,
210
- },
211
- positions,
212
- };
213
- }, { auto_refresh_interval: 1000 });
64
+ provideAccountInfoService(terminal, accountId, async () => getSuperMarginAccountInfo(credential, accountId), { auto_refresh_interval: 1000 });
214
65
  return superMarginAccountBalance$;
215
66
  };
216
67
  /**
217
68
  * 提供 SPOT 账户信息服务
218
69
  */
219
- export const provideSpotAccountInfoService = (terminal, accountId, credential, spotAccountUid) => {
220
- provideAccountInfoService(terminal, accountId, async () => {
221
- var _a, _b;
222
- const spotBalance = await getSpotAccountBalance(credential, spotAccountUid);
223
- const equity = +((_b = (_a = spotBalance.data.list.find((v) => v.currency === 'usdt')) === null || _a === void 0 ? void 0 : _a.balance) !== null && _b !== void 0 ? _b : 0);
224
- const free = equity;
225
- return {
226
- money: {
227
- currency: 'USDT',
228
- equity,
229
- free,
230
- },
231
- positions: [],
232
- };
233
- }, { auto_refresh_interval: 1000 });
70
+ export const provideSpotAccountInfoService = (terminal, accountId, credential) => {
71
+ provideAccountInfoService(terminal, accountId, async () => getSpotAccountInfo(credential, accountId), {
72
+ auto_refresh_interval: 1000,
73
+ });
234
74
  };
235
75
  //# sourceMappingURL=account-info.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-info.js","sourceRoot":"","sources":["../src/account-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAE5E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,cAAc,EACd,IAAI,EACJ,GAAG,EACH,QAAQ,EACR,MAAM,EACN,KAAK,EACL,WAAW,EACX,GAAG,EACH,OAAO,EACP,OAAO,GACR,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,wBAAwB,EACxB,qBAAqB,GAEtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,QAAkB,EAClB,SAAiB,EACjB,UAAuB,EACvB,EAAE;IACF,yBAAyB,CACvB,QAAQ,EACR,SAAS,EACT,KAAK,IAAI,EAAE;QACT,UAAU;QACV,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YACjB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;SACvD;QACD,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC;QACxE,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;SAC7D;QACD,MAAM,MAAM,GAAG,WAAW,CAAC,cAAc,CAAC;QAC1C,MAAM,IAAI,GAAG,WAAW,CAAC,kBAAkB,CAAC;QAE5C,YAAY;QACZ,MAAM,YAAY,GAAG,MAAM,wBAAwB,CAAC,UAAU,CAAC,CAAC;QAChE,MAAM,8BAA8B,GAAG,MAAM,cAAc,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;QACvG,MAAM,SAAS,GAAgB,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAa,EAAE;YAC5E,MAAM,UAAU,GAAG,CAAC,CAAC,aAAa,CAAC;YACnC,MAAM,UAAU,GAAG,8BAA8B,aAA9B,8BAA8B,uBAA9B,8BAA8B,CAAE,GAAG,CAAC,UAAU,CAAC,CAAC;YACnE,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,UAAU,GAAG,CAAC,CAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,WAAW,KAAI,CAAC,CAAC,CAAC;YAC3E,OAAO;gBACL,WAAW,EAAE,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,WAAW,EAAE;gBACpF,aAAa,EAAE,YAAY;gBAC3B,UAAU;gBACV,SAAS,EAAE,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;gBACnD,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,WAAW,EAAE,CAAC,CAAC,SAAS;gBACxB,cAAc,EAAE,CAAC,CAAC,SAAS;gBAC3B,cAAc,EAAE,CAAC,CAAC,UAAU;gBAC5B,eAAe,EAAE,CAAC,CAAC,aAAa;gBAChC,SAAS;aACV,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,SAAS;QACT,+BAA+B;QAC/B,sBAAsB;QACtB,wBAAwB;QAExB,iBAAiB;QACjB,iFAAiF;QACjF,yEAAyE;QACzE,aAAa;QACb,MAAM;QAEN,4EAA4E;QAC5E,eAAe;QACf,kCAAkC;QAClC,qCAAqC;QACrC,qCAAqC;QACrC,+DAA+D;QAC/D,qBAAqB;QACrB,kGAAkG;QAClG,kCAAkC;QAClC,cAAc;QACd,oBAAoB;QACpB,iDAAiD;QACjD,kBAAkB;QAClB,+CAA+C;QAC/C,kBAAkB;QAClB,wCAAwC;QACxC,yBAAyB;QACzB,iCAAiC;QACjC,iCAAiC;QACjC,4BAA4B;QAC5B,6BAA6B;QAC7B,iCAAiC;QACjC,4BAA4B;QAC5B,4BAA4B;QAC5B,0BAA0B;QAC1B,iCAAiC;QACjC,wBAAwB;QACxB,uCAAuC;QACvC,SAAS;QACT,QAAQ;QAER,gCAAgC;QAChC,kBAAkB;QAClB,IAAI;QAEJ,OAAO;YACL,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM;gBAChB,MAAM;gBACN,IAAI;aACL;YACD,SAAS;SACV,CAAC;IACJ,CAAC,EACD,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAChC,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,UAAuB,EAAE,qBAA6B,EAAE,EAAE;IACtG,OAAO,KAAK,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC,CAAC,IAAI;IAC/E,EAAE;IACF,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EACtB,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACvB,GAAG,CAAC;QACF,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;YACX,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;KACF,CAAC,EACF,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtB,WAAW,CAAC,CAAC,CAAC,CACf,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,sCAAsC,GAAG,CACpD,0BAA4E,EAC5E,aAA0B,EAC1B,EAAE;IACF,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE;QAC9C,aAAa,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IACH,6CAA6C;IAC7C,0BAA0B;SACvB,IAAI;IACH,EAAE;IACF,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CACf,IAAI,CAAC,CAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,IAAI,KAAI,EAAE,CAAC,CAAC,IAAI,CACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,EACpC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EACtB,QAAQ,EAAE,EACV,OAAO,EAAE,EACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CACvB,CACF,CACF;SACA,SAAS,CAAC,CAAC,CAAc,EAAE,EAAE;QAC5B,MAAM,aAAa,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE;YAClC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC1B,KAAK,EAAE,UAAU,MAAM,aAAa;aACrC,CAAC,CAAC;YACH,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SAC9B;QACD,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE;YAChC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC1B,GAAG,EAAE,UAAU,MAAM,aAAa;aACnC,CAAC,CAAC;YACH,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SAC3B;IACH,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAClD,QAAkB,EAClB,SAAiB,EACjB,UAAuB,EACvB,qBAA6B,EAC7B,aAA0B,EAC1B,EAAE;IACF,MAAM,0BAA0B,GAAG,6BAA6B,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;IACpG,sCAAsC,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC;IAElF,yBAAyB,CACvB,QAAQ,EACR,SAAS,EACT,KAAK,IAAI,EAAE;;QACT,sBAAsB;QACtB,MAAM,cAAc,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;QACtF,MAAM,WAAW,GAAG,CAAA,MAAA,cAAc,CAAC,IAAI,0CAAE,IAAI,KAAI,EAAE,CAAC;QAEpD,yBAAyB;QACzB,MAAM,WAAW,GAAG,WAAW;aAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;aACpC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAE/C,sCAAsC;QACtC,MAAM,SAAS,GAAgB,EAAE,CAAC;QAClC,MAAM,iBAAiB,GAAG,WAAW;aAClC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;aACpC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACnB,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpE,IAAI,QAAQ,EAAE;gBACZ,QAAQ,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;aAClC;iBAAM;gBACL,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;aAC7D;YACD,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAA6C,CAAC,CAAC;QAEpD,kCAAkC;QAClC,KAAK,MAAM,YAAY,IAAI,iBAAiB,EAAE;YAC5C,IAAI,YAAY,CAAC,OAAO,GAAG,CAAC,EAAE;gBAC5B,IAAI;oBACF,2DAA2D;oBAC3D,IAAI,KAAa,CAAC;oBAClB,IAAI;wBACF,MAAM,SAAS,GAAG,MAAM,cAAc,CACpC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI;wBACxB,EAAE;wBACF,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,eAAC,OAAA,CAAA,MAAA,CAAC,CAAC,EAAE,0CAAE,QAAQ,CAAC,QAAQ,CAAC,MAAI,MAAA,CAAC,CAAC,EAAE,0CAAE,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA,IAAI,CAAC,CAAC,IAAI,CAAA,EAAA,CAAC,EACzF,GAAG,CAAC,CAAC,CAAC,EAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC9B,OAAO,CAAC,IAAI,CAAC,EACb,GAAG,CAAC;4BACF,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;gCACX,aAAa,CAAC,KAAK,EAAE,CAAC;4BACxB,CAAC;yBACF,CAAC,CACH,CACF,CAAC;wBACF,KAAK,GAAG,SAAS,CAAC;qBACnB;oBAAC,WAAM;wBACN,uBAAuB;wBACvB,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC;wBAC5F,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;qBAC9B;oBAED,SAAS,CAAC,IAAI,CAAC;wBACb,WAAW,EAAE,GAAG,YAAY,CAAC,QAAQ,YAAY;wBACjD,UAAU,EAAE,GAAG,YAAY,CAAC,QAAQ,MAAM;wBAC1C,SAAS,EAAE,MAAM;wBACjB,MAAM,EAAE,YAAY,CAAC,OAAO;wBAC5B,WAAW,EAAE,YAAY,CAAC,OAAO;wBACjC,cAAc,EAAE,KAAK;wBACrB,cAAc,EAAE,KAAK;wBACrB,eAAe,EAAE,CAAC;wBAClB,SAAS,EAAE,YAAY,CAAC,OAAO,GAAG,KAAK;qBACxC,CAAC,CAAC;iBACJ;gBAAC,OAAO,KAAK,EAAE;oBACd,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,2BAA2B,YAAY,CAAC,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;iBAClG;aACF;SACF;QAED,mBAAmB;QACnB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,WAAW,CAAC;QAEtG,OAAO;YACL,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM;gBAChB,MAAM;gBACN,IAAI,EAAE,MAAM;aACb;YACD,SAAS;SACV,CAAC;IACJ,CAAC,EACD,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAChC,CAAC;IAEF,OAAO,0BAA0B,CAAC;AACpC,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,QAAkB,EAClB,SAAiB,EACjB,UAAuB,EACvB,cAAsB,EACtB,EAAE;IACF,yBAAyB,CACvB,QAAQ,EACR,SAAS,EACT,KAAK,IAAI,EAAE;;QACT,MAAM,WAAW,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAE5E,MAAM,MAAM,GAAG,CAAC,CAAC,MAAA,MAAA,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,0CAAE,OAAO,mCAAI,CAAC,CAAC,CAAC;QACzF,MAAM,IAAI,GAAG,MAAM,CAAC;QACpB,OAAO;YACL,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM;gBAChB,MAAM;gBACN,IAAI;aACL;YACD,SAAS,EAAE,EAAE;SACd,CAAC;IACJ,CAAC,EACD,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAChC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { IPosition, provideAccountInfoService } from '@yuants/data-account';\nimport { Terminal } from '@yuants/protocol';\nimport { formatTime } from '@yuants/utils';\nimport {\n defer,\n distinct,\n filter,\n first,\n firstValueFrom,\n from,\n map,\n mergeMap,\n repeat,\n retry,\n shareReplay,\n tap,\n timeout,\n toArray,\n} from 'rxjs';\nimport { client } from './api';\nimport {\n getSpotAccountBalance,\n getSpotTick,\n getSwapCrossPositionInfo,\n getUnifiedAccountInfo,\n ICredential,\n} from './api/private-api';\nimport { swapProductService } from './product';\n\n/**\n * 提供 SWAP 账户信息服务\n */\nexport const provideSwapAccountInfoService = (\n terminal: Terminal,\n accountId: string,\n credential: ICredential,\n) => {\n provideAccountInfoService(\n terminal,\n accountId,\n async () => {\n // balance\n const balance = await getUnifiedAccountInfo(credential);\n if (!balance.data) {\n throw new Error('Failed to get unified account info');\n }\n const balanceData = balance.data.find((v) => v.margin_asset === 'USDT');\n if (!balanceData) {\n throw new Error('No USDT balance found in unified account');\n }\n const equity = balanceData.margin_balance;\n const free = balanceData.withdraw_available;\n\n // positions\n const positionsRes = await getSwapCrossPositionInfo(credential);\n const mapProductIdToPerpetualProduct = await firstValueFrom(swapProductService.mapProductIdToProduct$);\n const positions: IPosition[] = (positionsRes.data || []).map((v): IPosition => {\n const product_id = v.contract_code;\n const theProduct = mapProductIdToPerpetualProduct?.get(product_id);\n const valuation = v.volume * v.last_price * (theProduct?.value_scale || 1);\n return {\n position_id: `${v.contract_code}/${v.contract_type}/${v.direction}/${v.margin_mode}`,\n datasource_id: 'HUOBI-SWAP',\n product_id,\n direction: v.direction === 'buy' ? 'LONG' : 'SHORT',\n volume: v.volume,\n free_volume: v.available,\n position_price: v.cost_hold,\n closable_price: v.last_price,\n floating_profit: v.profit_unreal,\n valuation,\n };\n });\n\n // orders\n // const orders: IOrder[] = [];\n // let page_index = 1;\n // const page_size = 50;\n\n // while (true) {\n // const ordersRes = await client.getSwapOpenOrders({ page_index, page_size });\n // if (!ordersRes.data?.orders || ordersRes.data.orders.length === 0) {\n // break;\n // }\n\n // const pageOrders: IOrder[] = ordersRes.data.orders.map((v): IOrder => {\n // return {\n // order_id: v.order_id_str,\n // account_id: SWAP_ACCOUNT_ID,\n // product_id: v.contract_code,\n // order_type: ['lightning'].includes(v.order_price_type)\n // ? 'MARKET'\n // : ['limit', 'opponent', 'post_only', 'optimal_5', 'optimal_10', 'optimal_20'].includes(\n // v.order_price_type,\n // )\n // ? 'LIMIT'\n // : ['fok'].includes(v.order_price_type)\n // ? 'FOK'\n // : v.order_price_type.includes('ioc')\n // ? 'IOC'\n // : 'STOP', // unreachable code\n // order_direction:\n // v.direction === 'open'\n // ? v.offset === 'buy'\n // ? 'OPEN_LONG'\n // : 'OPEN_SHORT'\n // : v.offset === 'buy'\n // ? 'CLOSE_SHORT'\n // : 'CLOSE_LONG',\n // volume: v.volume,\n // submit_at: v.created_at,\n // price: v.price,\n // traded_volume: v.trade_volume,\n // };\n // });\n\n // orders.push(...pageOrders);\n // page_index++;\n // }\n\n return {\n money: {\n currency: 'USDT',\n equity,\n free,\n },\n positions,\n };\n },\n { auto_refresh_interval: 1000 },\n );\n};\n\n/**\n * 获取超级保证金账户余额流\n */\nexport const getSuperMarginAccountBalance$ = (credential: ICredential, superMarginAccountUid: number) => {\n return defer(() => getSpotAccountBalance(credential, superMarginAccountUid)).pipe(\n //\n map((res) => res.data),\n repeat({ delay: 1000 }),\n tap({\n error: (e) => {\n console.error(formatTime(Date.now()), 'unifiedRaw', e);\n },\n }),\n retry({ delay: 5000 }),\n shareReplay(1),\n );\n};\n\n/**\n * 设置超级保证金账户的 WebSocket 订阅\n */\nexport const setupSuperMarginWebSocketSubscriptions = (\n superMarginAccountBalance$: ReturnType<typeof getSuperMarginAccountBalance$>,\n subscriptions: Set<string>,\n) => {\n from(client.spot_ws.connection$).subscribe(() => {\n subscriptions.clear();\n });\n // subscribe the symbols of positions we held\n superMarginAccountBalance$\n .pipe(\n //\n mergeMap((res) =>\n from(res?.list || []).pipe(\n filter((v) => v.currency !== 'usdt'),\n map((v) => v.currency),\n distinct(),\n toArray(),\n map((v) => new Set(v)),\n ),\n ),\n )\n .subscribe((v: Set<string>) => {\n const toUnsubscribe = [...subscriptions].filter((x) => !v.has(x));\n const toSubscribe = [...v].filter((x) => !subscriptions.has(x));\n\n for (const symbol of toUnsubscribe) {\n client.spot_ws.output$.next({\n unsub: `market.${symbol}usdt.ticker`,\n });\n subscriptions.delete(symbol);\n }\n for (const symbol of toSubscribe) {\n client.spot_ws.output$.next({\n sub: `market.${symbol}usdt.ticker`,\n });\n subscriptions.add(symbol);\n }\n });\n};\n\n/**\n * 提供超级保证金账户信息服务\n */\nexport const provideSuperMarginAccountInfoService = (\n terminal: Terminal,\n accountId: string,\n credential: ICredential,\n superMarginAccountUid: number,\n subscriptions: Set<string>,\n) => {\n const superMarginAccountBalance$ = getSuperMarginAccountBalance$(credential, superMarginAccountUid);\n setupSuperMarginWebSocketSubscriptions(superMarginAccountBalance$, subscriptions);\n\n provideAccountInfoService(\n terminal,\n accountId,\n async () => {\n // get account balance\n const accountBalance = await getSpotAccountBalance(credential, superMarginAccountUid);\n const balanceList = accountBalance.data?.list || [];\n\n // calculate usdt balance\n const usdtBalance = balanceList\n .filter((v) => v.currency === 'usdt')\n .reduce((acc, cur) => acc + +cur.balance, 0);\n\n // get positions (non-usdt currencies)\n const positions: IPosition[] = [];\n const nonUsdtCurrencies = balanceList\n .filter((v) => v.currency !== 'usdt')\n .reduce((acc, cur) => {\n const existing = acc.find((item) => item.currency === cur.currency);\n if (existing) {\n existing.balance += +cur.balance;\n } else {\n acc.push({ currency: cur.currency, balance: +cur.balance });\n }\n return acc;\n }, [] as { currency: string; balance: number }[]);\n\n // get prices and create positions\n for (const currencyData of nonUsdtCurrencies) {\n if (currencyData.balance > 0) {\n try {\n // get current price from websocket or fallback to REST API\n let price: number;\n try {\n const tickPrice = await firstValueFrom(\n client.spot_ws.input$.pipe(\n //\n first((v) => v.ch?.includes('ticker') && v.ch?.includes(currencyData.currency) && v.tick),\n map((v): number => v.tick.bid),\n timeout(5000),\n tap({\n error: (e) => {\n subscriptions.clear();\n },\n }),\n ),\n );\n price = tickPrice;\n } catch {\n // fallback to REST API\n const tickerRes = await getSpotTick(credential, { symbol: `${currencyData.currency}usdt` });\n price = tickerRes.tick.close;\n }\n\n positions.push({\n position_id: `${currencyData.currency}/usdt/spot`,\n product_id: `${currencyData.currency}usdt`,\n direction: 'LONG',\n volume: currencyData.balance,\n free_volume: currencyData.balance,\n position_price: price,\n closable_price: price,\n floating_profit: 0,\n valuation: currencyData.balance * price,\n });\n } catch (error) {\n console.warn(formatTime(Date.now()), `Failed to get price for ${currencyData.currency}:`, error);\n }\n }\n }\n\n // calculate equity\n const equity = positions.reduce((acc, cur) => acc + cur.closable_price * cur.volume, 0) + usdtBalance;\n\n return {\n money: {\n currency: 'USDT',\n equity,\n free: equity,\n },\n positions,\n };\n },\n { auto_refresh_interval: 1000 },\n );\n\n return superMarginAccountBalance$;\n};\n\n/**\n * 提供 SPOT 账户信息服务\n */\nexport const provideSpotAccountInfoService = (\n terminal: Terminal,\n accountId: string,\n credential: ICredential,\n spotAccountUid: number,\n) => {\n provideAccountInfoService(\n terminal,\n accountId,\n async () => {\n const spotBalance = await getSpotAccountBalance(credential, spotAccountUid);\n\n const equity = +(spotBalance.data.list.find((v) => v.currency === 'usdt')?.balance ?? 0);\n const free = equity;\n return {\n money: {\n currency: 'USDT',\n equity,\n free,\n },\n positions: [],\n };\n },\n { auto_refresh_interval: 1000 },\n );\n};\n"]}
1
+ {"version":3,"file":"account-info.js","sourceRoot":"","sources":["../src/account-info.ts"],"names":[],"mappings":"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","sourcesContent":["import { provideAccountInfoService } from '@yuants/data-account';\nimport { Terminal } from '@yuants/protocol';\nimport { formatTime } from '@yuants/utils';\nimport { defer, distinct, filter, from, map, mergeMap, repeat, retry, shareReplay, tap, toArray } from 'rxjs';\nimport { getSpotAccountInfo } from './accounts/spot';\nimport { getSuperMarginAccountInfo } from './accounts/super-margin';\nimport { getSwapAccountInfo } from './accounts/swap';\nimport { client } from './api';\nimport { getSpotAccountBalance, ICredential } from './api/private-api';\n\n/**\n * 提供 SWAP 账户信息服务\n */\nexport const provideSwapAccountInfoService = (\n terminal: Terminal,\n accountId: string,\n credential: ICredential,\n) => {\n provideAccountInfoService(terminal, accountId, async () => getSwapAccountInfo(credential, accountId), {\n auto_refresh_interval: 1000,\n });\n};\n\n/**\n * 获取超级保证金账户余额流\n */\nexport const getSuperMarginAccountBalance$ = (credential: ICredential, superMarginAccountUid: number) => {\n return defer(() => getSpotAccountBalance(credential, superMarginAccountUid)).pipe(\n //\n map((res) => res.data),\n repeat({ delay: 1000 }),\n tap({\n error: (e) => {\n console.error(formatTime(Date.now()), 'unifiedRaw', e);\n },\n }),\n retry({ delay: 5000 }),\n shareReplay(1),\n );\n};\n\n/**\n * 设置超级保证金账户的 WebSocket 订阅\n */\nexport const setupSuperMarginWebSocketSubscriptions = (\n superMarginAccountBalance$: ReturnType<typeof getSuperMarginAccountBalance$>,\n subscriptions: Set<string>,\n) => {\n from(client.spot_ws.connection$).subscribe(() => {\n subscriptions.clear();\n });\n // subscribe the symbols of positions we held\n superMarginAccountBalance$\n .pipe(\n //\n mergeMap((res) =>\n from(res?.list || []).pipe(\n filter((v) => v.currency !== 'usdt'),\n map((v) => v.currency),\n distinct(),\n toArray(),\n map((v) => new Set(v)),\n ),\n ),\n )\n .subscribe((v: Set<string>) => {\n const toUnsubscribe = [...subscriptions].filter((x) => !v.has(x));\n const toSubscribe = [...v].filter((x) => !subscriptions.has(x));\n\n for (const symbol of toUnsubscribe) {\n client.spot_ws.output$.next({\n unsub: `market.${symbol}usdt.ticker`,\n });\n subscriptions.delete(symbol);\n }\n for (const symbol of toSubscribe) {\n client.spot_ws.output$.next({\n sub: `market.${symbol}usdt.ticker`,\n });\n subscriptions.add(symbol);\n }\n });\n};\n\n/**\n * 提供超级保证金账户信息服务\n */\nexport const provideSuperMarginAccountInfoService = (\n terminal: Terminal,\n accountId: string,\n credential: ICredential,\n superMarginAccountUid: number,\n subscriptions: Set<string>,\n) => {\n const superMarginAccountBalance$ = getSuperMarginAccountBalance$(credential, superMarginAccountUid);\n setupSuperMarginWebSocketSubscriptions(superMarginAccountBalance$, subscriptions);\n\n provideAccountInfoService(\n terminal,\n accountId,\n async () => getSuperMarginAccountInfo(credential, accountId),\n { auto_refresh_interval: 1000 },\n );\n\n return superMarginAccountBalance$;\n};\n\n/**\n * 提供 SPOT 账户信息服务\n */\nexport const provideSpotAccountInfoService = (\n terminal: Terminal,\n accountId: string,\n credential: ICredential,\n) => {\n provideAccountInfoService(terminal, accountId, async () => getSpotAccountInfo(credential, accountId), {\n auto_refresh_interval: 1000,\n });\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import { getAccountIds } from '../uid';
2
+ export const listAccounts = async (credential) => {
3
+ const accounts = await getAccountIds(JSON.stringify(credential));
4
+ if (!accounts)
5
+ throw new Error('Failed to get Account IDs');
6
+ return [{ account_id: accounts.spot }, { account_id: accounts.superMargin }, { account_id: accounts.swap }];
7
+ };
8
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/accounts/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAEvC,MAAM,CAAC,MAAM,YAAY,GAA8C,KAAK,EAAE,UAAU,EAAE,EAAE;IAC1F,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAE5D,OAAO,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,WAAW,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9G,CAAC,CAAC","sourcesContent":["import { IActionHandlerOfListAccounts } from '@yuants/data-account';\nimport { ICredential } from '../api/private-api';\nimport { getAccountIds } from '../uid';\n\nexport const listAccounts: IActionHandlerOfListAccounts<ICredential> = async (credential) => {\n const accounts = await getAccountIds(JSON.stringify(credential));\n if (!accounts) throw new Error('Failed to get Account IDs');\n\n return [{ account_id: accounts.spot }, { account_id: accounts.superMargin }, { account_id: accounts.swap }];\n};\n"]}
@@ -0,0 +1,20 @@
1
+ import { getSpotAccountBalance } from '../api/private-api';
2
+ import { spotAccountUidCache } from '../uid';
3
+ export const getSpotAccountInfo = async (credential) => {
4
+ var _a, _b;
5
+ const spotAccountUid = await spotAccountUidCache.query(JSON.stringify(credential));
6
+ if (!spotAccountUid)
7
+ throw new Error('Failed to get Spot Account UID');
8
+ const spotBalance = await getSpotAccountBalance(credential, spotAccountUid);
9
+ const equity = +((_b = (_a = spotBalance.data.list.find((v) => v.currency === 'usdt')) === null || _a === void 0 ? void 0 : _a.balance) !== null && _b !== void 0 ? _b : 0);
10
+ const free = equity;
11
+ return {
12
+ money: {
13
+ currency: 'USDT',
14
+ equity,
15
+ free,
16
+ },
17
+ positions: [],
18
+ };
19
+ };
20
+ //# sourceMappingURL=spot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spot.js","sourceRoot":"","sources":["../../src/accounts/spot.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAe,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAE7C,MAAM,CAAC,MAAM,kBAAkB,GAAgD,KAAK,EAAE,UAAU,EAAE,EAAE;;IAClG,MAAM,cAAc,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IACnF,IAAI,CAAC,cAAc;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG,CAAC,CAAC,MAAA,MAAA,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,0CAAE,OAAO,mCAAI,CAAC,CAAC,CAAC;IACzF,MAAM,IAAI,GAAG,MAAM,CAAC;IACpB,OAAO;QACL,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM;YAChB,MAAM;YACN,IAAI;SACL;QACD,SAAS,EAAE,EAAE;KACd,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { IActionHandlerOfGetAccountInfo } from '@yuants/data-account';\nimport { getSpotAccountBalance, ICredential } from '../api/private-api';\nimport { spotAccountUidCache } from '../uid';\n\nexport const getSpotAccountInfo: IActionHandlerOfGetAccountInfo<ICredential> = async (credential) => {\n const spotAccountUid = await spotAccountUidCache.query(JSON.stringify(credential));\n if (!spotAccountUid) throw new Error('Failed to get Spot Account UID');\n const spotBalance = await getSpotAccountBalance(credential, spotAccountUid);\n\n const equity = +(spotBalance.data.list.find((v) => v.currency === 'usdt')?.balance ?? 0);\n const free = equity;\n return {\n money: {\n currency: 'USDT',\n equity,\n free,\n },\n positions: [],\n };\n};\n"]}
@@ -0,0 +1,74 @@
1
+ import { createCache } from '@yuants/cache';
2
+ import { formatTime } from '@yuants/utils';
3
+ import { getSpotAccountBalance } from '../api/private-api';
4
+ import { getSpotTick } from '../api/public-api';
5
+ import { superMarginAccountUidCache } from '../uid';
6
+ const spotTickCache = createCache((currency) => getSpotTick({ symbol: `${currency}usdt` }), {
7
+ expire: 300000,
8
+ swrAfter: 10000, // 10 seconds
9
+ });
10
+ /**
11
+ * 全仓杠杆账户 (Super Margin Account)
12
+ */
13
+ export const getSuperMarginAccountInfo = async (credential) => {
14
+ var _a;
15
+ // get account balance
16
+ const superMarginAccountUid = await superMarginAccountUidCache.query(JSON.stringify(credential));
17
+ if (!superMarginAccountUid)
18
+ throw new Error('Failed to get Super Margin Account UID');
19
+ const accountBalance = await getSpotAccountBalance(credential, superMarginAccountUid);
20
+ const balanceList = ((_a = accountBalance.data) === null || _a === void 0 ? void 0 : _a.list) || [];
21
+ // calculate usdt balance
22
+ const usdtBalance = balanceList
23
+ .filter((v) => v.currency === 'usdt')
24
+ .reduce((acc, cur) => acc + +cur.balance, 0);
25
+ // get positions (non-usdt currencies)
26
+ const positions = [];
27
+ const nonUsdtCurrencies = balanceList
28
+ .filter((v) => v.currency !== 'usdt')
29
+ .reduce((acc, cur) => {
30
+ const existing = acc.find((item) => item.currency === cur.currency);
31
+ if (existing) {
32
+ existing.balance += +cur.balance;
33
+ }
34
+ else {
35
+ acc.push({ currency: cur.currency, balance: +cur.balance });
36
+ }
37
+ return acc;
38
+ }, []);
39
+ // get prices and create positions
40
+ for (const currencyData of nonUsdtCurrencies) {
41
+ if (currencyData.balance > 0) {
42
+ const tickerRes = await spotTickCache.query(currencyData.currency);
43
+ const price = (tickerRes === null || tickerRes === void 0 ? void 0 : tickerRes.tick.close) || 0;
44
+ try {
45
+ // get current price from websocket or fallback to REST API
46
+ positions.push({
47
+ position_id: `${currencyData.currency}/usdt/spot`,
48
+ product_id: `${currencyData.currency}usdt`,
49
+ direction: 'LONG',
50
+ volume: currencyData.balance,
51
+ free_volume: currencyData.balance,
52
+ position_price: price,
53
+ closable_price: price,
54
+ floating_profit: 0,
55
+ valuation: currencyData.balance * price,
56
+ });
57
+ }
58
+ catch (error) {
59
+ console.warn(formatTime(Date.now()), `Failed to get price for ${currencyData.currency}:`, error);
60
+ }
61
+ }
62
+ }
63
+ // calculate equity
64
+ const equity = positions.reduce((acc, cur) => acc + cur.closable_price * cur.volume, 0) + usdtBalance;
65
+ return {
66
+ money: {
67
+ currency: 'USDT',
68
+ equity,
69
+ free: equity,
70
+ },
71
+ positions,
72
+ };
73
+ };
74
+ //# sourceMappingURL=super-margin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"super-margin.js","sourceRoot":"","sources":["../../src/accounts/super-margin.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCache } from '@yuants/cache';\nimport { IActionHandlerOfGetAccountInfo, IPosition } from '@yuants/data-account';\nimport { formatTime } from '@yuants/utils';\nimport { getSpotAccountBalance, ICredential } from '../api/private-api';\nimport { getSpotTick } from '../api/public-api';\nimport { superMarginAccountUidCache } from '../uid';\n\nconst spotTickCache = createCache((currency) => getSpotTick({ symbol: `${currency}usdt` }), {\n expire: 300_000, // 5 minutes\n swrAfter: 10_000, // 10 seconds\n});\n\n/**\n * 全仓杠杆账户 (Super Margin Account)\n */\nexport const getSuperMarginAccountInfo: IActionHandlerOfGetAccountInfo<ICredential> = async (credential) => {\n // get account balance\n const superMarginAccountUid = await superMarginAccountUidCache.query(JSON.stringify(credential));\n if (!superMarginAccountUid) throw new Error('Failed to get Super Margin Account UID');\n const accountBalance = await getSpotAccountBalance(credential, superMarginAccountUid);\n const balanceList = accountBalance.data?.list || [];\n\n // calculate usdt balance\n const usdtBalance = balanceList\n .filter((v) => v.currency === 'usdt')\n .reduce((acc, cur) => acc + +cur.balance, 0);\n\n // get positions (non-usdt currencies)\n const positions: IPosition[] = [];\n const nonUsdtCurrencies = balanceList\n .filter((v) => v.currency !== 'usdt')\n .reduce((acc, cur) => {\n const existing = acc.find((item) => item.currency === cur.currency);\n if (existing) {\n existing.balance += +cur.balance;\n } else {\n acc.push({ currency: cur.currency, balance: +cur.balance });\n }\n return acc;\n }, [] as { currency: string; balance: number }[]);\n\n // get prices and create positions\n for (const currencyData of nonUsdtCurrencies) {\n if (currencyData.balance > 0) {\n const tickerRes = await spotTickCache.query(currencyData.currency);\n const price = tickerRes?.tick.close || 0;\n try {\n // get current price from websocket or fallback to REST API\n\n positions.push({\n position_id: `${currencyData.currency}/usdt/spot`,\n product_id: `${currencyData.currency}usdt`,\n direction: 'LONG',\n volume: currencyData.balance,\n free_volume: currencyData.balance,\n position_price: price,\n closable_price: price,\n floating_profit: 0,\n valuation: currencyData.balance * price,\n });\n } catch (error) {\n console.warn(formatTime(Date.now()), `Failed to get price for ${currencyData.currency}:`, error);\n }\n }\n }\n\n // calculate equity\n const equity = positions.reduce((acc, cur) => acc + cur.closable_price * cur.volume, 0) + usdtBalance;\n\n return {\n money: {\n currency: 'USDT',\n equity,\n free: equity,\n },\n positions,\n };\n};\n"]}
@@ -0,0 +1,87 @@
1
+ import { firstValueFrom } from 'rxjs';
2
+ import { getSwapCrossPositionInfo, getUnifiedAccountInfo } from '../api/private-api';
3
+ import { swapProductService } from '../product';
4
+ export const getSwapAccountInfo = async (credential) => {
5
+ // balance
6
+ const balance = await getUnifiedAccountInfo(credential);
7
+ if (!balance.data) {
8
+ throw new Error('Failed to get unified account info');
9
+ }
10
+ const balanceData = balance.data.find((v) => v.margin_asset === 'USDT');
11
+ if (!balanceData) {
12
+ throw new Error('No USDT balance found in unified account');
13
+ }
14
+ const equity = balanceData.margin_balance;
15
+ const free = balanceData.withdraw_available;
16
+ // positions
17
+ const positionsRes = await getSwapCrossPositionInfo(credential);
18
+ const mapProductIdToPerpetualProduct = await firstValueFrom(swapProductService.mapProductIdToProduct$);
19
+ const positions = (positionsRes.data || []).map((v) => {
20
+ const product_id = v.contract_code;
21
+ const theProduct = mapProductIdToPerpetualProduct === null || mapProductIdToPerpetualProduct === void 0 ? void 0 : mapProductIdToPerpetualProduct.get(product_id);
22
+ const valuation = v.volume * v.last_price * ((theProduct === null || theProduct === void 0 ? void 0 : theProduct.value_scale) || 1);
23
+ return {
24
+ position_id: `${v.contract_code}/${v.contract_type}/${v.direction}/${v.margin_mode}`,
25
+ datasource_id: 'HUOBI-SWAP',
26
+ product_id,
27
+ direction: v.direction === 'buy' ? 'LONG' : 'SHORT',
28
+ volume: v.volume,
29
+ free_volume: v.available,
30
+ position_price: v.cost_hold,
31
+ closable_price: v.last_price,
32
+ floating_profit: v.profit_unreal,
33
+ valuation,
34
+ };
35
+ });
36
+ // orders
37
+ // const orders: IOrder[] = [];
38
+ // let page_index = 1;
39
+ // const page_size = 50;
40
+ // while (true) {
41
+ // const ordersRes = await client.getSwapOpenOrders({ page_index, page_size });
42
+ // if (!ordersRes.data?.orders || ordersRes.data.orders.length === 0) {
43
+ // break;
44
+ // }
45
+ // const pageOrders: IOrder[] = ordersRes.data.orders.map((v): IOrder => {
46
+ // return {
47
+ // order_id: v.order_id_str,
48
+ // account_id: SWAP_ACCOUNT_ID,
49
+ // product_id: v.contract_code,
50
+ // order_type: ['lightning'].includes(v.order_price_type)
51
+ // ? 'MARKET'
52
+ // : ['limit', 'opponent', 'post_only', 'optimal_5', 'optimal_10', 'optimal_20'].includes(
53
+ // v.order_price_type,
54
+ // )
55
+ // ? 'LIMIT'
56
+ // : ['fok'].includes(v.order_price_type)
57
+ // ? 'FOK'
58
+ // : v.order_price_type.includes('ioc')
59
+ // ? 'IOC'
60
+ // : 'STOP', // unreachable code
61
+ // order_direction:
62
+ // v.direction === 'open'
63
+ // ? v.offset === 'buy'
64
+ // ? 'OPEN_LONG'
65
+ // : 'OPEN_SHORT'
66
+ // : v.offset === 'buy'
67
+ // ? 'CLOSE_SHORT'
68
+ // : 'CLOSE_LONG',
69
+ // volume: v.volume,
70
+ // submit_at: v.created_at,
71
+ // price: v.price,
72
+ // traded_volume: v.trade_volume,
73
+ // };
74
+ // });
75
+ // orders.push(...pageOrders);
76
+ // page_index++;
77
+ // }
78
+ return {
79
+ money: {
80
+ currency: 'USDT',
81
+ equity,
82
+ free,
83
+ },
84
+ positions,
85
+ };
86
+ };
87
+ //# sourceMappingURL=swap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swap.js","sourceRoot":"","sources":["../../src/accounts/swap.ts"],"names":[],"mappings":"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","sourcesContent":["import { IActionHandlerOfGetAccountInfo, IPosition } from '@yuants/data-account';\nimport { firstValueFrom } from 'rxjs';\nimport { getSwapCrossPositionInfo, getUnifiedAccountInfo, ICredential } from '../api/private-api';\nimport { swapProductService } from '../product';\n\nexport const getSwapAccountInfo: IActionHandlerOfGetAccountInfo<ICredential> = async (credential) => {\n // balance\n const balance = await getUnifiedAccountInfo(credential);\n if (!balance.data) {\n throw new Error('Failed to get unified account info');\n }\n const balanceData = balance.data.find((v) => v.margin_asset === 'USDT');\n if (!balanceData) {\n throw new Error('No USDT balance found in unified account');\n }\n const equity = balanceData.margin_balance;\n const free = balanceData.withdraw_available;\n\n // positions\n const positionsRes = await getSwapCrossPositionInfo(credential);\n const mapProductIdToPerpetualProduct = await firstValueFrom(swapProductService.mapProductIdToProduct$);\n const positions: IPosition[] = (positionsRes.data || []).map((v): IPosition => {\n const product_id = v.contract_code;\n const theProduct = mapProductIdToPerpetualProduct?.get(product_id);\n const valuation = v.volume * v.last_price * (theProduct?.value_scale || 1);\n return {\n position_id: `${v.contract_code}/${v.contract_type}/${v.direction}/${v.margin_mode}`,\n datasource_id: 'HUOBI-SWAP',\n product_id,\n direction: v.direction === 'buy' ? 'LONG' : 'SHORT',\n volume: v.volume,\n free_volume: v.available,\n position_price: v.cost_hold,\n closable_price: v.last_price,\n floating_profit: v.profit_unreal,\n valuation,\n };\n });\n\n // orders\n // const orders: IOrder[] = [];\n // let page_index = 1;\n // const page_size = 50;\n\n // while (true) {\n // const ordersRes = await client.getSwapOpenOrders({ page_index, page_size });\n // if (!ordersRes.data?.orders || ordersRes.data.orders.length === 0) {\n // break;\n // }\n\n // const pageOrders: IOrder[] = ordersRes.data.orders.map((v): IOrder => {\n // return {\n // order_id: v.order_id_str,\n // account_id: SWAP_ACCOUNT_ID,\n // product_id: v.contract_code,\n // order_type: ['lightning'].includes(v.order_price_type)\n // ? 'MARKET'\n // : ['limit', 'opponent', 'post_only', 'optimal_5', 'optimal_10', 'optimal_20'].includes(\n // v.order_price_type,\n // )\n // ? 'LIMIT'\n // : ['fok'].includes(v.order_price_type)\n // ? 'FOK'\n // : v.order_price_type.includes('ioc')\n // ? 'IOC'\n // : 'STOP', // unreachable code\n // order_direction:\n // v.direction === 'open'\n // ? v.offset === 'buy'\n // ? 'OPEN_LONG'\n // : 'OPEN_SHORT'\n // : v.offset === 'buy'\n // ? 'CLOSE_SHORT'\n // : 'CLOSE_LONG',\n // volume: v.volume,\n // submit_at: v.created_at,\n // price: v.price,\n // traded_volume: v.trade_volume,\n // };\n // });\n\n // orders.push(...pageOrders);\n // page_index++;\n // }\n\n return {\n money: {\n currency: 'USDT',\n equity,\n free,\n },\n positions,\n };\n};\n"]}
@@ -89,14 +89,6 @@ export const getSpotAccountBalance = (credential, account_uid) => {
89
89
  export const getCrossMarginLoanInfo = (credential) => {
90
90
  return privateRequest(credential, 'GET', '/v1/cross-margin/loan-info', 'api.huobi.pro');
91
91
  };
92
- /**
93
- * 获取现货行情
94
- *
95
- * https://www.htx.com/zh-cn/opend/newApiPages/?id=7ec3fc25-7773-11ed-9966-0242ac110003
96
- */
97
- export const getSpotTick = (credential, params) => {
98
- return privateRequest(credential, 'GET', `/market/detail/merged`, 'api.huobi.pro', params);
99
- };
100
92
  /**
101
93
  * 现货下单
102
94
  *