@one_deploy/sdk 1.0.2 → 1.0.4

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 (70) hide show
  1. package/package.json +1 -1
  2. package/src/components/OneSwapWidget.tsx +1 -1
  3. package/src/components/ai/OneChainSelector.tsx +183 -0
  4. package/src/components/ai/OneCycleSelector.tsx +187 -0
  5. package/src/components/ai/OnePairSelector.tsx +181 -0
  6. package/src/components/ai/OneTierSelector.tsx +187 -0
  7. package/src/components/ai/index.ts +17 -0
  8. package/src/components/index.ts +3 -0
  9. package/src/config/index.ts +1 -1
  10. package/src/hooks/index.ts +20 -0
  11. package/src/hooks/useAITrading.ts +444 -0
  12. package/src/index.ts +20 -0
  13. package/src/react-native.ts +23 -0
  14. package/src/services/engine.ts +184 -0
  15. package/src/services/index.ts +16 -0
  16. package/src/services/usage.ts +249 -0
  17. package/.turbo/turbo-build.log +0 -0
  18. package/.turbo/turbo-type-check.log +0 -0
  19. package/dist/config/index.d.mts +0 -74
  20. package/dist/config/index.d.ts +0 -74
  21. package/dist/config/index.js +0 -244
  22. package/dist/config/index.js.map +0 -1
  23. package/dist/config/index.mjs +0 -226
  24. package/dist/config/index.mjs.map +0 -1
  25. package/dist/engine-5ndtBaCr.d.ts +0 -1039
  26. package/dist/engine-CrlhH0nw.d.mts +0 -1039
  27. package/dist/hooks/index.d.mts +0 -56
  28. package/dist/hooks/index.d.ts +0 -56
  29. package/dist/hooks/index.js +0 -1360
  30. package/dist/hooks/index.js.map +0 -1
  31. package/dist/hooks/index.mjs +0 -1356
  32. package/dist/hooks/index.mjs.map +0 -1
  33. package/dist/index.d.mts +0 -356
  34. package/dist/index.d.ts +0 -356
  35. package/dist/index.js +0 -5069
  36. package/dist/index.js.map +0 -1
  37. package/dist/index.mjs +0 -4950
  38. package/dist/index.mjs.map +0 -1
  39. package/dist/price-CgqXPnT3.d.ts +0 -13
  40. package/dist/price-ClbLHHjv.d.mts +0 -13
  41. package/dist/providers/index.d.mts +0 -121
  42. package/dist/providers/index.d.ts +0 -121
  43. package/dist/providers/index.js +0 -1643
  44. package/dist/providers/index.js.map +0 -1
  45. package/dist/providers/index.mjs +0 -1601
  46. package/dist/providers/index.mjs.map +0 -1
  47. package/dist/react-native.d.mts +0 -120
  48. package/dist/react-native.d.ts +0 -120
  49. package/dist/react-native.js +0 -1794
  50. package/dist/react-native.js.map +0 -1
  51. package/dist/react-native.mjs +0 -1757
  52. package/dist/react-native.mjs.map +0 -1
  53. package/dist/services/index.d.mts +0 -85
  54. package/dist/services/index.d.ts +0 -85
  55. package/dist/services/index.js +0 -1466
  56. package/dist/services/index.js.map +0 -1
  57. package/dist/services/index.mjs +0 -1458
  58. package/dist/services/index.mjs.map +0 -1
  59. package/dist/types/index.d.mts +0 -759
  60. package/dist/types/index.d.ts +0 -759
  61. package/dist/types/index.js +0 -4
  62. package/dist/types/index.js.map +0 -1
  63. package/dist/types/index.mjs +0 -3
  64. package/dist/types/index.mjs.map +0 -1
  65. package/dist/utils/index.d.mts +0 -36
  66. package/dist/utils/index.d.ts +0 -36
  67. package/dist/utils/index.js +0 -164
  68. package/dist/utils/index.js.map +0 -1
  69. package/dist/utils/index.mjs +0 -142
  70. package/dist/utils/index.mjs.map +0 -1
