Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加涨跌停盯盘 #504

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@
"command": "leek-fund.deleteStock",
"title": "删除股票"
},
{
"command": "leek-fund.addMyStock",
"title": "加入我的自选"
},
{
"command": "leek-fund.addStockToBar",
"title": "添加至状态栏"
Expand Down Expand Up @@ -439,42 +443,47 @@
},
{
"command": "leek-fund.setStockTop",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata && viewItem != limit",
"group": "group1"
},
{
"command": "leek-fund.setStockUp",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata && viewItem != limit",
"group": "group1"
},
{
"command": "leek-fund.setStockDown",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata && viewItem != limit",
"group": "group1"
},
{
"command": "leek-fund.stockTrendPic",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata && viewItem != limit",
"group": "group2"
},
{
"command": "leek-fund.setStockTop",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem != limit && viewItem != limit",
"group": "inline"
},
{
"command": "leek-fund.setStockUp",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata && viewItem != limit",
"group": "inline"
},
{
"command": "leek-fund.setStockDown",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata",
"when": "view == leekFundView.stock && viewItem != category && viewItem!=nodata && viewItem != limit",
"group": "inline"
},
{
"command": "leek-fund.deleteStock",
"when": "view == leekFundView.stock && viewItem != category",
"when": "view == leekFundView.stock && viewItem != category && viewItem != limit",
"group": "group5"
},
{
"command": "leek-fund.addMyStock",
"when": "view == leekFundView.stock && viewItem == limit",
"group": "group5"
},
{
Expand Down Expand Up @@ -688,6 +697,16 @@
"default": true,
"description": "默认展开A股"
},
"leek-fund.expandAUpStock": {
"type": "boolean",
"default": false,
"description": "默认展开涨停股"
},
"leek-fund.expandADownStock": {
"type": "boolean",
"default": false,
"description": "默认展开跌停股"
},
"leek-fund.expandHKStock": {
"type": "boolean",
"default": false,
Expand Down Expand Up @@ -803,6 +822,7 @@
"lodash": "4.17.21",
"moment": "^2.29.4",
"public-ip": "^4.0.3",
"puppeteer": "^23.10.4",
"ws": "^7.4.1"
},
"extensionKind": [
Expand Down
39 changes: 35 additions & 4 deletions src/explorer/stockProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ export class StockProvider implements TreeDataProvider<LeekTreeItem> {
private service: StockService;
private order: SortType;
private expandAStock: boolean;
private expandHKStock: boolean;
private expandUSStock: boolean;
private expandCNFuture: boolean;
private expandOverseaFuture: boolean;
private expandAUpStock: boolean = false;
private expandADownStock: boolean = false;
private expandHKStock: boolean = false;
private expandUSStock: boolean = false;
private expandCNFuture: boolean = false;
private expandOverseaFuture: boolean = false;

constructor(service: StockService) {
this.service = service;
this.order = LeekFundConfig.getConfig('leek-fund.stockSort') || SortType.NORMAL;
this.expandAStock = LeekFundConfig.getConfig('leek-fund.expandAStock', true);
this.expandAUpStock = LeekFundConfig.getConfig('leek-fund.expandAUpStock', false);
this.expandADownStock = LeekFundConfig.getConfig('leek-fund.expandADownStock', false);
this.expandHKStock = LeekFundConfig.getConfig('leek-fund.expandHKStock', false);
this.expandUSStock = LeekFundConfig.getConfig('leek-fund.expandUSStock', false);
this.expandCNFuture = LeekFundConfig.getConfig('leek-fund.expandCNFuture', false);
Expand All @@ -48,6 +52,10 @@ export class StockProvider implements TreeDataProvider<LeekTreeItem> {
) {
case StockCategory.A:
return this.getAStockNodes(resultPromise);
case StockCategory.UP:
return this.service.uplimitStockList;
case StockCategory.DOWN:
return this.service.downlimitStockList;
case StockCategory.HK:
return this.getHkStockNodes(resultPromise);
case StockCategory.US:
Expand Down Expand Up @@ -78,6 +86,9 @@ export class StockProvider implements TreeDataProvider<LeekTreeItem> {
label: element.info.name,
// tooltip: this.getSubCategoryTooltip(element),
collapsibleState:
(element.id === StockCategory.A && this.expandAStock) ||
(element.id === StockCategory.UP && this.expandAUpStock) ||
(element.id === StockCategory.DOWN && this.expandADownStock) ||
(element.id === StockCategory.A && this.expandAStock) ||
(element.id === StockCategory.HK && this.expandHKStock) ||
(element.id === StockCategory.US && this.expandUSStock) ||
Expand All @@ -104,6 +115,26 @@ export class StockProvider implements TreeDataProvider<LeekTreeItem> {
undefined,
true
),
new LeekTreeItem(
Object.assign({ contextValue: 'category' }, defaultFundInfo, {
id: StockCategory.UP,
name: `${StockCategory.UP}${
globalState.aLmitUpStockCount > 0 ? `(${globalState.aLmitUpStockCount})` : ''
}`,
}),
undefined,
true
),
new LeekTreeItem(
Object.assign({ contextValue: 'category' }, defaultFundInfo, {
id: StockCategory.DOWN,
name: `${StockCategory.DOWN}${
globalState.aLmitDownStockCount > 0 ? `(${globalState.aLmitDownStockCount})` : ''
}`,
}),
undefined,
true
),
new LeekTreeItem(
Object.assign({ contextValue: 'category' }, defaultFundInfo, {
id: StockCategory.HK,
Expand Down
90 changes: 88 additions & 2 deletions src/explorer/stockService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ import { ExtensionContext, QuickPickItem, window } from 'vscode';
import globalState from '../globalState';
import { LeekTreeItem } from '../shared/leekTreeItem';
import { executeStocksRemind } from '../shared/remindNotification';
import { HeldData } from '../shared/typed';
import { calcFixedPriceNumber, events, formatNumber, randHeader, sortData } from '../shared/utils';
import { FundInfo, HeldData } from '../shared/typed';
import { calcFixedPriceNumber, events, formatNumber, formatLimitTime, randHeader, sortData } from '../shared/utils';
import { getXueQiuToken } from '../shared/xueqiu-helper';
import { LeekService } from './leekService';
import moment = require('moment');
import Log from '../shared/log';
import { getTencentHKStockData, searchStockList } from '../shared/tencentStock';
import puppeteer from 'puppeteer';
import { URL } from 'url';
const querystring = require('querystring');

export default class StockService extends LeekService {
public stockList: Array<LeekTreeItem> = [];
public uplimitStockList: Array<LeekTreeItem> = [];
public downlimitStockList: Array<LeekTreeItem> = [];
private context: ExtensionContext;
private token: string = '';

Expand Down Expand Up @@ -77,6 +82,12 @@ export default class StockService extends LeekService {
stockList = stockList.concat(item.value);
}
});
// 自选
const customIds = stockList.map((item) => item.id);
const upList = await this.getLimitData('ztgc');
this.uplimitStockList = upList.filter(item => !customIds.includes(item.id));
const downList = await this.getLimitData('dtgc');
this.downlimitStockList = downList.filter(item => !customIds.includes(item.id));

const res = sortData(stockList, order);
executeStocksRemind(res, this.stockList);
Expand All @@ -87,6 +98,78 @@ export default class StockService extends LeekService {
return res;
}

async getLimitData(limitType = 'ztgc') {
const requestKey = limitType === 'ztgc' ? 'getTopicZTPool' : 'getTopicDTPool';
const stocks: Array<LeekTreeItem> = [];
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', request => {
// 只拦截 GET 请求
if (request.url().includes(requestKey)) {
const url = new URL(request.url());
// 修改查询参数
url.searchParams.set('pagesize', '500'); // 改变 pagesize 参数
// 继续请求,传入修改后的 URL
request.continue({ url: url.toString() });
} else {
// 对其他请求不做修改,直接继续
request.continue();
}
});
// 监听网络请求
page.on('response', async (response) => {
// 检查请求 URL 或请求的类型(可根据需要进行过滤)
const url = response.url();
// 假设我们要获取某个特定 API 请求的内容
if (url.includes(requestKey)) {
const paramsObject = querystring.parse(url.split('?')[1]);
const data = await response.text();
const regex = new RegExp(`^${paramsObject.cb}\\((.*)\\);$`);
const matchResult = data.match(regex);
if (matchResult && matchResult[1]) {
const resData = JSON.parse(matchResult[1]);
if (limitType === 'ztgc') {
globalState.aLmitUpStockCount = resData.data.tc;
} else {
globalState.aLmitDownStockCount = resData.data.tc;
}
resData.data.pool.forEach((item: any) => {
const type = item.m === 0 ? 'sz' : item.m === 1 ? 'sh' : 'nodata';
const stockItem: FundInfo = {
name: item.n,
code: type + item.c,
symbol: item.c,
isStock: true,
showLabel: true,
hybk: item.hybk,
type,
lbc: item.lbc,
contextValue: 'limit',
updown: `${item.zdp.toFixed(2)}%`,
percent: item.zdp > 0 ? `+${item.zdp}` : `${item.zdp}`,
price: `${item.p / 1000}`,
time: formatLimitTime(`${limitType === 'ztgc' ? item.fbt : item.lbt}`),
fbt: formatLimitTime(`${item.fbt}`),
lbt: formatLimitTime(`${item.lbt}`),
};
if (limitType === 'ztgc') {
stockItem.zttj = `${item.zttj.ct}/${item.zttj.days}`;
stockItem.fbzz = formatNumber(item.fund, 2, true);
}

const treeItem = new LeekTreeItem(stockItem, this.context);
stocks.push(treeItem);
});
}
await browser.close();
return stocks;
}
});
await page.goto(`https://quote.eastmoney.com/ztb/detail#type=${limitType}`);
return stocks;
}

async getStockData(codes: Array<string>): Promise<Array<LeekTreeItem>> {
if ((codes && codes.length === 0) || !codes) {
return [];
Expand Down Expand Up @@ -348,6 +431,7 @@ export default class StockService extends LeekService {
} catch (err) {
console.error(err);
}
stockItem.contextValue = 'FavoriteStock';
stockItem.showLabel = this.showLabel;
stockItem.isStock = true;
stockItem.type = type;
Expand All @@ -372,6 +456,7 @@ export default class StockService extends LeekService {
type: 'nodata',
contextValue: 'nodata',
};
stockItem.contextValue = 'FavoriteStock';
const treeItem = new LeekTreeItem(stockItem, this.context);
stockList.push(treeItem);
}
Expand Down Expand Up @@ -435,6 +520,7 @@ export default class StockService extends LeekService {
if (Number(open) <= 0) {
price = yestclose;
}
stockItem.contextValue = 'FavoriteStock';
stockItem.showLabel = this.showLabel;
stockItem.isStock = true;
stockItem.type = 'hk';
Expand Down
4 changes: 4 additions & 0 deletions src/globalState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ let labelFormat = DEFAULT_LABEL_FORMAT;
let stockHeldTipShow = true; // 是否开启股票持仓提示

let aStockCount = 0;
let aLmitUpStockCount = 0; // 涨停家数
let aLmitDownStockCount = 0; // 跌停家数
let usStockCount = 0;
let hkStockCount = 0;
let cnfStockCount = 0; // 期货数量
Expand Down Expand Up @@ -51,6 +53,8 @@ export default {
newsIntervalTime,
newsIntervalTimer,
aStockCount,
aLmitUpStockCount,
aLmitDownStockCount,
usStockCount,
hkStockCount,
cnfStockCount, // 期货
Expand Down
8 changes: 8 additions & 0 deletions src/registerCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,19 @@ export function registerViewEvent(
}, 1000);
});
commands.registerCommand('leek-fund.deleteStock', (target) => {
if (!target) return;
LeekFundConfig.removeStockCfg(target.id, () => {
stockProvider.refresh();
});
});
commands.registerCommand('leek-fund.addMyStock', (target) => {
if (!target) return;
LeekFundConfig.updateStockCfg(target.id, () => {
stockProvider.refresh();
});
});
commands.registerCommand('leek-fund.addStockToBar', (target) => {
if (!target) return;
LeekFundConfig.addStockToBarCfg(target.id, () => {
stockProvider.refresh();
});
Expand Down
13 changes: 13 additions & 0 deletions src/shared/leekTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ export class LeekTreeItem extends TreeItem {
publishDateTime = '',
heldAmount = 0,
heldPrice = 0,
hybk = '',
lbc = 1,
fbt = '',
lbt = '',
zttj = '',
fbzz = '',
} = info;

if (_itemType) {
Expand Down Expand Up @@ -200,6 +206,9 @@ export class LeekTreeItem extends TreeItem {
} else {
this.label = text;
}
if (hybk) {
this.label = `${text} ${lbc} ${zttj} [${hybk}]`;
}
this.id = info.id || code;
if (isStockItem || isFundItem || isBinanceItem) {
let typeAndSymbol = `${type}${symbol}`;
Expand Down Expand Up @@ -231,6 +240,8 @@ export class LeekTreeItem extends TreeItem {

const isFuture = /nf_/.test(code) || /hf_/.test(code);

const isZt = !!hybk;

// type字段:国内期货前缀 `nf_` 。股票的 type 是交易所 (sz,sh,bj)
const typeText = type;
const symbolText = isFuture ? name : symbol;
Expand All @@ -239,6 +250,8 @@ export class LeekTreeItem extends TreeItem {
this.tooltip = '接口不支持,右键删除关注';
} else if (isFuture) {
this.tooltip = `【今日行情】${name} ${code}\n 涨跌:${updown} 百分比:${_percent}%\n 最高:${high} 最低:${low}\n 今开:${open} 昨结:${yestclose}\n 成交量:${volume} 成交额:${amount}`;
} else if (isZt) {
this.tooltip = `首封时间:${fbt} 最后封板时间:${lbt}\n 涨停统计:${zttj} 连板次数:${lbc}\n 封板资金:${fbzz}`;
} else {
this.tooltip = `【今日行情】${labelText}${typeText}${symbolText}\n 涨跌:${updown} 百分比:${_percent}%\n 最高:${high} 最低:${low}\n 今开:${open} 昨收:${yestclose}\n 成交量:${volume} 成交额:${amount}\n ${heldAmount ? `持仓数:${volume} 持仓价:${heldPrice}` : ''
}`;
Expand Down
Loading
Loading