-
Notifications
You must be signed in to change notification settings - Fork 321
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of github.com:axiaoxin-com/investool into main
- Loading branch information
Showing
14 changed files
with
579 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package cmds | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strconv" | ||
|
||
"github.com/axiaoxin-com/investool/datacenter/eastmoney" | ||
"github.com/axiaoxin-com/logging" | ||
"github.com/olekukonko/tablewriter" | ||
) | ||
|
||
func showIndexData(data *eastmoney.IndexData) { | ||
table := tablewriter.NewWriter(os.Stdout) | ||
table.SetAlignment(tablewriter.ALIGN_LEFT) | ||
table.SetRowSeparator("") | ||
table.SetBorder(false) | ||
table.SetNoWhiteSpace(true) | ||
headers := []string{} | ||
table.SetHeader(headers) | ||
table.SetCaption(true, data.IndexCode+"指数信息") | ||
rows := [][]string{ | ||
{"指数名称", data.FullIndexName}, | ||
{"指数说明", data.Reaprofile}, | ||
{"编制方", data.MakerName}, | ||
{"估值", data.IndexValueCN()}, | ||
{"估值PE值", data.Petim}, | ||
{"估值PE百分位", data.Pep100}, | ||
{"指数代码", data.IndexCode}, | ||
{"板块名称", data.BKName}, | ||
{"当前点数", data.NewPrice}, | ||
{"最新涨幅", data.NewCHG}, | ||
{"最近一周涨幅", data.W}, | ||
{"最近一月涨幅", data.M}, | ||
{"最近三月涨幅", data.Q}, | ||
{"最近六月涨幅", data.Hy}, | ||
{"最近一年涨幅", data.Y}, | ||
{"最近两年涨幅", data.Twy}, | ||
{"最近三年涨幅", data.Try}, | ||
{"最近五年涨幅", data.Fy}, | ||
{"今年来涨幅", data.Sy}, | ||
} | ||
table.AppendBulk(rows) | ||
|
||
table.Render() | ||
} | ||
|
||
func showIndexStocks(stocks []eastmoney.ZSCFGItem) { | ||
table := tablewriter.NewWriter(os.Stdout) | ||
table.SetAlignment(tablewriter.ALIGN_LEFT) | ||
table.SetRowLine(true) | ||
headers := []string{"股票名称", "股票代码", "持仓占比"} | ||
table.SetHeader(headers) | ||
|
||
sum := 0.0 | ||
for _, stock := range stocks { | ||
row := []string{stock.StockName, stock.StockCode, stock.Marketcappct} | ||
table.Append(row) | ||
if stock.Marketcappct != "" && stock.Marketcappct != "--" { | ||
v, err := strconv.ParseFloat(stock.Marketcappct, 64) | ||
if err != nil { | ||
logging.Error(nil, err.Error()) | ||
continue | ||
} | ||
sum += v | ||
} | ||
} | ||
|
||
if len(stocks) > 0 { | ||
table.SetCaption(true, stocks[0].IndexName+"成分股") | ||
} | ||
footers := []string{fmt.Sprintf("总数:%d", len(stocks)), "--", fmt.Sprintf("占比求和:%.2f", sum)} | ||
table.SetFooter(footers) | ||
table.Render() | ||
} | ||
|
||
func showIntersecStocks(stocks1, stocks2 []eastmoney.ZSCFGItem) { | ||
table := tablewriter.NewWriter(os.Stdout) | ||
table.SetAlignment(tablewriter.ALIGN_LEFT) | ||
table.SetRowLine(true) | ||
headers := []string{"股票名称-代码"} | ||
table.SetHeader(headers) | ||
|
||
counter := map[string]int{} | ||
for _, stock := range stocks1 { | ||
key := fmt.Sprintf("%v-%v", stock.StockName, stock.StockCode) | ||
counter[key]++ | ||
} | ||
|
||
for _, stock := range stocks2 { | ||
key := fmt.Sprintf("%v-%v", stock.StockName, stock.StockCode) | ||
counter[key]++ | ||
} | ||
|
||
intersecCount := 0 | ||
for k, v := range counter { | ||
if v == 2 { | ||
table.Append([]string{k}) | ||
intersecCount++ | ||
} | ||
} | ||
|
||
if intersecCount > 0 { | ||
table.SetCaption(true, fmt.Sprintf("%s∩%s 成分股交集", stocks1[0].IndexName, stocks2[0].IndexName)) | ||
} | ||
footers := []string{fmt.Sprintf("交集总数:%d", intersecCount)} | ||
table.SetFooter(footers) | ||
table.Render() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// 指数数据 | ||
|
||
package cmds | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/axiaoxin-com/investool/datacenter" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
const ( | ||
// ProcessorIndex 指数数据处理 | ||
ProcessorIndex = "index" | ||
) | ||
|
||
// FlagsIndex cli flags | ||
func FlagsIndex() []cli.Flag { | ||
return []cli.Flag{ | ||
&cli.StringFlag{ | ||
Name: "code", | ||
Aliases: []string{"c"}, | ||
Value: "", | ||
Usage: "指定指数代码", | ||
Required: true, | ||
}, | ||
&cli.BoolFlag{ | ||
Name: "desc", | ||
Aliases: []string{"d"}, | ||
Value: false, | ||
Usage: "返回指数信息", | ||
Required: false, | ||
}, | ||
&cli.BoolFlag{ | ||
Name: "stocks", | ||
Aliases: []string{"s"}, | ||
Value: false, | ||
Usage: "返回指数成分股", | ||
Required: false, | ||
}, | ||
&cli.StringFlag{ | ||
Name: "intersec", | ||
Aliases: []string{"i"}, | ||
Value: "", | ||
Usage: "返回成分股交集", | ||
Required: false, | ||
}, | ||
} | ||
} | ||
|
||
// ActionIndex cli action | ||
func ActionIndex() func(c *cli.Context) error { | ||
return func(c *cli.Context) error { | ||
ctx := context.Background() | ||
indexCode := c.String("code") | ||
|
||
showDesc := c.Bool("desc") | ||
if showDesc { | ||
indexData, err := datacenter.EastMoney.Index(ctx, indexCode) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
showIndexData(indexData) | ||
} | ||
|
||
showStocks := c.Bool("stocks") | ||
if showStocks { | ||
stocks, err := datacenter.EastMoney.ZSCFG(ctx, indexCode) | ||
if err != nil { | ||
return err | ||
} | ||
showIndexStocks(stocks) | ||
} | ||
|
||
intersecIndexCode := c.String("intersec") | ||
if intersecIndexCode != "" { | ||
stocks1, err := datacenter.EastMoney.ZSCFG(ctx, indexCode) | ||
if err != nil { | ||
return err | ||
} | ||
stocks2, err := datacenter.EastMoney.ZSCFG(ctx, intersecIndexCode) | ||
if err != nil { | ||
return err | ||
} | ||
showIntersecStocks(stocks1, stocks2) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
// CommandIndex 指数成分股 cli command | ||
func CommandIndex() *cli.Command { | ||
flags := FlagsIndex() | ||
cmd := &cli.Command{ | ||
Name: ProcessorIndex, | ||
Usage: "指数数据", | ||
Flags: flags, | ||
Action: ActionIndex(), | ||
} | ||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// 沪深300成分股 | ||
|
||
package eastmoney | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/axiaoxin-com/goutils" | ||
"github.com/corpix/uarand" | ||
) | ||
|
||
// HS300Item 沪深300成分股信息 | ||
type HS300Item struct { | ||
Secucode string `json:"SECUCODE"` // 股票代码.XX | ||
SecurityCode string `json:"SECURITY_CODE"` // 股票代码 | ||
SecurityNameAbbr string `json:"SECURITY_NAME_ABBR"` // 股票简称 | ||
ClosePrice float64 `json:"CLOSE_PRICE"` // 最新价格 | ||
Industry string `json:"INDUSTRY"` // 主营行业 | ||
Region string `json:"REGION"` // 地区 | ||
Weight float64 `json:"WEIGHT"` // 持仓比例(%) | ||
Eps float64 `json:"EPS"` // 每股收益 | ||
Bps float64 `json:"BPS"` // 每股净资产 | ||
Roe float64 `json:"ROE"` // 净资产收益率 | ||
TotalShares float64 `json:"TOTAL_SHARES"` // 总股本(亿股) | ||
FreeShares float64 `json:"FREE_SHARES"` // 流通股本(亿股) | ||
FreeCap float64 `json:"FREE_CAP"` // 流通市值(亿元) | ||
Type string `json:"TYPE"` | ||
F2 interface{} `json:"f2"` | ||
F3 interface{} `json:"f3"` | ||
} | ||
|
||
// RspHS300 HS300接口返回结构 | ||
type RspHS300 struct { | ||
Version string `json:"version"` | ||
Result struct { | ||
Pages int `json:"pages"` | ||
Data []HS300Item `json:"data"` | ||
Count int `json:"count"` | ||
} `json:"result"` | ||
Success bool `json:"success"` | ||
Message string `json:"message"` | ||
Code int `json:"code"` | ||
} | ||
|
||
// HS300 返回沪深300成分股列表 | ||
func (e EastMoney) HS300(ctx context.Context) (results []HS300Item, err error) { | ||
apiurl := "https://datacenter-web.eastmoney.com/api/data/v1/get?sortColumns=ROE&sortTypes=-1&pageSize=300&pageNumber=1&reportName=RPT_INDEX_TS_COMPONENT&columns=SECUCODE%2CSECURITY_CODE%2CTYPE%2CSECURITY_NAME_ABBR%2CCLOSE_PRICE%2CINDUSTRY%2CREGION%2CWEIGHT%2CEPS%2CBPS%2CROE%2CTOTAL_SHARES%2CFREE_SHARES%2CFREE_CAP"eColumns=f2%2Cf3"eType=0&source=WEB&client=WEB&filter=(TYPE%3D%221%22)" | ||
header := map[string]string{ | ||
"user-agent": uarand.GetRandom(), | ||
} | ||
rsp := RspHS300{} | ||
if err := goutils.HTTPGET(ctx, e.HTTPClient, apiurl, header, &rsp); err != nil { | ||
return nil, err | ||
} | ||
if rsp.Code != 0 { | ||
return nil, fmt.Errorf("HS300 rsp code error, rsp:%+v", rsp) | ||
} | ||
if len(rsp.Result.Data) != 300 { | ||
return nil, fmt.Errorf("HS300 rsp data len != 300, len=%d", len(rsp.Result.Data)) | ||
} | ||
return rsp.Result.Data, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package eastmoney | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestHS300(t *testing.T) { | ||
results, err := _em.HS300(_ctx) | ||
require.Nil(t, err) | ||
t.Log(results) | ||
} |
Oops, something went wrong.