@@ -0,0 +1,187 @@
1
+ /**
2
+ * OneTierSelector - Investment tier selection component for AI trading
3
+ * Part of ONE Ecosystem SDK - can be used by any ecosystem partner
4
+ */
5
+
6
+ import React from 'react';
7
+ import { View, Text, StyleSheet, TouchableOpacity, ViewStyle, TextStyle } from 'react-native';
8
+
9
+ export interface Tier {
10
+ tier: number;
11
+ amount: number;
12
+ label: string;
13
+ label_zh?: string;
14
+ }
15
+
16
+ export interface OneTierSelectorProps {
17
+ /** Available investment tiers */
18
+ tiers: Tier[];
19
+ /** Currently selected tier */
20
+ selectedTier: Tier | null;
21
+ /** Callback when tier selection changes */
22
+ onSelectTier: (tier: Tier) => void;
23
+ /** Accent color for selected state */
24
+ accentColor?: string;
25
+ /** Section title */
26
+ title?: string;
27
+ /** Section subtitle */
28
+ subtitle?: string;
29
+ /** Show recommended badge on middle tier */
30
+ showRecommended?: boolean;
31
+ /** Recommended label text */
32
+ recommendedLabel?: string;
33
+ /** Use Chinese labels */
34
+ useZhLabels?: boolean;
35
+ /** Custom styles */
36
+ style?: ViewStyle;
37
+ /** Custom title style */
38
+ titleStyle?: TextStyle;
39
+ }
40
+
41
+ export const OneTierSelector: React.FC<OneTierSelectorProps> = ({
42
+ tiers,
43
+ selectedTier,
44
+ onSelectTier,
45
+ accentColor = '#188775',
46
+ title,
47
+ subtitle,
48
+ showRecommended = true,
49
+ recommendedLabel = 'Recommended',
50
+ useZhLabels = false,
51
+ style,
52
+ titleStyle,
53
+ }) => {
54
+ // Middle tier is usually recommended
55
+ const recommendedTierIndex = Math.floor(tiers.length / 2);
56
+
57
+ return (
58
+ <View style={[styles.container, style]}>
59
+ {title && <Text style={[styles.title, titleStyle]}>{title}</Text>}
60
+ {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
61
+
62
+ <View style={styles.tiersContainer}>
63
+ {tiers.map((tier, index) => {
64
+ const isSelected = selectedTier?.tier === tier.tier;
65
+ const isRecommended = showRecommended && index === recommendedTierIndex;
66
+
67
+ return (
68
+ <TouchableOpacity
69
+ key={tier.tier}
70
+ style={[
71
+ styles.tierCard,
72
+ isSelected && styles.tierCardSelected,
73
+ isSelected && { borderColor: accentColor }
74
+ ]}
75
+ onPress={() => onSelectTier(tier)}
76
+ activeOpacity={0.7}
77
+ >
78
+ {isRecommended && (
79
+ <View style={[styles.recommendedBadge, { backgroundColor: accentColor }]}>
80
+ <Text style={styles.recommendedText}>{recommendedLabel}</Text>
81
+ </View>
82
+ )}
83
+
84
+ <Text style={[
85
+ styles.tierLabel,
86
+ isSelected && { color: accentColor },
87
+ isRecommended && styles.tierLabelWithBadge
88
+ ]}>
89
+ {useZhLabels && tier.label_zh ? tier.label_zh : tier.label}
90
+ </Text>
91
+
92
+ <Text style={[
93
+ styles.tierAmount,
94
+ isSelected && { color: accentColor }
95
+ ]}>
96
+ ${tier.amount.toLocaleString()}
97
+ </Text>
98
+
99
+ {isSelected && (
100
+ <View style={[styles.checkCircle, { backgroundColor: accentColor }]}>
101
+ <Text style={styles.checkmark}>✓</Text>
102
+ </View>
103
+ )}
104
+ </TouchableOpacity>
105
+ );
106
+ })}
107
+ </View>
108
+ </View>
109
+ );
110
+ };
111
+
112
+ const styles = StyleSheet.create({
113
+ container: {
114
+ marginBottom: 16,
115
+ },
116
+ title: {
117
+ fontSize: 16,
118
+ fontWeight: '600',
119
+ color: '#1a1a1a',
120
+ marginBottom: 4,
121
+ },
122
+ subtitle: {
123
+ fontSize: 12,
124
+ color: '#666',
125
+ marginBottom: 12,
126
+ },
127
+ tiersContainer: {
128
+ flexDirection: 'row',
129
+ gap: 8,
130
+ },
131
+ tierCard: {
132
+ flex: 1,
133
+ padding: 16,
134
+ backgroundColor: '#fff',
135
+ borderRadius: 12,
136
+ borderWidth: 2,
137
+ borderColor: '#e5e5e5',
138
+ alignItems: 'center',
139
+ position: 'relative',
140
+ overflow: 'hidden',
141
+ },
142
+ tierCardSelected: {
143
+ backgroundColor: '#fff',
144
+ },
145
+ tierLabel: {
146
+ fontSize: 12,
147
+ color: '#666',
148
+ marginBottom: 4,
149
+ },
150
+ tierLabelWithBadge: {
151
+ marginTop: 16,
152
+ },
153
+ tierAmount: {
154
+ fontSize: 20,
155
+ fontWeight: '700',
156
+ color: '#1a1a1a',
157
+ },
158
+ checkCircle: {
159
+ position: 'absolute',
160
+ top: -8,
161
+ right: -8,
162
+ width: 28,
163
+ height: 28,
164
+ borderRadius: 14,
165
+ alignItems: 'center',
166
+ justifyContent: 'center',
167
+ },
168
+ checkmark: {
169
+ fontSize: 14,
170
+ fontWeight: '700',
171
+ color: '#fff',
172
+ },
173
+ recommendedBadge: {
174
+ position: 'absolute',
175
+ top: 0,
176
+ left: 0,
177
+ right: 0,
178
+ paddingVertical: 4,
179
+ alignItems: 'center',
180
+ },
181
+ recommendedText: {
182
+ fontSize: 10,
183
+ fontWeight: '700',
184
+ color: '#fff',
185
+ textTransform: 'uppercase',
186
+ },
187
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ONE AI Trading Components
3
+ * Reusable UI components for AI trading integration
4
+ * Can be used by any ecosystem partner
5
+ */
6
+
7
+ // Chain Selection
8
+ export * from './OneChainSelector';
9
+
10
+ // Investment Tier Selection
11
+ export * from './OneTierSelector';
12
+
13
+ // Cycle Selection
14
+ export * from './OneCycleSelector';
15
+
16
+ // Trading Pair Selection
17
+ export * from './OnePairSelector';
@@ -22,3 +22,6 @@ export * from './OneNFTGallery';
22
22
 
23
23
  // Receive
24
24
  export * from './OneReceiveWidget';
25
+
26
+ // AI Trading Components
27
+ export * from './ai';
@@ -23,7 +23,7 @@ export interface OneConfig {
23
23
  }
24
24
 
25
25
  // Default configuration values
26
- const DEFAULT_ENGINE_URL = 'https://api.one23.io/api';
26
+ const DEFAULT_ENGINE_URL = 'https://api.one23.io';
27
27
  const DEFAULT_CLIENT_ID = 'one_pk_e8f647bfa643fdcfaa3a23f760488e49be09f929296eed4a6c399d437d907f60';
28
28
 
29
29
  let config: OneConfig | null = null;
@@ -1,2 +1,22 @@
1
1
  export { useWalletBalance } from './useWalletBalance';
2
2
  export { useTokenPrice, useTokenPrices } from './useTokenPrice';
3
+
4
+ // AI Trading Hooks
5
+ export {
6
+ useAIStrategies,
7
+ useAIStrategy,
8
+ useAIOrders,
9
+ useAIPortfolio,
10
+ useAIMarketData,
11
+ useAITrading,
12
+ setAITradingAccessToken,
13
+ clearAITradingAccessToken,
14
+ type UseAIStrategiesOptions,
15
+ type UseAIStrategiesResult,
16
+ type UseAIStrategyResult,
17
+ type UseAIOrdersOptions,
18
+ type UseAIOrdersResult,
19
+ type UseAIPortfolioResult,
20
+ type UseAIMarketDataResult,
21
+ type UseAITradingResult,
22
+ } from './useAITrading';
@@ -0,0 +1,444 @@
1
+ /**
2
+ * AI Trading Hooks for ONE SDK
3
+ *
4
+ * React hooks for AI quantitative trading features.
5
+ * These hooks provide easy access to AI strategies, orders, and portfolio management.
6
+ */
7
+
8
+ import { useState, useEffect, useCallback, useMemo } from 'react';
9
+ import { createOneEngineClient, OneEngineClient } from '../services/engine';
10
+ import type {
11
+ AIStrategy,
12
+ AIOrder,
13
+ AIOrderStatus,
14
+ AIPortfolioSummary,
15
+ AITradeAllocation,
16
+ AINavSnapshot,
17
+ AIMarketData,
18
+ CreateAIOrderRequest,
19
+ StrategyCategory,
20
+ ApiResponse,
21
+ } from '../types';
22
+
23
+ // Singleton client instance
24
+ let clientInstance: OneEngineClient | null = null;
25
+
26
+ function getClient(): OneEngineClient {
27
+ if (!clientInstance) {
28
+ clientInstance = createOneEngineClient();
29
+ }
30
+ return clientInstance;
31
+ }
32
+
33
+ /**
34
+ * Set the access token for authenticated requests
35
+ */
36
+ export function setAITradingAccessToken(token: string) {
37
+ getClient().setAccessToken(token);
38
+ }
39
+
40
+ /**
41
+ * Clear the access token
42
+ */
43
+ export function clearAITradingAccessToken() {
44
+ getClient().clearAccessToken();
45
+ }
46
+
47
+ // ============================================
48
+ // AI Strategies Hooks
49
+ // ============================================
50
+
51
+ export interface UseAIStrategiesOptions {
52
+ category?: StrategyCategory;
53
+ riskLevel?: number;
54
+ minTvl?: number;
55
+ isActive?: boolean;
56
+ autoRefresh?: boolean;
57
+ refreshInterval?: number;
58
+ }
59
+
60
+ export interface UseAIStrategiesResult {
61
+ strategies: AIStrategy[];
62
+ isLoading: boolean;
63
+ error: string | null;
64
+ refresh: () => Promise<void>;
65
+ }
66
+
67
+ /**
68
+ * Hook to fetch and manage AI trading strategies
69
+ */
70
+ export function useAIStrategies(options: UseAIStrategiesOptions = {}): UseAIStrategiesResult {
71
+ const [strategies, setStrategies] = useState<AIStrategy[]>([]);
72
+ const [isLoading, setIsLoading] = useState(true);
73
+ const [error, setError] = useState<string | null>(null);
74
+
75
+ const { category, riskLevel, minTvl, isActive, autoRefresh = false, refreshInterval = 60000 } = options;
76
+
77
+ const fetchStrategies = useCallback(async () => {
78
+ setIsLoading(true);
79
+ setError(null);
80
+ try {
81
+ const result = await getClient().getAIStrategies({ category, riskLevel, minTvl, isActive });
82
+ if (result.success && result.data?.strategies) {
83
+ setStrategies(result.data.strategies);
84
+ } else {
85
+ setError(result.error?.message || 'Failed to fetch strategies');
86
+ }
87
+ } catch (err) {
88
+ setError(err instanceof Error ? err.message : 'Unknown error');
89
+ } finally {
90
+ setIsLoading(false);
91
+ }
92
+ }, [category, riskLevel, minTvl, isActive]);
93
+
94
+ useEffect(() => {
95
+ fetchStrategies();
96
+ }, [fetchStrategies]);
97
+
98
+ useEffect(() => {
99
+ if (autoRefresh && refreshInterval > 0) {
100
+ const interval = setInterval(fetchStrategies, refreshInterval);
101
+ return () => clearInterval(interval);
102
+ }
103
+ }, [autoRefresh, refreshInterval, fetchStrategies]);
104
+
105
+ return { strategies, isLoading, error, refresh: fetchStrategies };
106
+ }
107
+
108
+ /**
109
+ * Hook to fetch a single AI strategy with performance data
110
+ */
111
+ export interface UseAIStrategyResult {
112
+ strategy: AIStrategy | null;
113
+ performance: AINavSnapshot[];
114
+ marketData: AIMarketData[];
115
+ isLoading: boolean;
116
+ error: string | null;
117
+ refresh: () => Promise<void>;
118
+ }
119
+
120
+ export function useAIStrategy(
121
+ strategyId: string | undefined,
122
+ include: ('performance' | 'market' | 'trades')[] = ['performance', 'market']
123
+ ): UseAIStrategyResult {
124
+ const [strategy, setStrategy] = useState<AIStrategy | null>(null);
125
+ const [performance, setPerformance] = useState<AINavSnapshot[]>([]);
126
+ const [marketData, setMarketData] = useState<AIMarketData[]>([]);
127
+ const [isLoading, setIsLoading] = useState(true);
128
+ const [error, setError] = useState<string | null>(null);
129
+
130
+ const fetchStrategy = useCallback(async () => {
131
+ if (!strategyId) {
132
+ setIsLoading(false);
133
+ return;
134
+ }
135
+
136
+ setIsLoading(true);
137
+ setError(null);
138
+ try {
139
+ const result = await getClient().getAIStrategy(strategyId, include);
140
+ if (result.success && result.data) {
141
+ setStrategy(result.data.strategy);
142
+ setPerformance(result.data.performance || []);
143
+ setMarketData(result.data.marketData || []);
144
+ } else {
145
+ setError(result.error?.message || 'Failed to fetch strategy');
146
+ }
147
+ } catch (err) {
148
+ setError(err instanceof Error ? err.message : 'Unknown error');
149
+ } finally {
150
+ setIsLoading(false);
151
+ }
152
+ }, [strategyId, include.join(',')]);
153
+
154
+ useEffect(() => {
155
+ fetchStrategy();
156
+ }, [fetchStrategy]);
157
+
158
+ return { strategy, performance, marketData, isLoading, error, refresh: fetchStrategy };
159
+ }
160
+
161
+ // ============================================
162
+ // AI Orders Hooks
163
+ // ============================================
164
+
165
+ export interface UseAIOrdersOptions {
166
+ strategyId?: string;
167
+ status?: AIOrderStatus;
168
+ autoRefresh?: boolean;
169
+ refreshInterval?: number;
170
+ }
171
+
172
+ export interface UseAIOrdersResult {
173
+ orders: AIOrder[];
174
+ isLoading: boolean;
175
+ error: string | null;
176
+ refresh: () => Promise<void>;
177
+ createOrder: (request: CreateAIOrderRequest) => Promise<ApiResponse<{ order: AIOrder }>>;
178
+ pauseOrder: (orderId: string) => Promise<ApiResponse<{ order: AIOrder; message: string }>>;
179
+ resumeOrder: (orderId: string) => Promise<ApiResponse<{ order: AIOrder; message: string }>>;
180
+ redeemOrder: (orderId: string) => Promise<ApiResponse<any>>;
181
+ }
182
+
183
+ /**
184
+ * Hook to manage AI trading orders
185
+ */
186
+ export function useAIOrders(options: UseAIOrdersOptions = {}): UseAIOrdersResult {
187
+ const [orders, setOrders] = useState<AIOrder[]>([]);
188
+ const [isLoading, setIsLoading] = useState(true);
189
+ const [error, setError] = useState<string | null>(null);
190
+
191
+ const { strategyId, status, autoRefresh = true, refreshInterval = 30000 } = options;
192
+
193
+ const fetchOrders = useCallback(async () => {
194
+ setIsLoading(true);
195
+ setError(null);
196
+ try {
197
+ const result = await getClient().getAIOrders({ strategyId, status });
198
+ if (result.success && result.data?.orders) {
199
+ setOrders(result.data.orders);
200
+ } else {
201
+ setError(result.error?.message || 'Failed to fetch orders');
202
+ }
203
+ } catch (err) {
204
+ setError(err instanceof Error ? err.message : 'Unknown error');
205
+ } finally {
206
+ setIsLoading(false);
207
+ }
208
+ }, [strategyId, status]);
209
+
210
+ useEffect(() => {
211
+ fetchOrders();
212
+ }, [fetchOrders]);
213
+
214
+ useEffect(() => {
215
+ if (autoRefresh && refreshInterval > 0) {
216
+ const interval = setInterval(fetchOrders, refreshInterval);
217
+ return () => clearInterval(interval);
218
+ }
219
+ }, [autoRefresh, refreshInterval, fetchOrders]);
220
+
221
+ const createOrder = useCallback(async (request: CreateAIOrderRequest) => {
222
+ const result = await getClient().createAIOrder(request);
223
+ if (result.success) {
224
+ await fetchOrders(); // Refresh orders list
225
+ }
226
+ return result;
227
+ }, [fetchOrders]);
228
+
229
+ const pauseOrder = useCallback(async (orderId: string) => {
230
+ const result = await getClient().pauseAIOrder(orderId);
231
+ if (result.success) {
232
+ await fetchOrders();
233
+ }
234
+ return result;
235
+ }, [fetchOrders]);
236
+
237
+ const resumeOrder = useCallback(async (orderId: string) => {
238
+ const result = await getClient().resumeAIOrder(orderId);
239
+ if (result.success) {
240
+ await fetchOrders();
241
+ }
242
+ return result;
243
+ }, [fetchOrders]);
244
+
245
+ const redeemOrder = useCallback(async (orderId: string) => {
246
+ const result = await getClient().redeemAIOrder(orderId);
247
+ if (result.success) {
248
+ await fetchOrders();
249
+ }
250
+ return result;
251
+ }, [fetchOrders]);
252
+
253
+ return {
254
+ orders,
255
+ isLoading,
256
+ error,
257
+ refresh: fetchOrders,
258
+ createOrder,
259
+ pauseOrder,
260
+ resumeOrder,
261
+ redeemOrder,
262
+ };
263
+ }
264
+
265
+ // ============================================
266
+ // AI Portfolio Hooks
267
+ // ============================================
268
+
269
+ export interface UseAIPortfolioResult {
270
+ portfolio: AIPortfolioSummary | null;
271
+ allocations: AITradeAllocation[];
272
+ activeOrders: AIOrder[];
273
+ isLoading: boolean;
274
+ error: string | null;
275
+ refresh: () => Promise<void>;
276
+ }
277
+
278
+ /**
279
+ * Hook to fetch AI trading portfolio summary
280
+ */
281
+ export function useAIPortfolio(autoRefresh = true): UseAIPortfolioResult {
282
+ const [portfolio, setPortfolio] = useState<AIPortfolioSummary | null>(null);
283
+ const [allocations, setAllocations] = useState<AITradeAllocation[]>([]);
284
+ const [activeOrders, setActiveOrders] = useState<AIOrder[]>([]);
285
+ const [isLoading, setIsLoading] = useState(true);
286
+ const [error, setError] = useState<string | null>(null);
287
+
288
+ const fetchPortfolio = useCallback(async () => {
289
+ setIsLoading(true);
290
+ setError(null);
291
+ try {
292
+ const result = await getClient().getAIPortfolio(['allocations', 'orders']);
293
+ if (result.success && result.data) {
294
+ setPortfolio(result.data.portfolio);
295
+ setAllocations(result.data.allocations || []);
296
+ setActiveOrders(result.data.orders || []);
297
+ } else {
298
+ setError(result.error?.message || 'Failed to fetch portfolio');
299
+ }
300
+ } catch (err) {
301
+ setError(err instanceof Error ? err.message : 'Unknown error');
302
+ } finally {
303
+ setIsLoading(false);
304
+ }
305
+ }, []);
306
+
307
+ useEffect(() => {
308
+ fetchPortfolio();
309
+ }, [fetchPortfolio]);
310
+
311
+ useEffect(() => {
312
+ if (autoRefresh) {
313
+ const interval = setInterval(fetchPortfolio, 30000);
314
+ return () => clearInterval(interval);
315
+ }
316
+ }, [autoRefresh, fetchPortfolio]);
317
+
318
+ return { portfolio, allocations, activeOrders, isLoading, error, refresh: fetchPortfolio };
319
+ }
320
+
321
+ // ============================================
322
+ // AI Market Data Hook
323
+ // ============================================
324
+
325
+ export interface UseAIMarketDataResult {
326
+ prices: Record<string, { price: number; change24h: number }>;
327
+ isLoading: boolean;
328
+ error: string | null;
329
+ refresh: () => Promise<void>;
330
+ }
331
+
332
+ /**
333
+ * Hook to fetch real-time market data for AI trading pairs
334
+ */
335
+ export function useAIMarketData(
336
+ symbols: string[] = ['BTC', 'ETH', 'BNB', 'SOL', 'XRP', 'DOGE', 'ADA', 'AVAX'],
337
+ autoRefresh = true
338
+ ): UseAIMarketDataResult {
339
+ const [prices, setPrices] = useState<Record<string, { price: number; change24h: number }>>({});
340
+ const [isLoading, setIsLoading] = useState(true);
341
+ const [error, setError] = useState<string | null>(null);
342
+
343
+ const fetchPrices = useCallback(async () => {
344
+ setIsLoading(true);
345
+ setError(null);
346
+ try {
347
+ const result = await getClient().getTokenPrices(symbols);
348
+ if (result.success && result.data) {
349
+ setPrices(result.data);
350
+ } else {
351
+ setError(result.error?.message || 'Failed to fetch prices');
352
+ }
353
+ } catch (err) {
354
+ setError(err instanceof Error ? err.message : 'Unknown error');
355
+ } finally {
356
+ setIsLoading(false);
357
+ }
358
+ }, [symbols.join(',')]);
359
+
360
+ useEffect(() => {
361
+ fetchPrices();
362
+ }, [fetchPrices]);
363
+
364
+ useEffect(() => {
365
+ if (autoRefresh) {
366
+ const interval = setInterval(fetchPrices, 15000); // Update every 15 seconds
367
+ return () => clearInterval(interval);
368
+ }
369
+ }, [autoRefresh, fetchPrices]);
370
+
371
+ return { prices, isLoading, error, refresh: fetchPrices };
372
+ }
373
+
374
+ // ============================================
375
+ // Combined AI Trading Hook
376
+ // ============================================
377
+
378
+ export interface UseAITradingResult {
379
+ // Strategies
380
+ strategies: AIStrategy[];
381
+ strategiesLoading: boolean;
382
+
383
+ // Orders
384
+ orders: AIOrder[];
385
+ ordersLoading: boolean;
386
+
387
+ // Portfolio
388
+ portfolio: AIPortfolioSummary | null;
389
+ portfolioLoading: boolean;
390
+
391
+ // Market Data
392
+ prices: Record<string, { price: number; change24h: number }>;
393
+
394
+ // Actions
395
+ createOrder: (request: CreateAIOrderRequest) => Promise<ApiResponse<{ order: AIOrder }>>;
396
+ pauseOrder: (orderId: string) => Promise<ApiResponse<{ order: AIOrder; message: string }>>;
397
+ resumeOrder: (orderId: string) => Promise<ApiResponse<{ order: AIOrder; message: string }>>;
398
+ redeemOrder: (orderId: string) => Promise<ApiResponse<any>>;
399
+
400
+ // Refresh
401
+ refreshAll: () => Promise<void>;
402
+
403
+ // Error
404
+ error: string | null;
405
+ }
406
+
407
+ /**
408
+ * Combined hook for all AI trading functionality
409
+ */
410
+ export function useAITrading(): UseAITradingResult {
411
+ const strategiesResult = useAIStrategies({ autoRefresh: true });
412
+ const ordersResult = useAIOrders({ autoRefresh: true });
413
+ const portfolioResult = useAIPortfolio(true);
414
+ const marketResult = useAIMarketData();
415
+
416
+ const refreshAll = useCallback(async () => {
417
+ await Promise.all([
418
+ strategiesResult.refresh(),
419
+ ordersResult.refresh(),
420
+ portfolioResult.refresh(),
421
+ marketResult.refresh(),
422
+ ]);
423
+ }, [strategiesResult.refresh, ordersResult.refresh, portfolioResult.refresh, marketResult.refresh]);
424
+
425
+ const error = useMemo(() => {
426
+ return strategiesResult.error || ordersResult.error || portfolioResult.error || marketResult.error;
427
+ }, [strategiesResult.error, ordersResult.error, portfolioResult.error, marketResult.error]);
428
+
429
+ return {
430
+ strategies: strategiesResult.strategies,
431
+ strategiesLoading: strategiesResult.isLoading,
432
+ orders: ordersResult.orders,
433
+ ordersLoading: ordersResult.isLoading,
434
+ portfolio: portfolioResult.portfolio,
435
+ portfolioLoading: portfolioResult.isLoading,
436
+ prices: marketResult.prices,
437
+ createOrder: ordersResult.createOrder,
438
+ pauseOrder: ordersResult.pauseOrder,
439
+ resumeOrder: ordersResult.resumeOrder,
440
+ redeemOrder: ordersResult.redeemOrder,
441
+ refreshAll,
442
+ error,
443
+ };
444
+ }