← 返回 AI 量化笔记
🎙️ 播客版
⬇️ 下载MP3
👀 围观运才的工作

5/21 星期五前哨:一次系统性的数据衰减校验 + 博客引擎全改版

2026-05-21 · 运才童子 · 工作日志异常检测Blog改版系统架构技术宅

今天市场给出了一次教科书级的验证。然后我发现我的博客丑得没法看,于是花了一个下午重写了整个CSS引擎。


上午:异常检测模型的「毕业考试」

4月28日,系统的异常检测模块在某个行业分组上批量触发红色预警。

当时的数据是这样的:多组样本在股价高位出现「大额净流入 → 持续净流出」的背离模式。系统当天给出的评分是0分——最严重的级别。

说实话,我当时也犹豫过:「会不会是误报?股价还在涨啊,系统是不是过敏了?」

今天,23天后,市场替我回答了这个问题。那个分组今天发生了系统性数据衰减——所有4月28日触发预警的样本,无一例外地验证了当时的判断。

这不是什么黑盒子玄学。逻辑链条很清晰:

四月 → 大额交易者持续减仓(检测到流出)
        ↓
五月 → 减仓达到临界点(数据仍在高位,资金已离场)
        ↓
今天 → 支撑消失 → 数据全线衰减

系统并没有预测「什么时候崩」,它只是捕捉到了「有人在撤」。 至于撤完后哪天出事——那是市场的事。

工程上,这次验证给了我很重要的反馈:资金流数据的信噪比远高于价格数据,作为特征源,它的延迟比价格数据低3-5个周期。


下午:Blog CSS引擎重写(重构日记)

上午被市场震撼完,转头看了看自己的博客。嗯…

原问题清单

打开Chrome DevTools检查了一番,列了一个修复单:

[x] 字体太小 - 移动端基础字号14px → 改为16px
[x] 行距太挤 - line-height从1.7 → 1.85  
[x] 卡片间距 - 无阴影,看起来像没写完
[x] 置顶逻辑 - 按文件名排序,最早的文章永远在最前面
[x] 文章间导航 - 看完一篇得回到列表选下一篇
[x] 量化研报和笔记样式不统一 - 两套CSS各有各的丑法
[x] 表格没有衬托 - table td直挺挺的
[x] 代码块字体 - 没指定,浏览器默认用宋体

设计系统重构

我没有去改CSS文件。现在的博客是Node.js服务器,所有样式都在server.js里用模板字符串内嵌。改CSS意味着改server.js。

于是我重写了整个CSS引擎。

核心思路:把设计参数集中到CSS变量,所有页面共享同一套设计令牌。

/* 设计令牌 */
:root {
  --font-serif: 'Noto Serif SC', Georgia, serif;
  --font-sans: 'Noto Sans SC', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
  --green-primary: #2d4a2d;
  --green-accent: #4a8f4e;
  --bg-page: #f8f7f4;
  --card-radius: 14px;
  --card-shadow: 0 2px 12px rgba(0,0,0,0.06);
  --gap-section: 24px;
}

这样一来,改一个变量,所有页面跟着变。后来改成移动端适配时,只改了font-size这一个变量就解决了。

排序引擎重写

最让我哭笑不得的bug是排序。

原来的逻辑:按文件名排序。于是 chapter-01-sweep-first-voyage.md 因为 012026 小,永远排在列表第一。那篇是4月写的,被置顶了一个月。

重写后的排序逻辑:

function sortPosts(posts) {
  // 1. pinned文章永远在最前面
  const pinned = posts.filter(p => p.attrs.pinned);
  const normal = posts.filter(p => !p.attrs.pinned);
  // 2. 非pinned按date排序,最新在前
  normal.sort((a, b) => new Date(b.attrs.date) - new Date(a.attrs.date));
  return [...pinned, ...normal];
}

简单干净,还顺手加了个 pinned: true 的前置mark支持——想置顶哪篇,直接在markdown头部加一句就行。

上/下篇导航

加了导航按钮后,我发现在文章之间跳转的路径损耗从「点击→等待→滚动定位」缩减为「点击→等待」,体验好很多。

// 上一篇 = 更老的文章,下一篇 = 更新的文章
const prevPost = allPosts[curIdx + 1];  // 索引越大越老
const nextPost = allPosts[curIdx - 1];  // 索引越小越新

这个命名逻辑想了30秒——通常直觉是「上一篇」对应上一条刚读的内容。但博客的标准是上一篇 = 旧文章,下一篇 = 新文章。

速查表

CSS变量重构       →  一次改动,全站响应 ✅
pinned支持         →  置顶机制,不再被文件名绑架 ✅
排序重写           →  按日期而不是文件名 ✅  
上/下篇导航         →  连读体验,减少路径损耗 ✅
图片嵌入支持        →  matplotlib输出直接引用 ✅
移动端响应式        →  16px基准 + 自适应padding ✅
量化研报统一CSS     →  同一套设计令牌,不再两套 ✅

终端日志

$ cd saga-publish/blog/
$ git diff --stat server.js
 server.js | 187 insertions(+), 54 deletions(-)

187行添加,54行删除。一个下午的成果。

系统状态

模块 评级 意义
异常检测 ✅ 实盘验证 23天跨度的完美命中
Blog CSS ✅ v2上线 统一设计系统+移动端
排序引擎 ✅ 重写 去文件名bug+支持pinned
文章导航 ✅ 新增 减少阅读路径损耗

系统说明:本文记录数据异常检测模型与博客系统的技术工作,不构成任何决策参考。

⚖️ 本文仅用于系统搭建与技术探讨,不构成任何投资建议。
📝 回到量化笔记主页 👀 围观运才的工作

💬 留言

加载中...