diff --git a/frontend/src/components/screener/StrategyPoolDialog.tsx b/frontend/src/components/screener/StrategyPoolDialog.tsx index 8f41e09..ffee88a 100644 --- a/frontend/src/components/screener/StrategyPoolDialog.tsx +++ b/frontend/src/components/screener/StrategyPoolDialog.tsx @@ -8,8 +8,6 @@ interface Props { pool: string[] onConfirm: (newPool: string[]) => void onClose: () => void - /** 列表周期: 1d 日线 / 1m 分钟, 与策略页当前周期一致 */ - timeframe?: '1d' | '1m' } const SOURCE_CLS: Record = { @@ -26,6 +24,8 @@ const SOURCE_LABEL: Record = { invalid: '失效', } +const TF_BADGE_CLS = 'text-[8px] px-1 py-px rounded border leading-tight shrink-0 border-purple-500/30 bg-purple-500/10 text-purple-400' + type SourceTab = 'all' | 'builtin' | 'custom' | 'ai' const TABS: { id: SourceTab; label: string }[] = [ @@ -44,7 +44,7 @@ function fileStem(name: string): string { return name.replace(/\.py$/i, '').replace(/[^A-Za-z0-9_-]/g, '_').replace(/^_+|_+$/g, '') } -export function StrategyPoolDialog({ pool, onConfirm, onClose, timeframe = '1d' }: Props) { +export function StrategyPoolDialog({ pool, onConfirm, onClose }: Props) { const backdrop = useDialogBackdrop(onClose) // 草稿状态: 打开时从 pool 复制, 操作只改草稿, 点确定才提交 const [draftPool, setDraftPool] = useState(() => [...pool]) @@ -59,7 +59,8 @@ export function StrategyPoolDialog({ pool, onConfirm, onClose, timeframe = '1d' const loadStrategies = useCallback(async () => { setLoading(true) try { - const d = await api.strategyList(undefined, timeframe) + // 不按周期过滤: 日线+分钟策略合并展示, 分钟策略以徽章区分 + const d = await api.strategyList(undefined, 'all') setAllStrategies(d.strategies) } catch { setAllStrategies([]) @@ -238,6 +239,9 @@ export function StrategyPoolDialog({ pool, onConfirm, onClose, timeframe = '1d' {SOURCE_LABEL[s.source] ?? '内置'} + {s.timeframes?.includes('1m') && ( + 分钟 + )} ))} @@ -282,6 +286,9 @@ export function StrategyPoolDialog({ pool, onConfirm, onClose, timeframe = '1d' {SOURCE_LABEL[src] ?? '内置'} + {s?.timeframes?.includes('1m') && ( + 分钟 + )} - ) - })} - - {/* 周期切换: 日线 (盘后缓存) / 分钟 (本地分钟K分区实时计算) */} -
- {(['1d', '1m'] as const).map(tf => ( + {(['stock', 'etf'] as const).map(t => ( + ))} +
+ {/* 周期筛选: 全部 / 日线 / 分钟 — 只过滤卡片显示, 不影响池与执行路由 */} +
+ {(['all', '1d', '1m'] as const).map(tf => ( + ))}
@@ -754,13 +772,15 @@ export function Screener() { {cardSize !== 'hidden' && (
{strategies.isLoading &&
加载中…
} - {!strategies.isLoading && visiblePool.length === 0 && ( + {!strategies.isLoading && displayPool.length === 0 && (
- 策略池为空,点击右上角「策略池」按钮添加策略 + {pool.length === 0 + ? '策略池为空,点击右上角「策略池」按钮添加策略' + : '当前周期筛选下无策略,切换周期筛选或编辑策略池'}
)}
- {visiblePool.map(id => { + {displayPool.map(id => { const s = strategyMap.get(id) if (!s) return null return ( @@ -814,9 +834,9 @@ export function Screener() { / {showAll ? allRows.length : result!.total} )} - · {visiblePool.length} 策略 - {!showAll && visiblePool.length > 0 && ( - <> · 共 {visiblePool.reduce((sum, id) => sum + (hitCounts[id] ?? 0), 0)} 只 + · {displayPool.length} 策略 + {!showAll && displayPool.length > 0 && ( + <> · 共 {displayPool.reduce((sum, id) => sum + (hitCounts[id] ?? 0), 0)} 只 )} {runAll.isPending && ( @@ -1002,7 +1022,9 @@ export function Screener() { onSaved={(limit) => { if (settingsStrategyId) { setStrategyLimits(prev => ({ ...prev, [settingsStrategyId]: limit })) - run.mutate({ id: settingsStrategyId, date: asOf }) + // 按策略自身周期重跑: 日线用当前 asOf, 分钟实时单跑交后端取最新分区 + const tf = strategyMap.get(settingsStrategyId)?.timeframes?.includes('1m') ? '1m' as const : '1d' as const + run.mutate({ id: settingsStrategyId, date: tf === '1m' ? '' : asOf, timeframe: tf }) } }} onAiModify={async () => { @@ -1038,7 +1060,6 @@ export function Screener() { {showPoolDialog && ( { reorderPool(newPool) }} @@ -1055,7 +1076,7 @@ export function Screener() { if (!data.presets.some(s => s.id === id)) { throw new Error(`策略 ${id} 已保存但未加载,请检查策略代码`) } - addToPool(id, '1d') // 构建器创建的是日线策略, 即使在分钟页保存也入日线池 + addToPool(id) }} /> @@ -1064,7 +1085,7 @@ export function Screener() { onClose={() => setShowComposite(false)} onSavedId={async id => { await qc.fetchQuery({ queryKey: QK.screenerStrategies('all'), queryFn: () => api.screenerStrategies(), staleTime: 0 }) - addToPool(id, '1d') // 叠加策略为日线策略, 固定入日线池 + addToPool(id) }} />