mirror of
https://ghfast.top/https://github.com/aeroxw/easy-tdx.git
synced 2026-09-12 19:14:16 +08:00
纯前端 TypeScript 实现,零后端改动。回测/组合/寻优三处结果顶部 显示评级徽章,让普通人 1 秒判断「适不适合经常参与」。 评级不看收益率(避免被近期大涨误导),只看风险调整后的持有体验: 卡玛/最大回撤/胜率/利润因子/夏普/波动率六维加权 + 一票否决。 京东方「收益 126% 但胜率 35%」案例 = D 档(核心验证点)。 长线低频策略(6年6笔)不会被冤枉:交易<10笔时只降权胜率/利润因子 维度,不否决整个评级(修复用户实测反馈)。 - 新增 web-ui/src/grading/ 核心模块(engine/thresholds/combinedMetrics/index) - 新增 GradeBadge.vue + GradeDetails.vue 组件 - 接入 BacktestView/PortfolioView/OptimizeView(寻优排名表加评级列) - 15 个自检测试(node:test + rolldown 打包),覆盖京东方 D / 长线 B 等场景
51 lines
1.5 KiB
JavaScript
51 lines
1.5 KiB
JavaScript
/**
|
||
* 把评级测试入口打包成单文件 JS,再用 node:test 跑。
|
||
*
|
||
* 项目未引入 vitest/jest,临时用 rolldown(vite 自带依赖)打包,
|
||
* 避免 Node 原生 strip-types 对 ESM 无后缀 import 的限制。
|
||
*
|
||
* 运行:node scripts/run-grading-tests.mjs
|
||
*/
|
||
|
||
import { build } from 'rolldown'
|
||
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'
|
||
import { tmpdir } from 'node:os'
|
||
import { join, resolve } from 'node:path'
|
||
import { spawnSync } from 'node:child_process'
|
||
|
||
const tmpDir = mkdtempSync(join(tmpdir(), 'grading-tests-'))
|
||
const bundlePath = join(tmpDir, 'bundle.mjs')
|
||
|
||
// 入口:导入测试文件,触发 node:test 注册
|
||
const entryPath = join(tmpDir, 'entry.mjs')
|
||
writeFileSync(
|
||
entryPath,
|
||
`import '${resolve('src/grading/__tests__/grade.test.ts').replace(/\\/g, '/')}'\n`,
|
||
)
|
||
|
||
console.log('→ 打包中…')
|
||
try {
|
||
await build({
|
||
input: entryPath,
|
||
output: {
|
||
file: bundlePath,
|
||
format: 'esm',
|
||
},
|
||
// 顶层 await / dynamic import 都 OK
|
||
platform: 'node',
|
||
// 不外部化 node 内置
|
||
external: ['node:test', 'node:assert', 'node:assert/strict', 'node:os', 'node:fs', 'node:path', 'node:child_process'],
|
||
// 强制把测试文件和 grading 模块都打进 bundle
|
||
treeshake: false,
|
||
})
|
||
} catch (e) {
|
||
console.error('打包失败:', e)
|
||
process.exit(1)
|
||
}
|
||
|
||
console.log('→ 运行测试…')
|
||
const r = spawnSync('node', ['--test', bundlePath], { stdio: 'inherit' })
|
||
|
||
rmSync(tmpDir, { recursive: true, force: true })
|
||
process.exit(r.status ?? 0)
|