修复回测指标数据缺失提示问题

This commit is contained in:
shy3130
2026-07-22 13:30:02 +08:00
parent a12e49d66d
commit 60fe9e6fa6
3 changed files with 33 additions and 5 deletions
+1 -1
View File
@@ -686,7 +686,7 @@ def load_market_data_matrix_from_parquet(
raise ValueError(f"matrix parquet root does not exist: {root}")
available_start, available_end = _partition_date_bounds(root)
if available_start is None or available_end is None:
raise ValueError("matrix parquet root contains no dated partitions")
raise ValueError("本地指标数据为空,请先在数据页面同步日K并完成指标计算")
effective_start = max(start, available_start)
effective_end = min(end, available_end)
if effective_start > effective_end:
@@ -294,6 +294,19 @@ def test_market_matrix_derives_live_raw_close_when_requested():
np.testing.assert_array_equal(snapshot.field("raw_close")[-1], snapshot.close[-1])
def test_direct_parquet_matrix_reports_actionable_error_when_enriched_is_empty(tmp_path):
market_root = tmp_path / "kline_daily_enriched"
market_root.mkdir()
with pytest.raises(ValueError, match="本地指标数据为空"):
load_market_data_matrix_from_parquet(
market_root,
date(2024, 1, 1),
date(2024, 1, 31),
field_columns=set(),
)
def test_direct_parquet_matrix_matches_panel_builder_and_reuses_mmap(tmp_path):
market_root = tmp_path / "kline_daily_enriched"
days = (date(2024, 1, 2), date(2024, 1, 3), date(2024, 1, 4))
@@ -921,7 +921,12 @@ export function StrategyBacktest() {
const isPending = backtestTask?.isPending ?? false
const dataStatus = useDataStatus()
const earliestDate = dataStatus.data?.daily?.earliest_date ?? null
const backtestDataStatus = assetType === 'etf'
? dataStatus.data?.etf_enriched
: dataStatus.data?.enriched
const earliestDate = backtestDataStatus?.earliest_date ?? null
const backtestDataUnavailable = dataStatus.isSuccess && !earliestDate
const backtestDataLabel = assetType === 'etf' ? 'ETF 指标数据' : '股票指标数据'
const resetConfigFromDetail = (detail: StrategyDetail) => {
setStrategyParams(strategyDefaultParams(detail))
@@ -981,7 +986,7 @@ export function StrategyBacktest() {
}, [backtestTask])
const handleRun = () => {
if (!selectedStrategy) return
if (!selectedStrategy || backtestDataUnavailable) return
const requestOverrides = detail
? normalizeStrategyOverrides(detail, overrides)
: overrides
@@ -1587,6 +1592,13 @@ export function StrategyBacktest() {
</div>
)}
{backtestDataUnavailable && (
<div className="flex items-start gap-1.5 rounded-btn border border-danger/30 bg-danger/10 px-3 py-2 text-[11px] leading-4 text-danger">
<AlertTriangle className="mt-0.5 h-3 w-3 shrink-0" />
<span>{backtestDataLabel}K并完成指标计算</span>
</div>
)}
{isPending ? (
<button
onClick={stopBacktest}
@@ -1600,7 +1612,7 @@ export function StrategyBacktest() {
) : (
<button
onClick={handleRun}
disabled={!selectedStrategy || strategyDetail.isLoading}
disabled={!selectedStrategy || strategyDetail.isLoading || backtestDataUnavailable}
className="group w-full inline-flex items-center justify-center gap-2.5 rounded-btn border border-accent/40
bg-gradient-to-r from-accent to-blue-500 px-3 py-2.5 text-white shadow-[0_10px_24px_rgba(59,130,246,0.22)]
transition-all duration-150 ease-smooth hover:-translate-y-0.5 hover:shadow-[0_14px_28px_rgba(59,130,246,0.28)]
@@ -1671,7 +1683,10 @@ export function StrategyBacktest() {
{backtestTask?.error && (
<div className="text-sm text-danger bg-danger/10 border border-danger/30 rounded-btn px-3 py-2">
{backtestTask.error}
<div>{backtestTask.error}</div>
{result && (
<div className="mt-1 text-xs text-secondary"></div>
)}
</div>
)}