@microcosmmoney/portal-react 3.13.0 → 3.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main-portal/components/mining/MiningModal.js +1 -1
- package/dist/main-portal/components/providers/SolanaWalletProvider.js +1 -1
- package/dist/main-portal/components/resources/public-mining-modal.js +1 -1
- package/dist/main-portal/hooks/useAuth.js +3 -2
- package/dist/main-portal/lib/api/index.d.ts +2 -9
- package/dist/main-portal/lib/api/index.js +17 -210
- package/package.json +1 -1
- package/dist/main-portal/hooks/useMarketData.d.ts +0 -9
- package/dist/main-portal/hooks/useMarketData.js +0 -32
- package/dist/main-portal/hooks/usePriceHistory.d.ts +0 -9
- package/dist/main-portal/hooks/usePriceHistory.js +0 -36
- package/dist/main-portal/lib/analytics/hooks.d.ts +0 -139
- package/dist/main-portal/lib/analytics/hooks.js +0 -277
- package/dist/main-portal/lib/analytics/index.d.ts +0 -2
- package/dist/main-portal/lib/analytics/index.js +0 -19
- package/dist/main-portal/lib/analytics/types.d.ts +0 -611
- package/dist/main-portal/lib/analytics/types.js +0 -2
- package/dist/main-portal/lib/api/account.d.ts +0 -39
- package/dist/main-portal/lib/api/account.js +0 -86
- package/dist/main-portal/lib/api/admin.d.ts +0 -78
- package/dist/main-portal/lib/api/admin.js +0 -195
- package/dist/main-portal/lib/api/analytics.d.ts +0 -217
- package/dist/main-portal/lib/api/analytics.js +0 -55
- package/dist/main-portal/lib/api/dexscreener.d.ts +0 -126
- package/dist/main-portal/lib/api/dexscreener.js +0 -139
- package/dist/main-portal/lib/api/geckoterminal.d.ts +0 -10
- package/dist/main-portal/lib/api/geckoterminal.js +0 -43
- package/dist/main-portal/lib/api/mcc-holders.d.ts +0 -130
- package/dist/main-portal/lib/api/mcc-holders.js +0 -47
- package/dist/main-portal/lib/api/org-service-proxy.d.ts +0 -7
- package/dist/main-portal/lib/api/org-service-proxy.js +0 -55
- package/dist/main-portal/lib/api/strategies.d.ts +0 -101
- package/dist/main-portal/lib/api/strategies.js +0 -87
- package/dist/main-portal/lib/exchanges/config.d.ts +0 -34
- package/dist/main-portal/lib/exchanges/config.js +0 -185
- package/dist/main-portal/lib/exchanges/hooks/index.d.ts +0 -5
- package/dist/main-portal/lib/exchanges/hooks/index.js +0 -10
- package/dist/main-portal/lib/exchanges/hooks/useBinanceData.d.ts +0 -15
- package/dist/main-portal/lib/exchanges/hooks/useBinanceData.js +0 -216
- package/dist/main-portal/lib/exchanges/hooks/useBinanceDialogs.d.ts +0 -32
- package/dist/main-portal/lib/exchanges/hooks/useBinanceDialogs.js +0 -395
- package/dist/main-portal/lib/exchanges/hooks/useUserExchanges.d.ts +0 -15
- package/dist/main-portal/lib/exchanges/hooks/useUserExchanges.js +0 -51
- package/dist/main-portal/lib/exchanges/index.d.ts +0 -4
- package/dist/main-portal/lib/exchanges/index.js +0 -21
- package/dist/main-portal/lib/exchanges/types.d.ts +0 -102
- package/dist/main-portal/lib/exchanges/types.js +0 -2
- package/dist/main-portal/lib/exchanges/utils.d.ts +0 -1
- package/dist/main-portal/lib/exchanges/utils.js +0 -10
- package/dist/main-portal/lib/gcp-secrets.d.ts +0 -7
- package/dist/main-portal/lib/gcp-secrets.js +0 -45
- package/dist/main-portal/lib/mockWallet.d.ts +0 -130
- package/dist/main-portal/lib/mockWallet.js +0 -284
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// AI-generated · AI-managed · AI-maintained
|
|
3
|
-
"use client";
|
|
4
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
-
if (k2 === undefined) k2 = k;
|
|
6
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
-
}
|
|
10
|
-
Object.defineProperty(o, k2, desc);
|
|
11
|
-
}) : (function(o, m, k, k2) {
|
|
12
|
-
if (k2 === undefined) k2 = k;
|
|
13
|
-
o[k2] = m[k];
|
|
14
|
-
}));
|
|
15
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
-
}) : function(o, v) {
|
|
18
|
-
o["default"] = v;
|
|
19
|
-
});
|
|
20
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
-
var ownKeys = function(o) {
|
|
22
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
-
var ar = [];
|
|
24
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
-
return ar;
|
|
26
|
-
};
|
|
27
|
-
return ownKeys(o);
|
|
28
|
-
};
|
|
29
|
-
return function (mod) {
|
|
30
|
-
if (mod && mod.__esModule) return mod;
|
|
31
|
-
var result = {};
|
|
32
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
-
__setModuleDefault(result, mod);
|
|
34
|
-
return result;
|
|
35
|
-
};
|
|
36
|
-
})();
|
|
37
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.useBinanceDialogs = useBinanceDialogs;
|
|
39
|
-
const react_1 = require("react");
|
|
40
|
-
const sonner_1 = require("sonner");
|
|
41
|
-
const api_service_1 = require("../../api-service");
|
|
42
|
-
const auth_service_1 = require("../../auth-service");
|
|
43
|
-
const order_id_generator_1 = require("../../order-id-generator");
|
|
44
|
-
function detectPlatform() {
|
|
45
|
-
if (typeof window === 'undefined')
|
|
46
|
-
return 'web';
|
|
47
|
-
const ua = navigator.userAgent.toLowerCase();
|
|
48
|
-
if (ua.includes('android'))
|
|
49
|
-
return 'android';
|
|
50
|
-
if (ua.includes('iphone') || ua.includes('ipad'))
|
|
51
|
-
return 'ios';
|
|
52
|
-
return 'web';
|
|
53
|
-
}
|
|
54
|
-
function useBinanceDialogs(fetchData) {
|
|
55
|
-
const [dialogOpen, setDialogOpen] = (0, react_1.useState)(false);
|
|
56
|
-
const [dialogType, setDialogType] = (0, react_1.useState)(null);
|
|
57
|
-
const [selectedOrder, setSelectedOrder] = (0, react_1.useState)(null);
|
|
58
|
-
const [selectedPosition, setSelectedPosition] = (0, react_1.useState)(null);
|
|
59
|
-
const [dialogLoading, setDialogLoading] = (0, react_1.useState)(false);
|
|
60
|
-
const [cleanupSymbol, setCleanupSymbol] = (0, react_1.useState)('');
|
|
61
|
-
const [cleanupPreview, setCleanupPreview] = (0, react_1.useState)(null);
|
|
62
|
-
const [cleanupLoading, setCleanupLoading] = (0, react_1.useState)(false);
|
|
63
|
-
const [cleanupJobId, setCleanupJobId] = (0, react_1.useState)(null);
|
|
64
|
-
const [cleanupProgress, setCleanupProgress] = (0, react_1.useState)(null);
|
|
65
|
-
const [inputPrice, setInputPrice] = (0, react_1.useState)('');
|
|
66
|
-
const [inputQuantity, setInputQuantity] = (0, react_1.useState)('');
|
|
67
|
-
const [orderType, setOrderType] = (0, react_1.useState)('MARKET');
|
|
68
|
-
const handleCloseDialog = (0, react_1.useCallback)(() => {
|
|
69
|
-
setDialogOpen(false);
|
|
70
|
-
setDialogType(null);
|
|
71
|
-
setSelectedOrder(null);
|
|
72
|
-
setSelectedPosition(null);
|
|
73
|
-
setInputPrice('');
|
|
74
|
-
setInputQuantity('');
|
|
75
|
-
setOrderType('MARKET');
|
|
76
|
-
setDialogLoading(false);
|
|
77
|
-
setCleanupSymbol('');
|
|
78
|
-
setCleanupPreview(null);
|
|
79
|
-
}, []);
|
|
80
|
-
const handleOpenCancelDialog = (0, react_1.useCallback)((order) => {
|
|
81
|
-
setSelectedOrder(order);
|
|
82
|
-
setDialogType('cancel');
|
|
83
|
-
setDialogOpen(true);
|
|
84
|
-
}, []);
|
|
85
|
-
const handleOpenModifyDialog = (0, react_1.useCallback)((order) => {
|
|
86
|
-
setSelectedOrder(order);
|
|
87
|
-
setInputPrice(order.price.toString());
|
|
88
|
-
setDialogType('modify');
|
|
89
|
-
setDialogOpen(true);
|
|
90
|
-
}, []);
|
|
91
|
-
const handleOpenAddDialog = (0, react_1.useCallback)((position) => {
|
|
92
|
-
setSelectedPosition(position);
|
|
93
|
-
setInputQuantity('');
|
|
94
|
-
setDialogType('add');
|
|
95
|
-
setDialogOpen(true);
|
|
96
|
-
}, []);
|
|
97
|
-
const handleOpenCloseDialog = (0, react_1.useCallback)((position) => {
|
|
98
|
-
setSelectedPosition(position);
|
|
99
|
-
setInputQuantity(position.amount.toString());
|
|
100
|
-
setDialogType('close');
|
|
101
|
-
setDialogOpen(true);
|
|
102
|
-
}, []);
|
|
103
|
-
const handleOpenCleanupDialog = (0, react_1.useCallback)(async (symbol) => {
|
|
104
|
-
setCleanupSymbol(symbol);
|
|
105
|
-
setDialogType('cleanup');
|
|
106
|
-
setDialogOpen(true);
|
|
107
|
-
setCleanupLoading(true);
|
|
108
|
-
try {
|
|
109
|
-
const { getCurrentUserToken } = await Promise.resolve().then(() => __importStar(require('../../auth-service')));
|
|
110
|
-
const token = await getCurrentUserToken();
|
|
111
|
-
if (!token) {
|
|
112
|
-
sonner_1.toast.error("用户未登录");
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const res = (0, auth_service_1.guardAuthResponse)(await fetch(`/api/exchanges/binance/orders/cleanup/preview?symbol=${symbol}&priceBuffer=0.005`, {
|
|
116
|
-
headers: { 'Authorization': `Bearer ${token}` }
|
|
117
|
-
}));
|
|
118
|
-
if (res.ok) {
|
|
119
|
-
const data = await res.json();
|
|
120
|
-
setCleanupPreview(data.data);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
const errorData = await res.json();
|
|
124
|
-
throw new Error(errorData.error || '获取预览失败');
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '获取预览失败');
|
|
129
|
-
handleCloseDialog();
|
|
130
|
-
}
|
|
131
|
-
finally {
|
|
132
|
-
setCleanupLoading(false);
|
|
133
|
-
}
|
|
134
|
-
}, [handleCloseDialog]);
|
|
135
|
-
const pollCleanupStatus = (0, react_1.useCallback)(async (jobId, token) => {
|
|
136
|
-
const pollInterval = 2000;
|
|
137
|
-
const maxPolls = 300;
|
|
138
|
-
for (let i = 0; i < maxPolls; i++) {
|
|
139
|
-
try {
|
|
140
|
-
const res = (0, auth_service_1.guardAuthResponse)(await fetch(`/api/exchanges/binance/orders/cleanup/status?jobId=${jobId}`, {
|
|
141
|
-
headers: { 'Authorization': `Bearer ${token}` }
|
|
142
|
-
}));
|
|
143
|
-
if (!res.ok) {
|
|
144
|
-
const errorData = await res.json();
|
|
145
|
-
throw new Error(errorData.error || '获取状态失败');
|
|
146
|
-
}
|
|
147
|
-
const data = await res.json();
|
|
148
|
-
const progress = data.data;
|
|
149
|
-
setCleanupProgress(progress);
|
|
150
|
-
if (progress.status === 'completed') {
|
|
151
|
-
const result = progress.result;
|
|
152
|
-
const totalMerged = (result?.LONG?.tp_merged || 0) + (result?.SHORT?.tp_merged || 0);
|
|
153
|
-
const totalDeleted = (result?.LONG?.open_deleted || 0) + (result?.SHORT?.open_deleted || 0);
|
|
154
|
-
sonner_1.toast.success(`订单整理完成: 合并${totalMerged}个止盈, 删除${totalDeleted}个开仓`);
|
|
155
|
-
setCleanupJobId(null);
|
|
156
|
-
setCleanupProgress(null);
|
|
157
|
-
handleCloseDialog();
|
|
158
|
-
fetchData();
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (progress.status === 'failed') {
|
|
162
|
-
throw new Error(progress.error || '任务执行失败');
|
|
163
|
-
}
|
|
164
|
-
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
165
|
-
}
|
|
166
|
-
catch (err) {
|
|
167
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '获取状态失败');
|
|
168
|
-
setCleanupJobId(null);
|
|
169
|
-
setCleanupProgress(null);
|
|
170
|
-
setDialogLoading(false);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
sonner_1.toast.error('任务超时,请检查订单状态');
|
|
175
|
-
setCleanupJobId(null);
|
|
176
|
-
setCleanupProgress(null);
|
|
177
|
-
setDialogLoading(false);
|
|
178
|
-
}, [fetchData, handleCloseDialog]);
|
|
179
|
-
const handleExecuteCleanup = (0, react_1.useCallback)(async () => {
|
|
180
|
-
if (!cleanupSymbol)
|
|
181
|
-
return;
|
|
182
|
-
setDialogLoading(true);
|
|
183
|
-
setCleanupProgress(null);
|
|
184
|
-
try {
|
|
185
|
-
const { getCurrentUserToken } = await Promise.resolve().then(() => __importStar(require('../../auth-service')));
|
|
186
|
-
const token = await getCurrentUserToken();
|
|
187
|
-
if (!token) {
|
|
188
|
-
sonner_1.toast.error("用户未登录");
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const res = (0, auth_service_1.guardAuthResponse)(await fetch('/api/exchanges/binance/orders/cleanup', {
|
|
192
|
-
method: 'POST',
|
|
193
|
-
headers: {
|
|
194
|
-
'Authorization': `Bearer ${token}`,
|
|
195
|
-
'Content-Type': 'application/json'
|
|
196
|
-
},
|
|
197
|
-
body: JSON.stringify({ symbol: cleanupSymbol, priceBuffer: 0.005 })
|
|
198
|
-
}));
|
|
199
|
-
if (res.ok) {
|
|
200
|
-
const data = await res.json();
|
|
201
|
-
const jobId = data.jobId;
|
|
202
|
-
if (jobId) {
|
|
203
|
-
setCleanupJobId(jobId);
|
|
204
|
-
sonner_1.toast.info('任务已提交,正在执行...');
|
|
205
|
-
pollCleanupStatus(jobId, token);
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
throw new Error('未获取到任务ID');
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
const errorData = await res.json();
|
|
213
|
-
throw new Error(errorData.error || '执行整理失败');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
catch (err) {
|
|
217
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '执行整理失败');
|
|
218
|
-
setDialogLoading(false);
|
|
219
|
-
}
|
|
220
|
-
}, [cleanupSymbol, pollCleanupStatus]);
|
|
221
|
-
const handleCancelOrder = (0, react_1.useCallback)(async () => {
|
|
222
|
-
if (!selectedOrder)
|
|
223
|
-
return;
|
|
224
|
-
setDialogLoading(true);
|
|
225
|
-
try {
|
|
226
|
-
const result = await (0, api_service_1.cancelBinanceOrder)(selectedOrder.symbol, selectedOrder.clientOrderId || selectedOrder.orderId);
|
|
227
|
-
if (result.success) {
|
|
228
|
-
sonner_1.toast.success(`订单 ${selectedOrder.orderId} 已成功取消`);
|
|
229
|
-
handleCloseDialog();
|
|
230
|
-
fetchData();
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
throw new Error(result.error || '撤单失败');
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
catch (err) {
|
|
237
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '撤单失败');
|
|
238
|
-
}
|
|
239
|
-
finally {
|
|
240
|
-
setDialogLoading(false);
|
|
241
|
-
}
|
|
242
|
-
}, [selectedOrder, fetchData, handleCloseDialog]);
|
|
243
|
-
const handleModifyOrder = (0, react_1.useCallback)(async () => {
|
|
244
|
-
if (!selectedOrder || !inputPrice)
|
|
245
|
-
return;
|
|
246
|
-
const newPrice = parseFloat(inputPrice);
|
|
247
|
-
if (isNaN(newPrice) || newPrice <= 0) {
|
|
248
|
-
sonner_1.toast.error("请输入有效的价格");
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
setDialogLoading(true);
|
|
252
|
-
try {
|
|
253
|
-
const result = await (0, api_service_1.modifyBinanceOrder)(selectedOrder.symbol, selectedOrder.clientOrderId || selectedOrder.orderId, newPrice);
|
|
254
|
-
if (result.success) {
|
|
255
|
-
sonner_1.toast.success(`订单价格已修改为 ${newPrice}`);
|
|
256
|
-
handleCloseDialog();
|
|
257
|
-
fetchData();
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
throw new Error(result.error || '追单失败');
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
catch (err) {
|
|
264
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '追单失败');
|
|
265
|
-
}
|
|
266
|
-
finally {
|
|
267
|
-
setDialogLoading(false);
|
|
268
|
-
}
|
|
269
|
-
}, [selectedOrder, inputPrice, fetchData, handleCloseDialog]);
|
|
270
|
-
const handleAddPosition = (0, react_1.useCallback)(async () => {
|
|
271
|
-
if (!selectedPosition || !inputQuantity)
|
|
272
|
-
return;
|
|
273
|
-
const quantity = parseFloat(inputQuantity);
|
|
274
|
-
if (isNaN(quantity) || quantity <= 0) {
|
|
275
|
-
sonner_1.toast.error("请输入有效的数量");
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
if (orderType === 'LIMIT') {
|
|
279
|
-
const price = parseFloat(inputPrice);
|
|
280
|
-
if (isNaN(price) || price <= 0) {
|
|
281
|
-
sonner_1.toast.error("请输入有效的价格");
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
setDialogLoading(true);
|
|
286
|
-
try {
|
|
287
|
-
const side = selectedPosition.side === 'LONG' ? 'BUY' : 'SELL';
|
|
288
|
-
const positionSide = selectedPosition.side;
|
|
289
|
-
const clientOrderId = (0, order_id_generator_1.generateUserOrderId)(detectPlatform(), 'add');
|
|
290
|
-
const result = await (0, api_service_1.placeBinanceOrder)({
|
|
291
|
-
symbol: selectedPosition.symbol,
|
|
292
|
-
side: side,
|
|
293
|
-
positionSide: positionSide,
|
|
294
|
-
quantity: quantity,
|
|
295
|
-
orderType: orderType,
|
|
296
|
-
price: orderType === 'LIMIT' ? parseFloat(inputPrice) : undefined,
|
|
297
|
-
clientOrderId: clientOrderId
|
|
298
|
-
});
|
|
299
|
-
if (result.success) {
|
|
300
|
-
const orderTypeText = orderType === 'MARKET' ? '市价' : '限价';
|
|
301
|
-
sonner_1.toast.success(`${selectedPosition.symbol} ${positionSide} ${orderTypeText}开仓 ${quantity}`);
|
|
302
|
-
handleCloseDialog();
|
|
303
|
-
fetchData();
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
throw new Error(result.error || '开仓失败');
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
catch (err) {
|
|
310
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '开仓失败');
|
|
311
|
-
}
|
|
312
|
-
finally {
|
|
313
|
-
setDialogLoading(false);
|
|
314
|
-
}
|
|
315
|
-
}, [selectedPosition, inputQuantity, inputPrice, orderType, fetchData, handleCloseDialog]);
|
|
316
|
-
const handleClosePosition = (0, react_1.useCallback)(async () => {
|
|
317
|
-
if (!selectedPosition || !inputQuantity)
|
|
318
|
-
return;
|
|
319
|
-
const quantity = parseFloat(inputQuantity);
|
|
320
|
-
if (isNaN(quantity) || quantity <= 0) {
|
|
321
|
-
sonner_1.toast.error("请输入有效的数量");
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
if (quantity > selectedPosition.amount) {
|
|
325
|
-
sonner_1.toast.error(`平仓数量不能大于持仓数量 ${selectedPosition.amount}`);
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (orderType === 'LIMIT') {
|
|
329
|
-
const price = parseFloat(inputPrice);
|
|
330
|
-
if (isNaN(price) || price <= 0) {
|
|
331
|
-
sonner_1.toast.error("请输入有效的价格");
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
setDialogLoading(true);
|
|
336
|
-
try {
|
|
337
|
-
const side = selectedPosition.side === 'LONG' ? 'SELL' : 'BUY';
|
|
338
|
-
const positionSide = selectedPosition.side;
|
|
339
|
-
const clientOrderId = (0, order_id_generator_1.generateUserOrderId)(detectPlatform(), 'close');
|
|
340
|
-
const result = await (0, api_service_1.placeBinanceOrder)({
|
|
341
|
-
symbol: selectedPosition.symbol,
|
|
342
|
-
side: side,
|
|
343
|
-
positionSide: positionSide,
|
|
344
|
-
quantity: quantity,
|
|
345
|
-
orderType: orderType,
|
|
346
|
-
price: orderType === 'LIMIT' ? parseFloat(inputPrice) : undefined,
|
|
347
|
-
clientOrderId: clientOrderId
|
|
348
|
-
});
|
|
349
|
-
if (result.success) {
|
|
350
|
-
const orderTypeText = orderType === 'MARKET' ? '市价' : '限价';
|
|
351
|
-
sonner_1.toast.success(`${selectedPosition.symbol} ${positionSide} ${orderTypeText}平仓 ${quantity}`);
|
|
352
|
-
handleCloseDialog();
|
|
353
|
-
fetchData();
|
|
354
|
-
}
|
|
355
|
-
else {
|
|
356
|
-
throw new Error(result.error || '平仓失败');
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
catch (err) {
|
|
360
|
-
sonner_1.toast.error(err instanceof Error ? err.message : '平仓失败');
|
|
361
|
-
}
|
|
362
|
-
finally {
|
|
363
|
-
setDialogLoading(false);
|
|
364
|
-
}
|
|
365
|
-
}, [selectedPosition, inputQuantity, inputPrice, orderType, fetchData, handleCloseDialog]);
|
|
366
|
-
return {
|
|
367
|
-
dialogOpen,
|
|
368
|
-
dialogType,
|
|
369
|
-
selectedOrder,
|
|
370
|
-
selectedPosition,
|
|
371
|
-
dialogLoading,
|
|
372
|
-
inputPrice,
|
|
373
|
-
inputQuantity,
|
|
374
|
-
orderType,
|
|
375
|
-
cleanupSymbol,
|
|
376
|
-
cleanupPreview,
|
|
377
|
-
cleanupLoading,
|
|
378
|
-
cleanupJobId,
|
|
379
|
-
cleanupProgress,
|
|
380
|
-
setInputPrice,
|
|
381
|
-
setInputQuantity,
|
|
382
|
-
setOrderType,
|
|
383
|
-
handleOpenCancelDialog,
|
|
384
|
-
handleOpenModifyDialog,
|
|
385
|
-
handleOpenAddDialog,
|
|
386
|
-
handleOpenCloseDialog,
|
|
387
|
-
handleOpenCleanupDialog,
|
|
388
|
-
handleCloseDialog,
|
|
389
|
-
handleCancelOrder,
|
|
390
|
-
handleModifyOrder,
|
|
391
|
-
handleAddPosition,
|
|
392
|
-
handleClosePosition,
|
|
393
|
-
handleExecuteCleanup
|
|
394
|
-
};
|
|
395
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export interface UserExchangeAccount {
|
|
2
|
-
exchangeId: string;
|
|
3
|
-
exchangeName: string;
|
|
4
|
-
accountName: string;
|
|
5
|
-
displayName: string;
|
|
6
|
-
status: 'active' | 'inactive' | 'error';
|
|
7
|
-
}
|
|
8
|
-
export declare function useUserExchanges(): {
|
|
9
|
-
boundExchanges: string[];
|
|
10
|
-
isExchangeBound: (exchangeId: string) => boolean;
|
|
11
|
-
isSelectedExchangeAvailable: (selectedExchange: string) => boolean;
|
|
12
|
-
isLoading: boolean;
|
|
13
|
-
error: any;
|
|
14
|
-
refresh: import("swr").KeyedMutator<string[]>;
|
|
15
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// AI-generated · AI-managed · AI-maintained
|
|
3
|
-
'use client';
|
|
4
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
-
};
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.useUserExchanges = useUserExchanges;
|
|
9
|
-
const swr_1 = __importDefault(require("swr"));
|
|
10
|
-
const core_1 = require("../../api/core");
|
|
11
|
-
function transformResponse(response) {
|
|
12
|
-
if (!response.success || !response.data?.exchanges) {
|
|
13
|
-
return [];
|
|
14
|
-
}
|
|
15
|
-
const boundExchanges = [];
|
|
16
|
-
for (const [exchangeId, exchangeData] of Object.entries(response.data.exchanges)) {
|
|
17
|
-
const hasActiveAccount = Object.values(exchangeData.accounts || {}).some(account => account.status === 'active');
|
|
18
|
-
if (hasActiveAccount) {
|
|
19
|
-
boundExchanges.push(exchangeId.toLowerCase());
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return boundExchanges;
|
|
23
|
-
}
|
|
24
|
-
function useUserExchanges() {
|
|
25
|
-
const { data, error, isLoading, mutate } = (0, swr_1.default)('/account/exchanges', async (url) => {
|
|
26
|
-
const response = await (0, core_1.fetchApi)(url);
|
|
27
|
-
return transformResponse(response);
|
|
28
|
-
}, {
|
|
29
|
-
revalidateOnFocus: false,
|
|
30
|
-
revalidateOnReconnect: false,
|
|
31
|
-
dedupingInterval: 60000,
|
|
32
|
-
});
|
|
33
|
-
const isExchangeBound = (exchangeId) => {
|
|
34
|
-
if (!data)
|
|
35
|
-
return false;
|
|
36
|
-
return data.includes(exchangeId.toLowerCase());
|
|
37
|
-
};
|
|
38
|
-
const isSelectedExchangeAvailable = (selectedExchange) => {
|
|
39
|
-
if (selectedExchange === 'all')
|
|
40
|
-
return true;
|
|
41
|
-
return isExchangeBound(selectedExchange);
|
|
42
|
-
};
|
|
43
|
-
return {
|
|
44
|
-
boundExchanges: data || [],
|
|
45
|
-
isExchangeBound,
|
|
46
|
-
isSelectedExchangeAvailable,
|
|
47
|
-
isLoading,
|
|
48
|
-
error,
|
|
49
|
-
refresh: mutate,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
// AI-generated · AI-managed · AI-maintained
|
|
18
|
-
__exportStar(require("./types"), exports);
|
|
19
|
-
__exportStar(require("./config"), exports);
|
|
20
|
-
__exportStar(require("./utils"), exports);
|
|
21
|
-
__exportStar(require("./hooks"), exports);
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
export interface AccountBalance {
|
|
2
|
-
asset: string;
|
|
3
|
-
balance: number;
|
|
4
|
-
availableBalance: number;
|
|
5
|
-
unrealizedProfit: number;
|
|
6
|
-
}
|
|
7
|
-
export interface Position {
|
|
8
|
-
symbol: string;
|
|
9
|
-
side: "LONG" | "SHORT";
|
|
10
|
-
amount: number;
|
|
11
|
-
entryPrice: number;
|
|
12
|
-
markPrice: number;
|
|
13
|
-
liquidationPrice: number;
|
|
14
|
-
unrealizedProfit: number;
|
|
15
|
-
leverage: number;
|
|
16
|
-
}
|
|
17
|
-
export interface OpenOrder {
|
|
18
|
-
orderId: string;
|
|
19
|
-
symbol: string;
|
|
20
|
-
side: string;
|
|
21
|
-
type: string;
|
|
22
|
-
price: number;
|
|
23
|
-
quantity: number;
|
|
24
|
-
filled: number;
|
|
25
|
-
status: string;
|
|
26
|
-
time: string;
|
|
27
|
-
clientOrderId?: string;
|
|
28
|
-
}
|
|
29
|
-
export interface Trade {
|
|
30
|
-
id: string;
|
|
31
|
-
orderId: string;
|
|
32
|
-
symbol: string;
|
|
33
|
-
side: string;
|
|
34
|
-
price: number;
|
|
35
|
-
quantity: number;
|
|
36
|
-
realizedPnl: number;
|
|
37
|
-
commission: number;
|
|
38
|
-
time: number;
|
|
39
|
-
isMaker: boolean;
|
|
40
|
-
}
|
|
41
|
-
export interface GroupedPosition {
|
|
42
|
-
symbol: string;
|
|
43
|
-
longPosition?: Position;
|
|
44
|
-
shortPosition?: Position;
|
|
45
|
-
totalUnrealizedProfit: number;
|
|
46
|
-
orders: OpenOrder[];
|
|
47
|
-
}
|
|
48
|
-
export interface GroupedOrders {
|
|
49
|
-
symbol: string;
|
|
50
|
-
orders: OpenOrder[];
|
|
51
|
-
totalQuantity: number;
|
|
52
|
-
}
|
|
53
|
-
export interface GroupedTrades {
|
|
54
|
-
symbol: string;
|
|
55
|
-
trades: Trade[];
|
|
56
|
-
totalRealizedPnl: number;
|
|
57
|
-
totalVolume: number;
|
|
58
|
-
}
|
|
59
|
-
export interface CleanupProgress {
|
|
60
|
-
status: string;
|
|
61
|
-
phase: string;
|
|
62
|
-
total_operations: number;
|
|
63
|
-
completed_operations: number;
|
|
64
|
-
current_operation: string;
|
|
65
|
-
result?: {
|
|
66
|
-
LONG?: {
|
|
67
|
-
tp_merged: number;
|
|
68
|
-
open_deleted: number;
|
|
69
|
-
};
|
|
70
|
-
SHORT?: {
|
|
71
|
-
tp_merged: number;
|
|
72
|
-
open_deleted: number;
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
|
-
error?: string;
|
|
76
|
-
}
|
|
77
|
-
export interface CleanupPreview {
|
|
78
|
-
LONG?: {
|
|
79
|
-
tp_orders?: {
|
|
80
|
-
before: number;
|
|
81
|
-
after: number;
|
|
82
|
-
merge_count: number;
|
|
83
|
-
};
|
|
84
|
-
open_orders?: {
|
|
85
|
-
before: number;
|
|
86
|
-
after: number;
|
|
87
|
-
delete_count: number;
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
SHORT?: {
|
|
91
|
-
tp_orders?: {
|
|
92
|
-
before: number;
|
|
93
|
-
after: number;
|
|
94
|
-
merge_count: number;
|
|
95
|
-
};
|
|
96
|
-
open_orders?: {
|
|
97
|
-
before: number;
|
|
98
|
-
after: number;
|
|
99
|
-
delete_count: number;
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function formatNumber(value: number, decimals?: number): string;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatNumber = formatNumber;
|
|
4
|
-
// AI-generated · AI-managed · AI-maintained
|
|
5
|
-
function formatNumber(value, decimals = 2) {
|
|
6
|
-
return value.toLocaleString('en-US', {
|
|
7
|
-
minimumFractionDigits: decimals,
|
|
8
|
-
maximumFractionDigits: decimals
|
|
9
|
-
});
|
|
10
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read secrets from GCP Secret Manager via REST API (Workload Identity).
|
|
3
|
-
* Zero external dependencies — uses native fetch + GKE metadata API.
|
|
4
|
-
* Falls back to process.env for local development.
|
|
5
|
-
*/
|
|
6
|
-
export declare function getSecret(secretId: string, envFallback?: string): Promise<string>;
|
|
7
|
-
export declare function getGeminiApiKey(): Promise<string>;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Read secrets from GCP Secret Manager via REST API (Workload Identity).
|
|
4
|
-
* Zero external dependencies — uses native fetch + GKE metadata API.
|
|
5
|
-
* Falls back to process.env for local development.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.getSecret = getSecret;
|
|
9
|
-
exports.getGeminiApiKey = getGeminiApiKey;
|
|
10
|
-
const GCP_PROJECT = process.env.GCP_PROJECT_ID || 'double-helix-9f030';
|
|
11
|
-
const cache = {};
|
|
12
|
-
async function getSecret(secretId, envFallback) {
|
|
13
|
-
if (cache[secretId])
|
|
14
|
-
return cache[secretId];
|
|
15
|
-
try {
|
|
16
|
-
// Get access token from GKE metadata server (Workload Identity)
|
|
17
|
-
const tokenRes = await fetch('http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token', { headers: { 'Metadata-Flavor': 'Google' } });
|
|
18
|
-
if (!tokenRes.ok)
|
|
19
|
-
throw new Error(`Metadata token: ${tokenRes.status}`);
|
|
20
|
-
const { access_token } = await tokenRes.json();
|
|
21
|
-
// Fetch secret from Secret Manager REST API
|
|
22
|
-
const secretRes = await fetch(`https://secretmanager.googleapis.com/v1/projects/${GCP_PROJECT}/secrets/${secretId}/versions/latest:access`, { headers: { Authorization: `Bearer ${access_token}` } });
|
|
23
|
-
if (!secretRes.ok)
|
|
24
|
-
throw new Error(`Secret Manager: ${secretRes.status}`);
|
|
25
|
-
const data = await secretRes.json();
|
|
26
|
-
const value = Buffer.from(data.payload.data, 'base64').toString('utf-8').trim();
|
|
27
|
-
cache[secretId] = value;
|
|
28
|
-
console.log(`[gcp-secrets] Loaded '${secretId}' from Secret Manager`);
|
|
29
|
-
return value;
|
|
30
|
-
}
|
|
31
|
-
catch (e) {
|
|
32
|
-
console.warn(`[gcp-secrets] Fallback to env for '${secretId}':`, e instanceof Error ? e.message : e);
|
|
33
|
-
}
|
|
34
|
-
const value = envFallback ?? '';
|
|
35
|
-
cache[secretId] = value;
|
|
36
|
-
return value;
|
|
37
|
-
}
|
|
38
|
-
/** Pre-cached Gemini API key. Call initSecrets() at startup or use getGeminiApiKey(). */
|
|
39
|
-
let _geminiKey = null;
|
|
40
|
-
async function getGeminiApiKey() {
|
|
41
|
-
if (_geminiKey !== null)
|
|
42
|
-
return _geminiKey;
|
|
43
|
-
_geminiKey = await getSecret('gemini-api-key', process.env.GEMINI_API_KEY || '');
|
|
44
|
-
return _geminiKey;
|
|
45
|
-
}
|