@yuants/vendor-turboflow 1.1.1 → 1.2.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 (51) hide show
  1. package/.rush/temp/chunked-rush-logs/vendor-turboflow.build.chunks.jsonl +6 -6
  2. package/.rush/temp/operation/build/all.log +6 -6
  3. package/.rush/temp/operation/build/log-chunks.jsonl +6 -6
  4. package/.rush/temp/operation/build/state.json +1 -1
  5. package/.rush/temp/shrinkwrap-deps.json +1 -1
  6. package/CHANGELOG.json +17 -0
  7. package/CHANGELOG.md +8 -1
  8. package/README.md +134 -0
  9. package/lib/api/private-api.d.ts +2 -2
  10. package/lib/api/private-api.d.ts.map +1 -1
  11. package/lib/api/private-api.js +12 -15
  12. package/lib/api/private-api.js.map +1 -1
  13. package/lib/index.d.ts +2 -0
  14. package/lib/index.d.ts.map +1 -1
  15. package/lib/index.js +4 -0
  16. package/lib/index.js.map +1 -1
  17. package/lib/services/account-actions-with-credential.d.ts +2 -0
  18. package/lib/services/account-actions-with-credential.d.ts.map +1 -0
  19. package/lib/services/account-actions-with-credential.js +60 -0
  20. package/lib/services/account-actions-with-credential.js.map +1 -0
  21. package/lib/services/order-actions-with-credential.d.ts +2 -0
  22. package/lib/services/order-actions-with-credential.d.ts.map +1 -0
  23. package/lib/services/order-actions-with-credential.js +25 -0
  24. package/lib/services/order-actions-with-credential.js.map +1 -0
  25. package/lib/services/orders/cancelOrder.d.ts +4 -0
  26. package/lib/services/orders/cancelOrder.d.ts.map +1 -0
  27. package/lib/services/orders/cancelOrder.js +42 -0
  28. package/lib/services/orders/cancelOrder.js.map +1 -0
  29. package/lib/services/orders/listOrders.d.ts +7 -0
  30. package/lib/services/orders/listOrders.d.ts.map +1 -0
  31. package/lib/services/orders/listOrders.js +78 -0
  32. package/lib/services/orders/listOrders.js.map +1 -0
  33. package/lib/services/orders/modifyOrder.d.ts +4 -0
  34. package/lib/services/orders/modifyOrder.d.ts.map +1 -0
  35. package/lib/services/orders/modifyOrder.js +46 -0
  36. package/lib/services/orders/modifyOrder.js.map +1 -0
  37. package/lib/services/orders/submitOrder.d.ts +6 -0
  38. package/lib/services/orders/submitOrder.d.ts.map +1 -0
  39. package/lib/services/orders/submitOrder.js +61 -0
  40. package/lib/services/orders/submitOrder.js.map +1 -0
  41. package/package.json +3 -1
  42. package/rush-logs/vendor-turboflow.build.log +6 -6
  43. package/src/api/private-api.ts +25 -18
  44. package/src/index.ts +3 -0
  45. package/src/services/account-actions-with-credential.ts +76 -0
  46. package/src/services/order-actions-with-credential.ts +30 -0
  47. package/src/services/orders/cancelOrder.ts +43 -0
  48. package/src/services/orders/listOrders.ts +84 -0
  49. package/src/services/orders/modifyOrder.ts +46 -0
  50. package/src/services/orders/submitOrder.ts +63 -0
  51. package/temp/package-deps.json +15 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-actions-with-credential.js","sourceRoot":"","sources":["../../src/services/order-actions-with-credential.ts"],"names":[],"mappings":";;AAAA,mDAAuE;AACvE,+CAA4C;AAE5C,sDAAyD;AACzD,oDAAiD;AACjD,sDAAmD;AACnD,sDAAmD;AAEnD,MAAM,QAAQ,GAAG,mBAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,IAAA,8CAAiC,EAC/B,QAAQ,EACR,WAAW,EACX;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,aAAa,CAAC;IACzB,UAAU,EAAE;QACV,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,sCAAsC;SACpD;KACF;CACF,EACD;IACE,WAAW,EAAE,yBAAW;IACxB,WAAW,EAAE,+BAAiB;IAC9B,WAAW,EAAE,yBAAW;IACxB,UAAU,EAAE,uBAAU;CACvB,CACF,CAAC","sourcesContent":["import { provideOrderActionsWithCredential } from '@yuants/data-order';\nimport { Terminal } from '@yuants/protocol';\nimport { ICredential } from '../api/private-api';\nimport { cancelOrderAction } from './orders/cancelOrder';\nimport { listOrders } from './orders/listOrders';\nimport { modifyOrder } from './orders/modifyOrder';\nimport { submitOrder } from './orders/submitOrder';\n\nconst terminal = Terminal.fromNodeEnv();\n\nprovideOrderActionsWithCredential<ICredential>(\n terminal,\n 'TURBOFLOW',\n {\n type: 'object',\n required: ['private_key'],\n properties: {\n private_key: {\n type: 'string',\n description: 'ED25519 Private Key (base58 encoded)',\n },\n },\n },\n {\n submitOrder: submitOrder,\n cancelOrder: cancelOrderAction,\n modifyOrder: modifyOrder,\n listOrders: listOrders,\n },\n);\n"]}
