Skip to content

Commit bd06825

Browse files
refactor: centralize Binance WebSocket endpoints and default market type into a new constants file.
1 parent f4fed55 commit bd06825

15 files changed

Lines changed: 142 additions & 107 deletions

File tree

src/App.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ function App() {
3131
handleDataSourceChange,
3232
} = useDataSource();
3333

34-
// ========== 交易对状态 ==========
35-
const [activeSymbol, setActiveSymbol] = useState('BTCUSDT');
34+
// ========== 交易对状态 (本地持久化) ==========
35+
const SYMBOL_KEY = 'rustquantlab_symbol';
36+
const [activeSymbol, setActiveSymbol] = useState(() => {
37+
const saved = localStorage.getItem(SYMBOL_KEY);
38+
return saved || 'BTCUSDT';
39+
});
3640
const handleSymbolChange = useCallback((symbol: string) => {
3741
setActiveSymbol(symbol);
38-
// 切换 symbol 时也可以触发一些重置逻辑 if needed
42+
localStorage.setItem(SYMBOL_KEY, symbol);
3943
}, []);
4044

4145
const setSwitching = useUiStore((s: UiState) => s.setSwitching);

src/components/Dashboard/Chart/ChartView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function ChartView({
121121
<h2 className="text-[10px] md:text-[11px] font-medium text-gray-400 truncate max-w-[120px] md:max-w-none">
122122
{latestData?.symbol ?? 'BTC-USDT'} · Perp
123123
</h2>
124-
<span className="text-[9px] md:text-[10px] font-mono text-gray-600">
124+
<span className="text-[9px] md:text-[10px] font-mono text-gray-600 tabular-nums min-w-[70px]">
125125
{activeChartType === 'Depth'
126126
? 'Market Depth'
127127
: `${candleHistory.length} candles`}

src/components/Dashboard/Chart/LightweightChart/index.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ const LightweightChart = forwardRef<LightweightChartHandle, LightweightChartProp
133133
const priceColor = isUp ? CHART_COLORS.UP : CHART_COLORS.DOWN;
134134
const { changePercent } = displayCandle
135135
? calculateChange(displayCandle.open, displayCandle.close)
136-
: { change: 0, changePercent: 0 };
136+
: { changePercent: 0 };
137137

138138
// 指标数据
139139
const displayMa7 = indicatorData.ma7[displayIndex];
@@ -306,5 +306,3 @@ const LightweightChart = forwardRef<LightweightChartHandle, LightweightChartProp
306306
);
307307

308308
export default LightweightChart;
309-
export type { LightweightChartHandle };
310-

src/components/Dashboard/RecentTrades.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ function RecentTrades({ trades, symbol = 'BTC' }: RecentTradesProps) {
240240
<div
241241
key={trade.id}
242242
className={`relative flex items-center px-2 py-[2px] transition-colors hover:bg-white/5 ${
243-
isLarge ? 'bg-white/[0.04]' : ''
243+
isLarge ? 'bg-white/4' : ''
244244
}`}
245245
>
246246
{/* 背景数量条 */}

src/components/Dashboard/Trade/PositionCard.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface WasmPositionCardProps {
3535

3636
// 使用 CSS 变量,移除硬编码颜色常量
3737
/** 风险等级颜色映射 */
38-
const RISK_COLORS: Record<RiskLevel, string> = {
38+
export const RISK_COLORS: Record<RiskLevel, string> = {
3939
Safe: 'var(--color-success)',
4040
Low: 'var(--color-info)',
4141
Medium: 'var(--color-warning-alt)',
@@ -68,7 +68,7 @@ function WasmPositionCard({
6868

6969
// 增加保证金弹窗状态
7070
const [showAddMargin, setShowAddMargin] = useState(false);
71-
const [marginAmount, setMarginAmount] = useState('');
71+
const [_marginAmount, setMarginAmount] = useState('');
7272

7373
// 平仓确认弹窗状态
7474
const [showCloseConfirm, setShowCloseConfirm] = useState(false);
@@ -85,7 +85,6 @@ function WasmPositionCard({
8585
// 🔴 直接使用 Wasm 计算的值,无本地计算
8686
// Hedge Mode: 每个仓位有独立的字段,由 Rust 计算
8787
const pnlValue = position.unrealizedPnl;
88-
const pnlPercent = position.pnlPercentage;
8988

9089
// 区分全仓/逐仓模式的数据来源
9190
// 注意:Rust serde 序列化为小写 "cross"/"isolated"
@@ -111,13 +110,7 @@ function WasmPositionCard({
111110
? Math.abs(((currentPrice - liquidationPrice) / currentPrice) * 100)
112111
: 100;
113112

114-
// 风险预警:距离强平 < 10%
115-
const isLiqNear = distanceToLiq < 10;
116-
const isCritical = riskLevel === 'Critical' || riskLevel === 'High';
117-
118113
const borderColor = isLong ? 'var(--color-success)' : 'var(--color-danger)';
119-
const pnlColor = isProfit ? 'var(--color-success)' : 'var(--color-danger)';
120-
const riskColor = RISK_COLORS[riskLevel];
121114

122115

123116
// Use ref to track previous risk level for one-time vibration

src/hooks/useBinanceMarket.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111
*/
1212

1313
import { useState, useRef, useCallback, useEffect } from 'react';
14-
import {
15-
BinanceAPI,
16-
BinanceWebSocket,
17-
type BinanceKline,
18-
type BinanceInterval,
19-
type MarketType,
20-
type BinanceWsKlineMsg,
21-
type BinanceWsDepthMsg,
22-
type BinanceWsTradeMsg,
23-
type BinanceTicker24h,
24-
type BinancePremiumIndex,
25-
type ConnectionStatus,
14+
import { BinanceAPI, BinanceWebSocket } from '../services/binance';
15+
import type {
16+
BinanceKline,
17+
BinanceInterval,
18+
MarketType,
19+
BinanceWsKlineMsg,
20+
BinanceWsTradeMsg,
21+
BinanceWsDepthMsg,
22+
BinancePremiumIndex,
23+
BinanceTicker24h,
24+
ConnectionStatus,
2625
} from '../services/binance';
26+
import { DEFAULT_MARKET, DEFAULT_SYMBOL } from '../services/binance/constants';
2727
import type { OrderBook, HistoryCandle } from '../types/index';
2828

2929
/** 最近成交记录 */
@@ -96,12 +96,12 @@ export interface UseBinanceMarketReturn {
9696

9797
/** 默认配置 */
9898
const DEFAULT_OPTIONS: Required<UseBinanceMarketOptions> = {
99-
symbol: 'BTCUSDT',
100-
market: 'futures', // 使用合约 API (USDT 永续合约)
101-
historyInterval: '1m', // 历史数据用 1 分钟 K 线(Rust 引擎需要细粒度数据)
102-
realtimeInterval: '1s', // 实时用 1 秒 K 线
103-
historyCount: 5000, // 历史 K 线数量(5000 根 1m = 约 3.5 天,足够计算所有指标)
104-
tickInterval: 100, // 100ms 更新一次 OrderBook
99+
symbol: DEFAULT_SYMBOL,
100+
market: DEFAULT_MARKET,
101+
historyInterval: '1m',
102+
realtimeInterval: '1s',
103+
historyCount: 5000,
104+
tickInterval: 100,
105105
};
106106

107107
// ============================================================================

src/hooks/useMarketData.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useMockMarket } from './useMockMarket';
1313
import { useBinanceMarket, type TradeRecord } from './useBinanceMarket';
1414
import type { OrderBook, HistoryCandle } from '../types/index';
1515
import type { BinanceTicker24h, BinancePremiumIndex } from '../services/binance/types';
16+
import { DEFAULT_MARKET } from '../services/binance/constants';
1617

1718
// ============================================================================
1819
// 类型定义
@@ -99,7 +100,7 @@ export function useMarketData(
99100
tickInterval,
100101
historyCount,
101102
symbol,
102-
market: 'futures',
103+
market: DEFAULT_MARKET,
103104
});
104105

105106
// ========== 统一的历史数据请求封装 ==========

src/services/binance/api.ts

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,45 +13,12 @@ import type {
1313
BinanceInterval,
1414
MarketType,
1515
} from './types';
16-
17-
// ============================================================================
18-
// API 端点配置
19-
// ============================================================================
20-
21-
/**
22-
* 检测是否是本地开发环境
23-
*/
24-
const isDev = typeof window !== 'undefined' &&
25-
(window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');
26-
27-
/**
28-
* 获取 API 基础 URL
29-
* 本地开发使用 Vite 代理,生产环境直连 Binance
30-
*/
31-
function getBaseUrl(market: 'spot' | 'futures'): string {
32-
if (isDev) {
33-
// 本地开发: 使用 Vite 代理路径
34-
return market === 'spot' ? '/binance-spot' : '/binance-futures';
35-
}
36-
37-
// 生产环境: 直连 Binance API
38-
return market === 'spot'
39-
? 'https://api.binance.com'
40-
: 'https://fapi.binance.com';
41-
}
42-
43-
const ENDPOINTS = {
44-
spot: {
45-
klines: '/api/v3/klines',
46-
depth: '/api/v3/depth',
47-
ticker24h: '/api/v3/ticker/24hr',
48-
},
49-
futures: {
50-
klines: '/fapi/v1/klines',
51-
depth: '/fapi/v1/depth',
52-
ticker24h: '/fapi/v1/ticker/24hr',
53-
},
54-
} as const;
16+
import {
17+
DEFAULT_MARKET,
18+
DEFAULT_SYMBOL,
19+
REST_ENDPOINTS as ENDPOINTS,
20+
getBaseUrl,
21+
} from './constants';
5522

5623
// ============================================================================
5724
// 工具函数
@@ -111,10 +78,10 @@ function buildUrl(
11178
* @param endTime - 结束时间 (毫秒)
11279
*/
11380
export async function getKlines(
114-
symbol: string = 'BTCUSDT',
81+
symbol: string = DEFAULT_SYMBOL,
11582
interval: BinanceInterval = '1h',
11683
limit: number = 500,
117-
market: MarketType = 'spot',
84+
market: MarketType = DEFAULT_MARKET,
11885
startTime?: number,
11986
endTime?: number,
12087
): Promise<BinanceKline[]> {
@@ -159,10 +126,10 @@ export async function getKlines(
159126
* @param market - 市场类型
160127
*/
161128
export async function getKlinesBatch(
162-
symbol: string = 'BTCUSDT',
129+
symbol: string = DEFAULT_SYMBOL,
163130
interval: BinanceInterval = '1h',
164131
totalCount: number = 2000,
165-
market: MarketType = 'spot',
132+
market: MarketType = DEFAULT_MARKET,
166133
): Promise<BinanceKline[]> {
167134
const allKlines: BinanceKline[] = [];
168135
const batchSize = 1500; // Binance 单次最大限制
@@ -225,9 +192,9 @@ export async function getKlinesBatch(
225192
* @param market - 市场类型
226193
*/
227194
export async function getDepth(
228-
symbol: string = 'BTCUSDT',
229-
limit: number = 100, // 默认获取 100 档深度数据(Binance 支持: 5, 10, 20, 50, 100, 500, 1000, 5000)
230-
market: MarketType = 'spot',
195+
symbol: string = DEFAULT_SYMBOL,
196+
limit: number = 100,
197+
market: MarketType = DEFAULT_MARKET,
231198
): Promise<BinanceDepth> {
232199
// 验证 limit 参数(Binance 有效值)
233200
const validLimits = [5, 10, 20, 50, 100, 500, 1000, 5000];

src/services/binance/constants.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Binance 数据源常量
3+
*
4+
* 统一管理所有 Binance API 相关的端点、默认值和配置,
5+
* 避免 magic string 散落在各服务文件中。
6+
*/
7+
8+
import type { MarketType, BinanceInterval } from './types';
9+
10+
// ============================================================================
11+
// 全局默认值
12+
// ============================================================================
13+
14+
/** 默认市场类型:USDT 永续合约 */
15+
export const DEFAULT_MARKET: MarketType = 'futures';
16+
17+
/** 默认交易对 */
18+
export const DEFAULT_SYMBOL = 'BTCUSDT';
19+
20+
/** 默认 K 线周期 */
21+
export const DEFAULT_INTERVAL: BinanceInterval = '1m';
22+
23+
// ============================================================================
24+
// REST API 端点
25+
// ============================================================================
26+
27+
/** REST API 基础 URL(生产环境直连 Binance) */
28+
export const REST_BASE_URLS = {
29+
spot: 'https://api.binance.com',
30+
futures: 'https://fapi.binance.com',
31+
} as const;
32+
33+
/** Vite 代理路径(本地开发用) */
34+
export const PROXY_PATHS = {
35+
spot: '/binance-spot',
36+
futures: '/binance-futures',
37+
} as const;
38+
39+
/** REST API 路径 (按市场类型区分) */
40+
export const REST_ENDPOINTS = {
41+
spot: {
42+
klines: '/api/v3/klines',
43+
depth: '/api/v3/depth',
44+
ticker24h: '/api/v3/ticker/24hr',
45+
},
46+
futures: {
47+
klines: '/fapi/v1/klines',
48+
depth: '/fapi/v1/depth',
49+
ticker24h: '/fapi/v1/ticker/24hr',
50+
},
51+
} as const;
52+
53+
// ============================================================================
54+
// WebSocket 端点
55+
// ============================================================================
56+
57+
/** WebSocket 端点(直连 Binance) */
58+
export const WS_ENDPOINTS = {
59+
spot: 'wss://stream.binance.com:9443/ws',
60+
futures: 'wss://fstream.binance.com/ws',
61+
} as const;
62+
63+
// ============================================================================
64+
// 工具函数
65+
// ============================================================================
66+
67+
/** 检测是否是本地开发环境 */
68+
export const IS_DEV =
69+
typeof window !== 'undefined' &&
70+
(window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');
71+
72+
/**
73+
* 获取 REST API 基础 URL
74+
* 本地开发使用 Vite 代理,生产环境直连 Binance
75+
*/
76+
export function getBaseUrl(market: MarketType = DEFAULT_MARKET): string {
77+
return IS_DEV ? PROXY_PATHS[market] : REST_BASE_URLS[market];
78+
}

src/services/binance/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ export {
4646
toHistoryCandle,
4747
} from './api';
4848

49+
// 导出常量
50+
export {
51+
DEFAULT_MARKET,
52+
DEFAULT_SYMBOL,
53+
DEFAULT_INTERVAL,
54+
WS_ENDPOINTS,
55+
REST_ENDPOINTS,
56+
REST_BASE_URLS,
57+
PROXY_PATHS,
58+
IS_DEV,
59+
getBaseUrl,
60+
} from './constants';
61+
4962
// 导出 WebSocket
5063
export {
5164
BinanceWebSocket,

0 commit comments

Comments
 (0)