mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 15:34:16 +08:00
后端 - 新增 services/regime_builder.py:5 档日级市场状态分级(strong/lean_strong/range/lean_weak/weak) - 新增 api/regime.py:5 个 regime 查询接口 - daily_pipeline 接入 regime 构建(step 2.6,soft-fail + 双检测自愈) - 回测 strategy.py 新增 regime_filter 过滤:采用 T-1 防未来函数,仅作用于入场信号 在 composite / matrix_native / prepared 三处注入 entry_time_mask - backtest API 透传 regime_filter(REST + SSE);_make_job_key 纳入 regime_filter 以隔离缓存 - 兼容 _RepoStub 测试夹具(store 属性缺失场景) 前端 - 新增 Regime 页面、路由、导航入口、api 类型与 queryKeys - 叠加策略回测页新增 regime 过滤器控件 测试 - 新增 tests/test_regime_builder.py(18 项),覆盖分级逻辑、T-1 防未来函数、空值降级、三处 mask 注入 - 全量后端测试 582 passed;前端 pnpm build 通过;git diff --check 无空白错误
109 lines
5.3 KiB
TypeScript
109 lines
5.3 KiB
TypeScript
/**
|
|
* 集中管理所有 React Query key。
|
|
*
|
|
* - 新增查询只需在此加一行,所有消费方自动引用。
|
|
* - SSE invalidation 基于 SSE_INVALIDATE_PREFIXES 列表,新增 key 无需改 useQuoteStream。
|
|
*/
|
|
|
|
// ===== Query Key 工厂 =====
|
|
|
|
export const QK = {
|
|
// 全局 / 共享 (Layout 预取)
|
|
capabilities: ['capabilities'] as const,
|
|
settings: ['settings'] as const,
|
|
endpoints: ['endpoints'] as const,
|
|
version: ['version'] as const,
|
|
preferences: ['preferences'] as const,
|
|
dataSources: ['data-sources'] as const,
|
|
quoteStatus: ['quote-status'] as const,
|
|
quoteInterval: ['quote-interval'] as const,
|
|
overviewMarket: (asOf?: string) => ['overview-market', asOf ?? 'latest'] as const,
|
|
indexQuotes: ['index-quotes'] as const,
|
|
indexList: ['index-list'] as const,
|
|
|
|
// Watchlist
|
|
watchlist: ['watchlist'] as const,
|
|
watchlistQuotes: ['watchlist-quotes'] as const,
|
|
watchlistEnriched: (ext?: string) => ['watchlist-enriched', ext] as const,
|
|
watchlistKlineBatch: (symbols: string) => ['watchlist-kline-batch', symbols] as const,
|
|
// 不用 watchlist- 前缀: 避免被 SSE quotes_updated 高频失效(expert 1s/pro 2s)
|
|
// 导致每次都拉 TickFlow 触限流。分时图用固定 refetchInterval 刷新即可。
|
|
minuteBatch: (symbols: string) => ['minute-batch', symbols] as const,
|
|
instrumentSearch: (q: string, assetTypes?: string) => ['instrument-search', q, assetTypes ?? 'stock'] as const,
|
|
|
|
// Screener
|
|
screener: ['screener'] as const,
|
|
screenerStrategies: (assetType: string = 'stock') => ['screener-strategies', assetType] as const,
|
|
screenerCachedSummary: ['screener-cached', 'summary'] as const,
|
|
screenerCachedResult: (strategyId: string, asOf?: string, ext?: string) => ['screener-cached', 'strategy', strategyId, asOf ?? '', ext ?? ''] as const,
|
|
screenerCached: (asOf?: string, ext?: string) => ['screener-cached', 'all', asOf ?? '', ext ?? ''] as const,
|
|
screenerKlineBatch: (symbols: string) => ['screener-kline-batch', symbols] as const,
|
|
marketSnapshot: ['market-snapshot'] as const,
|
|
limitLadder: (asOf?: string) => ['limit-ladder', asOf] as const,
|
|
|
|
// Backtest
|
|
backtestStatus: ['backtest-status'] as const,
|
|
strategyDetail: (id: string) => ['strategy-detail', id] as const,
|
|
|
|
// Data / Pipeline
|
|
dataStatus: ['data-status'] as const,
|
|
pipelineJobs: ['pipeline-jobs'] as const,
|
|
pipelineJob: (id: string) => ['pipeline-job', id] as const,
|
|
extData: ['ext-data'] as const,
|
|
extDataRows: (id: string, date?: string, limit?: number, columns?: string) => ['ext-data-rows', id, date, limit, columns] as const,
|
|
dimensionMembers: (id: string, field: string, value: string, date?: string) => ['dimension-members', id, field, value, date] as const,
|
|
analysisMenus: ['analysis-menus'] as const,
|
|
analysisMenu: (id: string) => ['analysis-menu', id] as const,
|
|
|
|
// Kline
|
|
kline: (symbol: string, start: string, end: string, extColumns?: string) =>
|
|
['kline', symbol, start, end, extColumns ?? ''] as const,
|
|
stockLevels: (symbol: string, days?: number) => ['stock-levels', symbol, days ?? 120] as const,
|
|
klineMinute: (symbol: string, date: string) =>
|
|
['kline-minute', symbol, date] as const,
|
|
indexDaily: (symbol: string, start: string, end: string) =>
|
|
['index-daily', symbol, start, end] as const,
|
|
indexMinute: (symbol: string, date: string) =>
|
|
['index-minute', symbol, date] as const,
|
|
|
|
// Schema
|
|
extDataSchemaAll: ['ext-data-schema-all'] as const,
|
|
tableSchema: (table: string) => ['table-schema', table] as const,
|
|
|
|
// Custom Signals
|
|
customSignals: ['custom-signals'] as const,
|
|
customSignalsOptions: ['custom-signals-options'] as const,
|
|
|
|
// Monitor (监控规则 + 触发记录)
|
|
monitorRules: ['monitor-rules'] as const,
|
|
monitorRuleOptions: ['monitor-rule-options'] as const,
|
|
alerts: (source?: string) => ['alerts', source ?? ''] as const,
|
|
|
|
// AI 大盘复盘
|
|
reviewReports: ['review-reports'] as const,
|
|
|
|
// 概念涨幅轮动矩阵
|
|
rpsRotation: (days: number) => ['rps-rotation', days] as const,
|
|
|
|
// 市场环境(Regime) — 日级离线计算, 不进 SSE 刷新
|
|
regimeHistory: (limit?: number) => ['regime-history', limit ?? 0] as const,
|
|
regimeLatest: ['regime-latest'] as const,
|
|
regimeStates: (days: number) => ['regime-states', days] as const,
|
|
} as const
|
|
|
|
// ===== SSE 应该 invalidate 的 key 前缀列表 =====
|
|
// 新增需要 SSE 推送的查询,只需在此加一行
|
|
//
|
|
// 注意: 策略页 (screener-cached) 不在此列表 —— 行情刷新时策略结果不变
|
|
// (非监控策略读盘后静态缓存, 监控策略由独立的 strategy_results_updated 事件在
|
|
// 重算完成后刷新)。若加入 'screener', 会导致每个行情 tick 双重刷新策略页,
|
|
// 且在 monitor "重算" 窗口内读到空结果, 造成策略列表闪烁 (变 0 → 空失效 → 又出现)。
|
|
|
|
export const SSE_INVALIDATE_PREFIXES = [
|
|
'watchlist',
|
|
'quote-status',
|
|
'index-quotes',
|
|
'overview-market',
|
|
'limit-ladder',
|
|
] as const
|