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

QuoteHandler use quoteMultiSec #31

Merged
merged 9 commits into from
Oct 14, 2024
Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# sec change log

### WIP v0.1.3
### v0.1.3

1. 全部命令添加 `--debug`/`-D` flag
2. quote 命令最多支持查询 5 个证券
3. quote 支持实时 (3s) 更新行情信息

### v0.1.2

Expand Down
135 changes: 54 additions & 81 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,69 @@

security info CLI

## Demo

1. 搜索证券

```shell
$ sec search lxzk
证券代码 证券名称 证券类型 交易所
SH688047 龙芯中科 stock sh
SZ300112 万讯自控 stock sz
HK02186 绿叶制药 stock hk
```

![](https://github.com/alwqx/picx-images-hosting/raw/master/common/github/sec_search.3yeffybtam.gif)

2. 显示证券信息

```shell
$ sec info lxzk
证券代码 SH688047
简称历史 龙芯中科
公司名称 龙芯中科技术股份有限公司
上市日期 2022-06-24
发行价格 60.06
行业分类 半导体
主营业务 处理器及配套芯片的研制、销售及服务
办公地址 北京市海淀区中关村环保科技示范园区龙芯产业园 2 号楼
公司网址 http://www.loongson.cn
当前价格 119.62
市净率 PB 14.47
市盈率 TTM 0.00
总市值 479.68 亿
流通市值 334.51 亿
```
![](https://github.com/alwqx/picx-images-hosting/raw/master/common/github/sec_quote.3k7zp33ifg.gif)

2.1 显示证券基本信息+分红信息
## 命令

```shell
证券代码 SZ002475
简称历史 立讯精密
公司名称 立讯精密工业股份有限公司
上市日期 2010-09-15
发行价格 28.80
行业分类 消费电子
主营业务 公司专注于连接器的研发、生产和销售,产品主要应用于 3C(电脑、通讯、消费电子)、汽车和通讯设备等领域。
办公地址 广东省东莞市清溪镇北环路 313 号
公司网址 http://www.luxshare-ict.com
当前价格 43.46
市净率 PB 5.31
市盈率 TTM 58.01
总市值 3130.56 亿
流通市值 3123.79 亿

公告日期 分红送配 除权除息日 股权登记日
2024-07-05 10 派 2.99 元 2024-07-11 2024-07-10
2023-06-09 10 派 1.30 元 2023-06-15 2023-06-14
2022-07-07 10 派 1.10 元 2022-07-13 2022-07-12
2021-06-30 10 派 1.10 元 2021-07-08 2021-07-07
2020-06-10 10 转 3.00 股派 1.20 元 2020-06-17 2020-06-16
2019-06-28 10 转 3.00 股派 0.50 元 2019-07-05 2019-07-04
2018-07-10 10 转 3.00 股派 0.60 元 2018-07-17 2018-07-16
2017-06-28 10 转 5.00 股派 0.80 元 2017-07-06 2017-07-05
2016-06-03 10 转 5.00 股派 0.90 元 2016-06-13 2016-06-08
2015-06-12 10 转 5.00 股派 0.80 元 2015-06-19 2015-06-18
2014-05-15 10 转 4.00 股派 0.70 元 2014-05-21 2014-05-20
2013-06-15 10 转 5.00 股派 1.00 元 2013-06-21 2013-06-20
2012-06-02 10 转 4.00 股派 2.00 元 2012-06-08 2012-06-07
2011-05-20 10 转 5.00 股派 3.00 元 2011-05-26 2011-05-25
```
$ sec --help
Secutiry Information Client

![](https://github.com/alwqx/picx-images-hosting/raw/master/common/github/sec_info.eshq593ig.gif)
Usage:
sec [flags]
sec [command]

3. 显示单个证券行情
Available Commands:
help Help about any command
info Print basic information of a secutiry/stock
quote Secutiry quote root Command
search Search code and name of a secutiry/stock

```shell
$ sec quote lxzk
时间 当前价格 昨收 今开 最高 最低 成交量 成交额 名称 证券代码
2024-09-30 15:00:01 119.62 20% 99.68 106 119.62 104.5 825.67 万 9.38 亿 龙芯中科 SH688047
```
Flags:
-D, --debug Enable debug mode
-h, --help help for sec
-v, --version Show version information

3.1 显示多个证券行情,用逗号分隔

```shell
$ sec quote lxzk,lxjm,SH600036
时间 当前价格 昨收 今开 最高 最低 成交量 成交额 名称 证券代码
2024-09-30 15:00:00 43.46 7.4% 40.48 42 43.95 41.01 1.60 亿 68.42 亿 立讯精密 SZ002475
2024-09-30 15:00:01 119.62 20% 99.68 106 119.62 104.5 825.67 万 9.38 亿 龙芯中科 SH688047
2024-09-30 15:00:00 37.61 5.6% 35.63 36.35 38 35.92 2.56 亿 94.43 亿 招商银行 SH600036
Use "sec [command] --help" for more information about a command.
```

![](https://github.com/alwqx/picx-images-hosting/raw/master/common/github/sec_quote.3k7zp33ifg.gif)
1. 搜索证券
```shell
$ sec search lxzk
证券代码 证券名称 证券类型 交易所
SH688047 龙芯中科 stock sh
SZ300112 万讯自控 stock sz
HK02186 绿叶制药 stock hk
```
2. 查看证券基本信息
```shell
$ sec info lxzk
证券代码 SH688047
简称历史 龙芯中科
公司名称 龙芯中科技术股份有限公司
上市日期 2022-06-24
发行价格 60.06
行业分类 半导体
主营业务 处理器及配套芯片的研制、销售及服务
办公地址 北京市海淀区中关村环保科技示范园区龙芯产业园 2 号楼
公司网址 http://www.loongson.cn
当前价格 119.62
市净率 PB 14.47
市盈率 TTM 0.00
总市值 479.68 亿
流通市值 334.51 亿
```
3. 查看行情信息
```shell
$ sec quote lxzk
时间 当前价格 昨收 今开 最高 最低 成交量 成交额 名称 证券代码
2024-09-30 15:00:01 119.62 20% 99.68 106 119.62 104.5 825.67 万 9.38 亿 龙芯中科 SH688047
$ sec quote lxzk,lxjm,SH600036
时间 当前价格 昨收 今开 最高 最低 成交量 成交额 名称 证券代码
2024-09-30 15:00:00 43.46 7.4% 40.48 42 43.95 41.01 1.60 亿 68.42 亿 立讯精密 SZ002475
2024-09-30 15:00:01 119.62 20% 99.68 106 119.62 104.5 825.67 万 9.38 亿 龙芯中科 SH688047
2024-09-30 15:00:00 37.61 5.6% 35.63 36.35 38 35.92 2.56 亿 94.43 亿 招商银行 SH600036
```

## 安装

Expand Down
124 changes: 99 additions & 25 deletions cmd/quote/quote.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package quote

import (
"context"
"errors"
"fmt"
"log/slog"
"os"
"os/exec"
"os/signal"
"runtime"
"strconv"
"strings"
"syscall"
"time"

"github.com/alwqx/sec/provider/sina"
"github.com/alwqx/sec/types"
Expand All @@ -29,6 +35,7 @@ func NewQuoteCLI() *cobra.Command {
RunE: QuoteHandler,
}
rootCmd.Flags().BoolP("debug", "D", false, "Enable debug mode")
rootCmd.Flags().BoolP("realtime", "r", false, "Realtime updaet quote info")

return rootCmd
}
Expand All @@ -42,38 +49,41 @@ func QuoteHandler(cmd *cobra.Command, args []string) error {
keys := strings.Split(args[0], ",")
dedupKeys := stringSliceDedup(keys)
slog.Debug("QuoteHandler", "dedupKeys", dedupKeys)

if len(dedupKeys) == 1 {
return quoteOneSec(dedupKeys[0])
}

return quoteMultiSec(keys)
}

func quoteOneSec(key string) error {
// 1. search security
secs := sina.Search(key)
if len(secs) == 0 {
slog.Warn(fmt.Sprintf("no result of %s", key))
return nil
if len(dedupKeys) > 5 {
slog.Warn("QuoteHandler support 5 secs at most, will choose top 5 keys")
dedupKeys = dedupKeys[:5]
}

// 2. choose the first item
sec := secs[0]
quote, err := sina.QuerySecQuote(sec.ExCode)
realTime, err := cmd.Flags().GetBool("realtime")
if err != nil {
return err
}
if quote == nil {
slog.Warn(fmt.Sprintf("no result of %s", key))
return nil
if !realTime {
return quoteMultiSec(dedupKeys)
}
quote.Code = sec.Code
quote.ExCode = sec.ExCode
// TODO: 港股指数成交额 * 1000
printQuote([]*sina.SecurityQuote{quote})

return nil
ctx, cancel := context.WithCancel(cmd.Context())
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
go func() {
for {
s := <-c
slog.InfoContext(ctx, "QuoteHandler", "get a signal", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
cancel()
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}()

slog.DebugContext(ctx, "QuoteHandler", "realTime", realTime)
err = quoteMultiSecRealtime(ctx, dedupKeys)
return err
}

func quoteMultiSec(keys []string) error {
Expand Down Expand Up @@ -116,6 +126,53 @@ func quoteMultiSec(keys []string) error {
return nil
}

func quoteMultiSecRealtime(ctx context.Context, keys []string) error {
// keys 长度不能超过5
if len(keys) > 5 {
slog.WarnContext(ctx, "quoteMultiSecRealtime support 5 secs at most, will choose top 5 keys")
keys = keys[:5]
}
// 1. search security
secs := sina.MultiSearch(keys)
if len(secs) == 0 {
slog.Warn(fmt.Sprintf("no result of %v", keys))
return nil
}

slog.Debug("quoteMultiSecRealtime", "secs", secs)

codes := make([]string, 0, len(secs))
secMap := make(map[string]sina.BasicSecurity, len(secs))
for i, sec := range secs {
codes = append(codes, sec.ExCode)
secMap[sec.Name] = secs[i]
}

for {
select {
case <-ctx.Done():
return nil
default:
res, err := sina.QuoteWs(codes)
if err != nil {
return err
}

// 填充证券代码
for _, quote := range res {
if sec, ok := secMap[quote.Name]; ok {
quote.ExCode = sec.ExCode
quote.Code = sec.Code
}
}
clearTerm()
printQuote(res)

time.Sleep(3 * time.Second)
}
}
}

// printQuote 打印 quote 信息
// TODO: 修复列偏移
func printQuote(quotes []*sina.SecurityQuote) {
Expand Down Expand Up @@ -204,3 +261,20 @@ func stringSliceDedup(strs []string) []string {

return res
}

// clearTerm 终端清屏
func clearTerm() {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("cmd", "/c", "cls")
default:
cmd = exec.Command("clear")
}

cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
slog.Error("clearTerm", "cmd error", err)
}
}
2 changes: 1 addition & 1 deletion version/version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package version

var Version string = "v0.1.2"
var Version string = "v0.1.3"
Loading