1. 安装
1.1 环境要求
- Chrome 102 及以上,或新版 Edge
- 已获取扩展安装包(
dist文件夹或压缩包)
1.2 开发者模式加载
- 打开浏览器扩展管理页:
- Chrome:地址栏输入
chrome://extensions/ - Edge:地址栏输入
edge://extensions/
- Chrome:地址栏输入
- 打开右上角「开发者模式」开关
- 点击「加载已解压的扩展程序」,选择扩展的
dist文件夹(即构建产物所在目录,不是压缩包) - 加载成功后,点击浏览器工具栏的拼图图标,将「财运Up」固定到工具栏方便随时打开
1.3 打开方式
点击工具栏上的「财运Up」图标即可弹出面板;再次点击空白处或按Esc关闭。
::: tip
图标角标会显示持仓盈亏(角标与提醒),无需打开弹窗即可一眼看到持仓盈亏情况。
:::
2. 快速上手
- 点击工具栏「财运Up」图标打开弹窗
- 默认停留在「自选」页签,在上方搜索框输入股票名称/代码/拼音(支持股票、ETF、指数),点击搜索结果添加自选
- 行情会按设置的刷新间隔自动更新,底部状态栏显示「N 秒前更新 · 共 M 只」
- 点击任意行情行或大盘指数卡片,可打开该品种的分时/K 线图
弹窗共 5 个页签:
| 页签 | 用途 |
|---|---|
| 自选 | 自选股行情列表(本地保存) |
| 持仓 | 持仓成本、数量与盈亏(已注册账号可云端同步) |
| 大盘 | 三大指数、涨跌家数、两市成交额 |
| 资金 | 北向资金成交额、主力资金净流入 |
| 设置 | 注册码、行情、外观、角标与提醒等 |
3. 功能详解
3.1 自选
自选列表保存在本地浏览器中,不同设备之间不同步。
添加自选:在「自选」页顶部搜索框输入关键词(股票名称/代码/拼音),在下拉结果中点击所需品种即可添加;再次点击同名股票可快速查看或避免重复添加。
行情列:
- 固定列:名称、现价、涨跌(%)、涨跌额
- 可选列(在「设置 → 自选列」中勾选):今开、昨收、量、额、量比、换手、振幅、PE动、PE(TTM)、PB、总市值、流通市值、买一、卖一
分页:自选数量超过「每页行数」时,列表下方出现翻页按钮(‹ ›)。
删除:鼠标悬停在某一行时,行尾出现红色×按钮,点击删除。
打开图表:点击任意行情行,打开该品种的分时/K 线图。
::: warning 未注册限制
未注册或 VIP0 用户自选股最多2 只。验证注册码后可添加任意数量。
:::
3.2 持仓
「持仓」页用于记录持仓成本与数量,并计算盈亏。
添加持仓:在顶部搜索框搜索股票,点击结果后在弹层中输入成本价与数量,点击「添加持仓」。
编辑持仓:点击持仓行中「代码 · 成本xx · N股 ✎」字样,修改成本价/数量后点「保存」。
持仓信息:每行显示名称、现价、盈亏额与盈亏百分比。
仅关注标签:未填写成本与数量(数量=0 且成本=0)的持仓会标记「仅关注」,仅用于观察、不计入盈亏汇总。
添加到自选:点击行右侧 ☆/★ 图标可将该股票加入自选(★ 表示已在自选中)。
删除持仓:点击行右侧红色×。
汇总:列表底部显示「总市值」与「持仓盈亏(金额与百分比)」。
::: tip 云端同步
已注册账号的持仓会与服务器双向同步(注册与授权),换设备后重新验证注册码即可恢复持仓。自选不会同步。
:::
::: warning 未注册限制
未注册或 VIP0 用户最多可添加2 只持仓,且持仓列表仅显示前 2 只。验证注册码后显示全部。
:::
3.3 大盘
「大盘」页提供市场总览:
- 三大指数卡片:上证指数、深证成指、创业板指,显示点位、涨跌额与涨跌幅;点击卡片打开对应指数图表
- 涨跌家数:上涨 / 下跌 / 平盘个股数量
- 两市成交额:沪深两市合计成交额(沪、深、创业三大指数成交额之和)
页面底部同时显示数据更新时间。数据在弹窗打开期间按刷新间隔自动更新。
3.4 资金
「资金」页提供两类资金数据:
- 北向资金成交额(沪深港通):沪股通 + 深股通当日成交额合计
::: note
交易所自 2024-08 起不再实时披露沪深港通净买额,因此本页展示成交额而非净买入。休市(如周末)成交额为 0.00 亿属正常。
::: - 主力资金(沪深合计):两市主力净流入合计,以及「沪市主力净流入」「深市主力净流入」明细,单位均为亿元,正数红色、负数绿色。
3.5 图表
点击自选/持仓行情行或大盘指数卡片可打开图表浮层,支持:
- 周期切换:分时、日K、周K、月K(顶部页签切换)
- 成交量:分时图与 K 线图下方同步显示成交量柱
- 图表随弹窗放大显示,点击遮罩或右上角
×关闭
性能说明:首次打开某只股票的图表时,扩展会尝试多个行情服务器(备用分片主机),若主站被限流会切换到可用主机,因此第一次打开可能稍慢;之后同只股票图表在 30 秒内有本地缓存,可秒开,且会记住上次可用的服务器、后续打开更快。
4. 设置说明
设置项全部位于弹窗「设置」页签,修改后自动保存并立即生效。
4.1 账号
| 设置项 | 说明 |
|---|---|
| 服务器 | 固定为stockapi1 / stockapi2(主备自动切换,无需手动配置) |
| 注册码 | 联系管理员获取;输入后点击「验证」或按回车 |
| 状态 | 显示当前注册状态与 VIP 等级 |
| 未注册限制 | 自选 / 持仓各限 2 只,验证后解锁 |
4.2 行情
| 设置项 | 默认值 | 说明 |
|---|---|---|
| 刷新间隔 (ms) | 1500 | 行情刷新间隔,范围 1000–60000,步长 500 |
| 非交易时段暂停轮询 | 关 | 开启后,非交易时段(周一至周五 09:15–15:00 之外,不含节假日判断)暂停刷新 |
4.3 自选列
勾选在自选表中显示的可选列(今开、昨收、量、额、量比、换手、振幅、PE、PB、市值、买一、卖一等)。弹窗宽度会随所选列数自动调整。
4.4 外观
- 主题:浅色(默认)/ 深色
- 涨跌颜色:默认(涨红跌绿)/ 自定义(可分别设置涨色、跌色)
4.5 角标与提醒
| 设置项 | 默认值 | 说明 |
|---|---|---|
| 工具栏角标(持仓盈亏) | 开 | 在浏览器工具栏图标上显示持仓盈亏数字 |
| 角标内容 | 总盈亏 | 总盈亏:按(现价-成本)× 数量汇总;今日盈亏:按今日涨跌额 × 数量汇总 |
| 价格提醒 | 开 | 触发高价/低价提醒时发送桌面通知(通知权限需在浏览器中授权) |
4.6 其他
- 重置为默认设置:将全部设置恢复为出厂默认值
5. 注册与授权
扩展的持仓同步与数量限制与「注册码」绑定。
如何注册
- 联系管理员(QQ:
63579228,QQ群:164653500)获取注册码 - 打开「设置」页签,在「注册码」输入框粘贴并点击「验证」
- 验证成功后会显示用户名与 VIP 等级
注册后的权益
- 自选股、持仓不再受 2 只上限限制
- 持仓与服务器双向同步:在其他设备重新验证同一注册码,即可恢复持仓列表
- 受限时持仓列表仅显示前 2 只
数据同步机制
- 服务端 = 持仓镜像:已注册后,本地持仓与服务器互相覆盖同步;删除持仓会同步删除服务器记录
- 自选纯本地:自选列表仅保存在当前浏览器,不参与服务器同步
- 网络不可用时保留本地数据,联网后自动重试同步
6. 角标与提醒
6.1 工具栏角标
- 后台每 1 分钟更新一次持仓行情并计算盈亏显示在工具栏图标上
- 颜色区分方向:盈利显示涨色(默认红)、亏损显示跌色(默认绿)、持平灰色
- 数字格式:小于 1 万显示整数元(如
520),达到 1 万显示x.x万(如1.5万),不带正负号,靠颜色区分盈亏 - 关闭「工具栏角标」后图标不再显示数字
6.2 价格提醒
- 开启「价格提醒」后,后台会检测自选股是否触发高价/低价提醒,触发时发送桌面通知
- 同一提醒触发一次后,需等价格回到提醒区间内才会再次触发
- 通知权限:首次触发时浏览器会请求通知权限,请选择「允许」
::: note
当前版本自选股的高价/低价阈值暂未提供界面配置入口(属预留功能);若后续版本开放配置,请在对应位置设置阈值。
:::
6.3 工具栏悬停提示
鼠标悬停在工具栏「财运Up」图标上时,浏览器会显示一个原生提示框,内容为自选股行情摘要:
- 每行一只自选股,格式为「名称 现价 涨幅」,如
贵州茅台 1280.66 +4.57% - 最多显示前 5 只,超出后末尾显示
… - 与角标一样约每 1 分钟刷新一次(数据可能滞后最多 1 分钟)
- 无自选股时提示框显示「财运Up」
::: note
该提示框为浏览器原生的纯文本提示,无法自定义颜色、排版或展示更多字段;如需查看完整行情请点击图标打开弹窗。
:::
// 生成扩展图标:深色圆角方块 + 两根K线(绿涨/红跌)// 纯 Node 实现 PNG 编码(zlib + CRC32),无第三方依赖import{deflateSync}from'node:zlib'import{mkdirSync,writeFileSync}from'node:fs'import{dirname,join}from'node:path'import{fileURLToPath}from'node:url'const__dirname=dirname(fileURLToPath(import.meta.url))constOUT=join(__dirname,'..','public','icons')// ---------- PNG 编码 ----------constCRC_TABLE=(()=>{constt=newUint32Array(256)for(letn=0;n<256;n++){letc=nfor(letk=0;k<8;k++)c=c&1?0xedb88320^(c>>>1):c>>>1t[n]=c>>>0}returnt})()functioncrc32(buf){letc=0xfffffffffor(leti=0;i<buf.length;i++)c=CRC_TABLE[(c^buf[i])&0xff]^(c>>>8)return(c^0xffffffff)>>>0}functionchunk(type,data){constlen=Buffer.alloc(4)len.writeUInt32BE(data.length)constbody=Buffer.concat([Buffer.from(type,'ascii'),data])constcrc=Buffer.alloc(4)crc.writeUInt32BE(crc32(body))returnBuffer.concat([len,body,crc])}functionencodePng(width,height,rgba){constsig=Buffer.from([0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a])constihdr=Buffer.alloc(13)ihdr.writeUInt32BE(width,0)ihdr.writeUInt32BE(height,4)ihdr[8]=8// bit depthihdr[9]=6// color type RGBAconstraw=Buffer.alloc((width*4+1)*height)for(lety=0;y<height;y++){constrowStart=y*(width*4+1)raw[rowStart]=0// filter: nonergba.copy(raw,rowStart+1,y*width*4,(y+1)*width*4)}returnBuffer.concat([sig,chunk('IHDR',ihdr),chunk('IDAT',deflateSync(raw,{level:9})),chunk('IEND',Buffer.alloc(0)),])}// ---------- 绘制 ----------constGREEN=[0x00,0xb5,0x78,255]// A股 涨=绿constRED=[0xe3,0x4d,0x59,255]// A股 跌=红constBG=[0x0f,0x12,0x18,255]// 深色底constROUND=0.22// 圆角比例functiondraw(size){constpx=Buffer.alloc(size*size*4)consts=sizeconstr=Math.round(s*ROUND)constinRoundRect=(x,y)=>{// 圆角矩形内判定constnearLeft=x<rconstnearRight=x>=s-rconstnearTop=y<rconstnearBottom=y>=s-rif(nearLeft&&nearTop){constdx=x-r+0.5constdy=y-r+0.5returndx*dx+dy*dy<=r*r}if(nearRight&&nearTop){constdx=x-(s-r)+0.5constdy=y-r+0.5returndx*dx+dy*dy<=r*r}if(nearLeft&&nearBottom){constdx=x-r+0.5constdy=y-(s-r)+0.5returndx*dx+dy*dy<=r*r}if(nearRight&&nearBottom){constdx=x-(s-r)+0.5constdy=y-(s-r)+0.5returndx*dx+dy*dy<=r*r}returntrue}constput=(x,y,[cr,cg,cb,ca])=>{consti=(y*s+x)*4consta=ca/255// 与背景做 alpha 混合px[i]=Math.round(cr*a+BG[0]*(1-a))px[i+1]=Math.round(cg*a+BG[1]*(1-a))px[i+2]=Math.round(cb*a+BG[2]*(1-a))px[i+3]=255}// 蜡烛: 左绿(涨) 右红(跌)// 左边蜡烛constlx=Math.round(s*0.16)constlw=Math.round(s*0.3)constbodyTop=Math.round(s*0.34)constbodyBot=Math.round(s*0.62)constwickTop=Math.round(s*0.22)constwickBot=Math.round(s*0.76)// 右边蜡烛constrx=Math.round(s*0.54)constrw=Math.round(s*0.3)constrBodyTop=Math.round(s*0.40)constrBodyBot=Math.round(s*0.70)constrWickTop=Math.round(s*0.24)constrWickBot=Math.round(s*0.80)for(lety=0;y<s;y++){for(letx=0;x<s;x++){if(!inRoundRect(x,y))continue// 左侧蜡烛(绿涨)constinLBody=x>=lx&&x<lx+lw&&y>=bodyTop&&y<=bodyBotconstinLWick=x>=lx+Math.round(lw*0.42)&&x<lx+Math.round(lw*0.58)&&y>=wickTop&&y<=wickBot// 右侧蜡烛(红跌)constinRBody=x>=rx&&x<rx+rw&&y>=rBodyTop&&y<=rBodyBotconstinRWick=x>=rx+Math.round(rw*0.42)&&x<rx+Math.round(rw*0.58)&&y>=rWickTop&&y<=rWickBotif(inLBody||inLWick)put(x,y,GREEN)elseif(inRBody||inRWick)put(x,y,RED)}}returnencodePng(s,s,px)}mkdirSync(OUT,{recursive:true})for(constsizeof[16,32,48,128]){writeFileSync(join(OUT,`icon${size}.png`),draw(size))console.log(`generated icon${size}.png`)}