我写了个终端盯盘工具,按一下 b 键就能假装在编译代码
2026/8/10 11:55:44 网站建设 项目流程

我写了个终端盯盘工具,按一下 b 键就能假装在编译代码

项目已更新到 v0.2.1:新增持仓与收益显示(按t切换)、中英界面切换(按l)、快捷键提示(按h),并默认全英文 UI 强化「在工作」的伪装。

事情是这样的。

某天下午三点,我第五次切到同花顺看了一眼,又切回来继续写代码。动作很流畅,不到一秒。但隔壁工位的同事还是注意到了。

“你股票亏了多少?”

我说没亏。他不信。因为屏幕上一片红绿,你说没亏谁信啊。

但其实问题不是亏不亏,而是盯盘这件事本身是公开的。你每一次切屏、每一次盯着红绿数字看,都等于在告诉别人——我现在没在工作。哪怕你确实只是扫了一眼就回来改 bug 了,那种"被抓到"的感觉也很不爽。

我在终端里工作。一天八个小时,不是在 Vim 里就是在 tmux 里。我当时想的是:如果能在终端里看行情就好了,别人路过看到的全是代码,我也用不着来回切窗口了。

翻了翻,已有的方案都不太对劲:

  • tushare/baostock:要注册、要 token,数据接口是给量化分析用的,不是给人盯盘用的。
  • 同花顺/东方财富的 Web 版:一个浏览器标签页在那摆着,标题就写着"行情",掩耳盗铃。
  • curl 请求然后 grep:能用,但这个体验,讲真,你盯不了三分钟。

于是我开始写了。

选型

需求很明确:

  • 终端里跑,不要开浏览器
  • 不要 API Key,不要注册
  • 别人路过看一眼时,不能一眼看出是在看股票
  • 安装尽量简单

第三点是最重要的。纯文本还不够——要是上面写着"贵州茅台 1690.00 +0.90%",懂行的看一眼就知道你在干嘛。必须有一个一键切换伪装模式的功能。

所以最后的选型是:

  • Python 3.10+ 标准库 + 三个第三方包
  • Rich 做终端 UI(Live + Table)
  • Sina Finance API 做数据源(免费的,不需要 Key)
  • TOML 做配置文件

整个项目叫 BossKey-Stock。这个 BossKey(老板键)才是核心功能。

架构

代码不多,拆了几个模块:

bosskey_stock/ ├── __main__.py CLI 入口 ├── app.py 主循环 + 终端控制 ├── data.py Sina 数据源 ├── boss.py 老板模式伪装 ├── config.py 配置读写 └── i18n.py 中英文案对照表(v0.2.1 新增)

CLI 层没什么好说的,argparse 路由几个子命令。配置读写就是 tomlkit 读写 ~/.bosskey.toml。

有意思的部分是终端控制和老板模式。

Rich Live

Rich 自带一个 Live 组件,可以在终端里维护一个"动态区域",内容可以实时更新。实现上它用了 alternate screen buffer——就是 vim、top 那种模式,程序退出后终端会恢复到之前的内容。

典型用法就是:

withLive(auto_refresh=False,screen=True)aslive:whileTrue:live.update(build_table(),refresh=True)time.sleep(interval)

直接这样写的话,刷新间隔内程序是卡死的,没法处理键盘输入。所以需要一点改造。

非阻塞键盘输入

这也是踩坑最多的地方。

为什么不用 input()?input() 是行缓冲的——它要等到用户按了回车才会返回。但我要的是单键响应:按 b 立刻切模式,按 q 立刻退出,不能等回车。

为什么不用 curses?curses 可以做到,但它接管了整个终端,和 Rich 的 Live 组件有冲突。Rich 依赖底层的终端控制来做色彩和渲染,curses 一插手就乱套了。两个库抢终端控制权,谁都不让谁。

方案:直接操作 termios。Python 标准库提供了 termios 和 select,可以精确控制终端的行为。核心思路是:只改输入的配置,不改输出侧。

def_setup_tty(fd):attrs=termios.tcgetattr(fd)# 输入侧:关掉 ICANON(逐键模式)、ECHO(不回显)、ISIG(不发信号)attrs[3]&=~(termios.ECHO|termios.ICANON|termios.ISIG)# 输出侧:不动,保留 OPOST,确保 \n → \r\n 正常转换termios.tcsetattr(fd,termios.TCSAFLUSH,attrs)

改完之后,os.read(fd, 1) 就能读到单个按键了,不需要回车。然后主循环里用 select 做非阻塞检查:

def_read_key(fd):r,_,_=select.select([fd],[],[],0.5)# 最多等 0.5 秒ifr:returnos.read(fd,1).decode("utf-8",errors="replace")returnNone

这里有个细节:select 的 timeout 设成 0.5 秒,而不是用非阻塞模式。原因是主循环里还要做定时刷新(每 3 秒拉一次行情),不能真的阻塞在 read 上。select 返回后如果是超时(没按键),就继续往下走,检查要不要刷新数据。如果用户按了键,就处理按键逻辑。

这样整个主循环就在一个线程里完成了:键盘监听 + 定时刷新 + UI 渲染。不需要后台线程,不需要锁。

一个容易踩的坑:ICRNL。在调试过程中发现一个奇怪的现象:回车键(\r)会被转换成换行(\n),导致按键检测出错。这个问题只在某些终端模拟器上出现。查了一下,是 termios 的 ICRNL 标志在搞鬼。这个标志会把收到的 \r 自动转成 \n。我的解决方案是关掉它:

