优化三层打分模型:短期引入幅度因子与量能确认,中期资金信号连续化,长期加入价格维度,新增波动率调整

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
fish
2026-05-04 22:57:45 +08:00
parent 23a1149c5f
commit 76ddc495c1
5 changed files with 247 additions and 61 deletions

View File

@@ -34,10 +34,32 @@ watch(
}
},
)
const quadrantTag = (q: string) => {
const map: Record<string, string> = {
accumulation: 'success',
distribution: 'warning',
covering: 'info',
liquidation: 'danger',
flat: '',
}
return map[q] ?? ''
}
const quadrantLabel = (q: string) => {
const map: Record<string, string> = {
accumulation: '增仓涨',
distribution: '增仓跌',
covering: '减仓涨',
liquidation: '减仓跌',
flat: '持平',
}
return map[q] ?? q
}
</script>
<template>
<el-drawer v-model="visible" title="打分明细" :size="isMobile ? '92%' : '640px'" destroy-on-close>
<el-drawer v-model="visible" title="打分明细" :size="isMobile ? '92%' : '680px'" destroy-on-close>
<div v-loading="loading" v-if="score">
<el-descriptions :column="isMobile ? 1 : 2" border>
<el-descriptions-item label="品种">{{ parseTsCode(score.ts_code).symbol }}</el-descriptions-item>
@@ -60,20 +82,47 @@ watch(
<h4 class="section">短期 7 日逐日打分</h4>
<div class="table-wrapper">
<el-table :data="score.detail?.short_details ?? []" size="small" border class="detail-table">
<el-table
:data="score.detail?.short_details ?? []"
size="small"
border
class="detail-table"
max-height="400"
>
<el-table-column prop="trade_date" label="日期" width="100" />
<el-table-column prop="close" label="收盘" />
<el-table-column prop="pre_close" label="昨收" />
<el-table-column prop="oi" label="持仓" />
<el-table-column prop="oi_chg" label="持仓变化" />
<el-table-column prop="score" label="单日得分" />
<el-table-column prop="close" label="收盘" width="70" />
<el-table-column label="涨跌幅" width="80">
<template #default="{ row }">
<span :style="{ color: row.price_chg_pct >= 0 ? '#e4393c' : '#1ca11c' }">
{{ ((row.price_chg_pct ?? 0) * 100).toFixed(2) }}%
</span>
</template>
</el-table-column>
<el-table-column label="OI变化%" width="90">
<template #default="{ row }">
{{ ((row.oi_chg_pct ?? 0) * 100).toFixed(2) }}%
</template>
</el-table-column>
<el-table-column label="量比" width="65">
<template #default="{ row }">
{{ row.vol_ratio ?? '-' }}
</template>
</el-table-column>
<el-table-column label="象限" width="85">
<template #default="{ row }">
<el-tag :type="quadrantTag(row.quadrant)" size="small">
{{ quadrantLabel(row.quadrant) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="score" label="得分" width="65" />
</el-table>
</div>
<h4 class="section">中期(15d)细节</h4>
<el-descriptions :column="isMobile ? 1 : 2" border v-if="score.detail?.medium_detail">
<el-descriptions-item label="价格收益率">
{{ (score.detail.medium_detail.price_return_pct * 100).toFixed(2) }}%
{{ score.detail.medium_detail.price_return_pct.toFixed(2) }}%
</el-descriptions-item>
<el-descriptions-item label="价格信号分">
{{ score.detail.medium_detail.price_signal.toFixed(2) }}
@@ -85,20 +134,48 @@ watch(
{{ score.detail.medium_detail.long_down_days }}
</el-descriptions-item>
<el-descriptions-item label="资金意愿分" :span="isMobile ? 1 : 2">
{{ score.detail.medium_detail.fund_signal }}
{{ score.detail.medium_detail.fund_signal.toFixed(1) }}
<span class="formula-hint">(50 + (增仓涨 - 增仓跌)/{{ score.detail.medium_detail.window ?? 15 }} × 50)</span>
</el-descriptions-item>
</el-descriptions>
<h4 class="section">长期(30d)细节</h4>
<el-descriptions :column="isMobile ? 1 : 2" border v-if="score.detail?.long_detail">
<el-descriptions-item label="OI 趋势分">
{{ score.detail.long_detail.oi_score?.toFixed(1) ?? '-' }}
<span class="formula-hint">(权重 60%)</span>
</el-descriptions-item>
<el-descriptions-item label="价格趋势分">
{{ score.detail.long_detail.price_score?.toFixed(1) ?? '-' }}
<span class="formula-hint">(权重 40%)</span>
</el-descriptions-item>
<el-descriptions-item label="30 日价格收益">
{{ score.detail.long_detail.price_return_30d_pct?.toFixed(2) ?? '-' }}%
</el-descriptions-item>
<el-descriptions-item label="30 日前收盘">
{{ score.detail.long_detail.price_before_30d?.toFixed(2) ?? '-' }}
</el-descriptions-item>
<el-descriptions-item label="30 日均持仓">
{{ score.detail.long_detail.avg_oi.toFixed(0) }}
</el-descriptions-item>
<el-descriptions-item label="30 日前持仓">
{{ score.detail.long_detail.oi_before.toFixed(0) }}
</el-descriptions-item>
<el-descriptions-item label="变化幅度" :span="isMobile ? 1 : 2">
{{ (score.detail.long_detail.change_pct * 100).toFixed(2) }}%
<el-descriptions-item label="OI 变化幅度" :span="isMobile ? 1 : 2">
{{ score.detail.long_detail.change_pct.toFixed(2) }}%
</el-descriptions-item>
</el-descriptions>
<h4 class="section">波动率调整</h4>
<el-descriptions :column="isMobile ? 1 : 2" border v-if="score.detail?.volatility">
<el-descriptions-item label="日波动率(30d std)">
{{ (score.detail.volatility.daily_vol_pct * 100).toFixed(2) }}%
</el-descriptions-item>
<el-descriptions-item label="ATR%">
{{ (score.detail.volatility.atr_pct * 100).toFixed(2) }}%
</el-descriptions-item>
<el-descriptions-item label="波动率惩罚系数" :span="isMobile ? 1 : 2">
{{ score.detail.volatility.vol_penalty.toFixed(3) }}
</el-descriptions-item>
</el-descriptions>
</div>
@@ -113,6 +190,11 @@ watch(
overflow-x: auto;
}
.detail-table {
min-width: 520px;
min-width: 620px;
}
.formula-hint {
color: var(--el-text-color-secondary);
font-size: 12px;
margin-left: 6px;
}
</style>