dsh-plugin-wangcai 0.0.0-stage → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +75 -0
- package/README.md +259 -2
- package/client/client.js +87 -0
- package/cordis.patch.yml +4 -0
- package/docs/preview-dsh.jpg +0 -0
- package/docs/preview-fund.jpg +0 -0
- package/docs/preview-market.jpg +0 -0
- package/lib/index.js +208 -0
- package/package.json +58 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
|
2
|
+
|
|
3
|
+
# PolyForm Noncommercial License 1.0.0
|
|
4
|
+
|
|
5
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
|
|
14
|
+
|
|
15
|
+
## Distribution License
|
|
16
|
+
|
|
17
|
+
The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
|
|
18
|
+
|
|
19
|
+
## Notices
|
|
20
|
+
|
|
21
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
|
|
22
|
+
|
|
23
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
24
|
+
|
|
25
|
+
## Changes and New Works License
|
|
26
|
+
|
|
27
|
+
The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
|
|
28
|
+
|
|
29
|
+
## Patent License
|
|
30
|
+
|
|
31
|
+
The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
|
|
32
|
+
|
|
33
|
+
## Noncommercial Purposes
|
|
34
|
+
|
|
35
|
+
Any noncommercial purpose is a permitted purpose.
|
|
36
|
+
|
|
37
|
+
## Personal Uses
|
|
38
|
+
|
|
39
|
+
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
|
|
40
|
+
|
|
41
|
+
## Noncommercial Organizations
|
|
42
|
+
|
|
43
|
+
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
|
|
44
|
+
|
|
45
|
+
## Fair Use
|
|
46
|
+
|
|
47
|
+
You may have "fair use" rights for the software under the law. These terms do not limit them.
|
|
48
|
+
|
|
49
|
+
## No Other Rights
|
|
50
|
+
|
|
51
|
+
These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
|
|
52
|
+
|
|
53
|
+
## Patent Defense
|
|
54
|
+
|
|
55
|
+
If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
56
|
+
|
|
57
|
+
## Violations
|
|
58
|
+
|
|
59
|
+
The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
|
|
60
|
+
|
|
61
|
+
## No Liability
|
|
62
|
+
|
|
63
|
+
***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
|
|
64
|
+
|
|
65
|
+
## Definitions
|
|
66
|
+
|
|
67
|
+
The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
|
|
68
|
+
|
|
69
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
70
|
+
|
|
71
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
72
|
+
|
|
73
|
+
**Your licenses** are all the licenses granted to you for the software under these terms.
|
|
74
|
+
|
|
75
|
+
**Use** means anything you do with the software requiring one of your licenses.
|
package/README.md
CHANGED
|
@@ -1,3 +1,260 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 旺财看盘 · dsh-plugin-wangcai
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> 在 DeepSeek Harness 里看 A 股:**盘面 · 个股 · 资金面 · 消息面 · 直播**,装一个插件全都有。
|
|
4
|
+
|
|
5
|
+
**🌐 官网(含真实界面大图与功能详解):https://wangcai.hszl-bd.cn/plugin/**
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
大多数 A 股工具的问题是:数据散在五个网站、看完还得自己算、口径从不写清楚。
|
|
10
|
+
旺财看盘把「今天市场在发生什么」压成一句话结论,再让每个数字都能下钻到能验证的粒度。
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [装好之后你会看到什么](#装好之后你会看到什么)
|
|
17
|
+
- [📊 盘面数据](#-盘面数据)
|
|
18
|
+
- [📉 个股分析](#-个股分析)
|
|
19
|
+
- [💰 资金面](#-资金面)
|
|
20
|
+
- [📰 消息面](#-消息面)
|
|
21
|
+
- [📺 盘面直播](#-盘面直播)
|
|
22
|
+
- [🔒 暂未对外开放](#-暂未对外开放)
|
|
23
|
+
- [数据说明](#数据说明)
|
|
24
|
+
- [安装](#安装)
|
|
25
|
+
- [商务合作](#商务合作)
|
|
26
|
+
- [免责声明](#免责声明)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 装好之后你会看到什么
|
|
31
|
+
|
|
32
|
+
顶部五个标签页,每个标签下还有自己的子页。核心是**三层结构**:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
一句话结论 → 可验证的图表 → 能下钻的明细
|
|
36
|
+
(今天什么状态) (资金/涨跌/梯队) (哪只票、哪一笔)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 📊 盘面数据
|
|
44
|
+
|
|
45
|
+
六个子页,从「大盘现在什么温度」一路看到「哪只票封的板」。
|
|
46
|
+
|
|
47
|
+
### 大盘总览
|
|
48
|
+
|
|
49
|
+
- **两市成交额**:实时值 + 较昨日变化 + 按时间推算的**预计全天**
|
|
50
|
+
- **八大指数**:上证、深证成指、创业板指、北交所、沪深300、科创50、中证500、北证50
|
|
51
|
+
每个都带「较昨全天增减」和「今成交额」——不只看涨跌,还看**这波是真放量还是缩量拉的**
|
|
52
|
+
- **涨跌温度**:上涨/下跌/平盘家数 + **涨停/跌停家数**
|
|
53
|
+
- **情绪周期表**:近 20 个交易日的涨停数、跌停数、炸板数、主概念、连板高度,一屏看情绪潮汐
|
|
54
|
+
- **两融 vs 指数主图**:两融余额(左轴)叠上证(右轴)+ 融资净买入柱状,看杠杆和指数是否背离
|
|
55
|
+
|
|
56
|
+
### 连板梯队
|
|
57
|
+
|
|
58
|
+
- **按高度分组**:6 连板 / 4 连板 / 3 连板 / 2 连板 / 1 连板,每档可展开
|
|
59
|
+
- **行业涨停排行**:哪个行业今天涨停最多(如「广告营销 9 家 / 出版 8 家」),点行展开该行业涨停股
|
|
60
|
+
- **涨停明细**:代码、名称、行业、连板数、**换手率**、**封板资金**、**炸板次数**、**首封时间**、成交额
|
|
61
|
+
最后两项尤其关键——首封时间看资金抢筹早晚,封板资金看封得牢不牢
|
|
62
|
+
|
|
63
|
+
### 板块涨跌
|
|
64
|
+
|
|
65
|
+
行业 / 概念双维度切换,涨幅榜带**领涨个股**,一眼知道「这个板块是普涨还是龙头带飞」。
|
|
66
|
+
|
|
67
|
+
### 竞价异动
|
|
68
|
+
|
|
69
|
+
**9:25 竞价定格**后生成,专治开盘前的最后一分钟:
|
|
70
|
+
|
|
71
|
+
- 三类入选:竞价涨停(顶板)、高开 ≥5%、**昨日涨停股的承接监控**
|
|
72
|
+
- 字段:竞价涨幅、**当前涨跌**、竞价价、竞价额、换手%(竞价额/流通市值)、**末 1 分占比**、昨日表现、所属概念、**强度评级**
|
|
73
|
+
- 昨日表现直接标「首板 / 2 连板(一字) / 昨涨 3.42%」——一眼看出是**晋级**还是**核按钮**
|
|
74
|
+
- **末 1 分占比**:最后 1 分钟竞价成交额 ÷ 竞价总额,占比越高说明末段抢筹越猛
|
|
75
|
+
- **弱转强标签**:末段(9:24→9:25)拉升 ≥1 个点且末 1 分占比 ≥20% 自动打标并置顶——盘前 9:15-9:25 全程采样,能抓到「最后一分钟被资金顶上去」的票
|
|
76
|
+
|
|
77
|
+
### 美股盘面
|
|
78
|
+
|
|
79
|
+
道琼斯、纳斯达克、标普 500、纳指 100、VIX,外加 **20+ 个题材**(AI 算力、存储芯片、半导体、光通信、稀土永磁、商业航天、数字货币…),题材涨跌取代表性 ETF/龙头等权平均。
|
|
80
|
+
|
|
81
|
+
### 日韩盘面
|
|
82
|
+
|
|
83
|
+
日本 JPX、韩国 KRX,附带台湾加权与恒生作参照。**上涨红、下跌绿**,与 A 股口径一致。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 📉 个股分析
|
|
88
|
+
|
|
89
|
+
点任意股票代码(表格行、概念标签、消息里的个股标),弹出完整分析卡。**九块内容**:
|
|
90
|
+
|
|
91
|
+
| 区块 | 内容 |
|
|
92
|
+
|---|---|
|
|
93
|
+
| **行情条** | 现价、涨跌、开高低收、昨收、成交量额、换手率、PE、PB、总市值 |
|
|
94
|
+
| **概念标签** | 该股所属概念(茅指数、钠离子电池、固态电池…),**标签可点**,跳到同概念 |
|
|
95
|
+
| **股性评分** | 该股近期「活性」打分,判断好不好做 |
|
|
96
|
+
| **分时 / 日 K** | 双视图切换 |
|
|
97
|
+
| **四维评分** | **技术面 / 基本面 / 情绪面 / 综合**四个独立分数 |
|
|
98
|
+
| **技术指标** | RSI(6/12) 及超买超卖提示、MACD 红柱/绿柱状态、均线位置(跌破 60 日线)、BOLL 中轨位置 |
|
|
99
|
+
| **持有建议** | 结合**你是否持有**给结论:继续持有 / 观望 / 减持,并说明理由 |
|
|
100
|
+
| **板块与位置** | 所属板块强度、5/10/20 日涨幅、量比、MA5/MA20、当前价在 20 日高低点的分位 |
|
|
101
|
+
| **实时资讯** | 该股最近 8 条新闻(机构持股、回购、订单、评级) |
|
|
102
|
+
|
|
103
|
+
**两个别处少见的模块:**
|
|
104
|
+
|
|
105
|
+
**① 历史回测对比**
|
|
106
|
+
在 501 个交易日的历史里,找出与**当前形态最相似的 10 个案例**,给出:
|
|
107
|
+
- 平均后市收益(20 日内)
|
|
108
|
+
- 历史胜率
|
|
109
|
+
- 平均最高涨幅 / 平均最大回撤
|
|
110
|
+
|
|
111
|
+
**② AI 智能分析(Beta)**
|
|
112
|
+
分「规则分析」和「LLM 深度分析」两栏,输出行情概况 / 技术研判 / 量能分析三段判断,附综合评分与倾向。
|
|
113
|
+
|
|
114
|
+
> 所有分析都标注了「历史数据仅供参考,过去表现不代表未来收益」。
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 💰 资金面
|
|
119
|
+
|
|
120
|
+
这是整个产品的重心。
|
|
121
|
+
|
|
122
|
+
### 结论条
|
|
123
|
+
|
|
124
|
+
顶部两句话直说今天什么状态——**杠杆(两融,T+1)** 与 **今日板块资金(实时)**:
|
|
125
|
+
|
|
126
|
+
> 今日主力净流入 **+107.2 亿**(49 个板块流入 / 74 个流出)| 半导体 +44.5 亿、证券Ⅱ +28.1 亿、游戏Ⅱ +13.7 亿
|
|
127
|
+
|
|
128
|
+
下面这句是两融口径:
|
|
129
|
+
|
|
130
|
+
> 杠杆资金在撤:融资 5 日 −459 亿、20 日 −2,511 亿,两融余额继续下台阶。
|
|
131
|
+
> 板块层面(近 20 日累计):成长 −1,700 亿(半导体/通信设备/元件领跌),周期 −179 亿,防御 +21 亿。
|
|
132
|
+
|
|
133
|
+
下面挂三条**带箭头**的指标(杠杆 / 量能 / 主线)和一个 **0–100 的资金面温度**(冰点 / 中性 / 过热)。
|
|
134
|
+
|
|
135
|
+
### 板块资金流向(今日 / 3 / 5 / 10 / 20 日)
|
|
136
|
+
|
|
137
|
+
- 默认 **今日**,也可切换近 3 / 5 / 10 / 20 个交易日(今日为分钟级实时值,全量 124 个板块)
|
|
138
|
+
- **方块面积=净额**(金额越大面积越大),**左侧净流入、右侧净流出**,点方块看该板块成分股贡献
|
|
139
|
+
- 连续流入 / 连续流出 Top6,附连续天数与量能倍数
|
|
140
|
+
- 明细表:板块、涨跌、各周期净额、连续同向天数、量能倍数、成交额、20 日走势
|
|
141
|
+
|
|
142
|
+
### 融资盘动向(T+1)
|
|
143
|
+
|
|
144
|
+
按交易所披露节奏,展示**最近一个交易日**的融资资金去向:
|
|
145
|
+
|
|
146
|
+
- **板块维度**:哪些行业融资净买入、哪些在被融资盘卖出,附各行业融资余额与覆盖股票数
|
|
147
|
+
- **个股维度**:融资净买入 / 净卖出 Top 榜(已剔除 ETF)
|
|
148
|
+
- 页面标注「数据截至 MM-DD(T+1)」,不会把滞后数据说成实时
|
|
149
|
+
|
|
150
|
+
### 两融主图
|
|
151
|
+
|
|
152
|
+
两融余额(渐变面积,左轴)叠上证指数(右轴),下方独立红绿柱表示**每日融资净买入**。
|
|
153
|
+
悬停出十字线;点某一天可**锁定**并联动下方明细表。
|
|
154
|
+
|
|
155
|
+
### 板块资金透视
|
|
156
|
+
|
|
157
|
+
- 覆盖 **44 个行业**,周期可选 **3 / 5 / 10 / 20 日**
|
|
158
|
+
- 每行:涨跌、各周期净额、**连续同向天数**、量能倍数、成交额、20 日资金走势缩略图
|
|
159
|
+
- 五个筛选标签:全部 / 🔴 加速流出 / 🟢 加速流入 / ⚠️ **吸筹(价跌钱进)** / 🚨 **派发(价涨钱出)**
|
|
160
|
+
- 点行展开:20 日资金柱 + **个股贡献 Top5**
|
|
161
|
+
|
|
162
|
+
### 个股级下钻
|
|
163
|
+
|
|
164
|
+
点板块 → 拉出该板块**全部成分股**的当日资金(全量,不是抽样)。
|
|
165
|
+
所以这里翻**全量成分股**(行业板块最多 188 只,来自完整的行业成分数据,不是抽样、也不是前 40 只估算),能看到资金流出到底落在哪些具体标的上。
|
|
166
|
+
|
|
167
|
+
### 近 15 日资金明细
|
|
168
|
+
|
|
169
|
+
倒序排列(最新在上),含两融余额、融资余额、融券余额、融资买入占流通市值、涨跌家数,点击锁定主图。
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 📰 消息面
|
|
174
|
+
|
|
175
|
+
### 热度排行 TOP10
|
|
176
|
+
|
|
177
|
+
AI 归纳的每日十大事件,每条带:
|
|
178
|
+
|
|
179
|
+
- **利好 / 利空 / 中性** 标签
|
|
180
|
+
- **分类**(政策 / 行业动态 / 其他)
|
|
181
|
+
- 摘要 + **一句话点评**
|
|
182
|
+
- **自动识别的关联个股**(可点进个股分析,如「🎯 宁德时代 300750」)
|
|
183
|
+
- 热度条
|
|
184
|
+
|
|
185
|
+
### 快讯流
|
|
186
|
+
|
|
187
|
+
多源聚合,每条带来源标签、时间、标题、关联个股,点标题看详情。
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 📺 盘面直播
|
|
192
|
+
|
|
193
|
+
- **大盘直播**:盘中实时异动流,最新在前,一句话说清「谁在涨停、哪条线在走强、谁在跳水」
|
|
194
|
+
- **实时复盘**:按交易日切换(上一日 / 下一日)
|
|
195
|
+
- **导出复盘长图**:一键把当日复盘导成图片
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 🔒 暂未对外开放
|
|
200
|
+
|
|
201
|
+
以下两块在插件内**暂未开放**(页面可见,但相关接口未通过代理开启):
|
|
202
|
+
|
|
203
|
+
| 模块 | 状态 |
|
|
204
|
+
|---|---|
|
|
205
|
+
| 🎯 选股扫描 | 暂未对外开放 |
|
|
206
|
+
| 🧪 策略实验室 | 暂未对外开放 |
|
|
207
|
+
|
|
208
|
+
如果你需要,可以在本地部署旺财服务后自行开启。
|
|
209
|
+
|
|
210
|
+
## 数据说明
|
|
211
|
+
|
|
212
|
+
- 数据来自公开行情渠道的聚合,**可能存在延迟、缺失或偏差**
|
|
213
|
+
- 部分指标(如资金流向类)为**估算值**,不等同于权威统计,仅供参考
|
|
214
|
+
- 不同指标更新节奏不同,页面会标注「数据截至 MM-DD」
|
|
215
|
+
- 本插件不提供推荐、不代客理财、不承诺收益
|
|
216
|
+
|
|
217
|
+
## 安装
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# npm 安装(推荐)
|
|
221
|
+
dsh plugin --profile web add dsh-plugin-wangcai
|
|
222
|
+
|
|
223
|
+
# 或从 Gitee 源码
|
|
224
|
+
dsh plugin --profile web add gitee:shenzhen-huashuo-zhilian/dsh-plugin-wangcai
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
装完重启 `dsh web`,打开 **设置 → 旺财看盘**。
|
|
228
|
+
|
|
229
|
+
想先看看长什么样、有哪些功能,可以逛官网:**https://wangcai.hszl-bd.cn/plugin/**(含真实界面大图与数据说明)
|
|
230
|
+
|
|
231
|
+

|
|
232
|
+
|
|
233
|
+
| 环境变量 | 默认值 | 说明 |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `WANGCAI_BASE_URL` | `https://wangcai.hszl-bd.cn` | 旺财服务地址,自建可改(服务入口在 `/app/`,根路径为官网)|
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 免责声明
|
|
240
|
+
|
|
241
|
+
> **本站仅用于数据收集与展示,不构成任何投资建议。**
|
|
242
|
+
> 数据来源于第三方公开接口,可能存在延迟、缺失或错误,据此操作风险自负。
|
|
243
|
+
> 股市有风险,投资需谨慎。本站不代客理财、不承诺收益、不提供买卖点推荐。
|
|
244
|
+
> **仅供个人学习参考,未经许可不得商用。**
|
|
245
|
+
> 页面内的模拟盘与回测数据仅用于验证规则,不代表真实收益。
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
## 商务合作
|
|
249
|
+
|
|
250
|
+
插件定制、数据对接、私有化部署等需求,可在[产品官网](https://wangcai.hszl-bd.cn/plugin/)点击「联系」扫码添加微信(备注「旺财」)。
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
**PolyForm Noncommercial License 1.0.0** — 允许个人学习、研究与非商业使用;**未经许可不得商用**。
|
|
255
|
+
|
|
256
|
+
协议全文见 [LICENSE](LICENSE)。
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
<sub>English: **Wangcai Market Panel** — an A-share dashboard plugin for DeepSeek Harness. Seven panels: market breadth (indices, limit-up ladder, auction anomalies, US/JP/KR), per-stock analysis (4-dimension scoring, indicator suite, similar-pattern backtest, LLM commentary), eight screening strategies with paper-trading ledgers, capital flows (margin balance, 44-sector multi-period matrix, full constituent drill-down), AI news digest, and live market broadcast. Read-only by design: GET-only proxy, action paths blocked, 120 req/min rate limit, sandboxed iframe. **Not investment advice.**</sub>
|
package/client/client.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-plugin-wangcai — 客户端入口(DSH 模块加载器格式)
|
|
3
|
+
*
|
|
4
|
+
* 安全设计:iframe 用 sandbox 且**不给 allow-same-origin** → iframe 得到不透明源,
|
|
5
|
+
* 即使旺财页面的抓取内容里混进脚本,也够不到 DSH 的 localStorage / token / 接口。
|
|
6
|
+
*/
|
|
7
|
+
window.__ModuleLoader__.load({
|
|
8
|
+
id: 'dsh-plugin-wangcai',
|
|
9
|
+
factory: (require) => {
|
|
10
|
+
var module = { exports: {} }
|
|
11
|
+
var exports = module.exports
|
|
12
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
|
|
13
|
+
let react = require('react')
|
|
14
|
+
|
|
15
|
+
const name = 'dsh-plugin-wangcai'
|
|
16
|
+
const inject = ['slots']
|
|
17
|
+
|
|
18
|
+
const S = {
|
|
19
|
+
wrap: { height: '82vh', width: '100%', display: 'flex', flexDirection: 'column', gap: '6px' },
|
|
20
|
+
bar: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '10px', flexWrap: 'wrap' },
|
|
21
|
+
hint: { fontSize: '11.5px', opacity: 0.6 },
|
|
22
|
+
warn: {
|
|
23
|
+
fontSize: '11.5px',
|
|
24
|
+
lineHeight: 1.5,
|
|
25
|
+
color: '#e6b422',
|
|
26
|
+
background: 'rgba(230,180,34,.08)',
|
|
27
|
+
border: '1px solid rgba(230,180,34,.35)',
|
|
28
|
+
borderRadius: '8px',
|
|
29
|
+
padding: '6px 10px',
|
|
30
|
+
},
|
|
31
|
+
frame: {
|
|
32
|
+
flex: 1,
|
|
33
|
+
width: '100%',
|
|
34
|
+
border: '1px solid rgba(255,255,255,.08)',
|
|
35
|
+
borderRadius: '12px',
|
|
36
|
+
background: '#0b0e14',
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function Panel() {
|
|
41
|
+
return react.createElement(
|
|
42
|
+
'div',
|
|
43
|
+
{ style: S.wrap },
|
|
44
|
+
react.createElement(
|
|
45
|
+
'div',
|
|
46
|
+
{ style: S.bar },
|
|
47
|
+
react.createElement(
|
|
48
|
+
'div',
|
|
49
|
+
{ style: S.hint },
|
|
50
|
+
'旺财看盘 · 盘面数据 · 个股分析 · 盘面直播 · 消息面 · 资金面',
|
|
51
|
+
),
|
|
52
|
+
react.createElement(
|
|
53
|
+
'div',
|
|
54
|
+
{ style: S.warn },
|
|
55
|
+
'⚠️ 本站仅用于数据收集与展示,不构成任何投资建议。数据来源于第三方公开接口,可能存在延迟或错误,据此操作风险自负。',
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
react.createElement('iframe', {
|
|
59
|
+
src: '/wangcai-dsh/embed',
|
|
60
|
+
title: '旺财看盘',
|
|
61
|
+
sandbox: 'allow-scripts allow-forms allow-popups allow-modals',
|
|
62
|
+
referrerpolicy: 'no-referrer',
|
|
63
|
+
style: S.frame,
|
|
64
|
+
}),
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function apply(ctx) {
|
|
69
|
+
ctx.slots.inject('settings.section', () =>
|
|
70
|
+
ctx.slots.register(
|
|
71
|
+
{
|
|
72
|
+
name: 'settings.section',
|
|
73
|
+
id: 'wangcai',
|
|
74
|
+
order: 70,
|
|
75
|
+
label: () => '旺财看盘',
|
|
76
|
+
},
|
|
77
|
+
() => react.createElement(Panel),
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
exports.apply = apply
|
|
83
|
+
exports.inject = inject
|
|
84
|
+
exports.name = name
|
|
85
|
+
return module.exports
|
|
86
|
+
},
|
|
87
|
+
})
|
package/cordis.patch.yml
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-plugin-wangcai — 服务端入口(安全加固版 v0.2.0)
|
|
3
|
+
*
|
|
4
|
+
* 1) /wangcai-dsh/embed 下发旺财看盘 HTML(注入 API 路由 shim + 安全兜底)
|
|
5
|
+
* 2) /wangcai-dsh/api?p=/api/xxx 只读代理到旺财服务
|
|
6
|
+
*
|
|
7
|
+
* 安全边界(逐条对应实测发现):
|
|
8
|
+
* - 路径先 URL 规范化再校验前缀,堵住 `/api/market/../../xxx` 穿越
|
|
9
|
+
* - 只允许 GET/HEAD;POST/PUT/DELETE 一律 405(旺财写接口在代理层面不可达)
|
|
10
|
+
* - 交易/账户关键词二次拦截,403
|
|
11
|
+
* - 令牌桶限流 120 次/分钟/IP,防被当代理刷重接口
|
|
12
|
+
* - 白名单移除 /api/status(泄露登录态)与 /api/lab/*(含写接口)
|
|
13
|
+
* - 响应带 CSP(connect-src 'self')、nosniff,XSS 即便发生也出不去本站
|
|
14
|
+
*/
|
|
15
|
+
const WANGCAI_BASE = process.env.WANGCAI_BASE_URL || 'https://wangcai.hszl-bd.cn'
|
|
16
|
+
const PROXY_PATH = '/wangcai-dsh/api'
|
|
17
|
+
const EMBED_PATH = '/wangcai-dsh/embed'
|
|
18
|
+
|
|
19
|
+
const ALLOW_PREFIX = ['/api/market/', '/api/stock/', '/api/news/', '/api/ai/', '/api/health/', '/api/status']
|
|
20
|
+
// 少数接口需要更细的字段级过滤(页面启动依赖 /api/status,但不必暴露 cookie/交易器内部状态)
|
|
21
|
+
const FIELD_FILTER = { '/api/status': ['logged_in', 'trader_ready', 'cookie_exists'] }
|
|
22
|
+
const BLOCK_SEG = ['account', 'order', 'position', 'deal', 'trade', 'entrust', 'cancel', 'buy', 'sell', 'withdraw', 'transfer', 'delete', 'save', 'update']
|
|
23
|
+
// 用 GET 触发写操作的"动作型"分段(旺财的模拟盘买卖/结算就是 GET),代理层必须拦死
|
|
24
|
+
const ACTION_SEG = ['intraday_buy', 'close', 'settle', 'sim', 'force']
|
|
25
|
+
const RATE_LIMIT = 120 // 每窗口允许次数
|
|
26
|
+
const RATE_WINDOW_MS = 60_000
|
|
27
|
+
const buckets = new Map()
|
|
28
|
+
|
|
29
|
+
function buildCsp(req) {
|
|
30
|
+
// sandbox(无 allow-same-origin)下文档是不透明源,'self' 匹配不到服务器源,
|
|
31
|
+
// 必须把当前访问源显式写进 connect-src,否则页面所有接口请求会被 CSP 拦掉。
|
|
32
|
+
const host = req.headers['host'] || '127.0.0.1'
|
|
33
|
+
const proto = req.headers['x-forwarded-proto'] || 'http'
|
|
34
|
+
const origin = `${proto}://${host}`
|
|
35
|
+
return [
|
|
36
|
+
"default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:",
|
|
37
|
+
`connect-src 'self' ${origin}`,
|
|
38
|
+
"img-src 'self' data: blob: https:",
|
|
39
|
+
"style-src 'self' 'unsafe-inline'",
|
|
40
|
+
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
|
|
41
|
+
"frame-ancestors 'self'",
|
|
42
|
+
"base-uri 'self'",
|
|
43
|
+
"form-action 'none'",
|
|
44
|
+
].join('; ')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function json(res, status, obj) {
|
|
48
|
+
res.writeHead(status, {
|
|
49
|
+
'content-type': 'application/json; charset=utf-8',
|
|
50
|
+
'cache-control': 'no-store',
|
|
51
|
+
'x-content-type-options': 'nosniff',
|
|
52
|
+
})
|
|
53
|
+
res.end(JSON.stringify(obj))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function clientIp(req) {
|
|
57
|
+
return (req.socket && req.socket.remoteAddress) || req.headers['x-forwarded-for'] || 'unknown'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function rateOk(ip) {
|
|
61
|
+
const now = Date.now()
|
|
62
|
+
const b = buckets.get(ip)
|
|
63
|
+
if (!b || now > b.reset) {
|
|
64
|
+
buckets.set(ip, { count: 1, reset: now + RATE_WINDOW_MS })
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
b.count += 1
|
|
68
|
+
return b.count <= RATE_LIMIT
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** 规范化 + 校验目标路径,返回 {path, search} 或 null */
|
|
72
|
+
function parseTarget(raw) {
|
|
73
|
+
if (!raw || typeof raw !== 'string' || raw.length > 512) return null
|
|
74
|
+
let u
|
|
75
|
+
try {
|
|
76
|
+
u = new URL(raw, 'http://local.invalid') // URL 会把 ../ 与 %2e%2e 归一化
|
|
77
|
+
} catch {
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
const path = u.pathname
|
|
81
|
+
if (u.hostname !== 'local.invalid') return null // 拒绝 //evil.com 这类协议相对 URL
|
|
82
|
+
if (!path.startsWith('/api/')) return null
|
|
83
|
+
const low = path.toLowerCase()
|
|
84
|
+
if (low.includes('..') || low.includes('//') || low.includes('\\') || low.includes('\0')) return null
|
|
85
|
+
if (BLOCK_SEG.some((seg) => low.includes('/' + seg) || low.includes(seg + '/'))) return null
|
|
86
|
+
const segs = low.split('/').filter(Boolean)
|
|
87
|
+
if (segs.some((s) => ACTION_SEG.includes(s))) return null
|
|
88
|
+
if (!ALLOW_PREFIX.some((pre) => path.startsWith(pre))) return null
|
|
89
|
+
return { path, search: u.search || '' }
|
|
90
|
+
}
|
|
91
|
+
async function handleEmbed(req, res) {
|
|
92
|
+
if (!rateOk(clientIp(req))) return json(res, 429, { success: false, error: '请求过于频繁' })
|
|
93
|
+
try {
|
|
94
|
+
const r = await fetch(WANGCAI_BASE + '/app/', { signal: AbortSignal.timeout(20000) })
|
|
95
|
+
let html = await r.text()
|
|
96
|
+
const shim = `<script>
|
|
97
|
+
(function(){
|
|
98
|
+
var BASE = ${JSON.stringify(PROXY_PATH)};
|
|
99
|
+
function rewrite(u){
|
|
100
|
+
try {
|
|
101
|
+
var s = String(u);
|
|
102
|
+
if (s.indexOf('/api/') === 0) return BASE + '?p=' + encodeURIComponent(s);
|
|
103
|
+
return s;
|
|
104
|
+
} catch(e){ return u }
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
var of = window.fetch;
|
|
108
|
+
window.fetch = function(input, init){
|
|
109
|
+
if (typeof input === 'string') input = rewrite(input);
|
|
110
|
+
else if (input && input.url) { var u2 = rewrite(input.url); if (u2 !== input.url) input = new Request(u2, input); }
|
|
111
|
+
return of.call(this, input, init);
|
|
112
|
+
};
|
|
113
|
+
var oo = XMLHttpRequest.prototype.open;
|
|
114
|
+
XMLHttpRequest.prototype.open = function(m, u){
|
|
115
|
+
arguments[1] = rewrite(u);
|
|
116
|
+
return oo.apply(this, arguments);
|
|
117
|
+
};
|
|
118
|
+
// 沙箱/隐私模式下 storage 可能不可用,兜底成内存版,避免页面脚本抛错
|
|
119
|
+
try { window.localStorage.getItem('__t'); } catch (e) {
|
|
120
|
+
var mem = {};
|
|
121
|
+
var stub = { getItem: function(k){ return Object.prototype.hasOwnProperty.call(mem, k) ? mem[k] : null },
|
|
122
|
+
setItem: function(k,v){ mem[k] = String(v) }, removeItem: function(k){ delete mem[k] },
|
|
123
|
+
clear: function(){ mem = {} }, key: function(i){ return Object.keys(mem)[i] || null },
|
|
124
|
+
get length(){ return Object.keys(mem).length } };
|
|
125
|
+
try { Object.defineProperty(window, 'localStorage', { value: stub, configurable: true }); } catch (e2) {}
|
|
126
|
+
try { Object.defineProperty(window, 'sessionStorage', { value: stub, configurable: true }); } catch (e2) {}
|
|
127
|
+
}
|
|
128
|
+
} catch (e) {}
|
|
129
|
+
})();
|
|
130
|
+
</script>`
|
|
131
|
+
html = html.includes('</head>') ? html.replace('</head>', shim + '</head>') : shim + html
|
|
132
|
+
res.writeHead(200, {
|
|
133
|
+
'content-type': 'text/html; charset=utf-8',
|
|
134
|
+
'cache-control': 'no-store',
|
|
135
|
+
'content-security-policy': buildCsp(req),
|
|
136
|
+
'x-content-type-options': 'nosniff',
|
|
137
|
+
'referrer-policy': 'no-referrer',
|
|
138
|
+
})
|
|
139
|
+
res.end(html)
|
|
140
|
+
} catch (e) {
|
|
141
|
+
res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' })
|
|
142
|
+
res.end('旺财服务不可达:' + (e && e.message ? e.message : e))
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function handleProxy(req, res) {
|
|
147
|
+
const method = (req.method || 'GET').toUpperCase()
|
|
148
|
+
const cors = {
|
|
149
|
+
'access-control-allow-origin': '*',
|
|
150
|
+
'access-control-allow-methods': 'GET, HEAD, OPTIONS',
|
|
151
|
+
'access-control-allow-headers': 'content-type',
|
|
152
|
+
'x-content-type-options': 'nosniff',
|
|
153
|
+
}
|
|
154
|
+
if (method === 'OPTIONS') {
|
|
155
|
+
res.writeHead(204, cors)
|
|
156
|
+
return res.end()
|
|
157
|
+
}
|
|
158
|
+
if (method !== 'GET' && method !== 'HEAD') return json(res, 405, { success: false, error: '插件只读,仅支持 GET' })
|
|
159
|
+
|
|
160
|
+
if (!rateOk(clientIp(req))) return json(res, 429, { success: false, error: '请求过于频繁,请稍后再试' })
|
|
161
|
+
|
|
162
|
+
const url = new URL(req.url, 'http://local.invalid')
|
|
163
|
+
const t = parseTarget(url.searchParams.get('p') || '')
|
|
164
|
+
if (!t) return json(res, 403, { success: false, error: '该接口不在只读白名单内(插件只允许行情/资讯类 GET 接口)' })
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const r = await fetch(WANGCAI_BASE + t.path + t.search, {
|
|
168
|
+
method,
|
|
169
|
+
headers: { 'user-agent': 'dsh-plugin-wangcai/0.2' },
|
|
170
|
+
signal: AbortSignal.timeout(60000),
|
|
171
|
+
})
|
|
172
|
+
const body = await r.text()
|
|
173
|
+
let out = body
|
|
174
|
+
const keep = FIELD_FILTER[t.path]
|
|
175
|
+
if (keep) {
|
|
176
|
+
try {
|
|
177
|
+
const o = JSON.parse(body)
|
|
178
|
+
const f = {}
|
|
179
|
+
for (const k of keep) if (k in o) f[k] = o[k]
|
|
180
|
+
out = JSON.stringify(f)
|
|
181
|
+
} catch { out = '{}' }
|
|
182
|
+
}
|
|
183
|
+
res.writeHead(r.status, {
|
|
184
|
+
...cors,
|
|
185
|
+
'content-type': r.headers.get('content-type') || 'application/json; charset=utf-8',
|
|
186
|
+
'cache-control': 'no-store',
|
|
187
|
+
})
|
|
188
|
+
res.end(out)
|
|
189
|
+
} catch (e) {
|
|
190
|
+
json(res, 502, { success: false, error: '旺财接口请求失败:' + (e && e.message ? e.message : e) })
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const name = 'dsh-plugin-wangcai'
|
|
195
|
+
|
|
196
|
+
export function apply(ctx) {
|
|
197
|
+
ctx.inject(['webServer'], (host) => {
|
|
198
|
+
host.effect(() => {
|
|
199
|
+
const d1 = host.webServer.register({ kind: 'exact', path: EMBED_PATH, handler: handleEmbed })
|
|
200
|
+
const d2 = host.webServer.register({ kind: 'exact', path: PROXY_PATH, handler: handleProxy })
|
|
201
|
+
const timer = setInterval(() => {
|
|
202
|
+
const now = Date.now()
|
|
203
|
+
for (const [k, v] of buckets) if (now > v.reset) buckets.delete(k)
|
|
204
|
+
}, RATE_WINDOW_MS)
|
|
205
|
+
return () => { d1(); d2(); clearInterval(timer) }
|
|
206
|
+
}, 'wangcai: http routes')
|
|
207
|
+
})
|
|
208
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-wangcai",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "在 DeepSeek Harness 里看 A 股:盘面数据、个股分析、资金面、盘面直播、消息面。资金面含两融、44 板块多周期资金与个股全量下钻;个股支持四维评分与相似形态回测。仅数据展示与学习参考,不可商用,不构成任何投资建议。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./lib/index.js",
|
|
9
|
+
"./client": "./client/client.js",
|
|
10
|
+
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"lib",
|
|
14
|
+
"client",
|
|
15
|
+
"docs",
|
|
16
|
+
"cordis.patch.yml",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
21
|
+
"keywords": [
|
|
22
|
+
"deepseek",
|
|
23
|
+
"deepseek-harness",
|
|
24
|
+
"dsh",
|
|
25
|
+
"dsh-plugin",
|
|
26
|
+
"a-share",
|
|
27
|
+
"stock",
|
|
28
|
+
"market-data",
|
|
29
|
+
"capital-flow",
|
|
30
|
+
"dashboard",
|
|
31
|
+
"trading-view",
|
|
32
|
+
"cn-stock",
|
|
33
|
+
"finance"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=22.6"
|
|
37
|
+
},
|
|
38
|
+
"dsh": {
|
|
39
|
+
"bundle": {
|
|
40
|
+
"patch": "./cordis.patch.yml"
|
|
41
|
+
},
|
|
42
|
+
"client": {
|
|
43
|
+
"inject": [
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
45
|
+
],
|
|
46
|
+
"platform": "web"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@deepseek-ai/cordis": "4.0.1"
|
|
51
|
+
},
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://gitee.com/shenzhen-huashuo-zhilian/dsh-plugin-wangcai.git"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://wangcai.hszl-bd.cn/plugin/",
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://gitee.com/shenzhen-huashuo-zhilian/dsh-plugin-wangcai/issues"
|
|
59
|
+
}
|
|
60
|
+
}
|