@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.
- package/.rush/temp/chunked-rush-logs/vendor-turboflow.build.chunks.jsonl +6 -6
- package/.rush/temp/operation/build/all.log +6 -6
- package/.rush/temp/operation/build/log-chunks.jsonl +6 -6
- package/.rush/temp/operation/build/state.json +1 -1
- package/.rush/temp/shrinkwrap-deps.json +1 -1
- package/CHANGELOG.json +17 -0
- package/CHANGELOG.md +8 -1
- package/README.md +134 -0
- package/lib/api/private-api.d.ts +2 -2
- package/lib/api/private-api.d.ts.map +1 -1
- package/lib/api/private-api.js +12 -15
- package/lib/api/private-api.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -1
- package/lib/services/account-actions-with-credential.d.ts +2 -0
- package/lib/services/account-actions-with-credential.d.ts.map +1 -0
- package/lib/services/account-actions-with-credential.js +60 -0
- package/lib/services/account-actions-with-credential.js.map +1 -0
- package/lib/services/order-actions-with-credential.d.ts +2 -0
- package/lib/services/order-actions-with-credential.d.ts.map +1 -0
- package/lib/services/order-actions-with-credential.js +25 -0
- package/lib/services/order-actions-with-credential.js.map +1 -0
- package/lib/services/orders/cancelOrder.d.ts +4 -0
- package/lib/services/orders/cancelOrder.d.ts.map +1 -0
- package/lib/services/orders/cancelOrder.js +42 -0
- package/lib/services/orders/cancelOrder.js.map +1 -0
- package/lib/services/orders/listOrders.d.ts +7 -0
- package/lib/services/orders/listOrders.d.ts.map +1 -0
- package/lib/services/orders/listOrders.js +78 -0
- package/lib/services/orders/listOrders.js.map +1 -0
- package/lib/services/orders/modifyOrder.d.ts +4 -0
- package/lib/services/orders/modifyOrder.d.ts.map +1 -0
- package/lib/services/orders/modifyOrder.js +46 -0
- package/lib/services/orders/modifyOrder.js.map +1 -0
- package/lib/services/orders/submitOrder.d.ts +6 -0
- package/lib/services/orders/submitOrder.d.ts.map +1 -0
- package/lib/services/orders/submitOrder.js +61 -0
- package/lib/services/orders/submitOrder.js.map +1 -0
- package/package.json +3 -1
- package/rush-logs/vendor-turboflow.build.log +6 -6
- package/src/api/private-api.ts +25 -18
- package/src/index.ts +3 -0
- package/src/services/account-actions-with-credential.ts +76 -0
- package/src/services/order-actions-with-credential.ts +30 -0
- package/src/services/orders/cancelOrder.ts +43 -0
- package/src/services/orders/listOrders.ts +84 -0
- package/src/services/orders/modifyOrder.ts +46 -0
- package/src/services/orders/submitOrder.ts +63 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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.
|
|
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 (
|
|
12
|
+
---- Compile finished (3001ms) ----
|
|
13
13
|
---- Bundle started ----
|
|
14
|
-
---- Bundle finished (
|
|
14
|
+
---- Bundle finished (2ms) ----
|
|
15
15
|
---- Post-build started ----
|
|
16
16
|
---- Post-build finished (0ms) ----
|
|
17
17
|
---- Test started ----
|
|
18
|
-
---- Test finished (
|
|
19
|
-
-------------------- Finished (
|
|
20
|
-
Project: @yuants/vendor-turboflow@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-
|
|
23
|
+
2025-11-25T11:54:42.712Z no Dockerfile found, skip building docker image
|
package/src/api/private-api.ts
CHANGED
|
@@ -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 (
|
|
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
|
-
|
|
37
|
+
// 除了 host 之外的所有内容
|
|
38
|
+
const _path = url.pathname + url.search;
|
|
39
|
+
|
|
40
|
+
const data =
|
|
41
|
+
`method=${method}&path=${_path}×tamp=${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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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,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
|
+
};
|