"use client"; import { useEffect, useState } from "react"; import { apiGet, apiPost } from "@/lib/api"; import type { FactorMeta, FactorTestReport, ResearchSpec } from "@/lib/types"; export default function FactorsPage() { const [factors, setFactors] = useState([]); const [name, setName] = useState("momentum_60"); const [start, setStart] = useState("2024-03-01"); const [end, setEnd] = useState("2024-12-31"); const [report, setReport] = useState(null); const [running, setRunning] = useState(false); const [error, setError] = useState(""); useEffect(() => { apiGet("/factors") .then(setFactors) .catch((e: Error) => setError(e.message)); }, []); function run() { setRunning(true); setError(""); const spec: ResearchSpec = { type: "factor_test", universe: { exclude_st: true, min_listing_days: 0 }, factors: [{ name, weight: 1 }], selection: { top_n: 10 }, rebalance: "monthly", period: [start, end], }; apiPost("/factor-tests", spec) .then(setReport) .catch((e: Error) => setError(e.message)) .finally(() => setRunning(false)); } return ( <>

因子研究

因子目录(行情因子 · 无未来函数)

{factors.map((f) => ( ))}
名称 描述 公式 回看 方向
{f.name} {f.description} {f.formula} {f.lookback} {f.direction === "higher_is_better" ? "高为好" : "低为好"}

运行单因子测试(IC / RankIC / 分层)

{error &&
{error}
} {report && (
IC 均值
{report.ic_mean.toFixed(4)}
RankIC 均值
{report.rank_ic_mean.toFixed(4)}
ICIR
{report.icir.toFixed(3)}
正收益占比
{report.positive_ratio_pct.toFixed(1)}%
样本日数
{report.sample_days}
{report.quantile_returns.length > 0 && ( {report.quantile_returns.map((q) => ( ))} {report.quantile_returns.map((q) => ( ))}
分层(1 最低 → 5 最高)Q{q.quantile + 1}
未来 21 日平均收益{q.return_pct.toFixed(2)}%
)}
)}
); }