feat: 量化模型迁移——K线获取(日/分钟)+多因子打分+IC自适应微调+推荐卡推送/REST/前端
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""前端追加「量化推荐」区(筛选按钮 + 事件渲染 + 表格 + 权重展示)"""
|
||||
import io
|
||||
|
||||
p = r'src\web\index.html'
|
||||
s = io.open(p, encoding='utf-8').read()
|
||||
|
||||
# 1) 筛选按钮
|
||||
old1 = ' <button data-f="事件影响分析">事件影响</button>'
|
||||
new1 = (old1 + '\n <button data-f="量化推荐">量化推荐</button>\n'
|
||||
' <button data-f="模型微调">微调</button>')
|
||||
assert old1 in s, 'filters not found'
|
||||
s = s.replace(old1, new1)
|
||||
|
||||
# 2) 主区追加量化推荐表格
|
||||
old2 = ' <ul id="feed"><li class="empty">等待服务端推送…</li></ul>\n</main>'
|
||||
new2 = (' <ul id="feed"><li class="empty">等待服务端推送…</li></ul>\n</main>\n'
|
||||
'<section style="max-width:1100px;margin:0 auto 30px">\n'
|
||||
' <h2 style="font-size:15px;color:var(--text)">量化模型 · 自适应推荐'
|
||||
'(多因子 + IC 微调)</h2>\n'
|
||||
' <div style="font-size:12px;color:var(--text2);margin-bottom:8px">'
|
||||
'权重:<span id="qw">加载中…</span></div>\n'
|
||||
' <div style="background:var(--surface);border:1px solid var(--border);'
|
||||
'border-radius:8px;overflow:auto">\n'
|
||||
' <table style="width:100%;border-collapse:collapse;font-size:13px" id="qtable">\n'
|
||||
' <thead><tr style="color:var(--text2);text-align:left">\n'
|
||||
' <th style="padding:8px 10px">代码</th><th style="padding:8px 10px">名称</th>\n'
|
||||
' <th style="padding:8px 10px">现价</th><th style="padding:8px 10px">模型分</th>\n'
|
||||
' <th style="padding:8px 10px">购入区间</th>'
|
||||
'<th style="padding:8px 10px">预计收益(回测口径)</th>\n'
|
||||
' <th style="padding:8px 10px">推荐指数</th>'
|
||||
'<th style="padding:8px 10px">简易原因</th>\n'
|
||||
' </tr></thead><tbody></tbody>\n'
|
||||
' </table>\n'
|
||||
' </div>\n'
|
||||
' <div style="margin-top:6px;font-size:11px;color:#6b7280">'
|
||||
'⚠ 购入区间与预计收益为模型回测/推测口径,不构成投资建议。</div>\n'
|
||||
'</section>')
|
||||
assert old2 in s, 'feed ul not found'
|
||||
s = s.replace(old2, new2)
|
||||
|
||||
# 3) WS 事件渲染分支(量化推荐)
|
||||
old3 = (" } else {\n"
|
||||
" const txt = typeof d === 'object' ? JSON.stringify(d) : String(d)\n"
|
||||
" li.innerHTML = `<span class=\"t\">${e.ts}</span><span class=\"k ${e.kind}\">${e.kind}"
|
||||
"</span><span class=\"d\">${esc(txt)}</span>`\n }")
|
||||
new3 = (" } else if (e.kind === '量化推荐') {\n"
|
||||
" renderQuant(e.data)\n"
|
||||
" const txt = '自适应模型推送 ' + ((d.list || []).length) + ' 只推荐'\n"
|
||||
" li.innerHTML = `<span class=\"t\">${e.ts}</span><span class=\"k ${e.kind}\">${e.kind}"
|
||||
"</span><span class=\"d\">${esc(txt)}</span>`\n"
|
||||
" } else {\n"
|
||||
" const txt = typeof d === 'object' ? JSON.stringify(d) : String(d)\n"
|
||||
" li.innerHTML = `<span class=\"t\">${e.ts}</span><span class=\"k ${e.kind}\">${e.kind}"
|
||||
"</span><span class=\"d\">${esc(txt)}</span>`\n }")
|
||||
assert old3 in s, 'render branch not found'
|
||||
s = s.replace(old3, new3)
|
||||
|
||||
# 4) 渲染函数与加载
|
||||
old4 = 'connect()'
|
||||
new4 = (
|
||||
"function renderQuant(d) {\n"
|
||||
" const tb = document.querySelector('#qtable tbody')\n"
|
||||
" if (!tb) return\n"
|
||||
" tb.innerHTML = (d.list || []).map(r =>\n"
|
||||
" '<tr><td style=\"padding:6px 10px\">' + esc(r.code) + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\">' + esc(r.name) + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\">' + r.price + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\">' + r.score + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\">' + r.buy_low + ' ~ ' + r.buy_high + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\">' + (r.expected_return_pct == null ? '—' : r.expected_return_pct + '%') + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\" class=\"stars\">' + '★'.repeat(r.stars) + '</td>' +\n"
|
||||
" '<td style=\"padding:6px 10px\">' + esc(r.reason) + '</td></tr>').join('')\n"
|
||||
"}\n"
|
||||
"function loadQuant() {\n"
|
||||
" fetch('/api/quant/recommendations').then(r => r.json()).then(renderQuant).catch(() => {})\n"
|
||||
" fetch('/api/quant/weights').then(r => r.json()).then(w => {\n"
|
||||
" document.getElementById('qw').textContent =\n"
|
||||
" Object.entries(w || {}).map(([k, v]) => k + '=' + Number(v).toFixed(2)).join(' ') || '—'\n"
|
||||
" }).catch(() => {})\n"
|
||||
"}\n"
|
||||
"loadQuant()\n"
|
||||
"setInterval(loadQuant, 60000)\n"
|
||||
"connect()")
|
||||
assert old4 in s
|
||||
s = s.replace(old4, new4, 1)
|
||||
|
||||
io.open(p, 'w', encoding='utf-8').write(s)
|
||||
print('index.html 量化推荐区 OK')
|
||||
Reference in New Issue
Block a user