@@ -0,0 +1,4 @@
1
+ import { IOrder } from '@yuants/data-order';
2
+ import { ICredential } from '../../api/private-api';
3
+ export declare const cancelOrderAction: (credential: ICredential, order: IOrder) => Promise<void>;
4
+ //# sourceMappingURL=cancelOrder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancelOrder.d.ts","sourceRoot":"","sources":["../../../src/services/orders/cancelOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAC;AAEnF,eAAO,MAAM,iBAAiB,eAAsB,WAAW,SAAS,MAAM,KAAG,QAAQ,IAAI,CAsC5F,CAAC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cancelOrderAction = void 0;
4
+ const utils_1 = require("@yuants/utils");
5
+ const private_api_1 = require("../../api/private-api");
6
+ const cancelOrderAction = async (credential, order) => {
7
+ console.info(`[${(0, utils_1.formatTime)(Date.now())}] Cancelling order ${order.order_id}`);
8
+ try {
9
+ // Parse product_id to get pair_id
10
+ const productParts = order.product_id.split('/');
11
+ const pair_id = productParts[productParts.length - 1];
12
+ // Parse comment for pool_id
13
+ let pool_id = 1;
14
+ if (order.comment) {
15
+ try {
16
+ const params = JSON.parse(order.comment);
17
+ pool_id = params.pool_id || 1;
18
+ }
19
+ catch (e) {
20
+ console.warn(`[${(0, utils_1.formatTime)(Date.now())}] Failed to parse order comment:`, e);
21
+ }
22
+ }
23
+ if (!order.order_id) {
24
+ throw new Error('order_id is required for cancelling order');
25
+ }
26
+ const response = await (0, private_api_1.cancelOrder)(credential, {
27
+ pair_id,
28
+ order_id: order.order_id,
29
+ pool_id,
30
+ });
31
+ if (response.errno !== '0') {
32
+ throw new Error(`Failed to cancel order: ${response.msg}`);
33
+ }
34
+ console.info(`[${(0, utils_1.formatTime)(Date.now())}] Order ${order.order_id} cancelled successfully`);
35
+ }
36
+ catch (error) {
37
+ console.error(`[${(0, utils_1.formatTime)(Date.now())}] Error cancelling order:`, error);
38
+ throw error;
39
+ }
40
+ };
41
+ exports.cancelOrderAction = cancelOrderAction;
42
+ //# sourceMappingURL=cancelOrder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancelOrder.js","sourceRoot":"","sources":["../../../src/services/orders/cancelOrder.ts"],"names":[],"mappings":";;;AACA,yCAA2C;AAC3C,uDAAmF;AAE5E,MAAM,iBAAiB,GAAG,KAAK,EAAE,UAAuB,EAAE,KAAa,EAAiB,EAAE;IAC/F,OAAO,CAAC,IAAI,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,sBAAsB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE/E,IAAI;QACF,kCAAkC;QAClC,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEtD,4BAA4B;QAC5B,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,KAAK,CAAC,OAAO,EAAE;YACjB,IAAI;gBACF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACzC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;aAC/B;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,CAAC,IAAI,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAC;aAC/E;SACF;QAED,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;YACnB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;SAC9D;QAED,MAAM,QAAQ,GAAG,MAAM,IAAA,yBAAc,EAAC,UAAU,EAAE;YAChD,OAAO;YACP,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,EAAE;YAC1B,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;SAC5D;QAED,OAAO,CAAC,IAAI,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,KAAK,CAAC,QAAQ,yBAAyB,CAAC,CAAC;KAC5F;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,CAAC,KAAK,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAC5E,MAAM,KAAK,CAAC;KACb;AACH,CAAC,CAAC;AAtCW,QAAA,iBAAiB,qBAsC5B","sourcesContent":["import { IOrder } from '@yuants/data-order';\nimport { formatTime } from '@yuants/utils';\nimport { ICredential, cancelOrder as cancelOrderApi } from '../../api/private-api';\n\nexport const cancelOrderAction = async (credential: ICredential, order: IOrder): Promise<void> => {\n console.info(`[${formatTime(Date.now())}] Cancelling order ${order.order_id}`);\n\n try {\n // Parse product_id to get pair_id\n const productParts = order.product_id.split('/');\n const pair_id = productParts[productParts.length - 1];\n\n // Parse comment for pool_id\n let pool_id = 1;\n if (order.comment) {\n try {\n const params = JSON.parse(order.comment);\n pool_id = params.pool_id || 1;\n } catch (e) {\n console.warn(`[${formatTime(Date.now())}] Failed to parse order comment:`, e);\n }\n }\n\n if (!order.order_id) {\n throw new Error('order_id is required for cancelling order');\n }\n\n const response = await cancelOrderApi(credential, {\n pair_id,\n order_id: order.order_id,\n pool_id,\n });\n\n if (response.errno !== '0') {\n throw new Error(`Failed to cancel order: ${response.msg}`);\n }\n\n console.info(`[${formatTime(Date.now())}] Order ${order.order_id} cancelled successfully`);\n } catch (error) {\n console.error(`[${formatTime(Date.now())}] Error cancelling order:`, error);\n throw error;\n }\n};\n"]}
@@ -0,0 +1,7 @@
1
+ import { IActionHandlerOfListOrders } from '@yuants/data-order';
2
+ import { ICredential } from '../../api/private-api';
3
+ /**
4
+ * List orders implementation
5
+ */
6
+ export declare const listOrders: IActionHandlerOfListOrders<ICredential>;
7
+ //# sourceMappingURL=listOrders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listOrders.d.ts","sourceRoot":"","sources":["../../../src/services/orders/listOrders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAU,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,WAAW,EAAgB,MAAM,uBAAuB,CAAC;AAqDlE;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,0BAA0B,CAAC,WAAW,CAyB9D,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listOrders = void 0;
4
+ const utils_1 = require("@yuants/utils");
5
+ const private_api_1 = require("../../api/private-api");
6
+ /**
7
+ * Map TurboFlow order_way to order direction
8
+ * 1: 开多 (Open Long), 2: 平空 (Close Short), 3: 开空 (Open Short), 4: 平多 (Close Long)
9
+ */
10
+ const mapOrderDirection = (order_way) => {
11
+ switch (order_way) {
12
+ case 1:
13
+ return 'OPEN_LONG';
14
+ case 2:
15
+ return 'CLOSE_SHORT';
16
+ case 3:
17
+ return 'OPEN_SHORT';
18
+ case 4:
19
+ return 'CLOSE_LONG';
20
+ default:
21
+ return 'OPEN_LONG';
22
+ }
23
+ };
24
+ /**
25
+ * Map TurboFlow order to Yuan IOrder format
26
+ */
27
+ const mapOrder = (order, account_id) => {
28
+ const volume = parseFloat(order.size) || 0;
29
+ const price = parseFloat(order.price) || 0;
30
+ return {
31
+ order_id: order.id,
32
+ account_id,
33
+ product_id: (0, utils_1.encodePath)('PERPETUAL', order.pair_id),
34
+ order_type: order.order_type.toUpperCase(),
35
+ order_direction: mapOrderDirection(order.order_way),
36
+ volume: Number.isFinite(volume) ? volume : 0,
37
+ price: Number.isFinite(price) && price > 0 ? price : undefined,
38
+ submit_at: new Date(order.created_at).getTime(),
39
+ order_status: order.order_status.toLowerCase(),
40
+ comment: JSON.stringify({
41
+ pool_id: order.pool_id,
42
+ pair_id: order.pair_id,
43
+ coin_code: order.coin_code,
44
+ leverage: order.leverage,
45
+ margin_type: order.margin_type,
46
+ fee_mode: order.fee_mode,
47
+ pos_mode: order.pos_mode,
48
+ position_id: order.position_id,
49
+ }),
50
+ };
51
+ };
52
+ /**
53
+ * List orders implementation
54
+ */
55
+ const listOrders = async (credential, account_id) => {
56
+ console.info(`[${(0, utils_1.formatTime)(Date.now())}] Listing orders for account: ${account_id}`);
57
+ try {
58
+ // Get pending orders
59
+ const response = await (0, private_api_1.getOrderList)(credential, {
60
+ page_num: 1,
61
+ page_size: 100,
62
+ status: 'Pending',
63
+ });
64
+ if (response.errno !== '0') {
65
+ throw new Error(`Failed to list orders: ${response.msg}`);
66
+ }
67
+ const orders = response.data.data.map((order) => mapOrder(order, account_id));
68
+ console.info(`[${(0, utils_1.formatTime)(Date.now())}] Found ${orders.length} orders`);
69
+ return orders;
70
+ }
71
+ catch (error) {
72
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
73
+ console.error(`[${(0, utils_1.formatTime)(Date.now())}] Failed to list orders for ${account_id}: ${errorMessage}`);
74
+ throw new Error(`Failed to list orders: ${errorMessage}`);
75
+ }
76
+ };
77
+ exports.listOrders = listOrders;
78
+ //# sourceMappingURL=listOrders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listOrders.js","sourceRoot":"","sources":["../../../src/services/orders/listOrders.ts"],"names":[],"mappings":"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","sourcesContent":["import { IActionHandlerOfListOrders, IOrder } from '@yuants/data-order';\nimport { encodePath, formatTime } from '@yuants/utils';\nimport { ICredential, getOrderList } from '../../api/private-api';\n\ntype OrderDirection = 'OPEN_LONG' | 'OPEN_SHORT' | 'CLOSE_LONG' | 'CLOSE_SHORT';\n\n/**\n * Map TurboFlow order_way to order direction\n * 1: 开多 (Open Long), 2: 平空 (Close Short), 3: 开空 (Open Short), 4: 平多 (Close Long)\n */\nconst mapOrderDirection = (order_way: number): OrderDirection => {\n switch (order_way) {\n case 1:\n return 'OPEN_LONG';\n case 2:\n return 'CLOSE_SHORT';\n case 3:\n return 'OPEN_SHORT';\n case 4:\n return 'CLOSE_LONG';\n default:\n return 'OPEN_LONG';\n }\n};\n\n/**\n * Map TurboFlow order to Yuan IOrder format\n */\nconst mapOrder = (order: any, account_id: string): IOrder => {\n const volume = parseFloat(order.size) || 0;\n const price = parseFloat(order.price) || 0;\n\n return {\n order_id: order.id,\n account_id,\n product_id: encodePath('PERPETUAL', order.pair_id),\n order_type: order.order_type.toUpperCase() as any,\n order_direction: mapOrderDirection(order.order_way),\n volume: Number.isFinite(volume) ? volume : 0,\n price: Number.isFinite(price) && price > 0 ? price : undefined,\n submit_at: new Date(order.created_at).getTime(),\n order_status: order.order_status.toLowerCase(),\n comment: JSON.stringify({\n pool_id: order.pool_id,\n pair_id: order.pair_id,\n coin_code: order.coin_code,\n leverage: order.leverage,\n margin_type: order.margin_type,\n fee_mode: order.fee_mode,\n pos_mode: order.pos_mode,\n position_id: order.position_id,\n }),\n };\n};\n\n/**\n * List orders implementation\n */\nexport const listOrders: IActionHandlerOfListOrders<ICredential> = async (credential, account_id) => {\n console.info(`[${formatTime(Date.now())}] Listing orders for account: ${account_id}`);\n\n try {\n // Get pending orders\n const response = await getOrderList(credential, {\n page_num: 1,\n page_size: 100,\n status: 'Pending',\n });\n\n if (response.errno !== '0') {\n throw new Error(`Failed to list orders: ${response.msg}`);\n }\n\n const orders = response.data.data.map((order) => mapOrder(order, account_id));\n\n console.info(`[${formatTime(Date.now())}] Found ${orders.length} orders`);\n\n return orders;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n console.error(`[${formatTime(Date.now())}] Failed to list orders for ${account_id}: ${errorMessage}`);\n throw new Error(`Failed to list orders: ${errorMessage}`);\n }\n};\n"]}
@@ -0,0 +1,4 @@
1
+ import { IOrder } from '@yuants/data-order';
2
+ import { ICredential } from '../../api/private-api';
3
+ export declare const modifyOrder: (credential: ICredential, order: IOrder) => Promise<void>;
4
+ //# sourceMappingURL=modifyOrder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifyOrder.d.ts","sourceRoot":"","sources":["../../../src/services/orders/modifyOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAe,MAAM,uBAAuB,CAAC;AAEjE,eAAO,MAAM,WAAW,eAAsB,WAAW,SAAS,MAAM,KAAG,QAAQ,IAAI,CAyCtF,CAAC"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.modifyOrder = void 0;
4
+ const utils_1 = require("@yuants/utils");
5
+ const private_api_1 = require("../../api/private-api");
6
+ const modifyOrder = async (credential, order) => {
7
+ var _a;
8
+ console.info(`[${(0, utils_1.formatTime)(Date.now())}] Modifying order ${order.order_id}`);
9
+ try {
10
+ // Parse comment for position_id and other parameters
11
+ let position_id;
12
+ let tp_order;
13
+ let sl_order;
14
+ if (order.comment) {
15
+ try {
16
+ const params = JSON.parse(order.comment);
17
+ position_id = params.position_id;
18
+ tp_order = params.tp_order;
19
+ sl_order = params.sl_order;
20
+ }
21
+ catch (e) {
22
+ console.warn(`[${(0, utils_1.formatTime)(Date.now())}] Failed to parse order comment:`, e);
23
+ }
24
+ }
25
+ if (!position_id) {
26
+ throw new Error('position_id is required for modifying order');
27
+ }
28
+ const response = await (0, private_api_1.remendOrder)(credential, {
29
+ position_id,
30
+ price: (_a = order.price) === null || _a === void 0 ? void 0 : _a.toString(),
31
+ vol: order.volume.toString(),
32
+ tp_order,
33
+ sl_order,
34
+ });
35
+ if (response.errno !== '0') {
36
+ throw new Error(`Failed to modify order: ${response.msg}`);
37
+ }
38
+ console.info(`[${(0, utils_1.formatTime)(Date.now())}] Order modified successfully`);
39
+ }
40
+ catch (error) {
41
+ console.error(`[${(0, utils_1.formatTime)(Date.now())}] Error modifying order:`, error);
42
+ throw error;
43
+ }
44
+ };
45
+ exports.modifyOrder = modifyOrder;
46
+ //# sourceMappingURL=modifyOrder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifyOrder.js","sourceRoot":"","sources":["../../../src/services/orders/modifyOrder.ts"],"names":[],"mappings":";;;AACA,yCAA2C;AAC3C,uDAAiE;AAE1D,MAAM,WAAW,GAAG,KAAK,EAAE,UAAuB,EAAE,KAAa,EAAiB,EAAE;;IACzF,OAAO,CAAC,IAAI,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,qBAAqB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE9E,IAAI;QACF,qDAAqD;QACrD,IAAI,WAA+B,CAAC;QACpC,IAAI,QAAa,CAAC;QAClB,IAAI,QAAa,CAAC;QAElB,IAAI,KAAK,CAAC,OAAO,EAAE;YACjB,IAAI;gBACF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACzC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;gBACjC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;gBAC3B,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;aAC5B;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,CAAC,IAAI,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAC;aAC/E;SACF;QAED,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;SAChE;QAED,MAAM,QAAQ,GAAG,MAAM,IAAA,yBAAW,EAAC,UAAU,EAAE;YAC7C,WAAW;YACX,KAAK,EAAE,MAAA,KAAK,CAAC,KAAK,0CAAE,QAAQ,EAAE;YAC9B,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE;YAC5B,QAAQ;YACR,QAAQ;SACT,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,EAAE;YAC1B,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;SAC5D;QAED,OAAO,CAAC,IAAI,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,+BAA+B,CAAC,CAAC;KACzE;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,CAAC,KAAK,CAAC,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;QAC3E,MAAM,KAAK,CAAC;KACb;AACH,CAAC,CAAC;AAzCW,QAAA,WAAW,eAyCtB","sourcesContent":["import { IOrder } from '@yuants/data-order';\nimport { formatTime } from '@yuants/utils';\nimport { ICredential, remendOrder } from '../../api/private-api';\n\nexport const modifyOrder = async (credential: ICredential, order: IOrder): Promise<void> => {\n console.info(`[${formatTime(Date.now())}] Modifying order ${order.order_id}`);\n\n try {\n // Parse comment for position_id and other parameters\n let position_id: string | undefined;\n let tp_order: any;\n let sl_order: any;\n\n if (order.comment) {\n try {\n const params = JSON.parse(order.comment);\n position_id = params.position_id;\n tp_order = params.tp_order;\n sl_order = params.sl_order;\n } catch (e) {\n console.warn(`[${formatTime(Date.now())}] Failed to parse order comment:`, e);\n }\n }\n\n if (!position_id) {\n throw new Error('position_id is required for modifying order');\n }\n\n const response = await remendOrder(credential, {\n position_id,\n price: order.price?.toString(),\n vol: order.volume.toString(),\n tp_order,\n sl_order,\n });\n\n if (response.errno !== '0') {\n throw new Error(`Failed to modify order: ${response.msg}`);\n }\n\n console.info(`[${formatTime(Date.now())}] Order modified successfully`);\n } catch (error) {\n console.error(`[${formatTime(Date.now())}] Error modifying order:`, error);\n throw error;\n }\n};\n"]}
@@ -0,0 +1,6 @@
1
+ import { IOrder } from '@yuants/data-order';
2
+ import { ICredential } from '../../api/private-api';
3
+ export declare const submitOrder: (credential: ICredential, order: IOrder) => Promise<{
4
+ order_id: string;
5
+ }>;
6
+ //# sourceMappingURL=submitOrder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submitOrder.d.ts","sourceRoot":"","sources":["../../../src/services/orders/submitOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAC;AAEnF,eAAO,MAAM,WAAW,eAAsB,WAAW,SAAS,MAAM,KAAG,QAAQ;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CA0DtG,CAAC"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.submitOrder = void 0;
4
+ const private_api_1 = require("../../api/private-api");
5
+ const submitOrder = async (credential, order) => {
6
+ var _a;
7
+ // Parse product_id to get pair_id
8
+ const productParts = order.product_id.split('/');
9
+ const pair_id = productParts[productParts.length - 1];
10
+ // Determine order_way based on order_direction
11
+ // 1: 开多 (Open Long), 2: 平空 (Close Short), 3: 开空 (Open Short), 4: 平多 (Close Long)
12
+ let order_way;
13
+ switch (order.order_direction) {
14
+ case 'OPEN_LONG':
15
+ order_way = 1;
16
+ break;
17
+ case 'CLOSE_SHORT':
18
+ order_way = 2;
19
+ break;
20
+ case 'OPEN_SHORT':
21
+ order_way = 3;
22
+ break;
23
+ case 'CLOSE_LONG':
24
+ order_way = 4;
25
+ break;
26
+ default:
27
+ throw new Error(`Unsupported order direction: ${order.order_direction}`);
28
+ }
29
+ // Determine order_type
30
+ let order_type;
31
+ switch (order.order_type) {
32
+ case 'LIMIT':
33
+ order_type = 'limit';
34
+ break;
35
+ case 'MARKET':
36
+ order_type = 'market';
37
+ break;
38
+ default:
39
+ order_type = 'limit';
40
+ }
41
+ // Build the order request
42
+ const response = await (0, private_api_1.submitOrder)(credential, {
43
+ request_id: Date.now(),
44
+ pair_id,
45
+ pool_id: 2,
46
+ coin_code: '2',
47
+ order_type,
48
+ order_way,
49
+ margin_type: 2,
50
+ leverage: 100,
51
+ size: order.volume.toString(),
52
+ position_mode: 1,
53
+ time_in_force: 'GTC',
54
+ fee_mode: 1,
55
+ order_mode: 1,
56
+ price: (_a = order.price) === null || _a === void 0 ? void 0 : _a.toString(),
57
+ });
58
+ return { order_id: response.data.order.id };
59
+ };
60
+ exports.submitOrder = submitOrder;
61
+ //# sourceMappingURL=submitOrder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submitOrder.js","sourceRoot":"","sources":["../../../src/services/orders/submitOrder.ts"],"names":[],"mappings":";;;AAEA,uDAAmF;AAE5E,MAAM,WAAW,GAAG,KAAK,EAAE,UAAuB,EAAE,KAAa,EAAiC,EAAE;;IACzG,kCAAkC;IAClC,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEtD,+CAA+C;IAC/C,iFAAiF;IACjF,IAAI,SAAwB,CAAC;IAC7B,QAAQ,KAAK,CAAC,eAAe,EAAE;QAC7B,KAAK,WAAW;YACd,SAAS,GAAG,CAAC,CAAC;YACd,MAAM;QACR,KAAK,aAAa;YAChB,SAAS,GAAG,CAAC,CAAC;YACd,MAAM;QACR,KAAK,YAAY;YACf,SAAS,GAAG,CAAC,CAAC;YACd,MAAM;QACR,KAAK,YAAY;YACf,SAAS,GAAG,CAAC,CAAC;YACd,MAAM;QACR;YACE,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC;KAC5E;IAED,uBAAuB;IACvB,IAAI,UAA6D,CAAC;IAClE,QAAQ,KAAK,CAAC,UAAU,EAAE;QACxB,KAAK,OAAO;YACV,UAAU,GAAG,OAAO,CAAC;YACrB,MAAM;QACR,KAAK,QAAQ;YACX,UAAU,GAAG,QAAQ,CAAC;YACtB,MAAM;QACR;YACE,UAAU,GAAG,OAAO,CAAC;KACxB;IAED,0BAA0B;IAE1B,MAAM,QAAQ,GAAG,MAAM,IAAA,yBAAc,EAAC,UAAU,EAAE;QAChD,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;QACtB,OAAO;QACP,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,GAAG;QACd,UAAU;QACV,SAAS;QACT,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,GAAG;QACb,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE;QAC7B,aAAa,EAAE,CAAC;QAChB,aAAa,EAAE,KAAc;QAC7B,QAAQ,EAAE,CAAC;QACX,UAAU,EAAE,CAAU;QACtB,KAAK,EAAE,MAAA,KAAK,CAAC,KAAK,0CAAE,QAAQ,EAAE;KAC/B,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AAC9C,CAAC,CAAC;AA1DW,QAAA,WAAW,eA0DtB","sourcesContent":["import { IOrder } from '@yuants/data-order';\nimport { formatTime } from '@yuants/utils';\nimport { ICredential, submitOrder as submitOrderApi } from '../../api/private-api';\n\nexport const submitOrder = async (credential: ICredential, order: IOrder): Promise<{ order_id: string }> => {\n // Parse product_id to get pair_id\n const productParts = order.product_id.split('/');\n const pair_id = productParts[productParts.length - 1];\n\n // Determine order_way based on order_direction\n // 1: 开多 (Open Long), 2: 平空 (Close Short), 3: 开空 (Open Short), 4: 平多 (Close Long)\n let order_way: 1 | 2 | 3 | 4;\n switch (order.order_direction) {\n case 'OPEN_LONG':\n order_way = 1;\n break;\n case 'CLOSE_SHORT':\n order_way = 2;\n break;\n case 'OPEN_SHORT':\n order_way = 3;\n break;\n case 'CLOSE_LONG':\n order_way = 4;\n break;\n default:\n throw new Error(`Unsupported order direction: ${order.order_direction}`);\n }\n\n // Determine order_type\n let order_type: 'limit' | 'market' | 'stop_limit' | 'stop_market';\n switch (order.order_type) {\n case 'LIMIT':\n order_type = 'limit';\n break;\n case 'MARKET':\n order_type = 'market';\n break;\n default:\n order_type = 'limit';\n }\n\n // Build the order request\n\n const response = await submitOrderApi(credential, {\n request_id: Date.now(),\n pair_id,\n pool_id: 2, // usdc\n coin_code: '2', // usdc\n order_type,\n order_way,\n margin_type: 2, // Default to cross margin\n leverage: 100,\n size: order.volume.toString(), // usdc value\n position_mode: 1, // Default to one-way\n time_in_force: 'GTC' as const,\n fee_mode: 1,\n order_mode: 1 as const, // Normal order\n price: order.price?.toString(),\n });\n\n return { order_id: response.data.order.id };\n};\n"]}
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@yuants/vendor-turboflow",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "main": "lib/index.js",
5
5
  "dependencies": {
6
6
  "@yuants/protocol": "0.53.0",
7
7
  "@yuants/utils": "0.13.0",
8
+ "@yuants/data-account": "0.8.2",
9
+ "@yuants/data-order": "0.6.4",
8
10
  "rxjs": "~7.5.6"
9
11
  },
