├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── jestconfig.json
├── package-lock.json
├── package.json
├── src
├── index.ts
├── stocks
│ ├── base
│ │ ├── index.ts
│ │ ├── transforms
│ │ │ ├── api-code.ts
│ │ │ ├── common-code.ts
│ │ │ └── stock.ts
│ │ └── utils
│ │ │ └── constant.ts
│ ├── index.ts
│ ├── netease
│ │ ├── index.ts
│ │ ├── transforms
│ │ │ ├── api-code.ts
│ │ │ ├── common-code.ts
│ │ │ └── stock.ts
│ │ └── utils
│ │ │ └── constant.ts
│ ├── sina
│ │ ├── index.ts
│ │ ├── transforms
│ │ │ ├── api-code.ts
│ │ │ ├── common-code.ts
│ │ │ └── stock.ts
│ │ └── utils
│ │ │ └── constant.ts
│ ├── tencent
│ │ ├── index.ts
│ │ ├── transforms
│ │ │ ├── api-code.ts
│ │ │ ├── common-code.ts
│ │ │ └── stock.ts
│ │ └── utils
│ │ │ └── constant.ts
│ └── xueqiu
│ │ ├── index.ts
│ │ ├── transforms
│ │ ├── api-code.ts
│ │ ├── common-code.ts
│ │ └── stock.ts
│ │ └── utils
│ │ └── constant.ts
├── types
│ ├── index.d.ts
│ ├── stocks
│ │ ├── index.d.ts
│ │ └── transforms
│ │ │ ├── api-code.d.ts
│ │ │ ├── common-code.d.ts
│ │ │ └── stock.d.ts
│ └── utils
│ │ ├── dictionary.d.ts
│ │ └── stock.d.ts
└── utils
│ ├── constant.ts
│ ├── fetch.ts
│ └── iconv.ts
├── tea.yaml
├── test
└── stocks
│ ├── base
│ ├── index.test.ts
│ └── transforms
│ │ ├── api-code.test.ts
│ │ ├── common-code.test.ts
│ │ └── stock.test.ts
│ ├── netease
│ ├── index.test.ts
│ └── transforms
│ │ ├── api-code.test.ts
│ │ ├── common-code.test.ts
│ │ └── stock.test.ts
│ ├── sina
│ ├── index.test.ts
│ └── transforms
│ │ ├── api-code.test.ts
│ │ ├── common-code.test.ts
│ │ └── stock.test.ts
│ ├── tencent
│ ├── index.test.ts
│ └── transforms
│ │ ├── api-code.test.ts
│ │ ├── common-code.test.ts
│ │ └── stock.test.ts
│ └── xueqiu
│ ├── index.test.ts
│ └── transforms
│ ├── api-code.test.ts
│ ├── common-code.test.ts
│ └── stock.test.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | .DS_Store
3 | node_modules/
4 | coverage/
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024 zhangxiangliang
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
19 | OR OTHER DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
股票数据小助手
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## 简介
12 |
13 | 一款聚焦在 `股票实时数据` 和 `周边相关服务` 的接口小助手。
14 |
15 | ## 股票数据
16 |
17 | ### 已实现
18 |
19 | | 名称 | 接口名 | 搜索股票代码 | 获取股票实时数据 | 获取股票组实时数据 | 官网 |
20 | | :------: | :-----: | :---------------------: | :-------------------------: | :---------------------------: | :------------------------------: |
21 | | 网易财经 | netease | [已实现](#搜索股票代码) | [已实现](#获取股票实时数据) | [已实现](#获取股票组实时数据) | [传送门](https://money.163.com/) |
22 | | 腾讯股票 | tencent | [已实现](#搜索股票代码) | [已实现](#获取股票实时数据) | [已实现](#获取股票组实时数据) | [传送门](http://gu.qq.com/) |
23 |
24 | ### 待实现
25 |
26 | | 名称 | 接口名 | 搜索股票代码 | 获取股票实时数据 | 获取股票组实时数据 | 官网 |
27 | | :------: | :----: | :---------------------: | :-------------------------: | :---------------------------: | ----------------------------------------- |
28 | | 雪球 | xueqiu | [已实现](#搜索股票代码) | [待实现](#获取股票实时数据) | [待实现](#获取股票组实时数据) | [传送门](https://xueqiu.com/) |
29 | | 新浪股票 | sina | [已实现](#搜索股票代码) | [待实现](#获取股票实时数据) | [待实现](#获取股票组实时数据) | [传送门](https://finance.netease.com.cn/) |
30 |
31 | ## 安装
32 |
33 | ```shell
34 | npm install stock-api
35 | ```
36 |
37 | ## 使用
38 |
39 | ### 接口概览
40 |
41 | - [选择数据源](#选择数据源)
42 | - [搜索股票代码](#搜索股票代码)
43 | - [获取股票实时数据](#获取股票实时数据)
44 | - [获取股票组实时数据](#获取股票组实时数据)
45 |
46 | ### 股票代码
47 |
48 | 由于每个交易所数据规则不一样,为了能统一规范对代码定义了规则 `交易所+股票代码`。
49 |
50 | | 交易所 | 代号 | 实例 |
51 | | ---------- | ---- | -------- |
52 | | 上海交易所 | SH | SH000001 |
53 | | 深圳交易所 | SZ | SZ399001 |
54 | | 香港交易所 | HK | HKHSI |
55 | | 美国交易所 | US | USDJI |
56 |
57 | ### 选择数据源
58 |
59 | ##### 可选导入
60 |
61 | ```typescript
62 | import { stocks } from "stock-api";
63 |
64 | // 数据源
65 | const netease = stocks.netease;
66 | const tencent = stocks.tencent;
67 | ```
68 |
69 | ### 搜索股票代码
70 |
71 | ##### 示例
72 |
73 | ```typescript
74 | import { stocks } from "stock-api";
75 |
76 | // 获取股票组实时数据
77 | stocks.netease.searchStocks(["510500"]).then(console.log);
78 | ```
79 |
80 | ##### 输出
81 |
82 | ```typescript
83 | [
84 | {
85 | code: "SH510500",
86 | name: "500ETF",
87 | percent: 0.028383,
88 | now: 7.174,
89 | low: 6.93,
90 | high: 7.184,
91 | yesterday: 6.976,
92 | },
93 | ];
94 | ```
95 |
96 | ### 获取股票实时数据
97 |
98 | ##### 示例
99 |
100 | ```typescript
101 | import { stocks } from "stock-api";
102 |
103 | // 获取股票实时数据
104 | stocks.netease.getStock("SH510500").then(console.log);
105 | ```
106 |
107 | ##### 输出
108 |
109 | ```typescript
110 | {
111 | code: 'SH510500',
112 | name: '500ETF',
113 | percent: 0.028383,
114 | now: 7.174,
115 | low: 6.93,
116 | high: 7.184,
117 | yesterday: 6.976
118 | }
119 | ```
120 |
121 | ### 获取股票组实时数据
122 |
123 | ##### 示例
124 |
125 | ```typescript
126 | import { stocks } from "stock-api";
127 |
128 | // 获取股票组实时数据
129 | stocks.netease.getStocks(["SH510500"]).then(console.log);
130 | ```
131 |
132 | ##### 输出
133 |
134 | ```typescript
135 | [
136 | {
137 | code: "SH510500",
138 | name: "500ETF",
139 | percent: 0.028383,
140 | now: 7.174,
141 | low: 6.93,
142 | high: 7.184,
143 | yesterday: 6.976,
144 | },
145 | ];
146 | ```
147 |
148 | ## 一起成长
149 |
150 | - 在困惑的城市里总少不了并肩同行的 伙伴 让我们一起成长。
151 | - 如果您想激励小二可以到 Github 给个 小星星。
152 |
--------------------------------------------------------------------------------
/jestconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "verbose": true,
3 | "testTimeout": 15000,
4 | "transform": {
5 | "^.+\\.(t|j)sx?$": "ts-jest"
6 | },
7 | "testRegex": "(/test/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
8 | "moduleFileExtensions": [
9 | "ts",
10 | "tsx",
11 | "js",
12 | "jsx",
13 | "json",
14 | "node"
15 | ],
16 | "moduleDirectories": ["node_modules", "src"],
17 | "moduleNameMapper": {
18 | "^@stocks/(.*)$": "/src/stocks/$1",
19 | "^@utils/(.*)$": "/src/utils/$1",
20 | "^types/(.*)$": "/types/$1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stock-api",
3 | "version": "2.0.8",
4 | "description": "免费股票数据分析相关接口",
5 | "repository": "https://github.com/zhangxiangliang/stock-api",
6 | "author": "zhangxiangliang",
7 | "keywords": [
8 | "股票",
9 | "数据分析",
10 | "接口"
11 | ],
12 | "main": "dist/index.js",
13 | "types": "dist/index.d.ts",
14 | "scripts": {
15 | "test": "jest --config jestconfig.json --coverage",
16 | "build": "tsc"
17 | },
18 | "license": "MIT",
19 | "files": [
20 | "dist/**/*"
21 | ],
22 | "devDependencies": {
23 | "@types/jest": "^29.5.12",
24 | "@types/lodash": "^4.14.202",
25 | "@types/superagent": "^8.1.4",
26 | "jest": "^29.7.0",
27 | "ts-jest": "^29.1.2",
28 | "typescript": "^5.3.3"
29 | },
30 | "dependencies": {
31 | "iconv-lite": "^0.6.3",
32 | "lodash": "^4.17.21",
33 | "superagent": "^8.1.2"
34 | }
35 | }
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import stocks from "./stocks/index";
3 |
4 | export { stocks };
5 | export default { stocks };
6 |
--------------------------------------------------------------------------------
/src/stocks/base/index.ts:
--------------------------------------------------------------------------------
1 | // Utils
2 | import {
3 | ERROR_UNDEFINED_GET_STOCK,
4 | ERROR_UNDEFINED_GET_STOCKS,
5 | ERROR_UNDEFINED_SEARCH_STOCK,
6 | } from "../../utils/constant";
7 |
8 | // Types
9 | import Stock from "../../types/utils/stock";
10 | import StockApi from "../../types/stocks/index";
11 |
12 | /**
13 | * 基础股票代码接口
14 | */
15 | const Base: StockApi = {
16 | /**
17 | * 获取股票数据
18 | * @param code 股票代码
19 | */
20 | async getStock(code: string): Promise {
21 | throw new Error(ERROR_UNDEFINED_GET_STOCK);
22 | },
23 |
24 | /**
25 | * 获取股票数据组
26 | * @param codes 股票代码组
27 | */
28 | async getStocks(codes: string[]): Promise {
29 | throw new Error(ERROR_UNDEFINED_GET_STOCKS);
30 | },
31 |
32 | /**
33 | * 搜索股票代码
34 | * @param key 关键字
35 | */
36 | async searchStocks(key: string): Promise {
37 | throw new Error(ERROR_UNDEFINED_SEARCH_STOCK);
38 | },
39 | };
40 |
41 | export default Base;
42 |
--------------------------------------------------------------------------------
/src/stocks/base/transforms/api-code.ts:
--------------------------------------------------------------------------------
1 | // Utils
2 | import {
3 | COMMON_SH,
4 | COMMON_SZ,
5 | COMMON_HK,
6 | COMMON_US,
7 | } from "../../../stocks/base/utils/constant";
8 | import {
9 | ERROR_UNDEFINED_API_CODE,
10 | ERROR_UNDEFINED_SZ_API_CODE,
11 | ERROR_UNDEFINED_SH_API_CODE,
12 | ERROR_UNDEFINED_HK_API_CODE,
13 | ERROR_UNDEFINED_US_API_CODE,
14 | ERROR_API_CODE,
15 | } from "../../../utils/constant";
16 |
17 | // Types
18 | import ApiCodeTransform from "../../../types/stocks/transforms/api-code";
19 |
20 | /**
21 | * 【基础】股票代码转换统一代码
22 | */
23 | class BaseApiCodeTransform implements ApiCodeTransform {
24 | /**
25 | * 股票代码转换统一代码
26 | * @param code 股票代码
27 | */
28 | public transform(code: string): string {
29 | if (code.indexOf(COMMON_SH) === 0) {
30 | return this.SHTransform(code);
31 | }
32 |
33 | if (code.indexOf(COMMON_SZ) === 0) {
34 | return this.SZTransform(code);
35 | }
36 |
37 | if (code.indexOf(COMMON_HK) === 0) {
38 | return this.HKTransform(code);
39 | }
40 |
41 | if (code.indexOf(COMMON_US) === 0) {
42 | return this.USTransform(code);
43 | }
44 |
45 | throw new Error(ERROR_API_CODE);
46 | }
47 |
48 | /**
49 | * 股票代码组转换统一代码组
50 | * @param codes 股票代码组
51 | */
52 | public transforms(codes: string[]): string[] {
53 | return codes.map((code) => this.transform(code));
54 | }
55 |
56 | /**
57 | * 深交所股票代码转换统一代码
58 | * @param code 股票代码
59 | */
60 | public SZTransform(code: string): string {
61 | throw new Error(ERROR_UNDEFINED_SZ_API_CODE);
62 | }
63 |
64 | /**
65 | * 上交所股票代码转换统一代码
66 | * @param code 股票代码
67 | */
68 | public SHTransform(code: string): string {
69 | throw new Error(ERROR_UNDEFINED_SH_API_CODE);
70 | }
71 |
72 | /**
73 | * 港交所股票代码转换统一代码
74 | * @param code 股票代码
75 | */
76 | public HKTransform(code: string): string {
77 | throw new Error(ERROR_UNDEFINED_HK_API_CODE);
78 | }
79 |
80 | /**
81 | * 美交所股票代码转换统一代码
82 | * @param code 股票代码
83 | */
84 | public USTransform(code: string): string {
85 | throw new Error(ERROR_UNDEFINED_US_API_CODE);
86 | }
87 | }
88 |
89 | export default BaseApiCodeTransform;
90 |
--------------------------------------------------------------------------------
/src/stocks/base/transforms/common-code.ts:
--------------------------------------------------------------------------------
1 | // Utils
2 | import {
3 | ERROR_COMMON_CODE,
4 | ERROR_UNDEFINED_SZ_COMMON_CODE,
5 | ERROR_UNDEFINED_SH_COMMON_CODE,
6 | ERROR_UNDEFINED_HK_COMMON_CODE,
7 | ERROR_UNDEFINED_US_COMMON_CODE,
8 | } from "../../../utils/constant";
9 |
10 | // Types
11 | import CommonCodeTransform from "../../../types/stocks/transforms/common-code";
12 | import { COMMON_SH, COMMON_SZ, COMMON_HK, COMMON_US } from "../utils/constant";
13 |
14 | /**
15 | * 【基础】统一代码转换股票代码
16 | */
17 | class BaseCommonCodeTransform implements CommonCodeTransform {
18 | /**
19 | * 交易所统一代码转换股票代码
20 | * @param code 统一代码
21 | */
22 | public transform(code: string): string {
23 | if (code.indexOf(COMMON_SH) === 0) {
24 | return this.SHTransform(code);
25 | }
26 |
27 | if (code.indexOf(COMMON_SZ) === 0) {
28 | return this.SZTransform(code);
29 | }
30 |
31 | if (code.indexOf(COMMON_HK) === 0) {
32 | return this.HKTransform(code);
33 | }
34 |
35 | if (code.indexOf(COMMON_US) === 0) {
36 | return this.USTransform(code);
37 | }
38 |
39 | throw new Error(ERROR_COMMON_CODE);
40 | }
41 |
42 | /**
43 | * 交易所统一代码组转股票代码组
44 | * @param codes 统一代码组
45 | */
46 | public transforms(codes: string[]): string[] {
47 | return codes.map((code) => this.transform(code));
48 | }
49 |
50 | /**
51 | * 深交所统一代码转换股票代码
52 | * @param code 统一代码
53 | */
54 | public SZTransform(code: string): string {
55 | throw new Error(ERROR_UNDEFINED_SZ_COMMON_CODE);
56 | }
57 |
58 | /**
59 | * 上交所统一代码转换股票代码
60 | * @param code 统一代码
61 | */
62 | public SHTransform(code: string): string {
63 | throw new Error(ERROR_UNDEFINED_SH_COMMON_CODE);
64 | }
65 |
66 | /**
67 | * 港交所统一代码转换股票代码
68 | * @param code 统一代码
69 | */
70 | public HKTransform(code: string): string {
71 | throw new Error(ERROR_UNDEFINED_HK_COMMON_CODE);
72 | }
73 |
74 | /**
75 | * 美交所统一代码转换股票代码
76 | * @param code 统一代码
77 | */
78 | public USTransform(code: string): string {
79 | throw new Error(ERROR_UNDEFINED_US_COMMON_CODE);
80 | }
81 | }
82 |
83 | export default BaseCommonCodeTransform;
84 |
--------------------------------------------------------------------------------
/src/stocks/base/transforms/stock.ts:
--------------------------------------------------------------------------------
1 | // Utils
2 | import {
3 | ERROR_UNDEFINED_GET_CODE,
4 | ERROR_UNDEFINED_GET_NAME,
5 | ERROR_UNDEFINED_GET_NOW,
6 | ERROR_UNDEFINED_GET_LOW,
7 | ERROR_UNDEFINED_GET_HIGH,
8 | ERROR_UNDEFINED_GET_YESTERDAY,
9 | ERROR_UNDEFINED_GET_PERCENT,
10 | ERROR_UNDEFINED_GET_STOCK,
11 | } from "../../../utils/constant";
12 |
13 | // Types
14 | import Stock from "../../../types/utils/stock";
15 |
16 | /**
17 | * 基础股票数据解析
18 | */
19 | class BaseStockTransform {
20 | /**
21 | * 获取代码
22 | */
23 | getCode(): string {
24 | throw new Error(ERROR_UNDEFINED_GET_CODE);
25 | }
26 |
27 | /**
28 | * 获取名称
29 | */
30 | getName(): string {
31 | throw new Error(ERROR_UNDEFINED_GET_NAME);
32 | }
33 |
34 | /**
35 | * 获取现价
36 | */
37 | getNow(): number {
38 | throw new Error(ERROR_UNDEFINED_GET_NOW);
39 | }
40 |
41 | /**
42 | * 获取最低价
43 | */
44 | getLow(): number {
45 | throw new Error(ERROR_UNDEFINED_GET_LOW);
46 | }
47 |
48 | /**
49 | * 获取最高价
50 | */
51 | getHigh(): number {
52 | throw new Error(ERROR_UNDEFINED_GET_HIGH);
53 | }
54 |
55 | /**
56 | * 获取昨日收盘价
57 | */
58 | getYesterday(): number {
59 | throw new Error(ERROR_UNDEFINED_GET_YESTERDAY);
60 | }
61 |
62 | /**
63 | * 获取涨跌
64 | */
65 | getPercent(): number {
66 | throw new Error(ERROR_UNDEFINED_GET_PERCENT);
67 | }
68 |
69 | /**
70 | * 获取股票数据
71 | */
72 | getStock(): Stock {
73 | throw new Error(ERROR_UNDEFINED_GET_STOCK);
74 | }
75 | }
76 |
77 | export default BaseStockTransform;
78 |
--------------------------------------------------------------------------------
/src/stocks/base/utils/constant.ts:
--------------------------------------------------------------------------------
1 | // 默认交易所常量
2 | export const COMMON_SZ = "SZ"; // 深交所相关常量
3 | export const COMMON_SH = "SH"; // 上交所相关常量
4 | export const COMMON_HK = "HK"; // 港交所相关常量
5 | export const COMMON_US = "US"; // 美交所相关常量
6 |
--------------------------------------------------------------------------------
/src/stocks/index.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import base from "./base";
3 | import sina from "./sina";
4 | import xueqiu from "./xueqiu";
5 | import netease from "./netease";
6 | import tencent from "./tencent";
7 |
8 | export { base, sina, xueqiu, netease, tencent };
9 |
10 | export default {
11 | base,
12 | sina,
13 | xueqiu,
14 | netease,
15 | tencent,
16 | };
17 |
--------------------------------------------------------------------------------
/src/stocks/netease/index.ts:
--------------------------------------------------------------------------------
1 | // NPM
2 | import { uniq } from "lodash";
3 |
4 | // Stocks
5 | import NeteaseStockTransform from "../../stocks/netease/transforms/stock";
6 | import NeteaseCommonCodeTransform from "../../stocks/netease/transforms/common-code";
7 |
8 | // Utils
9 | import fetch from "../../utils/fetch";
10 | import { DEFAULT_STOCK } from "../../utils/constant";
11 | import { COMMON_SZ, COMMON_SH } from "../../stocks/base/utils/constant";
12 |
13 | // Types
14 | import Stock from "../../types/utils/stock";
15 | import StockApi from "../../types/stocks/index";
16 | import Dictionary from "../../types/utils/dictionary";
17 |
18 | /**
19 | * 网易股票代码接口
20 | */
21 | const Netease: StockApi = {
22 | /**
23 | * 获取股票数据
24 | * @param code 股票代码
25 | */
26 | async getStock(code: string): Promise {
27 | const transform = new NeteaseCommonCodeTransform().transform(code);
28 |
29 | const url = `https://api.money.126.net/data/feed/${transform},money.api?callback=topstock`;
30 | const res = await fetch.get(url);
31 |
32 | const items = JSON.parse(
33 | res.body
34 | .toString()
35 | .replace(/\(|\)|;|(topstock)|\s/g, "")
36 | .replace("{{", "{")
37 | .replace("}}}", "}}")
38 | );
39 | const params = items[transform];
40 |
41 | if (!params) {
42 | return { ...DEFAULT_STOCK, code };
43 | }
44 |
45 | const data = new NeteaseStockTransform(code, params);
46 | return data.getStock();
47 | },
48 |
49 | /**
50 | * 获取股票数据组
51 | * @param codes 股票代码组
52 | */
53 | async getStocks(codes: string[]): Promise {
54 | codes = uniq(codes.filter((i) => i !== ""));
55 |
56 | // 无股票时返回空数组
57 | if (codes.length === 0) {
58 | return [];
59 | }
60 |
61 | const transforms = new NeteaseCommonCodeTransform().transforms(codes);
62 |
63 | // 数据获取
64 | const url = `https://api.money.126.net/data/feed/${transforms.join(
65 | ","
66 | )},money.api?callback=topstock`;
67 | const res = await fetch.get(url);
68 |
69 | // 解析数据
70 | const items = JSON.parse(
71 | res.body
72 | .toString()
73 | .replace(/\(|\)|;|(topstock)|\s/g, "")
74 | .replace("{{", "{")
75 | .replace("}}}", "}}")
76 | );
77 | return codes.map((code) => {
78 | const transform = new NeteaseCommonCodeTransform().transform(code);
79 | const params = items[transform];
80 |
81 | if (!params) {
82 | return { ...DEFAULT_STOCK, code };
83 | }
84 |
85 | const data = new NeteaseStockTransform(code, params);
86 |
87 | return data.getStock();
88 | });
89 | },
90 |
91 | /**
92 | * 搜索股票代码
93 | * @param key 关键字
94 | */
95 | async searchStocks(key: string): Promise {
96 | // 数据获取
97 | const url = `https://quotes.money.163.com/stocksearch/json.do?type=&count=5&word=${encodeURIComponent(
98 | key
99 | )}&callback=topstock`;
100 | const res = await fetch.get(url);
101 |
102 | // 解析数据
103 | const row = res.body
104 | .toString()
105 | .replace(/\(|\)|;|(topstock)|\s/g, "")
106 | .replace("{{", "{")
107 | .replace("}}}", "}}");
108 | const items: Dictionary[] = JSON.parse(row);
109 |
110 | const codes: string[] = items.map((i) => {
111 | if (i.tag.includes(COMMON_SZ) || i.type.includes(COMMON_SZ)) {
112 | return COMMON_SZ + i.symbol;
113 | }
114 |
115 | if (i.tag.includes(COMMON_SH) || i.type.includes(COMMON_SH)) {
116 | return COMMON_SH + i.symbol;
117 | }
118 |
119 | return "";
120 | });
121 |
122 | return await Netease.getStocks(uniq(codes.filter((i) => i !== "")));
123 | },
124 | };
125 |
126 | export default Netease;
127 |
--------------------------------------------------------------------------------
/src/stocks/netease/transforms/api-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseApiCodeTransform from "../../../stocks/base/transforms/api-code";
3 |
4 | // Utils
5 | import { ERROR_API_CODE } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 | import {
13 | NETEASE_SZ,
14 | NETEASE_SH,
15 | NETEASE_HK,
16 | NETEASE_US,
17 | } from "../../../stocks/netease/utils/constant";
18 |
19 | /**
20 | * 网易股票代码转统一代码
21 | */
22 | class NeteaseApiCodeTransform extends BaseApiCodeTransform {
23 | /**
24 | * 股票代码转统一代码
25 | * @param code 股票代码
26 | */
27 | public transform(code: string): string {
28 | if (code.indexOf(NETEASE_SZ) === 0) {
29 | return this.SZTransform(code);
30 | }
31 |
32 | if (code.indexOf(NETEASE_SH) === 0) {
33 | return this.SHTransform(code);
34 | }
35 |
36 | if (code.indexOf(NETEASE_HK) === 0) {
37 | return this.HKTransform(code);
38 | }
39 |
40 | if (code.indexOf(NETEASE_US) === 0) {
41 | return this.USTransform(code);
42 | }
43 |
44 | throw new Error(ERROR_API_CODE);
45 | }
46 |
47 | /**
48 | * 股票代码组转统一代码组
49 | * @param codes 股票代码组
50 | */
51 | public transforms(codes: string[]): string[] {
52 | return codes.map((code) => this.transform(code));
53 | }
54 |
55 | /**
56 | * 深交所股票代码转统一代码
57 | * @param code 股票代码
58 | */
59 | public SZTransform(code: string): string {
60 | if (code.indexOf(NETEASE_SZ) !== 0) {
61 | throw new Error(ERROR_API_CODE);
62 | }
63 |
64 | return COMMON_SZ + code.replace(NETEASE_SZ, "");
65 | }
66 |
67 | /**
68 | * 上交所股票代码转统一代码
69 | * @param code 股票代码
70 | */
71 | public SHTransform(code: string): string {
72 | if (!code.includes(NETEASE_SH)) {
73 | throw new Error(ERROR_API_CODE);
74 | }
75 |
76 | return COMMON_SH + code.replace(NETEASE_SH, "");
77 | }
78 |
79 | /**
80 | * 港交所股票代码转统一代码
81 | * @param code 股票代码
82 | */
83 | public HKTransform(code: string): string {
84 | if (!code.includes(NETEASE_HK)) {
85 | throw new Error(ERROR_API_CODE);
86 | }
87 |
88 | return COMMON_HK + code.replace(NETEASE_HK, "");
89 | }
90 |
91 | /**
92 | * 美交所股票代码转统一代码
93 | * @param code 股票代码
94 | */
95 | public USTransform(code: string): string {
96 | if (!code.includes(NETEASE_US)) {
97 | throw new Error(ERROR_API_CODE);
98 | }
99 |
100 | return COMMON_US + code.replace(NETEASE_US, "");
101 | }
102 | }
103 |
104 | export default NeteaseApiCodeTransform;
105 |
--------------------------------------------------------------------------------
/src/stocks/netease/transforms/common-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseCommonCodeTransform from "../../../stocks/base/transforms/common-code";
3 |
4 | // Utils
5 | import { ERROR_COMMON_CODE } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 | import {
13 | NETEASE_SZ,
14 | NETEASE_SH,
15 | NETEASE_HK,
16 | NETEASE_US,
17 | } from "../../../stocks/netease/utils/constant";
18 |
19 | /**
20 | * 【网易】统一代码转股票代码
21 | */
22 | class NeteaseCommonCodeTransform extends BaseCommonCodeTransform {
23 | /**
24 | * 统一代码转股票代码
25 | * @param code 统一代码
26 | */
27 | public transform(code: string): string {
28 | return super.transform(code);
29 | }
30 |
31 | /**
32 | * 统一代码组转换股票代码组
33 | * @param codes 统一代码组
34 | */
35 | public transforms(codes: string[]): string[] {
36 | return super.transforms(codes);
37 | }
38 |
39 | /**
40 | * 深交所统一代码转股票代码
41 | * @param code 统一代码
42 | */
43 | public SZTransform(code: string): string {
44 | if (!code.includes(COMMON_SZ)) {
45 | throw new Error(ERROR_COMMON_CODE);
46 | }
47 |
48 | return NETEASE_SZ + code.replace(COMMON_SZ, "");
49 | }
50 |
51 | /**
52 | * 上交所统一代码转股票代码
53 | * @param code 统一代码
54 | */
55 | public SHTransform(code: string): string {
56 | if (!code.includes(COMMON_SH)) {
57 | throw new Error(ERROR_COMMON_CODE);
58 | }
59 |
60 | return NETEASE_SH + code.replace(COMMON_SH, "");
61 | }
62 |
63 | /**
64 | * 港交所统一代码转股票代码
65 | * @param code 统一代码
66 | */
67 | public HKTransform(code: string): string {
68 | if (!code.includes(COMMON_HK)) {
69 | throw new Error(ERROR_COMMON_CODE);
70 | }
71 |
72 | return NETEASE_HK + code.replace(COMMON_HK, "");
73 | }
74 |
75 | /**
76 | * 美交所统一代码转股票代码
77 | * @param code 统一代码
78 | */
79 | public USTransform(code: string): string {
80 | if (!code.includes(COMMON_US)) {
81 | throw new Error(ERROR_COMMON_CODE);
82 | }
83 |
84 | return NETEASE_US + code.replace(COMMON_US, "");
85 | }
86 | }
87 |
88 | export default NeteaseCommonCodeTransform;
89 |
--------------------------------------------------------------------------------
/src/stocks/netease/transforms/stock.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseStockTransform from "../../../stocks/base/transforms/stock";
3 |
4 | // Utils
5 | import { DEFAULT_STRING, DEFAULT_NUMBER } from "../../../utils/constant";
6 |
7 | // Types
8 | import Stock from "../../../types/utils/stock";
9 | import Dictionary from "../../../types/utils/dictionary";
10 |
11 | /**
12 | * 网易股票数据解析
13 | */
14 | class NeteaseStockTransform extends BaseStockTransform {
15 | /**
16 | * 构造函数
17 | */
18 | constructor(public code: string, public params: Dictionary) {
19 | super();
20 | }
21 |
22 | /**
23 | * 获取代码
24 | */
25 | getCode(): string {
26 | return String(this.code).toUpperCase();
27 | }
28 |
29 | /**
30 | * 获取名称
31 | */
32 | getName(): string {
33 | return String(this.params.name || DEFAULT_STRING);
34 | }
35 |
36 | /**
37 | * 获取现价
38 | */
39 | getNow(): number {
40 | return Number(this.params.price || DEFAULT_NUMBER);
41 | }
42 |
43 | /**
44 | * 获取最低价
45 | */
46 | getLow(): number {
47 | return Number(this.params.low || DEFAULT_NUMBER);
48 | }
49 |
50 | /**
51 | * 获取最高价
52 | */
53 | getHigh(): number {
54 | return Number(this.params.high || DEFAULT_NUMBER);
55 | }
56 |
57 | /**
58 | * 获取昨日收盘价
59 | */
60 | getYesterday(): number {
61 | return Number(this.params.yestclose || DEFAULT_NUMBER);
62 | }
63 |
64 | /**
65 | * 获取涨跌
66 | */
67 | getPercent(): number {
68 | return this.getNow() ? this.getNow() / this.getYesterday() - 1 : 0;
69 | }
70 |
71 | /**
72 | * 获取股票数据
73 | */
74 | getStock(): Stock {
75 | return {
76 | code: this.getCode(),
77 | name: this.getName(),
78 | percent: this.getPercent(),
79 |
80 | now: this.getNow(),
81 | low: this.getLow(),
82 | high: this.getHigh(),
83 | yesterday: this.getYesterday(),
84 | };
85 | }
86 | }
87 |
88 | export default NeteaseStockTransform;
89 |
--------------------------------------------------------------------------------
/src/stocks/netease/utils/constant.ts:
--------------------------------------------------------------------------------
1 | // 默认交易所常量
2 | export const NETEASE_SZ = "1"; // 深交所相关常量
3 | export const NETEASE_SH = "0"; // 上交所相关常量
4 | export const NETEASE_HK = "hk"; // 港交所相关常量
5 | export const NETEASE_US = "US_"; // 美交所相关常量
6 |
--------------------------------------------------------------------------------
/src/stocks/sina/index.ts:
--------------------------------------------------------------------------------
1 | // NPM
2 | import { uniq } from "lodash";
3 |
4 | // Stocks
5 | import SinaStockTransform from "../../stocks/sina/transforms/stock";
6 | import SinaCommonCodeTransform from "../../stocks/sina/transforms/common-code";
7 |
8 | // Utils
9 | import fetch from "../../utils/fetch";
10 | import iconv from "../../utils/iconv";
11 | import { DEFAULT_STOCK } from "../../utils/constant";
12 | import {
13 | COMMON_SZ,
14 | COMMON_SH,
15 | COMMON_US,
16 | COMMON_HK,
17 | } from "../../stocks/base/utils/constant";
18 |
19 | // Types
20 | import Stock from "../../types/utils/stock";
21 | import StockApi from "../../types/stocks/index";
22 |
23 | /**
24 | * 新浪股票代码接口
25 | */
26 | const Sina: StockApi = {
27 | /**
28 | * 获取股票数据
29 | * @param code 股票代码
30 | */
31 | async getStock(code: string): Promise {
32 | const transform = new SinaCommonCodeTransform().transform(code);
33 |
34 | // 数据获取
35 | const url = `https://hq.sinajs.cn/list=${transform}`;
36 | const res = await fetch.get(url);
37 |
38 | const body = iconv.decode(res.body, "gb18030");
39 | const rows = body.split(";\n");
40 | const row = rows[0];
41 |
42 | // 数据深解析
43 | const [_, paramsUnformat] = row.split("=");
44 |
45 | if (paramsUnformat === '""') {
46 | return { ...DEFAULT_STOCK, code };
47 | }
48 |
49 | const params = paramsUnformat.replace('"', "").split(",");
50 | const data = new SinaStockTransform(code, params);
51 |
52 | return data.getStock();
53 | },
54 |
55 | /**
56 | * 获取股票数据组
57 | * @param codes 股票代码组
58 | */
59 | async getStocks(codes: string[]): Promise {
60 | codes = uniq(codes.filter((i) => i !== ""));
61 |
62 | // 无股票时返回空数组
63 | if (codes.length === 0) {
64 | return [];
65 | }
66 |
67 | const transforms = new SinaCommonCodeTransform().transforms(codes);
68 |
69 | // 数据获取
70 | const url = `https://hq.sinajs.cn/list=${transforms.join(",")}`;
71 | const res = await fetch.get(url);
72 |
73 | const body = iconv.decode(res.body, "gb18030");
74 | const rows = body.split(";\n");
75 |
76 | return codes.map((code, index) => {
77 | // 数据深解析
78 | const [_, paramsUnformat] = rows[index].split("=");
79 |
80 | if (paramsUnformat === '""') {
81 | return { ...DEFAULT_STOCK, code };
82 | }
83 |
84 | const params = paramsUnformat.replace('"', "").split(",");
85 | const data = new SinaStockTransform(code, params);
86 |
87 | return data.getStock();
88 | });
89 | },
90 |
91 | /**
92 | * 搜索股票代码
93 | * @param key 关键字
94 | */
95 | async searchStocks(key: string): Promise {
96 | // 数据获取
97 | const url = `http://suggest3.sinajs.cn/suggest/type=2&key=${encodeURIComponent(
98 | key
99 | )}`;
100 | const res = await fetch.get(url);
101 |
102 | const body = iconv.decode(res.body, "gb18030");
103 | const rows: string[] = body
104 | .replace('var suggestvalue="', "")
105 | .replace('";', "")
106 | .split(";");
107 |
108 | let codes: string[] = [];
109 | for (let i = 0; i < rows.length; i++) {
110 | let code: string = rows[i].split(",")[0];
111 |
112 | if (code.indexOf("us") === 0) {
113 | code = code.replace("us", "");
114 | codes = [...codes, COMMON_US + code];
115 | }
116 |
117 | if (code.indexOf("sz") === 0) {
118 | code = code.replace("sz", "");
119 | codes = [...codes, COMMON_SZ + code];
120 | }
121 |
122 | if (code.indexOf("sh") === 0) {
123 | code = code.replace("sh", "");
124 | codes = [...codes, COMMON_SH + code];
125 | }
126 |
127 | if (code.indexOf("hk") === 0) {
128 | code = code.replace("hk", "");
129 | codes = [...codes, COMMON_HK + code];
130 | }
131 |
132 | if (code.indexOf("of") === 0) {
133 | code = code.replace("of", "");
134 | codes = [...codes, COMMON_SZ + code, COMMON_SH + code];
135 | }
136 | }
137 |
138 | return await Sina.getStocks(uniq(codes.filter((i) => i !== "")));
139 | },
140 | };
141 |
142 | export default Sina;
143 |
--------------------------------------------------------------------------------
/src/stocks/sina/transforms/api-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseCommonCodeTransform from "../../../stocks/base/transforms/common-code";
3 |
4 | // Utils
5 | import { ERROR_API_CODE } from "../../../utils/constant";
6 | import {
7 | SINA_SZ,
8 | SINA_SH,
9 | SINA_HK,
10 | SINA_US,
11 | } from "../../../stocks/sina/utils/constant";
12 | import {
13 | COMMON_SH,
14 | COMMON_SZ,
15 | COMMON_HK,
16 | COMMON_US,
17 | } from "../../../stocks/base/utils/constant";
18 |
19 | /**
20 | * 【新浪】股票代码转换统一代码
21 | */
22 | class SinaCommonCodeTransform extends BaseCommonCodeTransform {
23 | /**
24 | * 交易所股票代码转换统一代码
25 | * @param code 股票代码
26 | */
27 | public transform(code: string): string {
28 | if (code.indexOf(SINA_SZ) === 0) {
29 | return this.SZTransform(code);
30 | }
31 |
32 | if (code.indexOf(SINA_SH) === 0) {
33 | return this.SHTransform(code);
34 | }
35 |
36 | if (code.indexOf(SINA_HK) === 0) {
37 | return this.HKTransform(code);
38 | }
39 |
40 | if (code.indexOf(SINA_US) === 0) {
41 | return this.USTransform(code);
42 | }
43 |
44 | throw new Error(ERROR_API_CODE);
45 | }
46 |
47 | /**
48 | * 交易所股票代码组转换统一代码组
49 | * @param codes 股票代码组
50 | */
51 | public transforms(codes: string[]): string[] {
52 | return super.transforms(codes);
53 | }
54 |
55 | /**
56 | * 深交所股票代码转换统一代码
57 | * @param code 股票代码
58 | */
59 | public SZTransform(code: string): string {
60 | if (code.indexOf(SINA_SZ) !== 0) {
61 | throw new Error(ERROR_API_CODE);
62 | }
63 |
64 | return COMMON_SZ + code.replace(SINA_SZ, "");
65 | }
66 |
67 | /**
68 | * 上交所股票代码转换统一代码
69 | * @param code 股票代码
70 | */
71 | public SHTransform(code: string): string {
72 | if (code.indexOf(SINA_SH) !== 0) {
73 | throw new Error(ERROR_API_CODE);
74 | }
75 |
76 | return COMMON_SH + code.replace(SINA_SH, "");
77 | }
78 |
79 | /**
80 | * 港交所股票代码转换统一代码
81 | * @param code 股票代码
82 | */
83 | public HKTransform(code: string): string {
84 | if (code.indexOf(SINA_HK) !== 0) {
85 | throw new Error(ERROR_API_CODE);
86 | }
87 |
88 | return COMMON_HK + code.replace(SINA_HK, "");
89 | }
90 |
91 | /**
92 | * 美交所股票代码转换统一代码
93 | * @param code 股票代码
94 | */
95 | public USTransform(code: string): string {
96 | if (code.indexOf(SINA_US) !== 0) {
97 | throw new Error(ERROR_API_CODE);
98 | }
99 |
100 | return COMMON_US + code.replace(SINA_US, "").toLowerCase();
101 | }
102 | }
103 |
104 | export default SinaCommonCodeTransform;
105 |
--------------------------------------------------------------------------------
/src/stocks/sina/transforms/common-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseCommonCodeTransform from "../../../stocks/base/transforms/common-code";
3 |
4 | // Utils
5 | import { ERROR_COMMON_CODE } from "../../../utils/constant";
6 | import {
7 | SINA_SZ,
8 | SINA_SH,
9 | SINA_HK,
10 | SINA_US,
11 | } from "../../../stocks/sina/utils/constant";
12 | import {
13 | COMMON_SH,
14 | COMMON_SZ,
15 | COMMON_HK,
16 | COMMON_US,
17 | } from "../../../stocks/base/utils/constant";
18 |
19 | /**
20 | * 【新浪】统一代码转换股票代码
21 | */
22 | class SinaCommonCodeTransform extends BaseCommonCodeTransform {
23 | /**
24 | * 交易所统一代码转换股票代码
25 | * @param code 统一代码
26 | */
27 | public transform(code: string): string {
28 | return super.transform(code);
29 | }
30 |
31 | /**
32 | * 交易所统一代码组转换股票代码组
33 | * @param codes 统一代码组
34 | */
35 | public transforms(codes: string[]): string[] {
36 | return super.transforms(codes);
37 | }
38 |
39 | /**
40 | * 深交所统一代码转换股票代码
41 | * @param code 统一代码
42 | */
43 | public SZTransform(code: string): string {
44 | if (code.indexOf(COMMON_SZ) !== 0) {
45 | throw new Error(ERROR_COMMON_CODE);
46 | }
47 |
48 | return SINA_SZ + code.replace(COMMON_SZ, "");
49 | }
50 |
51 | /**
52 | * 上交所统一代码转换股票代码
53 | * @param code 统一代码
54 | */
55 | public SHTransform(code: string): string {
56 | if (code.indexOf(COMMON_SH) !== 0) {
57 | throw new Error(ERROR_COMMON_CODE);
58 | }
59 |
60 | return SINA_SH + code.replace(COMMON_SH, "");
61 | }
62 |
63 | /**
64 | * 港交所统一代码转换股票代码
65 | * @param code 统一代码
66 | */
67 | public HKTransform(code: string): string {
68 | if (code.indexOf(COMMON_HK) !== 0) {
69 | throw new Error(ERROR_COMMON_CODE);
70 | }
71 |
72 | return SINA_HK + code.replace(COMMON_HK, "");
73 | }
74 |
75 | /**
76 | * 美交所统一代码转换股票代码
77 | * @param code 统一代码
78 | */
79 | public USTransform(code: string): string {
80 | if (code.indexOf(COMMON_US) !== 0) {
81 | throw new Error(ERROR_COMMON_CODE);
82 | }
83 |
84 | return SINA_US + code.replace(COMMON_US, "").toLowerCase();
85 | }
86 | }
87 |
88 | export default SinaCommonCodeTransform;
89 |
--------------------------------------------------------------------------------
/src/stocks/sina/transforms/stock.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseStockTransform from "../../../stocks/base/transforms/stock";
3 |
4 | // Utils
5 | import { DEFAULT_STRING, DEFAULT_NUMBER } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 |
13 | // Types
14 | import Stock from "../../../types/utils/stock";
15 |
16 | /**
17 | * 新浪股票数据解析
18 | */
19 | class SinaStockTransform extends BaseStockTransform {
20 | /**
21 | * 构造函数
22 | */
23 | constructor(public code: string, public params: string[]) {
24 | super();
25 | }
26 |
27 | /**
28 | * 获取代码
29 | */
30 | getCode(): string {
31 | return String(this.code).toUpperCase();
32 | }
33 |
34 | /**
35 | * 获取名称
36 | */
37 | getName(): string {
38 | switch (this.code.slice(0, 2)) {
39 | case COMMON_SH:
40 | return String(this.params[0] || DEFAULT_STRING);
41 | case COMMON_SZ:
42 | return String(this.params[0] || DEFAULT_STRING);
43 | case COMMON_HK:
44 | return String(this.params[1] || DEFAULT_STRING);
45 | case COMMON_US:
46 | return String(this.params[0] || DEFAULT_STRING);
47 | default:
48 | return DEFAULT_STRING;
49 | }
50 | }
51 |
52 | /**
53 | * 获取现价
54 | */
55 | getNow(): number {
56 | switch (this.code.slice(0, 2)) {
57 | case COMMON_SH:
58 | return Number(this.params[3] || DEFAULT_NUMBER);
59 | case COMMON_SZ:
60 | return Number(this.params[3] || DEFAULT_NUMBER);
61 | case COMMON_HK:
62 | return Number(this.params[6] || DEFAULT_NUMBER);
63 | case COMMON_US:
64 | return Number(this.params[1] || DEFAULT_NUMBER);
65 | default:
66 | return DEFAULT_NUMBER;
67 | }
68 | }
69 |
70 | /**
71 | * 获取最低价
72 | */
73 | getLow(): number {
74 | switch (this.code.slice(0, 2)) {
75 | case COMMON_SH:
76 | return Number(this.params[5] || DEFAULT_NUMBER);
77 | case COMMON_SZ:
78 | return Number(this.params[5] || DEFAULT_NUMBER);
79 | case COMMON_HK:
80 | return Number(this.params[5] || DEFAULT_NUMBER);
81 | case COMMON_US:
82 | return Number(this.params[7] || DEFAULT_NUMBER);
83 | default:
84 | return DEFAULT_NUMBER;
85 | }
86 | }
87 |
88 | /**
89 | * 获取最高价
90 | */
91 | getHigh(): number {
92 | switch (this.code.slice(0, 2)) {
93 | case COMMON_SH:
94 | return Number(this.params[4] || DEFAULT_NUMBER);
95 | case COMMON_SZ:
96 | return Number(this.params[4] || DEFAULT_NUMBER);
97 | case COMMON_HK:
98 | return Number(this.params[4] || DEFAULT_NUMBER);
99 | case COMMON_US:
100 | return Number(this.params[6] || DEFAULT_NUMBER);
101 | default:
102 | return DEFAULT_NUMBER;
103 | }
104 | }
105 |
106 | /**
107 | * 获取昨日收盘价
108 | */
109 | getYesterday(): number {
110 | switch (this.code.slice(0, 2)) {
111 | case COMMON_SH:
112 | return Number(this.params[2] || DEFAULT_NUMBER);
113 | case COMMON_SZ:
114 | return Number(this.params[2] || DEFAULT_NUMBER);
115 | case COMMON_HK:
116 | return Number(this.params[3] || DEFAULT_NUMBER);
117 | case COMMON_US:
118 | return Number(this.params[26] || DEFAULT_NUMBER);
119 | default:
120 | return DEFAULT_NUMBER;
121 | }
122 | }
123 |
124 | /**
125 | * 获取涨跌
126 | */
127 | getPercent(): number {
128 | return this.getNow() ? this.getNow() / this.getYesterday() - 1 : 0;
129 | }
130 |
131 | /**
132 | * 获取股票数据
133 | */
134 | getStock(): Stock {
135 | return {
136 | code: this.getCode(),
137 | name: this.getName(),
138 | percent: this.getPercent(),
139 |
140 | now: this.getNow(),
141 | low: this.getLow(),
142 | high: this.getHigh(),
143 | yesterday: this.getYesterday(),
144 | };
145 | }
146 | }
147 |
148 | export default SinaStockTransform;
149 |
--------------------------------------------------------------------------------
/src/stocks/sina/utils/constant.ts:
--------------------------------------------------------------------------------
1 | // 默认交易所常量
2 | export const SINA_SZ = "sz"; // 深交所相关常量
3 | export const SINA_SH = "sh"; // 上交所相关常量
4 | export const SINA_HK = "hk"; // 港交所相关常量
5 | export const SINA_US = "gb_"; // 美交所相关常量
6 |
--------------------------------------------------------------------------------
/src/stocks/tencent/index.ts:
--------------------------------------------------------------------------------
1 | // NPM
2 | import { uniq } from "lodash";
3 |
4 | // Stocks
5 | import TencentStockTransform from "../../stocks/tencent/transforms/stock";
6 | import TencentCommonCodeTransform from "../../stocks/tencent/transforms/common-code";
7 |
8 | // Utils
9 | import fetch from "../../utils/fetch";
10 | import iconv from "../../utils/iconv";
11 | import { DEFAULT_STOCK } from "../../utils/constant";
12 | import {
13 | COMMON_SH,
14 | COMMON_SZ,
15 | COMMON_US,
16 | COMMON_HK,
17 | } from "../../stocks/base/utils/constant";
18 |
19 | // Types
20 | import Stock from "../../types/utils/stock";
21 | import StockApi from "../../types/stocks/index";
22 |
23 | /**
24 | * 腾讯股票代码接口
25 | */
26 | const Tencent: StockApi = {
27 | /**
28 | * 获取股票数据
29 | * @param code 股票代码
30 | */
31 | async getStock(code: string): Promise {
32 | const transform = new TencentCommonCodeTransform().transform(code);
33 |
34 | // 数据获取
35 | const url = `https://qt.gtimg.cn/q=${transform}`;
36 | const res = await fetch.get(url).responseType("blob");
37 |
38 | const body = iconv.decode(res.body, "gbk");
39 | const rows = body.split(";\n");
40 | const row = rows[0];
41 |
42 | if (!row.includes(transform)) {
43 | return { ...DEFAULT_STOCK, code };
44 | }
45 |
46 | // 数据深解析
47 | const [_, paramsUnformat] = row.split("=");
48 | const params = paramsUnformat.replace('"', "").split("~");
49 | const data = new TencentStockTransform(code, params);
50 |
51 | return data.getStock();
52 | },
53 |
54 | /**
55 | * 获取股票数据组
56 | * @param codes 股票代码组
57 | */
58 | async getStocks(codes: string[]): Promise {
59 | codes = uniq(codes.filter((i) => i !== ""));
60 |
61 | // 无股票时返回空数组
62 | if (codes.length === 0) {
63 | return [];
64 | }
65 |
66 | const transforms = new TencentCommonCodeTransform().transforms(codes);
67 |
68 | // 数据获取
69 | const url = `https://qt.gtimg.cn/q=${transforms.join(",")}`;
70 | const res = await fetch.get(url).responseType("blob");
71 |
72 | const body = iconv.decode(res.body, "gbk");
73 | const rows: string[] = body.split(";\n");
74 |
75 | return codes.map((code, index) => {
76 | const transform = new TencentCommonCodeTransform().transform(code);
77 | if (!rows.find((row) => row.includes(transform))) {
78 | return { ...DEFAULT_STOCK, code };
79 | }
80 |
81 | // 数据深解析
82 | const [_, paramsUnformat] = rows[index].split("=");
83 | const params = paramsUnformat.replace('"', "").split("~");
84 | const data = new TencentStockTransform(code, params);
85 |
86 | return data.getStock();
87 | });
88 | },
89 |
90 | /**
91 | * 搜索股票代码
92 | * @param key 关键字
93 | */
94 | async searchStocks(key: string): Promise {
95 | const url = `https://smartbox.gtimg.cn/s3/?v=2&t=all&c=1&q=${encodeURIComponent(
96 | key
97 | )}`;
98 | const res = await fetch.get(url).responseType("blob");
99 |
100 | const body = iconv.decode(res.body, "gbk");
101 | const rows: string[] = body
102 | .replace('v_hint="', "")
103 | .replace('"', "")
104 | .split("^");
105 |
106 | const codes: string[] = rows.map((row) => {
107 | const [type, code] = row.split("~");
108 |
109 | switch (type) {
110 | case "sz":
111 | return COMMON_SZ + code;
112 | case "sh":
113 | return COMMON_SH + code;
114 | case "hk":
115 | return COMMON_HK + code;
116 | case "us":
117 | return COMMON_US + code.split(".")[0].toUpperCase();
118 | default:
119 | return "";
120 | }
121 | });
122 |
123 | return await Tencent.getStocks(uniq(codes.filter((i) => i !== "")));
124 | },
125 | };
126 |
127 | export default Tencent;
128 |
--------------------------------------------------------------------------------
/src/stocks/tencent/transforms/api-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseApiCodeTransform from "../../../stocks/base/transforms/api-code";
3 |
4 | // Utils
5 | import { ERROR_API_CODE } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 | import {
13 | TENCENT_SZ,
14 | TENCENT_SH,
15 | TENCENT_HK,
16 | TENCENT_US,
17 | } from "../../../stocks/tencent/utils/constant";
18 |
19 | /**
20 | * 【腾讯】股票代码转换统一代码
21 | */
22 | class TencentApiCodeTransform extends BaseApiCodeTransform {
23 | /**
24 | * 交易所股票代码转换统一代码
25 | * @param code 股票代码
26 | */
27 | public transform(code: string): string {
28 | if (code.indexOf(TENCENT_SZ) === 0) {
29 | return this.SZTransform(code);
30 | }
31 |
32 | if (code.indexOf(TENCENT_SH) === 0) {
33 | return this.SHTransform(code);
34 | }
35 |
36 | if (code.indexOf(TENCENT_HK) === 0) {
37 | return this.HKTransform(code);
38 | }
39 |
40 | if (code.indexOf(TENCENT_US) === 0) {
41 | return this.USTransform(code);
42 | }
43 |
44 | throw new Error(ERROR_API_CODE);
45 | }
46 |
47 | /**
48 | * 交易所股票代码组转换统一代码组
49 | * @param codes 股票代码组
50 | */
51 | public transforms(codes: string[]): string[] {
52 | return super.transforms(codes);
53 | }
54 |
55 | /**
56 | * 深交所股票代码转换统一代码
57 | * @param code 股票代码
58 | */
59 | public SZTransform(code: string): string {
60 | if (!code.includes(TENCENT_SZ)) {
61 | throw new Error(ERROR_API_CODE);
62 | }
63 |
64 | return COMMON_SZ + code.replace(TENCENT_SZ, "");
65 | }
66 |
67 | /**
68 | * 上交所股票代码转换统一代码
69 | * @param code 股票代码
70 | */
71 | public SHTransform(code: string): string {
72 | if (!code.includes(TENCENT_SH)) {
73 | throw new Error(ERROR_API_CODE);
74 | }
75 |
76 | return COMMON_SH + code.replace(TENCENT_SH, "");
77 | }
78 |
79 | /**
80 | * 港交所股票代码转换统一代码
81 | * @param code 股票代码
82 | */
83 | public HKTransform(code: string): string {
84 | if (!code.includes(TENCENT_HK)) {
85 | throw new Error(ERROR_API_CODE);
86 | }
87 |
88 | return COMMON_HK + code.replace(TENCENT_HK, "");
89 | }
90 |
91 | /**
92 | * 美交所股票代码转换统一代码
93 | * @param code 股票代码
94 | */
95 | public USTransform(code: string): string {
96 | if (!code.includes(TENCENT_US)) {
97 | throw new Error(ERROR_API_CODE);
98 | }
99 |
100 | return COMMON_US + code.replace(TENCENT_US, "");
101 | }
102 | }
103 |
104 | export default TencentApiCodeTransform;
105 |
--------------------------------------------------------------------------------
/src/stocks/tencent/transforms/common-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseCommonCodeTransform from "../../../stocks/base/transforms/common-code";
3 |
4 | // Utils
5 | import { ERROR_COMMON_CODE } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 | import {
13 | TENCENT_SZ,
14 | TENCENT_SH,
15 | TENCENT_HK,
16 | TENCENT_US,
17 | } from "../../../stocks/tencent/utils/constant";
18 |
19 | /**
20 | * 【腾讯】统一代码转换股票代码
21 | */
22 | class TencentCommonCodeTransform extends BaseCommonCodeTransform {
23 | /**
24 | * 构造函数
25 | */
26 | constructor() {
27 | super();
28 | }
29 |
30 | /**
31 | * 交易所统一代码转换股票代码
32 | * @param code 统一代码
33 | */
34 | public transform(code: string): string {
35 | return super.transform(code);
36 | }
37 |
38 | /**
39 | * 交易所统一代码组转换股票代码组
40 | * @param codes 统一代码组
41 | */
42 | public transforms(codes: string[]): string[] {
43 | return super.transforms(codes);
44 | }
45 |
46 | /**
47 | * 深交所统一代码转换股票代码
48 | * @param code 统一代码
49 | */
50 | public SZTransform(code: string): string {
51 | if (!code.includes(COMMON_SZ)) {
52 | throw new Error(ERROR_COMMON_CODE);
53 | }
54 |
55 | return TENCENT_SZ + code.replace(COMMON_SZ, "");
56 | }
57 |
58 | /**
59 | * 上交所统一代码转换股票代码
60 | * @param code 统一代码
61 | */
62 | public SHTransform(code: string): string {
63 | if (!code.includes(COMMON_SH)) {
64 | throw new Error(ERROR_COMMON_CODE);
65 | }
66 |
67 | return TENCENT_SH + code.replace(COMMON_SH, "");
68 | }
69 |
70 | /**
71 | * 港交所统一代码转换股票代码
72 | * @param code 统一代码
73 | */
74 | public HKTransform(code: string): string {
75 | if (!code.includes(COMMON_HK)) {
76 | throw new Error(ERROR_COMMON_CODE);
77 | }
78 |
79 | return TENCENT_HK + code.replace(COMMON_HK, "").toUpperCase();
80 | }
81 |
82 | /**
83 | * 美交所统一代码转换股票代码
84 | * @param code 统一代码
85 | */
86 | public USTransform(code: string): string {
87 | if (!code.includes(COMMON_US)) {
88 | throw new Error(ERROR_COMMON_CODE);
89 | }
90 |
91 | return TENCENT_US + code.replace(COMMON_US, "").toUpperCase();
92 | }
93 | }
94 |
95 | export default TencentCommonCodeTransform;
96 |
--------------------------------------------------------------------------------
/src/stocks/tencent/transforms/stock.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseStockTransform from "../../../stocks/base/transforms/stock";
3 |
4 | // Utils
5 | import { DEFAULT_STRING, DEFAULT_NUMBER } from "../../../utils/constant";
6 |
7 | // Types
8 | import Stock from "../../../types/utils/stock";
9 |
10 | /**
11 | * 腾讯股票数据解析
12 | */
13 | class TencentStockTransform extends BaseStockTransform {
14 | /**
15 | * 构造函数
16 | */
17 | constructor(public code: string, public params: string[]) {
18 | super();
19 | }
20 |
21 | /**
22 | * 获取代码
23 | */
24 | getCode(): string {
25 | return String(this.code).toUpperCase();
26 | }
27 |
28 | /**
29 | * 获取名称
30 | */
31 | getName(): string {
32 | return String(this.params[1] || DEFAULT_STRING);
33 | }
34 |
35 | /**
36 | * 获取现价
37 | */
38 | getNow(): number {
39 | return Number(this.params[3] || DEFAULT_NUMBER);
40 | }
41 |
42 | /**
43 | * 获取最低价
44 | */
45 | getLow(): number {
46 | return Number(this.params[34] || DEFAULT_NUMBER);
47 | }
48 |
49 | /**
50 | * 获取最高价
51 | */
52 | getHigh(): number {
53 | return Number(this.params[33] || DEFAULT_NUMBER);
54 | }
55 |
56 | /**
57 | * 获取昨日收盘价
58 | */
59 | getYesterday(): number {
60 | return Number(this.params[4] || DEFAULT_NUMBER);
61 | }
62 |
63 | /**
64 | * 获取涨跌
65 | */
66 | getPercent(): number {
67 | return this.getNow() ? this.getNow() / this.getYesterday() - 1 : 0;
68 | }
69 |
70 | /**
71 | * 获取股票数据
72 | */
73 | getStock(): Stock {
74 | return {
75 | code: this.getCode(),
76 | name: this.getName(),
77 | percent: this.getPercent(),
78 |
79 | now: this.getNow(),
80 | low: this.getLow(),
81 | high: this.getHigh(),
82 | yesterday: this.getYesterday(),
83 | };
84 | }
85 | }
86 |
87 | export default TencentStockTransform;
88 |
--------------------------------------------------------------------------------
/src/stocks/tencent/utils/constant.ts:
--------------------------------------------------------------------------------
1 | // 默认交易所常量
2 | export const TENCENT_SZ = "sz"; // 深交所相关常量
3 | export const TENCENT_SH = "sh"; // 上交所相关常量
4 | export const TENCENT_HK = "hk"; // 港交所相关常量
5 | export const TENCENT_US = "us"; // 美交所相关常量
6 |
--------------------------------------------------------------------------------
/src/stocks/xueqiu/index.ts:
--------------------------------------------------------------------------------
1 | // NPM
2 | import { uniq } from "lodash";
3 |
4 | // Stocks
5 | import XueqiuStockTransform from "../xueqiu/transforms/stock";
6 | import XueqiuCommonCodeTransform from "../xueqiu/transforms/common-code";
7 |
8 | // Utils
9 | import fetch from "../../utils/fetch";
10 | import { DEFAULT_STOCK } from "../../utils/constant";
11 | import {
12 | COMMON_SZ,
13 | COMMON_SH,
14 | COMMON_HK,
15 | COMMON_US,
16 | } from "../base/utils/constant";
17 |
18 | // Types
19 | import Stock from "../../types/utils/stock";
20 | import StockApi from "../../types/stocks/index";
21 | import Dictionary from "../../types/utils/dictionary";
22 |
23 | let token: string = "";
24 |
25 | /**
26 | * 雪球股票代码接口
27 | */
28 | const Xueqiu: StockApi & { getToken(): Promise } = {
29 | /**
30 | * 获取 Token
31 | */
32 | async getToken(): Promise {
33 | if (token !== "") return token;
34 |
35 | const res = await fetch.get("https://xueqiu.com/");
36 | const cookies: string[] = res.headers["set-cookie"] as any;
37 |
38 | const param: string =
39 | cookies.filter((key) => key.includes("xq_a_token"))[0] || "";
40 | token = param.split(";")[0] || "";
41 |
42 | return token;
43 | },
44 |
45 | /**
46 | * 获取股票数据
47 | * @param code 股票代码
48 | */
49 | async getStock(code: string): Promise {
50 | const token = await this.getToken();
51 | const transform = new XueqiuCommonCodeTransform().transform(code);
52 |
53 | // 数据获取
54 | const url = `https://stock.xueqiu.com/v5/stock/quote.json?symbol=${transform}`;
55 | const res = await fetch.get(url).set("Cookie", token);
56 |
57 | const body = JSON.parse(res.text);
58 | const row: Dictionary = body.data.quote;
59 |
60 | // 数据深解析
61 | const params = row;
62 | const data = new XueqiuStockTransform(code, params);
63 |
64 | return params ? data.getStock() : { ...DEFAULT_STOCK, code };
65 | },
66 |
67 | /**
68 | * 获取股票数据组
69 | * @param codes 股票代码组
70 | */
71 | async getStocks(codes: string[]): Promise {
72 | codes = uniq(codes.filter((i) => i !== ""));
73 |
74 | // 无股票时返回空数组
75 | if (codes.length === 0) {
76 | return [];
77 | }
78 |
79 | const token = await this.getToken();
80 | const transforms = new XueqiuCommonCodeTransform().transforms(codes);
81 |
82 | // 数据获取
83 | const url = `https://stock.xueqiu.com/v5/stock/batch/quote.json?symbol=${transforms.join(
84 | ","
85 | )}`;
86 | const res = await fetch.get(url).set("Cookie", token);
87 |
88 | const body = JSON.parse(res.text);
89 | const rows: Dictionary>[] = body.data.items;
90 |
91 | return codes.map((code) => {
92 | // 数据深解析
93 | const transform = new XueqiuCommonCodeTransform().transform(code);
94 |
95 | const params =
96 | rows.find((i) => {
97 | if (!i.quote) {
98 | return false;
99 | }
100 |
101 | if (i.market.region === "US") {
102 | return i.quote.code === transform;
103 | }
104 |
105 | if (i.market.region === "CN") {
106 | return i.quote.symbol === transform;
107 | }
108 |
109 | if (i.market.region === "HK") {
110 | return i.market.region + i.quote.code === transform;
111 | }
112 | }) || null;
113 |
114 | if (!params) {
115 | return { ...DEFAULT_STOCK, code };
116 | }
117 |
118 | const data = new XueqiuStockTransform(code, params.quote);
119 | return data.getStock();
120 | });
121 | },
122 |
123 | /**
124 | * 搜索股票代码
125 | * @param key 关键字
126 | */
127 | async searchStocks(key: string): Promise {
128 | const token = await this.getToken();
129 |
130 | // 数据获取
131 | const url = `https://xueqiu.com/stock/search.json?code=${encodeURIComponent(
132 | key
133 | )}`;
134 | const res = await fetch.get(url).set("Cookie", token);
135 |
136 | const body = JSON.parse(res.text);
137 | const rows: Dictionary[] = body.stocks;
138 |
139 | let codes: string[] = [];
140 | for (let i = 0; i < rows.length; i++) {
141 | let code: string = rows[i].code;
142 |
143 | if (code.indexOf("SZ") === 0) {
144 | code = code.replace("SZ", "");
145 | codes = [...codes, COMMON_SZ + code];
146 | continue;
147 | }
148 |
149 | if (code.indexOf("SH") === 0) {
150 | code = code.replace("SH", "");
151 | codes = [...codes, COMMON_SH + code];
152 | continue;
153 | }
154 |
155 | codes = [...codes, COMMON_HK + code, COMMON_US + code];
156 | }
157 |
158 | return await Xueqiu.getStocks(uniq(codes.filter((i) => i !== "")));
159 | },
160 | };
161 |
162 | export default Xueqiu;
163 |
--------------------------------------------------------------------------------
/src/stocks/xueqiu/transforms/api-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseApiCodeTransform from "../../../stocks/base/transforms/api-code";
3 |
4 | // Utils
5 | import { ERROR_API_CODE } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 | import {
13 | XUEQIU_SZ,
14 | XUEQIU_SH,
15 | XUEQIU_HK,
16 | XUEQIU_US,
17 | } from "../../../stocks/xueqiu/utils/constant";
18 |
19 | /**
20 | * 【雪球】股票代码转换统一代码
21 | */
22 | class XueqiuApiCodeTransform extends BaseApiCodeTransform {
23 | /**
24 | * 交易所股票代码转换统一代码
25 | * @param code 股票代码
26 | */
27 | public transform(code: string): string {
28 | if (code.includes(XUEQIU_SZ)) {
29 | return this.SZTransform(code);
30 | }
31 |
32 | if (code.includes(XUEQIU_SH)) {
33 | return this.SHTransform(code);
34 | }
35 |
36 | if (code.includes(XUEQIU_HK)) {
37 | return this.HKTransform(code);
38 | }
39 |
40 | return this.USTransform(code);
41 | }
42 |
43 | /**
44 | * 交易所股票组代码组转换统一代码组
45 | * @param codes 股票代码组
46 | */
47 | public transforms(codes: string[]): string[] {
48 | return super.transforms(codes);
49 | }
50 |
51 | /**
52 | * 深交所股票代码转换统一代码
53 | * @param code 股票代码
54 | */
55 | public SZTransform(code: string): string {
56 | if (!code.includes(XUEQIU_SZ)) {
57 | throw new Error(ERROR_API_CODE);
58 | }
59 |
60 | return COMMON_SZ + code.replace(XUEQIU_SZ, "");
61 | }
62 |
63 | /**
64 | * 上交所股票代码转换统一代码
65 | * @param code 股票代码
66 | */
67 | public SHTransform(code: string): string {
68 | if (!code.includes(XUEQIU_SH)) {
69 | throw new Error(ERROR_API_CODE);
70 | }
71 |
72 | return COMMON_SH + code.replace(XUEQIU_SH, "");
73 | }
74 |
75 | /**
76 | * 港交所股票代码转换统一代码
77 | * @param code 股票代码
78 | */
79 | public HKTransform(code: string): string {
80 | if (!code.includes(XUEQIU_HK)) {
81 | throw new Error(ERROR_API_CODE);
82 | }
83 |
84 | return COMMON_HK + code.replace(XUEQIU_HK, "");
85 | }
86 |
87 | /**
88 | * 美交所股票代码转换统一代码
89 | * @param code 股票代码
90 | */
91 | public USTransform(code: string): string {
92 | if (
93 | code.includes(XUEQIU_SZ) ||
94 | code.includes(XUEQIU_SH) ||
95 | code.includes(XUEQIU_HK)
96 | ) {
97 | throw new Error(ERROR_API_CODE);
98 | }
99 |
100 | return COMMON_US + code.replace(XUEQIU_US, "");
101 | }
102 | }
103 |
104 | export default XueqiuApiCodeTransform;
105 |
--------------------------------------------------------------------------------
/src/stocks/xueqiu/transforms/common-code.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseCommonCodeTransform from "../../../stocks/base/transforms/common-code";
3 |
4 | // Utils
5 | import { ERROR_COMMON_CODE } from "../../../utils/constant";
6 | import {
7 | COMMON_SH,
8 | COMMON_SZ,
9 | COMMON_HK,
10 | COMMON_US,
11 | } from "../../../stocks/base/utils/constant";
12 | import {
13 | XUEQIU_SZ,
14 | XUEQIU_SH,
15 | XUEQIU_HK,
16 | XUEQIU_US,
17 | } from "../../../stocks/xueqiu/utils/constant";
18 |
19 | /**
20 | * 【雪球】统一代码转换股票代码
21 | */
22 | class XueqiuCommonCodeTransform extends BaseCommonCodeTransform {
23 | /**
24 | * 交易所统一代码转换股票代码
25 | * @param code 统一代码
26 | */
27 | public transform(code: string): string {
28 | return super.transform(code);
29 | }
30 |
31 | /**
32 | * 交易所股 统一代码 转换 票组代码
33 | * @param codes 统一代码组
34 | */
35 | public transforms(codes: string[]): string[] {
36 | return super.transforms(codes);
37 | }
38 |
39 | /**
40 | * 深交所统一代码转换股票代码
41 | * @param code 统一代码
42 | */
43 | public SZTransform(code: string): string {
44 | if (!code.includes(COMMON_SZ)) {
45 | throw new Error(ERROR_COMMON_CODE);
46 | }
47 |
48 | return XUEQIU_SZ + code.replace(COMMON_SZ, "");
49 | }
50 |
51 | /**
52 | * 上交所统一代码转换股票代码
53 | * @param code 统一代码
54 | */
55 | public SHTransform(code: string): string {
56 | if (!code.includes(COMMON_SH)) {
57 | throw new Error(ERROR_COMMON_CODE);
58 | }
59 |
60 | return XUEQIU_SH + code.replace(COMMON_SH, "");
61 | }
62 |
63 | /**
64 | * 港交所统一代码转换股票代码
65 | * @param code 统一代码
66 | */
67 | public HKTransform(code: string): string {
68 | if (!code.includes(COMMON_HK)) {
69 | throw new Error(ERROR_COMMON_CODE);
70 | }
71 |
72 | return XUEQIU_HK + code.replace(COMMON_HK, "");
73 | }
74 |
75 | /**
76 | * 美交所统一代码转换股票代码
77 | * @param code 统一代码
78 | */
79 | public USTransform(code: string): string {
80 | if (!code.includes(COMMON_US)) {
81 | throw new Error(ERROR_COMMON_CODE);
82 | }
83 |
84 | return XUEQIU_US + code.replace(COMMON_US, "");
85 | }
86 | }
87 |
88 | export default XueqiuCommonCodeTransform;
89 |
--------------------------------------------------------------------------------
/src/stocks/xueqiu/transforms/stock.ts:
--------------------------------------------------------------------------------
1 | // Stocks
2 | import BaseStockTransform from "../../../stocks/base/transforms/stock";
3 |
4 | // Utils
5 | import { DEFAULT_STRING, DEFAULT_NUMBER } from "../../../utils/constant";
6 |
7 | // Types
8 | import Stock from "../../../types/utils/stock";
9 | import Dictionary from "../../../types/utils/dictionary";
10 |
11 | /**
12 | * 雪球股票数据解析
13 | */
14 | class XueqiuStockTransform extends BaseStockTransform {
15 | /**
16 | * 构造函数
17 | */
18 | constructor(public code: string, public params: Dictionary) {
19 | super();
20 | }
21 |
22 | /**
23 | * 获取代码
24 | */
25 | getCode(): string {
26 | return String(this.code).toUpperCase();
27 | }
28 |
29 | /**
30 | * 获取名称
31 | */
32 | getName(): string {
33 | return String(this.params.name || DEFAULT_STRING);
34 | }
35 |
36 | /**
37 | * 获取现价
38 | */
39 | getNow(): number {
40 | return Number(this.params.current || DEFAULT_NUMBER);
41 | }
42 |
43 | /**
44 | * 获取最低价
45 | */
46 | getLow(): number {
47 | return Number(this.params.low || DEFAULT_NUMBER);
48 | }
49 |
50 | /**
51 | * 获取最高价
52 | */
53 | getHigh(): number {
54 | return Number(this.params.high || DEFAULT_NUMBER);
55 | }
56 |
57 | /**
58 | * 获取昨日收盘价
59 | */
60 | getYesterday(): number {
61 | return Number(this.params.last_close || DEFAULT_NUMBER);
62 | }
63 |
64 | /**
65 | * 获取涨跌
66 | */
67 | getPercent(): number {
68 | return this.getNow() ? this.getNow() / this.getYesterday() - 1 : 0;
69 | }
70 |
71 | /**
72 | * 获取股票数据
73 | */
74 | getStock(): Stock {
75 | return {
76 | code: this.getCode(),
77 | name: this.getName(),
78 | percent: this.getPercent(),
79 |
80 | now: this.getNow(),
81 | low: this.getLow(),
82 | high: this.getHigh(),
83 | yesterday: this.getYesterday(),
84 | };
85 | }
86 | }
87 |
88 | export default XueqiuStockTransform;
89 |
--------------------------------------------------------------------------------
/src/stocks/xueqiu/utils/constant.ts:
--------------------------------------------------------------------------------
1 | // 默认交易所常量
2 | export const XUEQIU_SZ = "SZ"; // 深交所相关常量
3 | export const XUEQIU_SH = "SH"; // 上交所相关常量
4 | export const XUEQIU_HK = "HK"; // 港交所相关常量
5 | export const XUEQIU_US = ""; // 美交所相关常量
6 |
--------------------------------------------------------------------------------
/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | import StockApi from "./stocks/index";
2 |
3 | export declare const stocks: {
4 | base: StockApi;
5 | netease: StockApi;
6 | sina: StockApi;
7 | tencent: StockApi;
8 | xueqiu: StockApi;
9 | };
10 |
11 | export declare const root: {
12 | stocks: {
13 | base: StockApi;
14 | netease: StockApi;
15 | sina: StockApi;
16 | tencent: StockApi;
17 | xueqiu: StockApi;
18 | };
19 | };
20 |
21 | export default root;
22 |
--------------------------------------------------------------------------------
/src/types/stocks/index.d.ts:
--------------------------------------------------------------------------------
1 | import Stock from "../utils/stock";
2 |
3 | export interface StockApi {
4 | /**
5 | * 获取股票数据
6 | * @param code 股票代码
7 | */
8 | getStock(code: string): Promise;
9 |
10 | /**
11 | * 获取股票数据组
12 | * @param codes 股票代码组
13 | */
14 | getStocks(codes: string[]): Promise;
15 |
16 | /**
17 | * 搜索股票代码
18 | * @param key 关键字
19 | */
20 | searchStocks(key: string): Promise;
21 | }
22 |
23 | export default StockApi;
24 |
--------------------------------------------------------------------------------
/src/types/stocks/transforms/api-code.d.ts:
--------------------------------------------------------------------------------
1 | export interface ApiCodeTransform {
2 | transform(code: string): string;
3 | transforms(codes: string[]): string[];
4 | SZTransform(code: string): string;
5 | SHTransform(code: string): string;
6 | HKTransform(code: string): string;
7 | USTransform(code: string): string;
8 | }
9 |
10 | export default ApiCodeTransform;
11 |
--------------------------------------------------------------------------------
/src/types/stocks/transforms/common-code.d.ts:
--------------------------------------------------------------------------------
1 | export interface CommonCodeTransform {
2 | transform(code: string): string;
3 | transforms(codes: string[]): string[];
4 | SZTransform(code: string): string;
5 | SHTransform(code: string): string;
6 | HKTransform(code: string): string;
7 | USTransform(code: string): string;
8 | }
9 |
10 | export default CommonCodeTransform;
11 |
--------------------------------------------------------------------------------
/src/types/stocks/transforms/stock.d.ts:
--------------------------------------------------------------------------------
1 | // Types
2 | import Stock from "../../utils/stock";
3 |
4 | /**
5 | * 基础股票数据解析
6 | */
7 | export interface StockTransform {
8 | /**
9 | * 获取代码
10 | */
11 | getCode(): string;
12 | /**
13 | * 获取名称
14 | */
15 | getName(): string;
16 |
17 | /**
18 | * 获取现价
19 | */
20 | getNow(): number;
21 |
22 | /**
23 | * 获取最低价
24 | */
25 | getLow(): number;
26 |
27 | /**
28 | * 获取最高价
29 | */
30 | getHigh(): number;
31 |
32 | /**
33 | * 获取昨日收盘价
34 | */
35 | getYesterday(): number;
36 |
37 | /**
38 | * 获取涨跌
39 | */
40 | getPercent(): number;
41 |
42 | /**
43 | * 获取股票数据
44 | */
45 | getStock(): Stock;
46 | }
47 |
48 | export default StockTransform;
49 |
--------------------------------------------------------------------------------
/src/types/utils/dictionary.d.ts:
--------------------------------------------------------------------------------
1 | export type Dictionary = {
2 | [key in K]: T;
3 | };
4 |
5 | export default Dictionary;
6 |
--------------------------------------------------------------------------------
/src/types/utils/stock.d.ts:
--------------------------------------------------------------------------------
1 | export interface Stock {
2 | name: string;
3 | code: string;
4 |
5 | now: number;
6 | low: number;
7 | high: number;
8 | percent: number;
9 | yesterday: number;
10 | }
11 |
12 | export default Stock;
13 |
--------------------------------------------------------------------------------
/src/utils/constant.ts:
--------------------------------------------------------------------------------
1 | // 默认股票名称常量
2 | export const DEFAULT_NUMBER = 0;
3 | export const DEFAULT_STRING = "---";
4 |
5 | // 默认错误提示常量
6 | export const ERROR_API_CODE = "请检查股票代码是否正确";
7 | export const ERROR_COMMON_CODE = "请检查统一代码是否正确";
8 |
9 | export const ERROR_UNDEFINED_GET_STOCK = "未实现获取股票数据";
10 | export const ERROR_UNDEFINED_GET_STOCKS = "未实现获取股票数据组";
11 | export const ERROR_UNDEFINED_SEARCH_STOCK = "未实现搜索股票代码";
12 |
13 | export const ERROR_UNDEFINED_COMMON_CODE = "未实现统一代码转换股票代码";
14 | export const ERROR_UNDEFINED_SZ_COMMON_CODE =
15 | "未实现深交所统一代码转换股票代码";
16 | export const ERROR_UNDEFINED_SH_COMMON_CODE =
17 | "未实现上交所统一代码转换股票代码";
18 | export const ERROR_UNDEFINED_HK_COMMON_CODE =
19 | "未实现港交所统一代码转换股票代码";
20 | export const ERROR_UNDEFINED_US_COMMON_CODE =
21 | "未实现美交所统一代码转换股票代码";
22 |
23 | export const ERROR_UNDEFINED_API_CODE = "未实现股票代码转换统一代码";
24 | export const ERROR_UNDEFINED_API_CODES = "未实现股票代码组转换统一代码组";
25 | export const ERROR_UNDEFINED_SZ_API_CODE = "未实现深交所股票代码转换统一代码";
26 | export const ERROR_UNDEFINED_SH_API_CODE = "未实现上交所股票代码转换统一代码";
27 | export const ERROR_UNDEFINED_HK_API_CODE = "未实现港交所股票代码转换统一代码";
28 | export const ERROR_UNDEFINED_US_API_CODE = "未实现美交所股票代码转换统一代码";
29 |
30 | export const ERROR_UNDEFINED_GET_CODE = "未实现获取代码";
31 | export const ERROR_UNDEFINED_GET_NAME = "未实现获取名称";
32 | export const ERROR_UNDEFINED_GET_NOW = "未实现获取现价";
33 | export const ERROR_UNDEFINED_GET_LOW = "未实现获取最低价";
34 | export const ERROR_UNDEFINED_GET_HIGH = "未实现获取最高价";
35 | export const ERROR_UNDEFINED_GET_PERCENT = "未实现获取涨跌";
36 | export const ERROR_UNDEFINED_GET_YESTERDAY = "未实现获取昨日收盘价";
37 |
38 | // 默认股票数据常量
39 | export const DEFAULT_STOCK = {
40 | code: DEFAULT_STRING,
41 | name: DEFAULT_STRING,
42 | percent: DEFAULT_NUMBER,
43 |
44 | now: DEFAULT_NUMBER,
45 | low: DEFAULT_NUMBER,
46 | high: DEFAULT_NUMBER,
47 | yesterday: DEFAULT_NUMBER,
48 | };
49 |
--------------------------------------------------------------------------------
/src/utils/fetch.ts:
--------------------------------------------------------------------------------
1 | import superagent from "superagent";
2 |
3 | export default superagent;
4 |
--------------------------------------------------------------------------------
/src/utils/iconv.ts:
--------------------------------------------------------------------------------
1 | import iconv from "iconv-lite";
2 |
3 | export default iconv;
4 |
--------------------------------------------------------------------------------
/tea.yaml:
--------------------------------------------------------------------------------
1 | # https://tea.xyz/what-is-this-file
2 | ---
3 | version: 1.0.0
4 | codeOwners:
5 | - '0xA1390CC463264639535Be612FC5358787a86B865'
6 | quorum: 1
7 |
--------------------------------------------------------------------------------
/test/stocks/base/index.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const Base = require("stocks/base").default;
3 |
4 | describe("【基础】股票代码接口", () => {
5 | const {
6 | ERROR_UNDEFINED_GET_STOCK,
7 | ERROR_UNDEFINED_GET_STOCKS,
8 | ERROR_UNDEFINED_SEARCH_STOCK,
9 | } = require("utils/constant");
10 |
11 | it("需要获取的股票代码", async () => {
12 | await expect(Base.getStock("SZ000000"))
13 | .rejects
14 | .toThrow(new Error(ERROR_UNDEFINED_GET_STOCK));
15 | });
16 |
17 | it("需要获取的股票代码组", async () => {
18 | await expect(Base.getStocks(["SZ000000"]))
19 | .rejects
20 | .toThrow(new Error(ERROR_UNDEFINED_GET_STOCKS));
21 | });
22 |
23 | it("搜索股票代码", async () => {
24 | await expect(Base.searchStocks("510500"))
25 | .rejects
26 | .toThrow(new Error(ERROR_UNDEFINED_SEARCH_STOCK));
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/test/stocks/base/transforms/api-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const BaseApiCodeTransform = require("stocks/base/transforms/api-code").default;
3 |
4 | describe("【基础】股票代码转换统一代码", () => {
5 | const {
6 | ERROR_API_CODE,
7 | ERROR_UNDEFINED_SZ_API_CODE,
8 | ERROR_UNDEFINED_SH_API_CODE,
9 | ERROR_UNDEFINED_HK_API_CODE,
10 | ERROR_UNDEFINED_US_API_CODE
11 | } = require("utils/constant");
12 |
13 | it("深交所股票代码转换统一代码", async () => {
14 | expect(() => (new BaseApiCodeTransform()).SZTransform("SZ000000"))
15 | .toThrow(new Error(ERROR_UNDEFINED_SZ_API_CODE));
16 | });
17 |
18 | it("上交所股票代码转换统一代码", async () => {
19 | expect(() => (new BaseApiCodeTransform()).SHTransform("SH000000"))
20 | .toThrow(new Error(ERROR_UNDEFINED_SH_API_CODE));
21 | });
22 |
23 | it("港交所股票代码转换统一代码", async () => {
24 | expect(() => new BaseApiCodeTransform().HKTransform("HK000000"))
25 | .toThrow(new Error(ERROR_UNDEFINED_HK_API_CODE));
26 | });
27 |
28 | it("美交所股票代码转换统一代码", async () => {
29 | expect(() => (new BaseApiCodeTransform()).USTransform("US000000"))
30 | .toThrow(new Error(ERROR_UNDEFINED_US_API_CODE));
31 | });
32 |
33 | it("交易所股票代码转换统一代码", async () => {
34 | expect(() => (new BaseApiCodeTransform()).transform("000000"))
35 | .toThrow(new Error(ERROR_API_CODE));
36 |
37 | expect(() => (new BaseApiCodeTransform()).transform("SZ000000"))
38 | .toThrow(new Error(ERROR_UNDEFINED_SZ_API_CODE));
39 |
40 | expect(() => (new BaseApiCodeTransform()).transform("SH000000"))
41 | .toThrow(new Error(ERROR_UNDEFINED_SH_API_CODE));
42 |
43 | expect(() => (new BaseApiCodeTransform()).transform("HK000000"))
44 | .toThrow(new Error(ERROR_UNDEFINED_HK_API_CODE));
45 |
46 | expect(() => (new BaseApiCodeTransform()).transform("US000000"))
47 | .toThrow(new Error(ERROR_UNDEFINED_US_API_CODE));
48 | });
49 |
50 | it("交易所股票代码组转换统一代码组", async () => {
51 | expect(() => (new BaseApiCodeTransform()).transforms(["000000"]))
52 | .toThrow(new Error(ERROR_API_CODE));
53 |
54 | expect(() => (new BaseApiCodeTransform()).transforms(["SZ000000"]))
55 | .toThrow(new Error(ERROR_UNDEFINED_SZ_API_CODE));
56 |
57 | expect(() => (new BaseApiCodeTransform()).transforms(["SH000000"]))
58 | .toThrow(new Error(ERROR_UNDEFINED_SH_API_CODE));
59 |
60 | expect(() => (new BaseApiCodeTransform()).transforms(["HK000000"]))
61 | .toThrow(new Error(ERROR_UNDEFINED_HK_API_CODE));
62 |
63 | expect(() => (new BaseApiCodeTransform()).transforms(["US000000"]))
64 | .toThrow(new Error(ERROR_UNDEFINED_US_API_CODE));
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/test/stocks/base/transforms/common-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const BaseCommonCodeTransform = require("stocks/base/transforms/common-code").default;
3 |
4 | describe("【基础】统一代码转换股票代码", () => {
5 | const {
6 | ERROR_COMMON_CODE,
7 | ERROR_UNDEFINED_SZ_COMMON_CODE,
8 | ERROR_UNDEFINED_SH_COMMON_CODE,
9 | ERROR_UNDEFINED_HK_COMMON_CODE,
10 | ERROR_UNDEFINED_US_COMMON_CODE
11 | } = require("utils/constant");
12 |
13 | it("深交所统一代码转换股票代码", async () => {
14 | expect(() => (new BaseCommonCodeTransform()).SZTransform("SZ000000"))
15 | .toThrow(new Error(ERROR_UNDEFINED_SZ_COMMON_CODE));
16 | });
17 |
18 | it("上交所统一代码转换股票代码", async () => {
19 | expect(() => (new BaseCommonCodeTransform()).SHTransform("SH000000"))
20 | .toThrow(new Error(ERROR_UNDEFINED_SH_COMMON_CODE));
21 | });
22 |
23 | it("港交所统一代码转换股票代码", async () => {
24 | expect(() => new BaseCommonCodeTransform().HKTransform("HK000000"))
25 | .toThrow(new Error(ERROR_UNDEFINED_HK_COMMON_CODE));
26 | });
27 |
28 | it("美交所统一代码转换股票代码", async () => {
29 | expect(() => (new BaseCommonCodeTransform()).USTransform("US000000"))
30 | .toThrow(new Error(ERROR_UNDEFINED_US_COMMON_CODE));
31 | });
32 |
33 | it("交易所统一代码转换股票代码", async () => {
34 | expect(() => (new BaseCommonCodeTransform()).transform("000000"))
35 | .toThrow(new Error(ERROR_COMMON_CODE));
36 |
37 | expect(() => (new BaseCommonCodeTransform()).transform("SZ000000"))
38 | .toThrow(new Error(ERROR_UNDEFINED_SZ_COMMON_CODE));
39 |
40 | expect(() => (new BaseCommonCodeTransform()).transform("SH000000"))
41 | .toThrow(new Error(ERROR_UNDEFINED_SH_COMMON_CODE));
42 |
43 | expect(() => (new BaseCommonCodeTransform()).transform("HK000000"))
44 | .toThrow(new Error(ERROR_UNDEFINED_HK_COMMON_CODE));
45 |
46 | expect(() => (new BaseCommonCodeTransform()).transform("US000000"))
47 | .toThrow(new Error(ERROR_UNDEFINED_US_COMMON_CODE));
48 | });
49 |
50 | it("交易所统一代码组转换股票代码组", async () => {
51 | expect(() => (new BaseCommonCodeTransform()).transforms(["000000"]))
52 | .toThrow(new Error(ERROR_COMMON_CODE));
53 |
54 | expect(() => (new BaseCommonCodeTransform()).transforms(["SZ000000"]))
55 | .toThrow(new Error(ERROR_UNDEFINED_SZ_COMMON_CODE));
56 |
57 | expect(() => (new BaseCommonCodeTransform()).transforms(["SH000000"]))
58 | .toThrow(new Error("未实现上交所统一代码转换股票代码"));
59 |
60 | expect(() => (new BaseCommonCodeTransform()).transforms(["HK000000"]))
61 | .toThrow(new Error(ERROR_UNDEFINED_HK_COMMON_CODE));
62 |
63 | expect(() => (new BaseCommonCodeTransform()).transforms(["US000000"]))
64 | .toThrow(new Error(ERROR_UNDEFINED_US_COMMON_CODE));
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/test/stocks/base/transforms/stock.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const BaseStockTransform = require("stocks/base/transforms/stock").default;
3 |
4 | describe("【基础】股票数据转换测试", () => {
5 | const {
6 | ERROR_UNDEFINED_GET_CODE,
7 | ERROR_UNDEFINED_GET_NAME,
8 | ERROR_UNDEFINED_GET_NOW,
9 | ERROR_UNDEFINED_GET_LOW,
10 | ERROR_UNDEFINED_GET_HIGH,
11 | ERROR_UNDEFINED_GET_STOCK,
12 | ERROR_UNDEFINED_GET_PERCENT,
13 | ERROR_UNDEFINED_GET_YESTERDAY,
14 | } = require("utils/constant");
15 |
16 | it("获取股票代码", async () => {
17 | expect(() => (new BaseStockTransform()).getCode())
18 | .toThrow(new Error(ERROR_UNDEFINED_GET_CODE));
19 | });
20 |
21 | it("获取股票名称", async () => {
22 | expect(() => (new BaseStockTransform()).getName())
23 | .toThrow(new Error(ERROR_UNDEFINED_GET_NAME));
24 | });
25 |
26 | it("获取股票现价", async () => {
27 | expect(() => (new BaseStockTransform()).getNow())
28 | .toThrow(new Error(ERROR_UNDEFINED_GET_NOW));
29 | });
30 |
31 | it("获取股票最低价", async () => {
32 | expect(() => (new BaseStockTransform()).getLow())
33 | .toThrow(new Error(ERROR_UNDEFINED_GET_LOW));
34 | });
35 |
36 | it("获取股票最高价", async () => {
37 | expect(() => (new BaseStockTransform()).getHigh())
38 | .toThrow(new Error(ERROR_UNDEFINED_GET_HIGH));
39 | });
40 |
41 | it("获取股票昨日收盘价", async () => {
42 | expect(() => (new BaseStockTransform()).getYesterday())
43 | .toThrow(new Error(ERROR_UNDEFINED_GET_YESTERDAY));
44 | });
45 |
46 | it("获取股票涨跌", async () => {
47 | expect(() => (new BaseStockTransform()).getPercent())
48 | .toThrow(new Error(ERROR_UNDEFINED_GET_PERCENT));
49 | });
50 |
51 | it("获取股票数据", async () => {
52 | expect(() => (new BaseStockTransform()).getStock())
53 | .toThrow(new Error(ERROR_UNDEFINED_GET_STOCK));
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/test/stocks/netease/index.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const Netease = require("stocks/netease").default;
3 |
4 | describe("【网易】股票代码接口", () => {
5 | it("基础测试", async () => {
6 | await expect(true).toEqual(true);
7 | });
8 |
9 | it("需要获取的股票代码", async () => {
10 | await expect(Netease.getStock("SH510500")).resolves.toMatchObject({
11 | code: "SH510500",
12 | name: "500ETF",
13 | });
14 |
15 | await expect(Netease.getStock("SZ510500")).resolves.toMatchObject({
16 | code: "SZ510500",
17 | name: "---",
18 | });
19 | });
20 |
21 | it("需要获取的股票代码组", async () => {
22 | await expect(Netease.getStocks(["SH510500"])).resolves.toEqual(
23 | expect.arrayContaining([
24 | expect.objectContaining({ code: "SH510500", name: "500ETF" }),
25 | ])
26 | );
27 |
28 | await expect(Netease.getStocks(["SZ510500"])).resolves.toEqual(
29 | expect.arrayContaining([
30 | expect.objectContaining({ code: "SZ510500", name: "---" }),
31 | ])
32 | );
33 |
34 | await expect(Netease.getStocks([])).resolves.toEqual([]);
35 | });
36 |
37 | it("搜索股票代码", async () => {
38 | await expect(Netease.searchStocks("格力电器")).resolves.toEqual(
39 | expect.arrayContaining([
40 | expect.objectContaining({ code: "SZ000651", name: "格力电器" }),
41 | ])
42 | );
43 |
44 | await expect(Netease.searchStocks("贵州茅台")).resolves.toEqual(
45 | expect.arrayContaining([
46 | expect.objectContaining({ code: "SH600519", name: "贵州茅台" }),
47 | ])
48 | );
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/test/stocks/netease/transforms/api-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const NeteaseApiCodeTransform = require("stocks/netease/transforms/api-code").default;
3 |
4 | describe("【网易】股票代码转换统一代码", () => {
5 | const {
6 | ERROR_API_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所股票代码转换统一代码", async () => {
10 | expect(() => (new NeteaseApiCodeTransform()).SZTransform("STOCKAPI"))
11 | .toThrow(new Error(ERROR_API_CODE));
12 |
13 | expect((new NeteaseApiCodeTransform()).SZTransform("1000000"))
14 | .toBe("SZ000000");
15 | });
16 |
17 | it("上交所股票代码转换统一代码", async () => {
18 | expect(() => (new NeteaseApiCodeTransform()).SHTransform("STOCKAPI"))
19 | .toThrow(new Error(ERROR_API_CODE));
20 |
21 | expect((new NeteaseApiCodeTransform()).SHTransform("0000000"))
22 | .toBe("SH000000");
23 | });
24 |
25 | it("港交所股票代码转换统一代码", async () => {
26 | expect(() => (new NeteaseApiCodeTransform()).HKTransform("STOCKAPI"))
27 | .toThrow(new Error(ERROR_API_CODE));
28 |
29 | expect((new NeteaseApiCodeTransform()).HKTransform("hk000000"))
30 | .toBe("HK000000");
31 | });
32 |
33 | it("美交所股票代码转换统一代码", async () => {
34 | expect(() => (new NeteaseApiCodeTransform()).USTransform("STOCKAPI"))
35 | .toThrow(new Error(ERROR_API_CODE));
36 |
37 | expect((new NeteaseApiCodeTransform()).USTransform("US_000000"))
38 | .toBe("US000000");
39 | });
40 |
41 | it("交易所股票代码转换统一代码", async () => {
42 | expect((new NeteaseApiCodeTransform()).transform("1000000"))
43 | .toBe("SZ000000");
44 |
45 | expect((new NeteaseApiCodeTransform()).transform("0000000"))
46 | .toBe("SH000000");
47 |
48 | expect((new NeteaseApiCodeTransform()).transform("hk000000"))
49 | .toBe("HK000000");
50 |
51 | expect((new NeteaseApiCodeTransform()).transform("US_000000"))
52 | .toBe("US000000");
53 |
54 | expect(() => (new NeteaseApiCodeTransform()).transform("STOCKAPI"))
55 | .toThrow(new Error(ERROR_API_CODE));
56 | });
57 |
58 | it("交易所股票代码组转换统一代码组", async () => {
59 | expect((new NeteaseApiCodeTransform()).transforms(["1000000"]))
60 | .toStrictEqual(["SZ000000"]);
61 |
62 | expect((new NeteaseApiCodeTransform()).transforms(["0000000"]))
63 | .toStrictEqual(["SH000000"]);
64 |
65 | expect((new NeteaseApiCodeTransform()).transforms(["hk000000"]))
66 | .toStrictEqual(["HK000000"]);
67 |
68 | expect((new NeteaseApiCodeTransform()).transforms(["US_000000"]))
69 | .toStrictEqual(["US000000"]);
70 |
71 | expect(() => (new NeteaseApiCodeTransform()).transforms(["STOCKAPI"]))
72 | .toThrow(new Error(ERROR_API_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/netease/transforms/common-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const NeteaseCommonCodeTransform = require("stocks/netease/transforms/common-code").default;
3 |
4 | describe("【网易】统一代码转换股票代码", () => {
5 | const {
6 | ERROR_COMMON_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所统一代码转换股票代码", async () => {
10 | expect(() => (new NeteaseCommonCodeTransform()).SZTransform("STOCKAPI"))
11 | .toThrow(new Error(ERROR_COMMON_CODE));
12 |
13 | expect((new NeteaseCommonCodeTransform()).SZTransform("SZ000000"))
14 | .toBe("1000000");
15 | });
16 |
17 | it("上交所统一代码转换股票代码", async () => {
18 | expect(() => (new NeteaseCommonCodeTransform()).SHTransform("STOCKAPI"))
19 | .toThrow(new Error(ERROR_COMMON_CODE));
20 |
21 | expect((new NeteaseCommonCodeTransform()).SHTransform("SH000000"))
22 | .toBe("0000000");
23 | });
24 |
25 | it("港交所统一代码转换股票代码", async () => {
26 | expect(() => (new NeteaseCommonCodeTransform()).HKTransform("STOCKAPI"))
27 | .toThrow(new Error(ERROR_COMMON_CODE));
28 |
29 | expect((new NeteaseCommonCodeTransform()).HKTransform("HK000000"))
30 | .toBe("hk000000");
31 | });
32 |
33 | it("美交所统一代码转换股票代码", async () => {
34 | expect(() => (new NeteaseCommonCodeTransform()).USTransform("STOCKAPI"))
35 | .toThrow(new Error(ERROR_COMMON_CODE));
36 |
37 | expect((new NeteaseCommonCodeTransform()).USTransform("US000000"))
38 | .toBe("US_000000");
39 | });
40 |
41 | it("交易所统一代码转换股票代码", async () => {
42 | expect((new NeteaseCommonCodeTransform()).transform("SZ000000"))
43 | .toBe("1000000");
44 |
45 | expect((new NeteaseCommonCodeTransform()).transform("SH000000"))
46 | .toBe("0000000");
47 |
48 | expect((new NeteaseCommonCodeTransform()).transform("HK000000"))
49 | .toBe("hk000000");
50 |
51 | expect((new NeteaseCommonCodeTransform()).transform("US000000"))
52 | .toBe("US_000000");
53 |
54 | expect(() => (new NeteaseCommonCodeTransform()).transform("STOCKAPI"))
55 | .toThrow(new Error(ERROR_COMMON_CODE));
56 | });
57 |
58 | it("交易所统一代码组转换股票代码组", async () => {
59 | expect((new NeteaseCommonCodeTransform()).transforms(["SZ000000"]))
60 | .toStrictEqual(["1000000"]);
61 |
62 | expect((new NeteaseCommonCodeTransform()).transforms(["SH000000"]))
63 | .toStrictEqual(["0000000"]);
64 |
65 | expect((new NeteaseCommonCodeTransform()).transforms(["HK000000"]))
66 | .toStrictEqual(["hk000000"]);
67 |
68 | expect((new NeteaseCommonCodeTransform()).transforms(["US000000"]))
69 | .toStrictEqual(["US_000000"]);
70 |
71 | expect(() => (new NeteaseCommonCodeTransform()).transforms(["STOCKAPI"]))
72 | .toThrow(new Error(ERROR_COMMON_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/netease/transforms/stock.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const NeteaseStockTransform = require("stocks/netease/transforms/stock").default;
3 |
4 | describe("【网易】股票数据转换测试", () => {
5 | const code = 'SH510500';
6 | const body = `topstock({"0510500":{"code": "0510500", "precloseiopv": 7.152, "percent": 0.010491, "high": 7.28, "askvol3": 32300, "askvol2": 88400, "askvol5": 19000, "askvol4": 572800, "iopv": 7.226, "price": 7.224, "open": 7.147, "bid5": 7.22, "bid4": 7.221, "bid3": 7.222, "bid2": 7.223, "bid1": 7.224, "low": 7.085, "updown": 0.075, "type": "SH", "symbol": "510500", "status": 0, "ask4": 7.228, "bidvol3": 37000, "bidvol2": 32900, "bidvol1": 6300, "update": "2020/07/31 15:59:59", "bidvol5": 14300, "bidvol4": 28600, "yestclose": 7.149, "askvol1": 389300, "ask5": 7.229, "volume": 272478144, "ask1": 7.225, "name": "500ETF", "ask3": 7.227, "ask2": 7.226, "arrow": "\u2191", "time": "2020/07/31 15:59:58", "turnover": 1964297124} });`;
7 | const items = JSON.parse(body.replace(/\(|\)|;|(topstock)/g, ''));
8 | const params = items['0510500'];
9 |
10 | it("获取股票代码", async () => {
11 | expect(new NeteaseStockTransform(code, params).getCode())
12 | .toBe('SH510500');
13 | });
14 |
15 | it("获取股票名称", async () => {
16 | expect(new NeteaseStockTransform(code, params).getName())
17 | .toBe('500ETF');
18 | });
19 |
20 | it("获取股票现价", async () => {
21 | expect(new NeteaseStockTransform(code, params).getNow())
22 | .toBe(7.224);
23 | });
24 |
25 | it("获取股票最低价", async () => {
26 | expect(new NeteaseStockTransform(code, params).getLow())
27 | .toBe(7.085);
28 | });
29 |
30 | it("获取股票最高价", async () => {
31 | expect(new NeteaseStockTransform(code, params).getHigh())
32 | .toBe(7.28);
33 | });
34 |
35 | it("获取股票昨日收盘价", async () => {
36 | expect(new NeteaseStockTransform(code, params).getYesterday())
37 | .toBe(7.149);
38 | });
39 |
40 | it("获取股票涨跌", async () => {
41 | expect(new NeteaseStockTransform(code, params).getPercent())
42 | .toBe(7.224 / 7.149 - 1);
43 | });
44 |
45 | it("获取股票数据", async () => {
46 | expect(new NeteaseStockTransform(code, params).getStock())
47 | .toStrictEqual({ "code": "SH510500", "high": 7.28, "low": 7.085, "name": "500ETF", "now": 7.224, "percent": 7.224 / 7.149 - 1, "yesterday": 7.149 });
48 | });
49 | });
50 |
51 |
--------------------------------------------------------------------------------
/test/stocks/sina/index.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const Sina = require("stocks/sina").default;
3 |
4 | describe("【新浪】股票代码接口", () => {
5 | it("基础测试", async () => {
6 | await expect(true).toEqual(true);
7 | });
8 |
9 | // it("需要获取的股票代码", async () => {
10 | // await expect(Sina.getStock("SH510500")).resolves.toMatchObject({
11 | // code: "SH510500",
12 | // name: "500ETF",
13 | // });
14 | // await expect(Sina.getStock("SZ510500")).resolves.toMatchObject({
15 | // code: "SZ510500",
16 | // name: "---",
17 | // });
18 | // });
19 | // it("需要获取的股票代码组", async () => {
20 | // await expect(Sina.getStocks(["SH510500"]))
21 | // .resolves
22 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SH510500", name: "500ETF" })]));
23 | // await expect(Sina.getStocks(["SZ510500"]))
24 | // .resolves
25 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SZ510500", name: "---" })]));
26 | // await expect(Sina.getStocks([]))
27 | // .resolves
28 | // .toEqual([]);
29 | // });
30 | // it("搜索股票代码", async () => {
31 | // await expect(Sina.searchStocks("格力电器"))
32 | // .resolves
33 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SZ000651", name: "格力电器" })]));
34 | // await expect(Sina.searchStocks("贵州茅台"))
35 | // .resolves
36 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SH600519", name: "贵州茅台" })]));
37 | // await expect(Sina.searchStocks("安踏体育"))
38 | // .resolves
39 | // .toEqual(expect.arrayContaining([
40 | // expect.objectContaining({ code: "HK02020", name: "安踏体育" }),
41 | // expect.objectContaining({ code: "USANPDF", name: "安踏" }),
42 | // ]));
43 | // });
44 | });
45 |
--------------------------------------------------------------------------------
/test/stocks/sina/transforms/api-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const SinaApiCodeTransform = require("stocks/sina/transforms/api-code").default;
3 |
4 | describe("【新浪】股票代码转换统一代码", () => {
5 | const {
6 | ERROR_API_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所股票代码转换统一代码", async () => {
10 | expect(() => (new SinaApiCodeTransform()).SZTransform("STOCKAPI"))
11 | .toThrow(new Error(ERROR_API_CODE));
12 |
13 | expect((new SinaApiCodeTransform()).SZTransform("sz000000"))
14 | .toBe("SZ000000");
15 | });
16 |
17 | it("上交所股票代码转换统一代码", async () => {
18 | expect(() => (new SinaApiCodeTransform()).SHTransform("STOCKAPI"))
19 | .toThrow(new Error(ERROR_API_CODE));
20 |
21 | expect((new SinaApiCodeTransform()).SHTransform("sh000000"))
22 | .toBe("SH000000");
23 | });
24 |
25 | it("港交所股票代码转换统一代码", async () => {
26 | expect(() => (new SinaApiCodeTransform()).HKTransform("STOCKAPI"))
27 | .toThrow(new Error(ERROR_API_CODE));
28 |
29 | expect((new SinaApiCodeTransform()).HKTransform("hk000000"))
30 | .toBe("HK000000");
31 | });
32 |
33 | it("美交所股票代码转换统一代码", async () => {
34 | expect(() => (new SinaApiCodeTransform()).USTransform("STOCKAPI"))
35 | .toThrow(new Error(ERROR_API_CODE));
36 |
37 | expect((new SinaApiCodeTransform()).USTransform("gb_000000"))
38 | .toBe("US000000");
39 | });
40 |
41 | it("交易所股票代码转换统一代码", async () => {
42 | expect((new SinaApiCodeTransform()).transform("sz000000"))
43 | .toBe("SZ000000");
44 |
45 | expect((new SinaApiCodeTransform()).transform("sh000000"))
46 | .toBe("SH000000");
47 |
48 | expect((new SinaApiCodeTransform()).transform("hk000000"))
49 | .toBe("HK000000");
50 |
51 | expect((new SinaApiCodeTransform()).transform("gb_000000"))
52 | .toBe("US000000");
53 |
54 | expect(() => (new SinaApiCodeTransform()).transform("STOCKAPI"))
55 | .toThrow(new Error(ERROR_API_CODE));
56 | });
57 |
58 | it("交易所股票代码转换统一代码", async () => {
59 | expect((new SinaApiCodeTransform()).transforms(["sz000000"]))
60 | .toStrictEqual(["SZ000000"]);
61 |
62 | expect((new SinaApiCodeTransform()).transforms(["sh000000"]))
63 | .toStrictEqual(["SH000000"]);
64 |
65 | expect((new SinaApiCodeTransform()).transforms(["hk000000"]))
66 | .toStrictEqual(["HK000000"]);
67 |
68 | expect((new SinaApiCodeTransform()).transforms(["gb_000000"]))
69 | .toStrictEqual(["US000000"]);
70 |
71 | expect(() => (new SinaApiCodeTransform()).transforms(["STOCKAPI"]))
72 | .toThrow(new Error(ERROR_API_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/sina/transforms/common-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const SinaCommonCodeTransform = require("stocks/sina/transforms/common-code").default;
3 |
4 | describe("【新浪】统一代码转换股票代码", () => {
5 | const {
6 | ERROR_COMMON_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所统一代码转换股票代码", async () => {
10 | expect(() => (new SinaCommonCodeTransform()).SZTransform("000000"))
11 | .toThrow(new Error(ERROR_COMMON_CODE));
12 |
13 | expect((new SinaCommonCodeTransform()).SZTransform("SZ000000"))
14 | .toBe("sz000000");
15 | });
16 |
17 | it("上交所统一代码转换股票代码", async () => {
18 | expect(() => (new SinaCommonCodeTransform()).SHTransform("000000"))
19 | .toThrow(new Error(ERROR_COMMON_CODE));
20 |
21 | expect((new SinaCommonCodeTransform()).SHTransform("SH000000"))
22 | .toBe("sh000000");
23 | });
24 |
25 | it("港交所统一代码转换股票代码", async () => {
26 | expect(() => (new SinaCommonCodeTransform()).HKTransform("000000"))
27 | .toThrow(new Error(ERROR_COMMON_CODE));
28 |
29 | expect((new SinaCommonCodeTransform()).HKTransform("HK000000"))
30 | .toBe("hk000000");
31 | });
32 |
33 | it("美交所统一代码转换股票代码", async () => {
34 | expect(() => (new SinaCommonCodeTransform()).USTransform("000000"))
35 | .toThrow(new Error(ERROR_COMMON_CODE));
36 |
37 | expect((new SinaCommonCodeTransform()).USTransform("US000000"))
38 | .toBe("gb_000000");
39 | });
40 |
41 | it("交易所统一代码转换股票代码", async () => {
42 | expect((new SinaCommonCodeTransform()).transform("SZ000000"))
43 | .toBe("sz000000");
44 |
45 | expect((new SinaCommonCodeTransform()).transform("SH000000"))
46 | .toBe("sh000000");
47 |
48 | expect((new SinaCommonCodeTransform()).transform("HK000000"))
49 | .toBe("hk000000");
50 |
51 | expect((new SinaCommonCodeTransform()).transform("US000000"))
52 | .toBe("gb_000000");
53 |
54 | expect(() => (new SinaCommonCodeTransform()).transform("000000"))
55 | .toThrow(new Error(ERROR_COMMON_CODE));
56 | });
57 |
58 | it("交易所统一代码组转换股票代码组", async () => {
59 | expect((new SinaCommonCodeTransform()).transforms(["SZ000000"]))
60 | .toStrictEqual(["sz000000"]);
61 |
62 | expect((new SinaCommonCodeTransform()).transforms(["SH000000"]))
63 | .toStrictEqual(["sh000000"]);
64 |
65 | expect((new SinaCommonCodeTransform()).transforms(["HK000000"]))
66 | .toStrictEqual(["hk000000"]);
67 |
68 | expect((new SinaCommonCodeTransform()).transforms(["US000000"]))
69 | .toStrictEqual(["gb_000000"]);
70 |
71 | expect(() => (new SinaCommonCodeTransform()).transforms(["000000"]))
72 | .toThrow(new Error(ERROR_COMMON_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/sina/transforms/stock.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const SinaStockTransform = require("stocks/sina/transforms/stock").default;
3 |
4 | describe("【新浪】股票数据转换测试", () => {
5 | // 上交所相关代码
6 | const SHCode = 'SH510500';
7 | const SHBody = `var hq_str_sh510500="500ETF,7.147,7.149,7.224,7.280,7.085,7.224,7.225,272478144,1964297124.000,6300,7.224,32900,7.223,37000,7.222,28600,7.221,14300,7.220,389300,7.225,88400,7.226,32300,7.227,572800,7.228,19000,7.229,2020-07-31,15:00:00,00,";`
8 | const SHRow = SHBody.split(";\n")[0];
9 | const SHParams = SHRow.split('=').reverse()[0].replace('"', '').split(",");
10 |
11 | // 深交所
12 | const SZCode = 'SZ399001';
13 | const SZBody = `var hq_str_sz399001="深证成指,13464.207,13466.854,13637.883,13748.034,13399.859,0.000,0.000,48559923962,650202505377.656,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,2020-07-31,15:00:03,00";`;
14 | const SZRow = SZBody.split(";\n")[0];
15 | const SZParams = SZRow.split('=').reverse()[0].replace('"', '').split(",");
16 |
17 | // 港交所
18 | const HKCode = 'HKHSI';
19 | const HKBody = `var hq_str_hkHSI="Hang Seng Index,恒生指数,24747.29,24710.59,24938.85,24534.79,24595.35,-115.24,-0.47,0.000,0.000,119153830,0,0.000,0.00,29174.92,21139.26,2020/07/31,16:08";`;
20 | const HKRow = HKBody.split(";\n")[0];
21 | const HKParams = HKRow.split('=').reverse()[0].replace('"', '').split(",");
22 |
23 | // 美交所
24 | const USCode = 'USDJI';
25 | const USBody = `var hq_str_gb_dji="道琼斯,26428.3203,0.44,2020-08-01 05:07:40,114.6700,26409.3301,26440.0195,26013.5898,29568.5703,18213.6504,491372564,397524206,0,0.00,--,0.00,0.00,0.00,0.00,0,0,0.0000,0.00,0.0000,,Jul 31 05:07PM EDT,26313.6504,0,1,2020";`;
26 | const USRow = USBody.split(";\n")[0];
27 | const USParams = USRow.split('=').reverse()[0].replace('"', '').split(",");
28 |
29 | it("获取股票代码", async () => {
30 | expect(new SinaStockTransform(SHCode, SHParams).getCode()).toBe("SH510500");
31 | expect(new SinaStockTransform(SZCode, SZParams).getCode()).toBe("SZ399001");
32 | expect(new SinaStockTransform(HKCode, HKParams).getCode()).toBe("HKHSI");
33 | expect(new SinaStockTransform(USCode, USParams).getCode()).toBe("USDJI");
34 | expect(new SinaStockTransform("000000", []).getCode()).toBe("000000");
35 | });
36 |
37 | it("获取股票名称", async () => {
38 | expect(new SinaStockTransform(SHCode, SHParams).getName()).toBe('500ETF');
39 | expect(new SinaStockTransform(SZCode, SZParams).getName()).toBe('深证成指');
40 | expect(new SinaStockTransform(HKCode, HKParams).getName()).toBe('恒生指数');
41 | expect(new SinaStockTransform(USCode, USParams).getName()).toBe("道琼斯");
42 | });
43 |
44 | it("获取股票现价", async () => {
45 | expect(new SinaStockTransform(SHCode, SHParams).getNow()).toBe(7.224);
46 | expect(new SinaStockTransform(SZCode, SZParams).getNow()).toBe(13637.883);
47 | expect(new SinaStockTransform(HKCode, HKParams).getNow()).toBe(24595.35);
48 | expect(new SinaStockTransform(USCode, USParams).getNow()).toBe(26428.3203);
49 | });
50 |
51 | it("获取股票最低价", async () => {
52 | expect(new SinaStockTransform(SHCode, SHParams).getLow()).toBe(7.085);
53 | expect(new SinaStockTransform(SZCode, SZParams).getLow()).toBe(13399.859);
54 | expect(new SinaStockTransform(HKCode, HKParams).getLow()).toBe(24534.79);
55 | expect(new SinaStockTransform(USCode, USParams).getLow()).toBe(26013.5898);
56 | });
57 |
58 | it("获取股票最高价", async () => {
59 | expect(new SinaStockTransform(SHCode, SHParams).getHigh()).toBe(7.28);
60 | expect(new SinaStockTransform(SZCode, SZParams).getHigh()).toBe(13748.034);
61 | expect(new SinaStockTransform(HKCode, HKParams).getHigh()).toBe(24938.85);
62 | expect(new SinaStockTransform(USCode, USParams).getHigh()).toBe(26440.0195);
63 | });
64 |
65 | it("获取股票昨日收盘价", async () => {
66 | expect(new SinaStockTransform(SHCode, SHParams).getYesterday()).toBe(7.149);
67 | expect(new SinaStockTransform(SZCode, SZParams).getYesterday()).toBe(13466.854);
68 | expect(new SinaStockTransform(HKCode, HKParams).getYesterday()).toBe(24710.59);
69 | expect(new SinaStockTransform(USCode, USParams).getYesterday()).toBe(26313.6504);
70 | });
71 |
72 | it("获取股票涨跌", async () => {
73 | expect(new SinaStockTransform(SHCode, SHParams).getPercent()).toBe(7.224 / 7.149 - 1);
74 | expect(new SinaStockTransform(SZCode, SZParams).getPercent()).toBe(13637.883 / 13466.854 - 1);
75 | expect(new SinaStockTransform(HKCode, HKParams).getPercent()).toBe(24595.35 / 24710.59 - 1);
76 | expect(new SinaStockTransform(USCode, USParams).getPercent()).toBe(26428.3203 / 26313.6504 - 1);
77 | });
78 |
79 | it("获取股票数据", async () => {
80 | expect(new SinaStockTransform(SHCode, SHParams).getStock()).toStrictEqual({ code: "SH510500", name: "500ETF", percent: 7.224 / 7.149 - 1, now: 7.224, low: 7.085, high: 7.28, yesterday: 7.149 });
81 | expect(new SinaStockTransform(SZCode, SZParams).getStock()).toStrictEqual({ code: 'SZ399001', name: '深证成指', percent: 13637.883 / 13466.854 - 1, now: 13637.883, low: 13399.859, high: 13748.034, yesterday: 13466.854 });
82 | expect(new SinaStockTransform(HKCode, HKParams).getStock()).toStrictEqual({ code: 'HKHSI', name: '恒生指数', percent: 24595.35 / 24710.59 - 1, now: 24595.35, low: 24534.79, high: 24938.85, yesterday: 24710.59 });
83 | expect(new SinaStockTransform(USCode, USParams).getStock()).toStrictEqual({ code: 'USDJI', name: '道琼斯', percent: 26428.3203 / 26313.6504 - 1, now: 26428.3203, low: 26013.5898, high: 26440.0195, yesterday: 26313.6504 });
84 | });
85 | });
86 |
87 |
--------------------------------------------------------------------------------
/test/stocks/tencent/index.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const Tencent = require("stocks/tencent").default;
3 |
4 | describe("【腾讯】股票代码接口", () => {
5 | const { ERROR_UNDEFINED_SEARCH_STOCK } = require("utils/constant");
6 | it("基础测试", async () => {
7 | await expect(true).toEqual(true);
8 | });
9 |
10 | it("需要获取的股票代码", async () => {
11 | await expect(Tencent.getStock("SH510500")).resolves.toMatchObject({
12 | code: "SH510500",
13 | name: "中证500ETF",
14 | });
15 |
16 | await expect(Tencent.getStock("SZ510500")).resolves.toMatchObject({
17 | code: "SZ510500",
18 | name: "---",
19 | });
20 | });
21 |
22 | it("需要获取的股票代码组", async () => {
23 | await expect(Tencent.getStocks(["SH510500"])).resolves.toEqual(
24 | expect.arrayContaining([
25 | expect.objectContaining({ code: "SH510500", name: "中证500ETF" }),
26 | ])
27 | );
28 |
29 | await expect(Tencent.getStocks(["SZ510500"])).resolves.toEqual(
30 | expect.arrayContaining([
31 | expect.objectContaining({ code: "SZ510500", name: "---" }),
32 | ])
33 | );
34 |
35 | await expect(Tencent.getStocks([])).resolves.toEqual([]);
36 | });
37 |
38 | it("搜索股票代码", async () => {
39 | await expect(Tencent.searchStocks("格力电器")).resolves.toEqual(
40 | expect.arrayContaining([
41 | expect.objectContaining({ code: "SZ000651", name: "格力电器" }),
42 | ])
43 | );
44 |
45 | await expect(Tencent.searchStocks("贵州茅台")).resolves.toEqual(
46 | expect.arrayContaining([
47 | expect.objectContaining({ code: "SH600519", name: "贵州茅台" }),
48 | ])
49 | );
50 |
51 | await expect(Tencent.searchStocks("安踏体育")).resolves.toEqual(
52 | expect.arrayContaining([
53 | expect.objectContaining({ code: "HK02020", name: "安踏体育" }),
54 | expect.objectContaining({ code: "USANPDY", name: "安踏体育" }),
55 | ])
56 | );
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/stocks/tencent/transforms/api-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const TencentApiCodeTransform = require("stocks/tencent/transforms/api-code").default;
3 |
4 | describe("【腾讯】股票代码转换统一代码", () => {
5 | const {
6 | ERROR_API_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所股票代码转换统一代码", async () => {
10 | expect(() => (new TencentApiCodeTransform()).SZTransform("STOCKAPI"))
11 | .toThrow(new Error(ERROR_API_CODE));
12 |
13 | expect((new TencentApiCodeTransform()).SZTransform("sz000000"))
14 | .toBe("SZ000000");
15 | });
16 |
17 | it("上交所股票代码转换统一代码", async () => {
18 | expect(() => (new TencentApiCodeTransform()).SHTransform("STOCKAPI"))
19 | .toThrow(new Error(ERROR_API_CODE));
20 |
21 | expect((new TencentApiCodeTransform()).SHTransform("sh000000"))
22 | .toBe("SH000000");
23 | });
24 |
25 | it("港交所股票代码转换统一代码", async () => {
26 | expect(() => (new TencentApiCodeTransform()).HKTransform("STOCKAPI"))
27 | .toThrow(new Error(ERROR_API_CODE));
28 |
29 | expect((new TencentApiCodeTransform()).HKTransform("hk000000"))
30 | .toBe("HK000000");
31 | });
32 |
33 | it("美交所股票代码转换统一代码", async () => {
34 | expect(() => (new TencentApiCodeTransform()).USTransform("STOCKAPI"))
35 | .toThrow(new Error(ERROR_API_CODE));
36 |
37 | expect((new TencentApiCodeTransform()).USTransform("us000000"))
38 | .toBe("US000000");
39 | });
40 |
41 | it("交易所股票代码转换统一代码", async () => {
42 | expect((new TencentApiCodeTransform()).transform("sz000000"))
43 | .toBe("SZ000000");
44 |
45 | expect((new TencentApiCodeTransform()).transform("sh000000"))
46 | .toBe("SH000000");
47 |
48 | expect((new TencentApiCodeTransform()).transform("hk000000"))
49 | .toBe("HK000000");
50 |
51 | expect((new TencentApiCodeTransform()).transform("us000000"))
52 | .toBe("US000000");
53 |
54 | expect(() => (new TencentApiCodeTransform()).transform("STOCKAPI"))
55 | .toThrow(new Error(ERROR_API_CODE));
56 | });
57 |
58 | it("交易所股票代码组转换统一代码组", async () => {
59 | expect((new TencentApiCodeTransform()).transforms(["sz000000"]))
60 | .toStrictEqual(["SZ000000"]);
61 |
62 | expect((new TencentApiCodeTransform()).transforms(["sh000000"]))
63 | .toStrictEqual(["SH000000"]);
64 |
65 | expect((new TencentApiCodeTransform()).transforms(["hk000000"]))
66 | .toStrictEqual(["HK000000"]);
67 |
68 | expect((new TencentApiCodeTransform()).transforms(["us000000"]))
69 | .toStrictEqual(["US000000"]);
70 |
71 | expect(() => (new TencentApiCodeTransform()).transforms(["STOCKAPI"]))
72 | .toThrow(new Error(ERROR_API_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/tencent/transforms/common-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const TencentCommonCodeTransform = require("stocks/tencent/transforms/common-code").default;
3 |
4 | describe("【腾讯】统一代码转换股票代码", () => {
5 | const {
6 | ERROR_COMMON_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所统一代码转换股票代码", async () => {
10 | expect(() => (new TencentCommonCodeTransform()).SZTransform("000000"))
11 | .toThrow(new Error(ERROR_COMMON_CODE));
12 |
13 | expect((new TencentCommonCodeTransform()).SZTransform("SZ000000"))
14 | .toBe("sz000000");
15 | });
16 |
17 | it("上交所统一代码转换股票代码", async () => {
18 | expect(() => (new TencentCommonCodeTransform()).SHTransform("000000"))
19 | .toThrow(new Error(ERROR_COMMON_CODE));
20 |
21 | expect((new TencentCommonCodeTransform()).SHTransform("SH000000"))
22 | .toBe("sh000000");
23 | });
24 |
25 | it("港交所统一代码转换股票代码", async () => {
26 | expect(() => (new TencentCommonCodeTransform()).HKTransform("000000"))
27 | .toThrow(new Error(ERROR_COMMON_CODE));
28 |
29 | expect((new TencentCommonCodeTransform()).HKTransform("HK000000"))
30 | .toBe("hk000000");
31 | });
32 |
33 | it("美交所统一代码转换股票代码", async () => {
34 | expect(() => (new TencentCommonCodeTransform()).USTransform("000000"))
35 | .toThrow(new Error(ERROR_COMMON_CODE));
36 |
37 | expect((new TencentCommonCodeTransform()).USTransform("US000000"))
38 | .toBe("us000000");
39 | });
40 |
41 | it("交易所统一代码转换股票代码", async () => {
42 | expect((new TencentCommonCodeTransform()).transform("SZ000000"))
43 | .toBe("sz000000");
44 |
45 | expect((new TencentCommonCodeTransform()).transform("SH000000"))
46 | .toBe("sh000000");
47 |
48 | expect((new TencentCommonCodeTransform()).transform("HK000000"))
49 | .toBe("hk000000");
50 |
51 | expect((new TencentCommonCodeTransform()).transform("US000000"))
52 | .toBe("us000000");
53 |
54 | expect(() => (new TencentCommonCodeTransform()).transform("000000"))
55 | .toThrow(new Error(ERROR_COMMON_CODE));
56 | });
57 |
58 | it("交易所统一代码组转换股票代码组", async () => {
59 | expect((new TencentCommonCodeTransform()).transforms(["SZ000000"]))
60 | .toStrictEqual(["sz000000"]);
61 |
62 | expect((new TencentCommonCodeTransform()).transforms(["SH000000"]))
63 | .toStrictEqual(["sh000000"]);
64 |
65 | expect((new TencentCommonCodeTransform()).transforms(["HK000000"]))
66 | .toStrictEqual(["hk000000"]);
67 |
68 | expect((new TencentCommonCodeTransform()).transforms(["US000000"]))
69 | .toStrictEqual(["us000000"]);
70 |
71 | expect(() => (new TencentCommonCodeTransform()).transforms(["000000"]))
72 | .toThrow(new Error(ERROR_COMMON_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/tencent/transforms/stock.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const TencentStockTransform = require("stocks/tencent/transforms/stock").default;
3 |
4 | describe("【腾讯】股票数据转换测试", () => {
5 | const code = 'SH510500';
6 | const body = `v_sh510500="1~500ETF~510500~7.224~7.149~7.147~2724781~1351032~1373749~7.224~63~7.223~329~7.222~370~7.221~286~7.220~143~7.225~3893~7.226~884~7.227~323~7.228~5728~7.229~190~~20200731154041~0.075~1.05~7.280~7.085~7.224/2724781/1964297124~2724781~196430~~~~7.280~7.085~2.73~~~0.00~7.864~6.434~1.20~-9827~7.209~~~~~~196429.7124~0.0000~0~ ~ETF~26.51~~~~";`
7 |
8 | const rows = body.split(";\n");
9 | const row = rows[0];
10 |
11 | const [_, paramsUnformat] = row.split('=');
12 | const params = paramsUnformat.replace('"', '').split("~");
13 |
14 | it("获取股票代码", async () => {
15 | expect(new TencentStockTransform(code, params).getCode())
16 | .toBe('SH510500');
17 | });
18 |
19 | it("获取股票名称", async () => {
20 | expect(new TencentStockTransform(code, params).getName())
21 | .toBe('500ETF');
22 | });
23 |
24 | it("获取股票现价", async () => {
25 | expect(new TencentStockTransform(code, params).getNow())
26 | .toBe(7.224);
27 | });
28 |
29 | it("获取股票最低价", async () => {
30 | expect(new TencentStockTransform(code, params).getLow())
31 | .toBe(7.085);
32 | });
33 |
34 | it("获取股票最高价", async () => {
35 | expect(new TencentStockTransform(code, params).getHigh())
36 | .toBe(7.28);
37 | });
38 |
39 | it("获取股票昨日收盘价", async () => {
40 | expect(new TencentStockTransform(code, params).getYesterday())
41 | .toBe(7.149);
42 | });
43 |
44 | it("获取股票涨跌", async () => {
45 | expect(new TencentStockTransform(code, params).getPercent())
46 | .toBe(7.224 / 7.149 - 1);
47 | });
48 |
49 | it("获取股票数据", async () => {
50 | expect(new TencentStockTransform(code, params).getStock())
51 | .toStrictEqual({ "code": "SH510500", "high": 7.28, "low": 7.085, "name": "500ETF", "now": 7.224, "percent": 7.224 / 7.149 - 1, "yesterday": 7.149 });
52 | });
53 | });
54 |
55 |
--------------------------------------------------------------------------------
/test/stocks/xueqiu/index.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const Xueqiu = require("stocks/xueqiu").default;
3 |
4 | describe("【雪球】股票代码接口", () => {
5 | it("基础测试", async () => {
6 | await expect(true).toEqual(true);
7 | });
8 |
9 | // it("获取 Token", async () => {
10 | // await expect(Xueqiu.getToken())
11 | // .resolves
12 | // .toContain('xq_a_token');
13 | // });
14 | // it("需要获取的股票代码", async () => {
15 | // await expect(Xueqiu.getStock("SH510500"))
16 | // .resolves
17 | // .toMatchObject({ code: "SH510500", name: "中证500ETF" });
18 | // await expect(Xueqiu.getStock("SZ510500"))
19 | // .resolves
20 | // .toMatchObject({ code: "SZ510500", name: "---" });
21 | // });
22 | // it("需要获取的股票代码组", async () => {
23 | // await expect(Xueqiu.getStocks(["SH510500"]))
24 | // .resolves
25 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SH510500", name: "中证500ETF" })]));
26 | // await expect(Xueqiu.getStocks(["SZ510500"]))
27 | // .resolves
28 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SZ510500", name: "---" })]));
29 | // await expect(Xueqiu.getStocks([]))
30 | // .resolves
31 | // .toEqual([]);
32 | // });
33 | // it("搜索股票代码", async () => {
34 | // await expect(Xueqiu.searchStocks("格力电器"))
35 | // .resolves
36 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SZ000651", name: "格力电器" })]));
37 | // await expect(Xueqiu.searchStocks("贵州茅台"))
38 | // .resolves
39 | // .toEqual(expect.arrayContaining([expect.objectContaining({ code: "SH600519", name: "贵州茅台" })]));
40 | // await expect(Xueqiu.searchStocks("安踏体育"))
41 | // .resolves
42 | // .toEqual(expect.arrayContaining([
43 | // expect.objectContaining({ code: "HK02020", name: "安踏体育" }),
44 | // expect.objectContaining({ code: "USANPDY", name: "安踏体育ADR" }),
45 | // ]));
46 | // });
47 | });
48 |
--------------------------------------------------------------------------------
/test/stocks/xueqiu/transforms/api-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const XueqiuApiCodeTransform = require("stocks/xueqiu/transforms/api-code").default;
3 |
4 | describe("【雪球】股票代码转换统一代码", () => {
5 | const {
6 | ERROR_API_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所股票代码转换统一代码", async () => {
10 | expect(() => (new XueqiuApiCodeTransform()).SZTransform("000000"))
11 | .toThrow(new Error(ERROR_API_CODE));
12 |
13 | expect((new XueqiuApiCodeTransform()).SZTransform("SZ000000"))
14 | .toBe("SZ000000");
15 | });
16 |
17 | it("上交所股票代码转换统一代码", async () => {
18 | expect(() => (new XueqiuApiCodeTransform()).SHTransform("000000"))
19 | .toThrow(new Error(ERROR_API_CODE));
20 |
21 | expect((new XueqiuApiCodeTransform()).SHTransform("SH000000"))
22 | .toBe("SH000000");
23 | });
24 |
25 | it("港交所股票代码转换统一代码", async () => {
26 | expect(() => (new XueqiuApiCodeTransform()).HKTransform("000000"))
27 | .toThrow(new Error(ERROR_API_CODE));
28 |
29 | expect((new XueqiuApiCodeTransform()).HKTransform("HK000000"))
30 | .toBe("HK000000");
31 | });
32 |
33 | it("美交所股票代码转换统一代码", async () => {
34 | expect(() => (new XueqiuApiCodeTransform()).USTransform("SZ000000"))
35 | .toThrow(new Error(ERROR_API_CODE));
36 |
37 | expect((new XueqiuApiCodeTransform()).USTransform("000000"))
38 | .toBe("US000000");
39 | });
40 |
41 | it("交易所股票代码转换统一代码", async () => {
42 | expect((new XueqiuApiCodeTransform()).transform("SZ000000"))
43 | .toBe("SZ000000");
44 |
45 | expect((new XueqiuApiCodeTransform()).transform("SH000000"))
46 | .toBe("SH000000");
47 |
48 | expect((new XueqiuApiCodeTransform()).transform("HK000000"))
49 | .toBe("HK000000");
50 |
51 | expect((new XueqiuApiCodeTransform()).transform("000000"))
52 | .toBe("US000000");
53 | });
54 |
55 | it("交易所股票代码组转换统一代码组", async () => {
56 | expect((new XueqiuApiCodeTransform()).transforms(["SZ000000"]))
57 | .toStrictEqual(["SZ000000"]);
58 |
59 | expect((new XueqiuApiCodeTransform()).transforms(["SH000000"]))
60 | .toStrictEqual(["SH000000"]);
61 |
62 | expect((new XueqiuApiCodeTransform()).transforms(["HK000000"]))
63 | .toStrictEqual(["HK000000"]);
64 |
65 | expect((new XueqiuApiCodeTransform()).transforms(["000000"]))
66 | .toStrictEqual(["US000000"]);
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/test/stocks/xueqiu/transforms/common-code.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const XueqiuCommonCodeTransform = require("stocks/xueqiu/transforms/common-code").default;
3 |
4 | describe("【雪球】统一代码转换股票代码", () => {
5 | const {
6 | ERROR_COMMON_CODE,
7 | } = require("utils/constant");
8 |
9 | it("深交所统一代码转换股票代码", async () => {
10 | expect(() => (new XueqiuCommonCodeTransform()).SZTransform("000000"))
11 | .toThrow(new Error(ERROR_COMMON_CODE));
12 |
13 | expect((new XueqiuCommonCodeTransform()).SZTransform("SZ000000"))
14 | .toBe("SZ000000");
15 | });
16 |
17 | it("上交所统一代码转换股票代码", async () => {
18 | expect(() => (new XueqiuCommonCodeTransform()).SHTransform("000000"))
19 | .toThrow(new Error(ERROR_COMMON_CODE));
20 |
21 | expect((new XueqiuCommonCodeTransform()).SHTransform("SH000000"))
22 | .toBe("SH000000");
23 | });
24 |
25 | it("港交所统一代码转换股票代码", async () => {
26 | expect(() => (new XueqiuCommonCodeTransform()).HKTransform("000000"))
27 | .toThrow(new Error(ERROR_COMMON_CODE));
28 |
29 | expect((new XueqiuCommonCodeTransform()).HKTransform("HK000000"))
30 | .toBe("HK000000");
31 | });
32 |
33 | it("美交所统一代码转换股票代码", async () => {
34 | expect(() => (new XueqiuCommonCodeTransform()).USTransform("000000"))
35 | .toThrow(new Error(ERROR_COMMON_CODE));
36 |
37 | expect((new XueqiuCommonCodeTransform()).USTransform("US000000"))
38 | .toBe("000000");
39 | });
40 |
41 | it("交易所统一代码转换股票代码", async () => {
42 | expect((new XueqiuCommonCodeTransform()).transform("SZ000000"))
43 | .toBe("SZ000000");
44 |
45 | expect((new XueqiuCommonCodeTransform()).transform("SH000000"))
46 | .toBe("SH000000");
47 |
48 | expect((new XueqiuCommonCodeTransform()).transform("HK000000"))
49 | .toBe("HK000000");
50 |
51 | expect((new XueqiuCommonCodeTransform()).transform("US000000"))
52 | .toBe("000000");
53 |
54 | expect(() => (new XueqiuCommonCodeTransform()).transform("000000"))
55 | .toThrow(new Error(ERROR_COMMON_CODE));
56 | });
57 |
58 | it("交易所统一代码组转换股票代码组", async () => {
59 | expect((new XueqiuCommonCodeTransform()).transforms(["SZ000000"]))
60 | .toStrictEqual(["SZ000000"]);
61 |
62 | expect((new XueqiuCommonCodeTransform()).transforms(["SH000000"]))
63 | .toStrictEqual(["SH000000"]);
64 |
65 | expect((new XueqiuCommonCodeTransform()).transforms(["HK000000"]))
66 | .toStrictEqual(["HK000000"]);
67 |
68 | expect((new XueqiuCommonCodeTransform()).transforms(["US000000"]))
69 | .toStrictEqual(["000000"]);
70 |
71 | expect(() => (new XueqiuCommonCodeTransform()).transforms(["000000"]))
72 | .toThrow(new Error(ERROR_COMMON_CODE));
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/stocks/xueqiu/transforms/stock.test.ts:
--------------------------------------------------------------------------------
1 | // Stock
2 | const XueqiuStockTransform = require("stocks/xueqiu/transforms/stock").default;
3 |
4 | describe("【雪球】股票数据转换测试", () => {
5 | const code = 'SH510500';
6 | const body = `{"data":{"market":{"status_id":8,"region":"CN","status":"休市","time_zone":"Asia/Shanghai","time_zone_desc":null},"quote":{"symbol":"SH510500","code":"510500","avg_price":6.982,"delayed":0,"type":13,"percent":0.5,"tick_size":0.001,"float_shares":null,"amplitude":null,"current":7.224,"high":7.28,"current_year_percent":22.38,"float_market_capital":null,"issue_date":1363276800000,"low": 7.085,"sub_type":"EBS","market_capital":4.25501735904E10,"currency":"CNY","lot_size":100,"lock_set":null,"timestamp":1595207715950,"amount":null,"chg":0.035,"last_close":7.149,"volume":null,"turnover_rate":null,"name":"中证500ETF","exchange":"SH","time":1595207715000,"total_shares":6094267200,"open":null,"status":1},"others":{"pankou_ratio":null,"cyb_switch":false},"tags":[{"description":"融","value":6},{"description":"空","value":7}]},"error_code":0,"error_description":""}`
7 |
8 | const params = JSON.parse(body).data.quote;
9 |
10 | it("获取股票代码", async () => {
11 | expect(new XueqiuStockTransform(code, params).getCode())
12 | .toBe('SH510500');
13 | });
14 |
15 | it("获取股票名称", async () => {
16 | expect(new XueqiuStockTransform(code, params).getName())
17 | .toBe('中证500ETF');
18 | });
19 |
20 | it("获取股票现价", async () => {
21 | expect(new XueqiuStockTransform(code, params).getNow())
22 | .toBe(7.224);
23 | });
24 |
25 | it("获取股票最低价", async () => {
26 | expect(new XueqiuStockTransform(code, params).getLow())
27 | .toBe(7.085);
28 | });
29 |
30 | it("获取股票最高价", async () => {
31 | expect(new XueqiuStockTransform(code, params).getHigh())
32 | .toBe(7.28);
33 | });
34 |
35 | it("获取股票昨日收盘价", async () => {
36 | expect(new XueqiuStockTransform(code, params).getYesterday())
37 | .toBe(7.149);
38 | });
39 |
40 | it("获取股票涨跌", async () => {
41 | expect(new XueqiuStockTransform(code, params).getPercent())
42 | .toBe(7.224 / 7.149 - 1);
43 | });
44 |
45 | it("获取股票数据", async () => {
46 | expect(new XueqiuStockTransform(code, params).getStock())
47 | .toStrictEqual({ "code": "SH510500", "high": 7.28, "low": 7.085, "name": "中证500ETF", "now": 7.224, "percent": 7.224 / 7.149 - 1, "yesterday": 7.149 });
48 | });
49 | });
50 |
51 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "lib": [
6 | "es6"
7 | ],
8 | "declaration": true,
9 | "outDir": "./dist",
10 | "strict": true,
11 | "esModuleInterop": true,
12 | "skipLibCheck": true
13 | },
14 | "include": [
15 | "src"
16 | ],
17 | "exclude": [
18 | "node_modules",
19 | "**/__tests__/*"
20 | ]
21 | }
--------------------------------------------------------------------------------