attrs[0]&=~(termios.ICRNL|termios.IXON)# ICRNL 是关键

老板模式

老板模式的实现其实很简单。就是按 b 键时,切换一个布尔值,然后渲染不同的内容:

ifboss_mode:live.update(boss.render(),refresh=True)continue

boss.render() 生成一段模拟的 Docker build 日志。核心逻辑就是随机选一些步骤,组合成看起来像正经构建的输出。

为了让日志更逼真,我加了一些细节:

  • Docker 的构建步骤编号
  • 偶尔的 WARNING 信息
  • Running time: MM:SS 的计时器
  • 日志每秒滚动两行(通过时间来偏移数组位置)

这些逻辑都在 BossGenerator 类里,有个预生成的日志池子,5 倍重复后循环滚动。效果还不错——我让公司另一个同事看了看,他说"你又在折腾 Docker?"

我说对,一直在折腾。

数据层

数据源是 Sina Finance 的行情接口。不需要 API Key,只要一个 HTTP 请求:

GET https://hq.sinajs.cn/list=sh600519,sz000001 Referer: https://finance.sina.com.cn

返回的是 JavaScript 变量赋值,GBK 编码:

var hq_str_sh600519="贵州茅台,1680.00,1675.00,1690.00,1700.00,1670.00,...";

解析逻辑不复杂,按逗号分割,取需要的字段。但有一些需要注意的点:

  1. 代码前缀转换。以 6 和 9 开头的代码是上交所(sh 前缀),其他是深交所(sz 前缀)。正则从响应行里提取代码时,用的是 hq_str_[a-z]+(\d+)=" 这个模式。
  2. 成交量格式化。Sina 返回的成交量单位是股(不是手)。A 股一手等于 100 股。显示时要转成手为单位。
  3. 交易时段检测。没必要在非交易日和休息时间刷数据。判断逻辑是:周一到周五,9:30-11:30 或 13:00-15:00。非交易时段显示 [After Hours] 并展示数据源的最后成交时间。
  4. 离线处理。网络请求超时或异常时,requests 不会抛异常,而是返回 None。主循环里检测到 None 会显示 [Offline] 黄色提示,并且保留上一次拉到的数据,而不是清空表格。

v0.2.x:持仓收益、中英切换、快捷键提示

首版能看行情、能伪装之后,这个月又迭代了两版(v0.2.0 / v0.2.1),几个关键更新:

持仓与收益显示

光看行情还不够,摸鱼党还得知道自己赚没赚钱。v0.2.0 加了完整的持仓管理:

  • CLI 子命令pos add/pos rm/pos listpos add是交互式的——从监控列表里多选股票,逐个录入股数和成本价,自动加入监控列表。
  • TUI 里按t循环切换持仓、成本、持仓收益(率)、今日收益(率)列。
  • 底部同步汇总总市值 / 总成本、总收益(率)、今日收益(率)。

收益计算很简单:持仓收益 = (现价 − 成本) × 股数;今日收益 = 涨跌额 × 股数。收益列红盈绿亏独立着色,和行情表反过来,一眼看清。

中英界面切换

v0.2.1 把界面文案全部抽到了 i18n.py(key → (en, zh) 对照表),然后默认英文。

这个默认值是有讲究的:英文界面配合老板模式,伪装才完整——中文一眼就能读出"持仓"“收益"这几个词,英文(对非母语者)一眼难读,看起来更像"在写代码时瞥一眼日志”。

切换方式有三种,按需选:

  • TUI 内按l,会话内即时切换;
  • CLI 全局参数--lang {en,zh}单次覆盖;
  • 配置文件 ~/.bosskey.toml 的 [display] lang 设置初始语言。

老板模式的日志主体保持英文 Docker 命令,只有底部状态行本地化——毕竟 Docker 日志本来就是英文的,中英都改了反而穿帮。

快捷键提示

h开关底部快捷键提示行(默认隐藏,维持极简)。第一次用不知道按什么键,按一下 h 就全列出来了;用熟了再按一下隐藏。

顺手还清理了一处冗余:原来"今日收益"模式里有个 TodayP/L% 列,数值和基础列 Chg%(涨跌幅)完全一样,删了,模式 3 现在是 14 列。

现在的完整快捷键:

功能
b老板模式 / 切回行情
t切换持仓 / 成本 / 持仓收益 / 今日收益列
l中英界面切换
h快捷键提示行开关
r手动刷新
q/ Ctrl+C退出

摸鱼之外

回到最开始的问题。

这个工具解决的其实不是"能看股票",而是"看股票这件事不给别人带来心理压力"。

老板键这个概念其实很老了——从 DOS 时代就有,按一下 F1 把一个游戏界面变成一张正版的 Lotus 1-2-3 表格。我做的这个,只不过是把终端变成了伪装工具。

技术上没什么特别高深的。但这个过程让我想通了一件事:很多看似"偷懒"的需求,本质是对当前环境的一种不适应。程序员在终端里工作 8 小时,偶尔想看一眼行情,这是很正常的。不正常的是这个行为在办公室里带有负面的社会信号——“他不好好工作”。

工具解决不了这个问题,但至少让人少了一点尴尬。

安装

pipinstallbosskey-stock

运行bosskey即可。需要 Python 3.10+。当前版本 v0.2.1。

相关链接

  • 项目源码:github.com/Angryshark128/bosskey-stock
  • PyPI:pypi.org/project/bosskey-stock
  • 使用说明:README.md(含 normal / boss / demo 三份截图,可用 scripts/make_screenshots.py 复现)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询