10
12
  "devDependencies": {
@@ -9,15 +9,15 @@ Starting test
9
9
  ---- Pre-compile finished (0ms) ----
10
10
  ---- Compile started ----
11
11
  [typescript] Using TypeScript version 4.7.4
12
- ---- Compile finished (3754ms) ----
12
+ ---- Compile finished (3001ms) ----
13
13
  ---- Bundle started ----
14
- ---- Bundle finished (1ms) ----
14
+ ---- Bundle finished (2ms) ----
15
15
  ---- Post-build started ----
16
16
  ---- Post-build finished (0ms) ----
17
17
  ---- Test started ----
18
- ---- Test finished (3ms) ----
19
- -------------------- Finished (4.113s) --------------------
20
- Project: @yuants/vendor-turboflow@1.1.1
18
+ ---- Test finished (2ms) ----
19
+ -------------------- Finished (3.313s) --------------------
20
+ Project: @yuants/vendor-turboflow@1.2.0
21
21
  Heft version: 0.47.11
22
22
  Node version: v22.14.0
23
- 2025-11-25T07:11:30.054Z no Dockerfile found, skip building docker image
23
+ 2025-11-25T11:54:42.712Z no Dockerfile found, skip building docker image
@@ -1,4 +1,4 @@
1
- import { decodeBase58, fromPrivateKey, HmacSHA256, signMessageByEd25519 } from '@yuants/utils';
1
+ import { decodeBase58, fromPrivateKey, HmacSHA256, scopeError, signMessageByEd25519 } from '@yuants/utils';
2
2
 
3
3
  export interface ICredential {
4
4
  /**
@@ -9,10 +9,21 @@ export interface ICredential {
9
9
 
10
10
  const BASE_URL = 'https://surfv2-api.surf.one';
11
11
 
12
- export const privateRequest = async (credential: ICredential, method: string, path: string, params: any) => {
12
+ export const privateRequest = async (
13
+ credential: ICredential,
14
+ method: string,
15
+ path: string,
16
+ params: any = {},
17
+ ) => {
13
18
  const url = new URL(BASE_URL);
14
19
  url.pathname = path;
15
20
 
21
+ if (method === 'GET') {
22
+ for (const [key, value] of Object.entries(params)) {
23
+ url.searchParams.set(key, `${value}`);
24
+ }
25
+ }
26
+
16
27
  const publicKey = fromPrivateKey(credential.private_key).public_key;
17
28
  const publicKeyBinary = decodeBase58(publicKey);
18
29
  const publicKeyHex = Buffer.from(publicKeyBinary).toString('hex');
@@ -23,7 +34,12 @@ export const privateRequest = async (credential: ICredential, method: string, pa
23
34
 
24
35
  const timestamp = Math.floor(Date.now() / 1000).toString();
25
36
 
26
- const data = `method=${method}&path=${path}&timestamp=${timestamp}&access-key=${publicKeyHex}`;
37
+ // 除了 host 之外的所有内容
38
+ const _path = url.pathname + url.search;
39
+
40
+ const data =
41
+ `method=${method}&path=${_path}&timestamp=${timestamp}&access-key=${publicKeyHex}` +
42
+ (method === 'POST' ? `&body=${JSON.stringify(params)}` : '');
27
43
  const hashData = await HmacSHA256(new TextEncoder().encode(data), publicKeyBinary);
28
44
 
29
45
  const signature = signMessageByEd25519(hashData, privateKeyBinary);
@@ -34,14 +50,6 @@ export const privateRequest = async (credential: ICredential, method: string, pa
34
50
  headers['SIGN'] = signatureHex;
35
51
  headers['LANG'] = 'zh-cn';
36
52
 
37
- console.info(url.toString(), headers);
38
-
39
- if (method === 'GET') {
40
- for (const [key, value] of Object.entries(params)) {
41
- url.searchParams.set(key, `${value}`);
42
- }
43
- }
44
-
45
53
  const response = await fetch(url.toString(), {
46
54
  method,
47
55
  headers,
@@ -50,12 +58,11 @@ export const privateRequest = async (credential: ICredential, method: string, pa
50
58
 
51
59
  const text = await response.text();
52
60
 
53
- try {
54
- const res = JSON.parse(text);
55
- return res;
56
- } catch (e) {
57
- throw `APIError: ${response.status} ${response.statusText} ${text}`;
58
- }
61
+ console.info(url.toString(), headers, text);
62
+
63
+ return scopeError('TurboAPIError', { status: response.status, statusText: response.statusText, text }, () =>
64
+ JSON.parse(text),
65
+ );
59
66
  };
60
67
 
61
68
  export const createPrivateApi =
@@ -460,7 +467,7 @@ export const getPositionList = createPrivateApi<
460
467
  page_num: number;
461
468
  count: number;
462
469
  page_count: number;
463
- data: Array<{
470
+ data?: Array<{
464
471
  id: string;
465
472
  pool_id: number;
466
473
  pair_id: string;
package/src/index.ts CHANGED
@@ -0,0 +1,3 @@
1
+ // Import services
2
+ import './services/account-actions-with-credential';
3
+ import './services/order-actions-with-credential';
@@ -0,0 +1,76 @@
1
+ import { IPosition, makeSpotPosition, provideAccountActionsWithCredential } from '@yuants/data-account';
2
+ import { Terminal } from '@yuants/protocol';
3
+ import { encodePath, scopeError } from '@yuants/utils';
4
+ import { getAccountAssets, getAccountInfo, getPositionList, ICredential } from '../api/private-api';
5
+
6
+ provideAccountActionsWithCredential<ICredential>(
7
+ Terminal.fromNodeEnv(),
8
+ 'TURBOFLOW',
9
+ {
10
+ type: 'object',
11
+ required: ['private_key'],
12
+ properties: {
13
+ private_key: {
14
+ type: 'string',
15
+ description: 'ED25519 Private Key (base58 encoded)',
16
+ },
17
+ },
18
+ },
19
+ {
20
+ listAccounts: async (credential) => {
21
+ const accountInfo = await getAccountInfo(credential, undefined);
22
+
23
+ return scopeError(
24
+ 'ListAccountsError::TurboFlow',
25
+ { error: accountInfo.errno, message: accountInfo.msg },
26
+ () => [
27
+ {
28
+ account_id: `turboflow/${accountInfo.data.account_id}`,
29
+ },
30
+ ],
31
+ );
32
+ },
33
+
34
+ getAccountInfo: async (credential, account_id) => {
35
+ const assetsResponse = await getAccountAssets(credential, {
36
+ fill_coin_sub_info: '1',
37
+ });
38
+
39
+ const assetPositions = assetsResponse.data.list.map((x) =>
40
+ makeSpotPosition({
41
+ position_id: x.coin_code,
42
+ product_id: encodePath('SPOT', x.coin_name),
43
+ volume: parseFloat(x.available_balance),
44
+ free_volume: parseFloat(x.available_balance),
45
+ closable_price: 1,
46
+ }),
47
+ );
48
+
49
+ const positionsResponse = await getPositionList(credential, { status: 'Holding' });
50
+
51
+ const positions: IPosition[] = (positionsResponse.data.data || []).map((position) => {
52
+ const side = position.side === 1 ? 'LONG' : 'SHORT';
53
+ const holdSize = parseFloat(position.hold_size);
54
+ const holdAv = parseFloat(position.hold_av);
55
+ const unpnl = parseFloat(position.unpnl);
56
+ const im = parseFloat(position.im);
57
+
58
+ return {
59
+ position_id: position.id,
60
+ datasource_id: 'TURBOFLOW',
61
+ product_id: encodePath('PERP', position.symbol),
62
+ direction: side,
63
+ volume: holdSize,
64
+ free_volume: holdSize, // Assuming all volume is free
65
+ position_price: holdAv,
66
+ closable_price: holdAv,
67
+ floating_profit: unpnl,
68
+ valuation: holdSize * holdAv,
69
+ margin: im,
70
+ };
71
+ });
72
+
73
+ return [...assetPositions, ...positions];
74
+ },
75
+ },
76
+ );
@@ -0,0 +1,30 @@
1
+ import { provideOrderActionsWithCredential } from '@yuants/data-order';
2
+ import { Terminal } from '@yuants/protocol';
3
+ import { ICredential } from '../api/private-api';
4
+ import { cancelOrderAction } from './orders/cancelOrder';
5
+ import { listOrders } from './orders/listOrders';
6
+ import { modifyOrder } from './orders/modifyOrder';
7
+ import { submitOrder } from './orders/submitOrder';
8
+
9
+ const terminal = Terminal.fromNodeEnv();
10
+
11
+ provideOrderActionsWithCredential<ICredential>(
12
+ terminal,
13
+ 'TURBOFLOW',
14
+ {
15
+ type: 'object',
16
+ required: ['private_key'],
17
+ properties: {
18
+ private_key: {
19
+ type: 'string',
20
+ description: 'ED25519 Private Key (base58 encoded)',
21
+ },
22
+ },
23
+ },
24
+ {
25
+ submitOrder: submitOrder,
26
+ cancelOrder: cancelOrderAction,
27
+ modifyOrder: modifyOrder,
28
+ listOrders: listOrders,
29
+ },
30
+ );
@@ -0,0 +1,43 @@
1
+ import { IOrder } from '@yuants/data-order';
2
+ import { formatTime } from '@yuants/utils';
3
+ import { ICredential, cancelOrder as cancelOrderApi } from '../../api/private-api';
4
+
5
+ export const cancelOrderAction = async (credential: ICredential, order: IOrder): Promise<void> => {
6
+ console.info(`[${formatTime(Date.now())}] Cancelling order ${order.order_id}`);
7
+
8
+ try {
9
+ // Parse product_id to get pair_id
10
+ const productParts = order.product_id.split('/');
11
+ const pair_id = productParts[productParts.length - 1];
12
+
13
+ // Parse comment for pool_id
14
+ let pool_id = 1;
15
+ if (order.comment) {
16
+ try {
17
+ const params = JSON.parse(order.comment);
18
+ pool_id = params.pool_id || 1;
19
+ } catch (e) {
20
+ console.warn(`[${formatTime(Date.now())}] Failed to parse order comment:`, e);
21
+ }
22
+ }
23
+
24
+ if (!order.order_id) {
25
+ throw new Error('order_id is required for cancelling order');
26
+ }
27
+
28
+ const response = await cancelOrderApi(credential, {
29
+ pair_id,
30
+ order_id: order.order_id,
31
+ pool_id,
32
+ });
33
+
34
+ if (response.errno !== '0') {
35
+ throw new Error(`Failed to cancel order: ${response.msg}`);
36
+ }
37
+
38
+ console.info(`[${formatTime(Date.now())}] Order ${order.order_id} cancelled successfully`);
39
+ } catch (error) {
40
+ console.error(`[${formatTime(Date.now())}] Error cancelling order:`, error);
41
+ throw error;
42
+ }
43
+ };