mirror of
https://github.com/injoyai/tdx.git
synced 2025-11-26 21:25:35 +08:00
增加获取所有股票代码的接口
This commit is contained in:
@@ -7,3 +7,5 @@
|
||||

|
||||
* 基本信息(5档报价)
|
||||

|
||||
* 基本信息(股票列表)
|
||||

|
||||
22
client.go
22
client.go
@@ -21,18 +21,13 @@ func Dial(addr string, op ...client.Option) (cli *Client, err error) {
|
||||
cli.c, err = dial.TCP(addr, func(c *client.Client) {
|
||||
c.Logger.WithHEX() //以HEX显示
|
||||
c.SetOption(op...) //自定义选项
|
||||
//c.AllReader = ios.NewAllReader(c.Reader.(io.Reader), protocol.ReadFrom) //分包
|
||||
c.Event.OnReadFrom = protocol.ReadFrom //分包
|
||||
c.Event.OnDealMessage = cli.handlerDealMessage //处理分包数据
|
||||
|
||||
logs.Debug("option")
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logs.Debug("run")
|
||||
logs.Debugf("%#v\n", cli.c.Event.OnReadFrom)
|
||||
go cli.c.Run()
|
||||
|
||||
err = cli.connect()
|
||||
@@ -62,10 +57,10 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) {
|
||||
var resp any
|
||||
switch f.Type {
|
||||
case protocol.TypeSecurityQuote:
|
||||
resp = protocol.MSecurityQuote.Decode(f.Data)
|
||||
resp = protocol.MStockQuote.Decode(f.Data)
|
||||
|
||||
case protocol.TypeSecurityList:
|
||||
resp, err = protocol.MSecurityList.Decode(f.Data)
|
||||
resp, err = protocol.MStockList.Decode(f.Data)
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +69,6 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) {
|
||||
return
|
||||
}
|
||||
|
||||
logs.Debug(resp)
|
||||
this.w.Done(conv.String(f.MsgID), resp)
|
||||
|
||||
}
|
||||
@@ -112,19 +106,19 @@ func (this *Client) connect() error {
|
||||
}
|
||||
|
||||
// GetSecurityList 获取市场内指定范围内的所有证券代码
|
||||
func (this *Client) GetSecurityList(exchange protocol.Exchange, starts ...uint16) (*protocol.SecurityListResp, error) {
|
||||
f := protocol.MSecurityList.Frame(exchange, starts...)
|
||||
func (this *Client) GetSecurityList(exchange protocol.Exchange, starts ...uint16) (*protocol.StockListResp, error) {
|
||||
f := protocol.MStockList.Frame(exchange, starts...)
|
||||
result, err := this.SendFrame(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*protocol.SecurityListResp), nil
|
||||
return result.(*protocol.StockListResp), nil
|
||||
|
||||
}
|
||||
|
||||
// GetSecurityQuotes 获取盘口五档报价
|
||||
func (this *Client) GetSecurityQuotes(m map[protocol.Exchange]string) (protocol.SecurityQuotesResp, error) {
|
||||
f, err := protocol.MSecurityQuote.Frame(m)
|
||||
func (this *Client) GetSecurityQuotes(m map[protocol.Exchange]string) (protocol.StockQuotesResp, error) {
|
||||
f, err := protocol.MStockQuote.Frame(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -132,5 +126,5 @@ func (this *Client) GetSecurityQuotes(m map[protocol.Exchange]string) (protocol.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(protocol.SecurityQuotesResp), nil
|
||||
return result.(protocol.StockQuotesResp), nil
|
||||
}
|
||||
|
||||
BIN
docs/plan20241025.png
Normal file
BIN
docs/plan20241025.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
BIN
docs/plan20241028.png
Normal file
BIN
docs/plan20241028.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 374 KiB |
@@ -1,12 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"github.com/injoyai/goutil/g"
|
||||
"github.com/injoyai/ios/client"
|
||||
"github.com/injoyai/ios/server"
|
||||
"github.com/injoyai/ios/server/listen"
|
||||
"github.com/injoyai/logs"
|
||||
"github.com/injoyai/tdx"
|
||||
"github.com/injoyai/tdx/protocol"
|
||||
@@ -40,20 +34,3 @@ func main() {
|
||||
select {}
|
||||
|
||||
}
|
||||
|
||||
// 监听第三方包发送的数据,确定协议用
|
||||
func _listen() {
|
||||
listen.RunTCP(7709, func(s *server.Server) {
|
||||
s.SetClientOption(func(c *client.Client) {
|
||||
c.Logger.WithHEX()
|
||||
})
|
||||
})
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err := binary.Write(buf, binary.LittleEndian, g.Map{
|
||||
"name": "名称",
|
||||
"age": 17,
|
||||
})
|
||||
logs.PrintErr(err)
|
||||
logs.Debug(buf.String())
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func main() {
|
||||
logs.PrintErr(err)
|
||||
|
||||
for _, v := range resp.List {
|
||||
logs.Debugf("%#v\n", v)
|
||||
logs.Debug(v)
|
||||
}
|
||||
|
||||
select {}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -6,7 +6,7 @@ require (
|
||||
github.com/injoyai/base v1.0.18
|
||||
github.com/injoyai/conv v1.1.10
|
||||
github.com/injoyai/goutil v0.0.0-20241009040015-3d20afe3efe6
|
||||
github.com/injoyai/ios v0.0.3
|
||||
github.com/injoyai/ios v0.0.4
|
||||
github.com/injoyai/logs v1.0.9
|
||||
golang.org/x/text v0.16.0
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1068,8 +1068,8 @@ github.com/injoyai/goutil v0.0.0-20241009040015-3d20afe3efe6 h1:ShXZNuV2tQOD9xlz
|
||||
github.com/injoyai/goutil v0.0.0-20241009040015-3d20afe3efe6/go.mod h1:lXrP8bGSoueX7sBniT5pZctp1e2z3cVZYVeRrjQSKoc=
|
||||
github.com/injoyai/io v0.1.8 h1:C+pt2LLUNhCu80EVuzCs6+vetHf6Ny5ANAIOH8QUAco=
|
||||
github.com/injoyai/io v0.1.8/go.mod h1:khts/5VvSJVm8Dl1fp0C+D8L0pmRrXtWsp+SJqlTgpw=
|
||||
github.com/injoyai/ios v0.0.3 h1:AAwcMbm9/eBNOT1rqdbvwMlZQFxNCyMUfDDQQYTK7m4=
|
||||
github.com/injoyai/ios v0.0.3/go.mod h1:heABkaIUwoRRe424otl6mKgdU6LYt5gadav/V4gaojA=
|
||||
github.com/injoyai/ios v0.0.4 h1:yEZ6wN5uCSjAJB4qwpT6R77aMtjkblZo4giKwu9/s7Y=
|
||||
github.com/injoyai/ios v0.0.4/go.mod h1:heABkaIUwoRRe424otl6mKgdU6LYt5gadav/V4gaojA=
|
||||
github.com/injoyai/logs v1.0.7/go.mod h1:CLchJCGhb39Obyrci816R+KMtbxZhgPs0FuikhyixK4=
|
||||
github.com/injoyai/logs v1.0.9 h1:Wq7rCVIQKcPx+z+lzKQb2qyDK4TML/cgmaSZN9tx33c=
|
||||
github.com/injoyai/logs v1.0.9/go.mod h1:CLchJCGhb39Obyrci816R+KMtbxZhgPs0FuikhyixK4=
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/injoyai/base/bytes"
|
||||
"github.com/injoyai/base/g"
|
||||
"github.com/injoyai/conv"
|
||||
"github.com/injoyai/logs"
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -16,7 +15,7 @@ const (
|
||||
Prefix = 0x0c
|
||||
|
||||
// PrefixResp 响应帧头
|
||||
PrefixResp = 0xb1cb74
|
||||
PrefixResp = 0xb1cb7400
|
||||
)
|
||||
|
||||
type Message interface {
|
||||
@@ -109,7 +108,7 @@ func Decode(bs []byte) (*Response, error) {
|
||||
|
||||
// ReadFrom 这里的r推荐传入*bufio.Reader
|
||||
func ReadFrom(r io.Reader) (result []byte, err error) {
|
||||
logs.Debug("ReadFrom")
|
||||
|
||||
prefix := make([]byte, 4)
|
||||
for {
|
||||
result = []byte(nil)
|
||||
@@ -133,8 +132,7 @@ func ReadFrom(r io.Reader) (result []byte, err error) {
|
||||
result = append(result, buf...)
|
||||
|
||||
//获取后续字节长度
|
||||
length := uint16(result[11])<<8 + uint16(result[10])
|
||||
logs.Debug("长度:", length)
|
||||
length := uint16(result[13])<<8 + uint16(result[12])
|
||||
buf = make([]byte, length)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
@@ -59,3 +60,25 @@ func TestDecode(t *testing.T) {
|
||||
//
|
||||
//t.Log(result)
|
||||
}
|
||||
|
||||
func TestReadFrom(t *testing.T) {
|
||||
s := "b1cb74001c00000000000d005100bd00789c6378c12ec325c7cb2061c5b4898987b9050ed1f90c2db74c1825bd18c1b42890fecff09c81819191f13fc3c9f3bb169f5e7dfefeb5ef57f7199a305009308208e5b32bb6bcbf701487120031c61e1e"
|
||||
bs, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
result, err := ReadFrom(bytes.NewReader(bs))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(hex.EncodeToString(result))
|
||||
resp, err := Decode(result)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(hex.EncodeToString(resp.Data))
|
||||
t.Log(string(resp.Data))
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
var (
|
||||
MConnect = connect{}
|
||||
MSecurityQuote = securityQuote{}
|
||||
MSecurityList = securityList{}
|
||||
MStockQuote = stockQuote{}
|
||||
MStockList = stockList{}
|
||||
)
|
||||
|
||||
type ConnectResp struct {
|
||||
@@ -41,22 +41,26 @@ func (connect) Decode(bs []byte) (*ConnectResp, error) {
|
||||
|
||||
*/
|
||||
|
||||
type SecurityListResp struct {
|
||||
type StockListResp struct {
|
||||
Count uint16
|
||||
List []*Security
|
||||
List []*Stock
|
||||
}
|
||||
|
||||
type Security struct {
|
||||
Code string
|
||||
VolUnit uint16
|
||||
DecimalPoint int8
|
||||
Name string
|
||||
PreClose float64
|
||||
type Stock struct {
|
||||
Name string //股票名称
|
||||
Code string //股票代码
|
||||
VolUnit uint16 //未知
|
||||
DecimalPoint int8 //未知
|
||||
PreClose float64 //未知
|
||||
}
|
||||
|
||||
type securityList struct{}
|
||||
func (this *Stock) String() string {
|
||||
return fmt.Sprintf("%s(%s)", this.Name, this.Code)
|
||||
}
|
||||
|
||||
func (securityList) Frame(exchange Exchange, starts ...uint16) *Frame {
|
||||
type stockList struct{}
|
||||
|
||||
func (stockList) Frame(exchange Exchange, starts ...uint16) *Frame {
|
||||
start := conv.DefaultUint16(0, starts...)
|
||||
return &Frame{
|
||||
Control: Control01,
|
||||
@@ -65,25 +69,26 @@ func (securityList) Frame(exchange Exchange, starts ...uint16) *Frame {
|
||||
}
|
||||
}
|
||||
|
||||
func (securityList) Decode(bs []byte) (*SecurityListResp, error) {
|
||||
func (stockList) Decode(bs []byte) (*StockListResp, error) {
|
||||
|
||||
if len(bs) < 2 {
|
||||
return nil, errors.New("数据长度不足")
|
||||
}
|
||||
|
||||
resp := &SecurityListResp{
|
||||
resp := &StockListResp{
|
||||
Count: Uint16(bs[:2]),
|
||||
}
|
||||
bs = bs[2:]
|
||||
|
||||
for i := uint16(0); i < resp.Count; i++ {
|
||||
sec := &Security{
|
||||
Code: String(bs[:6]),
|
||||
sec := &Stock{
|
||||
Code: string(bs[:6]),
|
||||
VolUnit: Uint16(bs[6:8]),
|
||||
Name: string(UTF8ToGBK(bs[8:16])),
|
||||
PreClose: getVolume(Uint32(bs[16:20])),
|
||||
DecimalPoint: int8(bs[20]),
|
||||
PreClose: getVolume(Uint32(bs[21:25])),
|
||||
}
|
||||
bs = bs[20:]
|
||||
bs = bs[29:]
|
||||
resp.List = append(resp.List, sec)
|
||||
}
|
||||
|
||||
@@ -97,9 +102,9 @@ func (securityList) Decode(bs []byte) (*SecurityListResp, error) {
|
||||
|
||||
*/
|
||||
|
||||
type SecurityQuotesResp []*SecurityQuote
|
||||
type StockQuotesResp []*StockQuote
|
||||
|
||||
func (this SecurityQuotesResp) String() string {
|
||||
func (this StockQuotesResp) String() string {
|
||||
ls := []string(nil)
|
||||
for _, v := range this {
|
||||
ls = append(ls, v.String())
|
||||
@@ -107,7 +112,7 @@ func (this SecurityQuotesResp) String() string {
|
||||
return strings.Join(ls, "\n")
|
||||
}
|
||||
|
||||
type SecurityQuote struct {
|
||||
type StockQuote struct {
|
||||
Exchange Exchange // 市场
|
||||
Code string // 股票代码 6个ascii字符串
|
||||
Active1 uint16 // 活跃度
|
||||
@@ -136,7 +141,7 @@ type SecurityQuote struct {
|
||||
Active2 uint16 // 活跃度
|
||||
}
|
||||
|
||||
func (this *SecurityQuote) String() string {
|
||||
func (this *StockQuote) String() string {
|
||||
return fmt.Sprintf(`%s%s
|
||||
%s
|
||||
总量:%s, 现量:%s, 总金额:%s, 内盘:%s, 外盘:%s
|
||||
@@ -149,9 +154,9 @@ func (this *SecurityQuote) String() string {
|
||||
)
|
||||
}
|
||||
|
||||
type securityQuote struct{}
|
||||
type stockQuote struct{}
|
||||
|
||||
func (this securityQuote) Frame(m map[Exchange]string) (*Frame, error) {
|
||||
func (this stockQuote) Frame(m map[Exchange]string) (*Frame, error) {
|
||||
f := &Frame{
|
||||
Control: Control01,
|
||||
Type: TypeSecurityQuote,
|
||||
@@ -196,11 +201,11 @@ b212 昨天收盘价1186
|
||||
8defd10c 服务时间
|
||||
c005bed2668e05be15804d8ba12cb3b13a0083c3034100badc029d014201bc990384f70443029da503b7af074403a6e501b9db044504a6e2028dd5048d050000000000005909
|
||||
*/
|
||||
func (this securityQuote) Decode(bs []byte) SecurityQuotesResp {
|
||||
func (this stockQuote) Decode(bs []byte) StockQuotesResp {
|
||||
|
||||
//logs.Debug(hex.EncodeToString(bs))
|
||||
|
||||
resp := SecurityQuotesResp{}
|
||||
resp := StockQuotesResp{}
|
||||
|
||||
//前2字节是什么?
|
||||
bs = bs[2:]
|
||||
@@ -209,7 +214,7 @@ func (this securityQuote) Decode(bs []byte) SecurityQuotesResp {
|
||||
bs = bs[2:]
|
||||
|
||||
for i := uint16(0); i < number; i++ {
|
||||
sec := &SecurityQuote{
|
||||
sec := &StockQuote{
|
||||
Exchange: Exchange(bs[0]),
|
||||
Code: string(UTF8ToGBK(bs[1:7])),
|
||||
Active1: Uint16(bs[7:9]),
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
0c02000000011a001a003e05050000000000000002000030303030303101363030303038
|
||||
*/
|
||||
func TestNewSecurityQuotes(t *testing.T) {
|
||||
f, err := MSecurityQuote.Frame(map[Exchange]string{
|
||||
f, err := MStockQuote.Frame(map[Exchange]string{
|
||||
ExchangeSH: "000001",
|
||||
ExchangeSZ: "600008",
|
||||
})
|
||||
@@ -48,6 +48,6 @@ func Test_getPrice(t *testing.T) {
|
||||
0c020000000106000600500400000000
|
||||
*/
|
||||
func Test_securityList_Frame(t *testing.T) {
|
||||
f := MSecurityList.Frame(ExchangeSH, 0)
|
||||
f := MStockList.Frame(ExchangeSH, 0)
|
||||
t.Log(f.Bytes().HEX())
|
||||
}
|
||||
@@ -10,18 +10,22 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// String 字节先转小端,再转字符
|
||||
func String(bs []byte) string {
|
||||
return string(bytes2.Reverse(bs))
|
||||
}
|
||||
|
||||
// Bytes 任意类型转小端字节
|
||||
func Bytes(n any) []byte {
|
||||
return bytes2.Reverse(conv.Bytes(n))
|
||||
}
|
||||
|
||||
// Uint32 字节通过小端方式转为uint32
|
||||
func Uint32(bs []byte) uint32 {
|
||||
return conv.Uint32(bytes2.Reverse(bs))
|
||||
}
|
||||
|
||||
// Uint16 字节通过小端方式转为uint16
|
||||
func Uint16(bs []byte) uint16 {
|
||||
return conv.Uint16(bytes2.Reverse(bs))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user