feat(frontend): 完成 Zustand 状态管理迁移
- 将 App.jsx 中的 useState 迁移到 5 个 Zustand stores - useRuntimeStore: 连接状态、运行时配置 - useMarketStore: 市场数据、股票价格 - usePortfolioStore: 组合、持仓、交易 - useAgentStore: Agent 技能,工作区 - useUIStore: UI 状态、视图切换 - 保留 tickers useState(需与 INITIAL_TICKERS 同步) - 恢复 newsApi.js 和 tradingApi.js Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,11 @@ import {
|
||||
|
||||
// Hooks
|
||||
import { useFeedProcessor } from './hooks/useFeedProcessor';
|
||||
import { useRuntimeStore } from './store/runtimeStore';
|
||||
import { useMarketStore } from './store/marketStore';
|
||||
import { usePortfolioStore } from './store/portfolioStore';
|
||||
import { useAgentStore } from './store/agentStore';
|
||||
import { useUIStore } from './store/uiStore';
|
||||
|
||||
// Styles
|
||||
import GlobalStyles from './styles/GlobalStyles';
|
||||
@@ -70,100 +75,73 @@ function ViewLoadingFallback({ label = '加载中...' }) {
|
||||
*/
|
||||
|
||||
export default function LiveTradingApp() {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [connectionStatus, setConnectionStatus] = useState('connecting'); // 'connecting' | 'connected' | 'disconnected'
|
||||
const [systemStatus, setSystemStatus] = useState('initializing'); // 'initializing' | 'running' | 'completed'
|
||||
const [currentDate, setCurrentDate] = useState(null);
|
||||
const [progress, setProgress] = useState({ current: 0, total: 0 });
|
||||
const [now, setNow] = useState(() => new Date());
|
||||
// Connection & system state - from runtimeStore
|
||||
const { isConnected, setIsConnected, connectionStatus, setConnectionStatus, systemStatus, setSystemStatus, currentDate, setCurrentDate, progress, setProgress, now, setNow } = useRuntimeStore();
|
||||
|
||||
// View toggle: 'traders' | 'room' | 'explain' | 'chart' | 'statistics' | 'runtime'
|
||||
const [currentView, setCurrentView] = useState('traders');
|
||||
const [isInitialAnimating, setIsInitialAnimating] = useState(true);
|
||||
const [lastUpdate, setLastUpdate] = useState(new Date());
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
const { currentView, setCurrentView, chartTab, setChartTab, isInitialAnimating, setIsInitialAnimating, lastUpdate, setLastUpdate, isUpdating, setIsUpdating } = useUIStore();
|
||||
|
||||
// Chart data
|
||||
const [chartTab, setChartTab] = useState('all');
|
||||
const [portfolioData, setPortfolioData] = useState({
|
||||
netValue: 10000,
|
||||
pnl: 0,
|
||||
equity: [],
|
||||
baseline: [], // Baseline strategy (Buy & Hold - Equal Weight)
|
||||
baseline_vw: [], // Baseline strategy (Buy & Hold - Value Weighted)
|
||||
momentum: [], // Momentum strategy
|
||||
strategies: [] // Other strategies
|
||||
});
|
||||
// Chart data - from portfolioStore
|
||||
const { portfolioData, setPortfolioData, holdings, setHoldings, trades, setTrades, stats, setStats, leaderboard, setLeaderboard } = usePortfolioStore();
|
||||
|
||||
// Feed data (using hook for simplified processing)
|
||||
const { feed, processHistoricalFeed, processFeedEvent, addSystemMessage } = useFeedProcessor();
|
||||
|
||||
// Statistics data
|
||||
const [holdings, setHoldings] = useState([]);
|
||||
const [trades, setTrades] = useState([]);
|
||||
const [stats, setStats] = useState(null);
|
||||
const [leaderboard, setLeaderboard] = useState([]);
|
||||
|
||||
// Ticker prices (now from real-time data)
|
||||
// Ticker prices - keep local state with INITIAL_TICKERS
|
||||
const [tickers, setTickers] = useState(INITIAL_TICKERS);
|
||||
const [rollingTickers, setRollingTickers] = useState({});
|
||||
const [priceHistoryByTicker, setPriceHistoryByTicker] = useState({});
|
||||
const [ohlcHistoryByTicker, setOhlcHistoryByTicker] = useState({});
|
||||
const [explainEventsByTicker, setExplainEventsByTicker] = useState({});
|
||||
const [newsByTicker, setNewsByTicker] = useState({});
|
||||
const [insiderTradesByTicker, setInsiderTradesByTicker] = useState({});
|
||||
const [technicalIndicatorsByTicker, setTechnicalIndicatorsByTicker] = useState({});
|
||||
const [selectedExplainSymbol, setSelectedExplainSymbol] = useState('');
|
||||
const [historySourceByTicker, setHistorySourceByTicker] = useState({});
|
||||
const { rollingTickers, setRollingTickers, priceHistoryByTicker, setPriceHistoryByTicker, ohlcHistoryByTicker, setOhlcHistoryByTicker, explainEventsByTicker, setExplainEventsByTicker, newsByTicker, setNewsByTicker, insiderTradesByTicker, setInsiderTradesByTicker, technicalIndicatorsByTicker, setTechnicalIndicatorsByTicker, selectedExplainSymbol, setSelectedExplainSymbol, historySourceByTicker, setHistorySourceByTicker } = useMarketStore();
|
||||
|
||||
// Room bubbles
|
||||
const [bubbles, setBubbles] = useState({});
|
||||
// Room bubbles - from uiStore
|
||||
const { bubbles, setBubbles, leftWidth, setLeftWidth, isResizing, setIsResizing } = useUIStore();
|
||||
|
||||
// Resizable panels
|
||||
const [leftWidth, setLeftWidth] = useState(70); // percentage
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
// Market status & runtime config - from runtimeStore
|
||||
const {
|
||||
serverMode, setServerMode,
|
||||
marketStatus, setMarketStatus,
|
||||
virtualTime, setVirtualTime,
|
||||
dataSources, setDataSources,
|
||||
runtimeConfig, setRuntimeConfig,
|
||||
isWatchlistPanelOpen, setIsWatchlistPanelOpen,
|
||||
isRuntimeSettingsOpen, setIsRuntimeSettingsOpen,
|
||||
watchlistDraftSymbols, setWatchlistDraftSymbols,
|
||||
watchlistInputValue, setWatchlistInputValue,
|
||||
watchlistFeedback, setWatchlistFeedback,
|
||||
isWatchlistSaving, setIsWatchlistSaving,
|
||||
scheduleModeDraft, setScheduleModeDraft,
|
||||
intervalMinutesDraft, setIntervalMinutesDraft,
|
||||
triggerTimeDraft, setTriggerTimeDraft,
|
||||
maxCommCyclesDraft, setMaxCommCyclesDraft,
|
||||
initialCashDraft, setInitialCashDraft,
|
||||
marginRequirementDraft, setMarginRequirementDraft,
|
||||
enableMemoryDraft, setEnableMemoryDraft,
|
||||
modeDraft, setModeDraft,
|
||||
pollIntervalDraft, setPollIntervalDraft,
|
||||
startDateDraft, setStartDateDraft,
|
||||
endDateDraft, setEndDateDraft,
|
||||
enableMockDraft, setEnableMockDraft,
|
||||
runtimeConfigFeedback, setRuntimeConfigFeedback,
|
||||
isRuntimeConfigSaving, setIsRuntimeConfigSaving,
|
||||
lastDayHistory, setLastDayHistory
|
||||
} = useRuntimeStore();
|
||||
|
||||
// Market status
|
||||
const [serverMode, setServerMode] = useState(null); // 'live' | 'backtest' | null
|
||||
const [marketStatus, setMarketStatus] = useState(null); // { status, status_text, ... }
|
||||
const [virtualTime, setVirtualTime] = useState(null); // Virtual time from server (for mock mode)
|
||||
const [dataSources, setDataSources] = useState(null);
|
||||
const [runtimeConfig, setRuntimeConfig] = useState(null);
|
||||
const [isWatchlistPanelOpen, setIsWatchlistPanelOpen] = useState(false);
|
||||
const [isRuntimeSettingsOpen, setIsRuntimeSettingsOpen] = useState(false);
|
||||
const [watchlistDraftSymbols, setWatchlistDraftSymbols] = useState([]);
|
||||
const [watchlistInputValue, setWatchlistInputValue] = useState('');
|
||||
const [watchlistFeedback, setWatchlistFeedback] = useState(null);
|
||||
const [isWatchlistSaving, setIsWatchlistSaving] = useState(false);
|
||||
const [scheduleModeDraft, setScheduleModeDraft] = useState('daily');
|
||||
const [intervalMinutesDraft, setIntervalMinutesDraft] = useState('60');
|
||||
const [triggerTimeDraft, setTriggerTimeDraft] = useState('09:30');
|
||||
const [maxCommCyclesDraft, setMaxCommCyclesDraft] = useState('2');
|
||||
const [initialCashDraft, setInitialCashDraft] = useState('100000');
|
||||
const [marginRequirementDraft, setMarginRequirementDraft] = useState('0');
|
||||
const [enableMemoryDraft, setEnableMemoryDraft] = useState(false);
|
||||
const [modeDraft, setModeDraft] = useState('live');
|
||||
const [pollIntervalDraft, setPollIntervalDraft] = useState('10');
|
||||
const [startDateDraft, setStartDateDraft] = useState('');
|
||||
const [endDateDraft, setEndDateDraft] = useState('');
|
||||
const [enableMockDraft, setEnableMockDraft] = useState(false);
|
||||
const [runtimeConfigFeedback, setRuntimeConfigFeedback] = useState(null);
|
||||
const [isRuntimeConfigSaving, setIsRuntimeConfigSaving] = useState(false);
|
||||
const [selectedSkillAgentId, setSelectedSkillAgentId] = useState(AGENTS[0]?.id || 'portfolio_manager');
|
||||
const [agentProfilesByAgent, setAgentProfilesByAgent] = useState({});
|
||||
const [agentSkillsByAgent, setAgentSkillsByAgent] = useState({});
|
||||
const [skillDetailsByName, setSkillDetailsByName] = useState({});
|
||||
const [localSkillDraftsByKey, setLocalSkillDraftsByKey] = useState({});
|
||||
const [isAgentSkillsLoading, setIsAgentSkillsLoading] = useState(false);
|
||||
const [skillDetailLoadingKey, setSkillDetailLoadingKey] = useState(null);
|
||||
const [agentSkillsSavingKey, setAgentSkillsSavingKey] = useState(null);
|
||||
const [agentSkillsFeedback, setAgentSkillsFeedback] = useState(null);
|
||||
const [selectedWorkspaceFile, setSelectedWorkspaceFile] = useState(EDITABLE_AGENT_WORKSPACE_FILES[0]);
|
||||
const [workspaceFilesByAgent, setWorkspaceFilesByAgent] = useState({});
|
||||
const [workspaceDraftContent, setWorkspaceDraftContent] = useState('');
|
||||
const [isWorkspaceFileLoading, setIsWorkspaceFileLoading] = useState(false);
|
||||
const [workspaceFileSavingKey, setWorkspaceFileSavingKey] = useState(null);
|
||||
const [workspaceFileFeedback, setWorkspaceFileFeedback] = useState(null);
|
||||
// Agent state - from agentStore
|
||||
const {
|
||||
selectedSkillAgentId, setSelectedSkillAgentId,
|
||||
agentProfilesByAgent, setAgentProfilesByAgent,
|
||||
agentSkillsByAgent, setAgentSkillsByAgent,
|
||||
skillDetailsByName, setSkillDetailsByName,
|
||||
localSkillDraftsByKey, setLocalSkillDraftsByKey,
|
||||
isAgentSkillsLoading, setIsAgentSkillsLoading,
|
||||
skillDetailLoadingKey, setSkillDetailLoadingKey,
|
||||
agentSkillsSavingKey, setAgentSkillsSavingKey,
|
||||
agentSkillsFeedback, setAgentSkillsFeedback,
|
||||
selectedWorkspaceFile, setSelectedWorkspaceFile,
|
||||
workspaceFilesByAgent, setWorkspaceFilesByAgent,
|
||||
workspaceDraftContent, setWorkspaceDraftContent,
|
||||
isWorkspaceFileLoading, setIsWorkspaceFileLoading,
|
||||
workspaceFileSavingKey, setWorkspaceFileSavingKey,
|
||||
workspaceFileFeedback, setWorkspaceFileFeedback
|
||||
} = useAgentStore();
|
||||
|
||||
const clientRef = useRef(null);
|
||||
const containerRef = useRef(null);
|
||||
@@ -176,9 +154,6 @@ export default function LiveTradingApp() {
|
||||
const lastVirtualTimeRef = useRef(null);
|
||||
const virtualTimeOffsetRef = useRef(0);
|
||||
|
||||
// Last day history for replay
|
||||
const [lastDayHistory, setLastDayHistory] = useState([]);
|
||||
|
||||
const buildTickersFromSymbols = useCallback((symbols, previousTickers = []) => {
|
||||
if (!Array.isArray(symbols) || symbols.length === 0) {
|
||||
return previousTickers;
|
||||
|
||||
Reference in New Issue
Block a user