diff --git a/README.md b/README.md index 1f69225..3a393b0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ ### 数据校对 * 日K线校对 - ![](docs/check_kline.png) ![](docs/check_kline_right.png) +![](docs/check_kline.png) +![](docs/check_kline_right.png) * 校对分时成交 ![](docs/check_trade.png) @@ -40,7 +41,7 @@ func main() { if err != nil { panic(err) } - resp, err := c.GetStockQuotes(map[protocol.Exchange]string{ + resp, err := c.GetQuote(map[protocol.Exchange]string{ protocol.ExchangeSH: "000001", protocol.ExchangeSZ: "600008", }) diff --git a/client.go b/client.go index aab2e00..3527a37 100644 --- a/client.go +++ b/client.go @@ -1,7 +1,6 @@ package tdx import ( - "errors" "fmt" "github.com/injoyai/base/maps" "github.com/injoyai/base/maps/wait/v2" @@ -102,26 +101,26 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) { case protocol.TypeHeart: - case protocol.TypeStockCount: - resp, err = protocol.MStockCount.Decode(f.Data) + case protocol.TypeCount: + resp, err = protocol.MCount.Decode(f.Data) - case protocol.TypeStockList: - resp, err = protocol.MStockList.Decode(f.Data) + case protocol.TypeCode: + resp, err = protocol.MCode.Decode(f.Data) - case protocol.TypeStockQuote: - resp = protocol.MStockQuote.Decode(f.Data) + case protocol.TypeQuote: + resp = protocol.MQuote.Decode(f.Data) - case protocol.TypeStockMinute: - resp, err = protocol.MStockMinute.Decode(f.Data) + case protocol.TypeMinute: + resp, err = protocol.MMinute.Decode(f.Data) - case protocol.TypeStockMinuteTrade: - resp, err = protocol.MStockMinuteTrade.Decode(f.Data, conv.String(val)) //todo + case protocol.TypeMinuteTrade: + resp, err = protocol.MMinuteTrade.Decode(f.Data, conv.String(val)) //todo - case protocol.TypeStockHistoryMinuteTrade: - resp, err = protocol.MStockHistoryMinuteTrade.Decode(f.Data, conv.String(val)) + case protocol.TypeHistoryMinuteTrade: + resp, err = protocol.MHistoryMinuteTrade.Decode(f.Data, conv.String(val)) - case protocol.TypeStockKline: - resp, err = protocol.MStockKline.Decode(f.Data, protocol.TypeKline(conv.Uint16(val))) + case protocol.TypeKline: + resp, err = protocol.MKline.Decode(f.Data, conv.Uint8(val)) default: err = fmt.Errorf("通讯类型未解析:0x%X", f.Type) @@ -149,36 +148,36 @@ func (this *Client) SendFrame(f *protocol.Frame, cache ...any) (any, error) { return this.Wait.Wait(conv.String(this.msgID)) } -// GetStockCount 获取市场内的股票数量 -func (this *Client) GetStockCount(exchange protocol.Exchange) (*protocol.StockCountResp, error) { - f := protocol.MStockCount.Frame(exchange) +// GetCount 获取市场内的股票数量 +func (this *Client) GetCount(exchange protocol.Exchange) (*protocol.CountResp, error) { + f := protocol.MCount.Frame(exchange) result, err := this.SendFrame(f) if err != nil { return nil, err } - return result.(*protocol.StockCountResp), nil + return result.(*protocol.CountResp), nil } -// GetStockList 获取市场内指定范围内的所有证券代码,一次固定返回1000只,上证股票有效范围370-1480 +// GetCode 获取市场内指定范围内的所有证券代码,一次固定返回1000只,上证股票有效范围370-1480 // 上证前370只是395/399开头的(中证500/总交易等辅助类),在后面的话是一些100开头的国债 // 600开头的股票是上证A股,属于大盘股,其中6006开头的股票是最早上市的股票, 6016开头的股票为大盘蓝筹股;900开头的股票是上证B股; // 000开头的股票是深证A股,001、002开头的股票也都属于深证A股, 其中002开头的股票是深证A股中小企业股票;200开头的股票是深证B股; // 300开头的股票是创业板股票;400开头的股票是三板市场股票。 -func (this *Client) GetStockList(exchange protocol.Exchange, start uint16) (*protocol.StockListResp, error) { - f := protocol.MStockList.Frame(exchange, start) +func (this *Client) GetCode(exchange protocol.Exchange, start uint16) (*protocol.CodeResp, error) { + f := protocol.MCode.Frame(exchange, start) result, err := this.SendFrame(f) if err != nil { return nil, err } - return result.(*protocol.StockListResp), nil + return result.(*protocol.CodeResp), nil } -// GetStockAll 通过多次请求的方式获取全部证券代码 -func (this *Client) GetStockAll(exchange protocol.Exchange) (*protocol.StockListResp, error) { - resp := &protocol.StockListResp{} +// GetCodeAll 通过多次请求的方式获取全部证券代码 +func (this *Client) GetCodeAll(exchange protocol.Exchange) (*protocol.CodeResp, error) { + resp := &protocol.CodeResp{} size := uint16(1000) for start := uint16(0); ; start += size { - r, err := this.GetStockList(exchange, start) + r, err := this.GetCode(exchange, start) if err != nil { return nil, err } @@ -191,9 +190,9 @@ func (this *Client) GetStockAll(exchange protocol.Exchange) (*protocol.StockList return resp, nil } -// GetStockQuotes 获取盘口五档报价 -func (this *Client) GetStockQuotes(m map[protocol.Exchange]string) (protocol.StockQuotesResp, error) { - f, err := protocol.MStockQuote.Frame(m) +// GetQuote 获取盘口五档报价 +func (this *Client) GetQuote(m map[protocol.Exchange]string) (protocol.QuotesResp, error) { + f, err := protocol.MQuote.Frame(m) if err != nil { return nil, err } @@ -201,12 +200,12 @@ func (this *Client) GetStockQuotes(m map[protocol.Exchange]string) (protocol.Sto if err != nil { return nil, err } - return result.(protocol.StockQuotesResp), nil + return result.(protocol.QuotesResp), nil } -// GetStockMinute 获取分时数据,todo 解析好像不对 -func (this *Client) GetStockMinute(exchange protocol.Exchange, code string) (*protocol.StockMinuteResp, error) { - f, err := protocol.MStockMinute.Frame(exchange, code) +// GetMinute 获取分时数据,todo 解析好像不对 +func (this *Client) GetMinute(exchange protocol.Exchange, code string) (*protocol.MinuteResp, error) { + f, err := protocol.MMinute.Frame(exchange, code) if err != nil { return nil, err } @@ -214,31 +213,33 @@ func (this *Client) GetStockMinute(exchange protocol.Exchange, code string) (*pr if err != nil { return nil, err } - return result.(*protocol.StockMinuteResp), nil + return result.(*protocol.MinuteResp), nil } -// GetStockMinuteTrade 获取分时交易详情,服务器最多返回1800条,count-start<=1800 -func (this *Client) GetStockMinuteTrade(exchange protocol.Exchange, code string, start, count uint16) (*protocol.StockMinuteTradeResp, error) { - if count > 1800 { - return nil, errors.New("数量不能超过1800") - } - f, err := protocol.MStockMinuteTrade.Frame(exchange, code, start, count) +// GetMinuteTrade 获取分时交易详情,服务器最多返回1800条,count-start<=1800 +func (this *Client) GetMinuteTrade(req protocol.MinuteTradeReq) (*protocol.MinuteTradeResp, error) { + f, err := protocol.MMinuteTrade.Frame(req) if err != nil { return nil, err } - result, err := this.SendFrame(f, code) + result, err := this.SendFrame(f, req.Code) if err != nil { return nil, err } - return result.(*protocol.StockMinuteTradeResp), nil + return result.(*protocol.MinuteTradeResp), nil } -// GetStockMinuteTradeAll 获取分时全部交易详情,todo 只做参考 因为交易实时在进行,然后又是分页读取的,所以会出现读取间隔内产生的交易会丢失 -func (this *Client) GetStockMinuteTradeAll(exchange protocol.Exchange, code string) (*protocol.StockMinuteTradeResp, error) { - resp := &protocol.StockMinuteTradeResp{} +// GetMinuteTradeAll 获取分时全部交易详情,todo 只做参考 因为交易实时在进行,然后又是分页读取的,所以会出现读取间隔内产生的交易会丢失 +func (this *Client) GetMinuteTradeAll(exchange protocol.Exchange, code string) (*protocol.MinuteTradeResp, error) { + resp := &protocol.MinuteTradeResp{} size := uint16(1800) - for i := uint16(0); ; i += size { - r, err := this.GetStockMinuteTrade(exchange, code, i, size) + for start := uint16(0); ; start += size { + r, err := this.GetMinuteTrade(protocol.MinuteTradeReq{ + Exchange: exchange, + Code: code, + Start: start, + Count: size, + }) if err != nil { return nil, err } @@ -252,33 +253,36 @@ func (this *Client) GetStockMinuteTradeAll(exchange protocol.Exchange, code stri return resp, nil } -// GetStockHistoryMinuteTrade 获取历史分时交易,,只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000 -func (this *Client) GetStockHistoryMinuteTrade(t time.Time, exchange protocol.Exchange, code string, start, count uint16) (*protocol.StockHistoryMinuteTradeResp, error) { - if count > 2000 { - return nil, errors.New("数量不能超过2000") - } - f, err := protocol.MStockHistoryMinuteTrade.Frame(t, exchange, code, start, count) +// GetHistoryMinuteTrade 获取历史分时交易,,只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000,如果日期输入错误,则返回0 +func (this *Client) GetHistoryMinuteTrade(req protocol.HistoryMinuteTradeReq) (*protocol.HistoryMinuteTradeResp, error) { + f, err := protocol.MHistoryMinuteTrade.Frame(req) if err != nil { return nil, err } - result, err := this.SendFrame(f, code) + result, err := this.SendFrame(f, req.Code) if err != nil { return nil, err } - return result.(*protocol.StockHistoryMinuteTradeResp), nil + return result.(*protocol.HistoryMinuteTradeResp), nil } -// GetStockHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据 -func (this *Client) GetStockHistoryMinuteTradeAll(exchange protocol.Exchange, code string) (*protocol.StockMinuteTradeResp, error) { - resp := &protocol.StockMinuteTradeResp{} +// GetHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据 +func (this *Client) GetHistoryMinuteTradeAll(req protocol.HistoryMinuteTradeAllReq) (*protocol.HistoryMinuteTradeResp, error) { + resp := &protocol.HistoryMinuteTradeResp{} size := uint16(2000) - for i := uint16(0); ; i += size { - r, err := this.GetStockMinuteTrade(exchange, code, i, size) + for start := uint16(0); ; start += size { + r, err := this.GetHistoryMinuteTrade(protocol.HistoryMinuteTradeReq{ + Date: req.Date, + Exchange: req.Exchange, + Code: req.Code, + Start: start, + Count: size, + }) if err != nil { return nil, err } resp.Count += r.Count - resp.List = append(resp.List, r.List...) + resp.List = append(r.List, resp.List...) if r.Count < size { break } @@ -286,26 +290,26 @@ func (this *Client) GetStockHistoryMinuteTradeAll(exchange protocol.Exchange, co return resp, nil } -// GetStockKline 获取k线数据 -func (this *Client) GetStockKline(Type protocol.TypeKline, req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - f, err := protocol.MStockKline.Frame(Type, req) +// GetKline 获取k线数据 +func (this *Client) GetKline(Type uint8, req protocol.KlineReq) (*protocol.KlineResp, error) { + f, err := protocol.MKline.Frame(Type, req) if err != nil { return nil, err } - result, err := this.SendFrame(f, Type.Uint16()) + result, err := this.SendFrame(f, Type) if err != nil { return nil, err } - return result.(*protocol.StockKlineResp), nil + return result.(*protocol.KlineResp), nil } -// GetStockKlineAll 获取全部k线数据 -func (this *Client) GetStockKlineAll(Type protocol.TypeKline, exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - resp := &protocol.StockKlineResp{} +// GetKlineAll 获取全部k线数据 +func (this *Client) GetKlineAll(Type uint8, exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + resp := &protocol.KlineResp{} size := uint16(800) - var last *protocol.StockKline + var last *protocol.Kline for i := uint16(0); ; i += size { - r, err := this.GetStockKline(Type, &protocol.StockKlineReq{ + r, err := this.GetKline(Type, protocol.KlineReq{ Exchange: exchange, Code: code, Start: i, @@ -329,102 +333,102 @@ func (this *Client) GetStockKlineAll(Type protocol.TypeKline, exchange protocol. return resp, nil } -// GetStockKlineMinute 获取一分钟k线数据 -func (this *Client) GetStockKlineMinute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineMinute, req) +// GetKlineMinute 获取一分钟k线数据 +func (this *Client) GetKlineMinute(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineMinute, req) } -// GetStockKlineMinuteAll 获取一分钟k线全部数据 -func (this *Client) GetStockKlineMinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineMinute, exchange, code) +// GetKlineMinuteAll 获取一分钟k线全部数据 +func (this *Client) GetKlineMinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineMinute, exchange, code) } -// GetStockKline5Minute 获取五分钟k线数据 -func (this *Client) GetStockKline5Minute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKline5Minute, req) +// GetKline5Minute 获取五分钟k线数据 +func (this *Client) GetKline5Minute(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKline5Minute, req) } -// GetStockKline5MinuteAll 获取5分钟k线全部数据 -func (this *Client) GetStockKline5MinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKline5Minute, exchange, code) +// GetKline5MinuteAll 获取5分钟k线全部数据 +func (this *Client) GetKline5MinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKline5Minute, exchange, code) } -// GetStockKline15Minute 获取十五分钟k线数据 -func (this *Client) GetStockKline15Minute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKline15Minute, req) +// GetKline15Minute 获取十五分钟k线数据 +func (this *Client) GetKline15Minute(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKline15Minute, req) } -// GetStockKline15MinuteAll 获取十五分钟k线全部数据 -func (this *Client) GetStockKline15MinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKline15Minute, exchange, code) +// GetKline15MinuteAll 获取十五分钟k线全部数据 +func (this *Client) GetKline15MinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKline15Minute, exchange, code) } -// GetStockKline30Minute 获取三十分钟k线数据 -func (this *Client) GetStockKline30Minute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKline30Minute, req) +// GetKline30Minute 获取三十分钟k线数据 +func (this *Client) GetKline30Minute(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKline30Minute, req) } -// GetStockKline30MinuteAll 获取三十分钟k线全部数据 -func (this *Client) GetStockKline30MinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKline30Minute, exchange, code) +// GetKline30MinuteAll 获取三十分钟k线全部数据 +func (this *Client) GetKline30MinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKline30Minute, exchange, code) } -// GetStockKlineHour 获取小时k线数据 -func (this *Client) GetStockKlineHour(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineHour, req) +// GetKlineHour 获取小时k线数据 +func (this *Client) GetKlineHour(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineHour, req) } -// GetStockKlineHourAll 获取小时k线全部数据 -func (this *Client) GetStockKlineHourAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineHour, exchange, code) +// GetKlineHourAll 获取小时k线全部数据 +func (this *Client) GetKlineHourAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineHour, exchange, code) } -// GetStockKlineDay 获取日k线数据 -func (this *Client) GetStockKlineDay(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineDay, req) +// GetKlineDay 获取日k线数据 +func (this *Client) GetKlineDay(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineDay, req) } -// GetStockKlineDayAll 获取日k线全部数据 -func (this *Client) GetStockKlineDayAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineDay, exchange, code) +// GetKlineDayAll 获取日k线全部数据 +func (this *Client) GetKlineDayAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineDay, exchange, code) } -// GetStockKlineWeek 获取周k线数据 -func (this *Client) GetStockKlineWeek(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineWeek, req) +// GetKlineWeek 获取周k线数据 +func (this *Client) GetKlineWeek(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineWeek, req) } -// GetStockKlineWeekAll 获取周k线全部数据 -func (this *Client) GetStockKlineWeekAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineWeek, exchange, code) +// GetKlineWeekAll 获取周k线全部数据 +func (this *Client) GetKlineWeekAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineWeek, exchange, code) } // GetStockKlineMonth 获取月k线数据 -func (this *Client) GetStockKlineMonth(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineMonth, req) +func (this *Client) GetStockKlineMonth(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineMonth, req) } -// GetStockKlineMonthAll 获取月k线全部数据 -func (this *Client) GetStockKlineMonthAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineMonth, exchange, code) +// GetKlineMonthAll 获取月k线全部数据 +func (this *Client) GetKlineMonthAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineMonth, exchange, code) } -// GetStockKlineQuarter 获取季k线数据 -func (this *Client) GetStockKlineQuarter(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineQuarter, req) +// GetKlineQuarter 获取季k线数据 +func (this *Client) GetKlineQuarter(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineQuarter, req) } -// GetStockKlineQuarterAll 获取季k线全部数据 -func (this *Client) GetStockKlineQuarterAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineQuarter, exchange, code) +// GetKlineQuarterAll 获取季k线全部数据 +func (this *Client) GetKlineQuarterAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineQuarter, exchange, code) } -// GetStockKlineYear 获取年k线数据 -func (this *Client) GetStockKlineYear(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { - return this.GetStockKline(protocol.TypeKlineYear, req) +// GetKlineYear 获取年k线数据 +func (this *Client) GetKlineYear(req protocol.KlineReq) (*protocol.KlineResp, error) { + return this.GetKline(protocol.TypeKlineYear, req) } -// GetStockKlineYearAll 获取年k线数据 -func (this *Client) GetStockKlineYearAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { - return this.GetStockKlineAll(protocol.TypeKlineYear, exchange, code) +// GetKlineYearAll 获取年k线数据 +func (this *Client) GetKlineYearAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) { + return this.GetKlineAll(protocol.TypeKlineYear, exchange, code) } diff --git a/client_test.go b/client_test.go index 32df501..adb9c74 100644 --- a/client_test.go +++ b/client_test.go @@ -23,9 +23,14 @@ func init() { } func TestClient_GetStockHistoryMinuteTrade(t *testing.T) { - ti := time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local) do(func(c *Client) { - resp, err := c.GetStockHistoryMinuteTrade(ti, protocol.ExchangeSH, "000001", 0, 100) + resp, err := c.GetStockHistoryMinuteTrade(protocol.StockHistoryMinuteTradeReq{ + Time: time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local), + Exchange: protocol.ExchangeSZ, + Code: "000001", + Start: 0, + Count: 100, + }) if err != nil { t.Error(err) return diff --git a/example/GetStockList/main.go b/example/GetCode/main.go similarity index 85% rename from example/GetStockList/main.go rename to example/GetCode/main.go index 84210cf..591de8c 100644 --- a/example/GetStockList/main.go +++ b/example/GetCode/main.go @@ -10,7 +10,7 @@ func main() { c, err := tdx.Dial("124.71.187.122:7709") logs.PanicErr(err) - resp, err := c.GetStockList(protocol.ExchangeSH, 369) + resp, err := c.GetCode(protocol.ExchangeSH, 369) logs.PanicErr(err) for i, v := range resp.List { diff --git a/example/GetStockAll/main.go b/example/GetCodeAll/main.go similarity index 86% rename from example/GetStockAll/main.go rename to example/GetCodeAll/main.go index b8d9224..fb5acb9 100644 --- a/example/GetStockAll/main.go +++ b/example/GetCodeAll/main.go @@ -9,7 +9,7 @@ import ( func main() { common.Test(func(c *tdx.Client) { - resp, err := c.GetStockAll(protocol.ExchangeSZ) + resp, err := c.GetCodeAll(protocol.ExchangeSZ) logs.PanicErr(err) for _, v := range resp.List { diff --git a/example/GetStockCount/main.go b/example/GetCount/main.go similarity index 83% rename from example/GetStockCount/main.go rename to example/GetCount/main.go index b9d59bd..d80cf19 100644 --- a/example/GetStockCount/main.go +++ b/example/GetCount/main.go @@ -10,7 +10,7 @@ func main() { c, err := tdx.Dial("124.71.187.122:7709") logs.PanicErr(err) - resp, err := c.GetStockCount(protocol.ExchangeSH) + resp, err := c.GetCount(protocol.ExchangeSH) logs.PanicErr(err) logs.Debug(resp.Count) diff --git a/example/GetHistoryMinuteTrade/main.go b/example/GetHistoryMinuteTrade/main.go new file mode 100644 index 0000000..138767b --- /dev/null +++ b/example/GetHistoryMinuteTrade/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "github.com/injoyai/logs" + "github.com/injoyai/tdx" + "github.com/injoyai/tdx/example/common" + "github.com/injoyai/tdx/protocol" +) + +func main() { + common.Test(func(c *tdx.Client) { + resp, err := c.GetHistoryMinuteTrade(protocol.HistoryMinuteTradeReq{ + Date: "20241027", + Exchange: protocol.ExchangeSZ, + Code: "000001", + Count: 10, + }) + logs.PanicErr(err) + + for _, v := range resp.List { + logs.Debug(v) + } + + logs.Debug("总数:", resp.Count) + }) +} diff --git a/example/GetStockHistoryMinuteTrade/main.go b/example/GetHistoryMinuteTradeAll/main.go similarity index 66% rename from example/GetStockHistoryMinuteTrade/main.go rename to example/GetHistoryMinuteTradeAll/main.go index e2fe06a..6cb9886 100644 --- a/example/GetStockHistoryMinuteTrade/main.go +++ b/example/GetHistoryMinuteTradeAll/main.go @@ -5,13 +5,15 @@ import ( "github.com/injoyai/tdx" "github.com/injoyai/tdx/example/common" "github.com/injoyai/tdx/protocol" - "time" ) func main() { common.Test(func(c *tdx.Client) { - t := time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local) - resp, err := c.GetStockHistoryMinuteTrade(t, protocol.ExchangeSH, "000001", 0, 2000) + resp, err := c.GetHistoryMinuteTradeAll(protocol.HistoryMinuteTradeAllReq{ + Date: "20241027", + Exchange: protocol.ExchangeSZ, + Code: "000001", + }) logs.PanicErr(err) for _, v := range resp.List { diff --git a/example/GetStockKline/main.go b/example/GetKline/main.go similarity index 82% rename from example/GetStockKline/main.go rename to example/GetKline/main.go index cd49936..76dc7fa 100644 --- a/example/GetStockKline/main.go +++ b/example/GetKline/main.go @@ -9,7 +9,7 @@ import ( func main() { common.Test(func(c *tdx.Client) { - resp, err := c.GetStockKlineDayAll(protocol.ExchangeSH, "000001") + resp, err := c.GetKlineDayAll(protocol.ExchangeSH, "000001") logs.PanicErr(err) for _, v := range resp.List { diff --git a/example/GetStockMinute/main.go b/example/GetMinute/main.go similarity index 81% rename from example/GetStockMinute/main.go rename to example/GetMinute/main.go index 4da7cef..97b67b2 100644 --- a/example/GetStockMinute/main.go +++ b/example/GetMinute/main.go @@ -10,7 +10,7 @@ func main() { c, err := tdx.Dial("124.71.187.122:7709") logs.PanicErr(err) - resp, err := c.GetStockMinute(protocol.ExchangeSH, "000001") + resp, err := c.GetMinute(protocol.ExchangeSH, "000001") logs.PanicErr(err) for _, v := range resp.List { diff --git a/example/GetStockMinuteTrade/main.go b/example/GetMinuteTrade/main.go similarity index 68% rename from example/GetStockMinuteTrade/main.go rename to example/GetMinuteTrade/main.go index a13a8b1..26acc8f 100644 --- a/example/GetStockMinuteTrade/main.go +++ b/example/GetMinuteTrade/main.go @@ -10,7 +10,12 @@ import ( func main() { common.Test(func(c *tdx.Client) { - resp, err := c.GetStockMinuteTrade(protocol.ExchangeSH, "000001", 0, 100) + resp, err := c.GetMinuteTrade(protocol.MinuteTradeReq{ + Exchange: protocol.ExchangeSZ, + Code: "000001", + Start: 0, + Count: 100, + }) logs.PanicErr(err) for _, v := range resp.List { diff --git a/example/GetStockQuotes/main.go b/example/GetQuote/main.go similarity index 88% rename from example/GetStockQuotes/main.go rename to example/GetQuote/main.go index 9327796..e6a8c88 100644 --- a/example/GetStockQuotes/main.go +++ b/example/GetQuote/main.go @@ -21,9 +21,9 @@ func main() { b1cb74001c00000000000d005100bd00789c6378c1cecb252ace6066c5b4898987b9050ed1f90cc5b74c18a5bc18c1b43490fecff09c81819191f13fc3c9f3bb169f5e7dfefeb5ef57f7199a305009308208e5b32bb6bcbf70148712002d7f1e13 b1cb74000c02000000003e05ac00ac000102020000303030303031601294121a1c2d4eadabcf0ed412aae5fc01afb0024561124fbcc08301afa47900b2e3174100bf68871a4201b741b6144302bb09af334403972e96354504ac09b619560e00000000f8ff601201363030303038b60fba04060607429788a70efa04ada37ab2531c12974d91e7449dbc354184b6010001844bad324102b5679ea1014203a65abd8d0143048a6ba4dd01440587e101b3d2029613000000000000b60f */ - resp, err := c.GetStockQuotes(map[protocol.Exchange]string{ - protocol.ExchangeSH: "000001", - protocol.ExchangeSZ: "600008", + resp, err := c.GetQuote(map[protocol.Exchange]string{ + protocol.ExchangeSZ: "000001", + protocol.ExchangeSH: "600008", }) logs.PanicErr(err) diff --git a/protocol/const.go b/protocol/const.go index 196fc8d..40bdc72 100644 --- a/protocol/const.go +++ b/protocol/const.go @@ -1,15 +1,15 @@ package protocol const ( - TypeConnect = 0x000D //建立连接 - TypeHeart = 0x0004 //心跳 - TypeStockCount = 0x044E //获取股票数量 - TypeStockList = 0x0450 //获取股票代码 - TypeStockQuote = 0x053E //行情信息 - TypeStockMinute = 0x051D //分时数据 - TypeStockMinuteTrade = 0x0FC5 //分时交易 - TypeStockHistoryMinuteTrade = 0x0FB5 //历史分时交易 - TypeStockKline = 0x052D //K线图 + TypeConnect = 0x000D //建立连接 + TypeHeart = 0x0004 //心跳 + TypeCount = 0x044E //获取股票数量 + TypeCode = 0x0450 //获取股票代码 + TypeQuote = 0x053E //行情信息 + TypeMinute = 0x051D //分时数据 + TypeMinuteTrade = 0x0FC5 //分时交易 + TypeHistoryMinuteTrade = 0x0FB5 //历史分时交易 + TypeKline = 0x052D //K线图 ) /* diff --git a/protocol/frame.go b/protocol/frame.go index 4e9e305..664429e 100644 --- a/protocol/frame.go +++ b/protocol/frame.go @@ -84,7 +84,7 @@ func Decode(bs []byte) (*Response, error) { } if resp.Control&0x10 != 0x10 { - //return nil, fmt.Errorf("控制码不匹配,预期0x1c,得到0x%x", resp.Control) + return nil, fmt.Errorf("请求失败,请检查参数") } if int(resp.ZipLength) != len(bs[16:]) { diff --git a/protocol/model_stock_list.go b/protocol/model_code.go similarity index 74% rename from protocol/model_stock_list.go rename to protocol/model_code.go index 066f8c6..501982d 100644 --- a/protocol/model_stock_list.go +++ b/protocol/model_code.go @@ -5,12 +5,12 @@ import ( "fmt" ) -type StockListResp struct { +type CodeResp struct { Count uint16 - List []*Stock + List []*Code } -type Stock struct { +type Code struct { Name string //股票名称 Code string //股票代码 Multiple uint16 //倍数,基本是0x64=100 @@ -18,33 +18,33 @@ type Stock struct { PreClose float64 //未知 } -func (this *Stock) String() string { +func (this *Code) String() string { return fmt.Sprintf("%s(%s)", this.Code, this.Name) } -type stockList struct{} +type code struct{} -func (stockList) Frame(exchange Exchange, start uint16) *Frame { +func (code) Frame(exchange Exchange, start uint16) *Frame { return &Frame{ Control: Control01, - Type: TypeStockList, + Type: TypeCode, Data: []byte{exchange.Uint8(), 0x0, uint8(start), uint8(start >> 8)}, } } -func (stockList) Decode(bs []byte) (*StockListResp, error) { +func (code) Decode(bs []byte) (*CodeResp, error) { if len(bs) < 2 { return nil, errors.New("数据长度不足") } - resp := &StockListResp{ + resp := &CodeResp{ Count: Uint16(bs[:2]), } bs = bs[2:] for i := uint16(0); i < resp.Count; i++ { - sec := &Stock{ + sec := &Code{ Code: string(bs[:6]), Multiple: Uint16(bs[6:8]), Name: string(UTF8ToGBK(bs[8:16])), diff --git a/protocol/model_connect.go b/protocol/model_connect.go index ae69758..4a7a10e 100644 --- a/protocol/model_connect.go +++ b/protocol/model_connect.go @@ -5,15 +5,15 @@ import ( ) var ( - MConnect = connect{} - MHeart = heart{} - MStockCount = stockCount{} - MStockQuote = stockQuote{} - MStockList = stockList{} - MStockMinute = stockMinute{} - MStockMinuteTrade = stockMinuteTrade{} - MStockHistoryMinuteTrade = stockHistoryMinuteTrade{} - MStockKline = stockKline{} + MConnect = connect{} + MHeart = heart{} + MCount = count{} + MQuote = quote{} + MCode = code{} + MMinute = minute{} + MMinuteTrade = minuteTrade{} + MHistoryMinuteTrade = historyMinuteTrade{} + MKline = kline{} ) type ConnectResp struct { diff --git a/protocol/model_stock_count.go b/protocol/model_count.go similarity index 55% rename from protocol/model_stock_count.go rename to protocol/model_count.go index 7abf5f7..8510dfb 100644 --- a/protocol/model_stock_count.go +++ b/protocol/model_count.go @@ -2,24 +2,24 @@ package protocol import "errors" -type StockCountResp struct { +type CountResp struct { Count uint16 } -type stockCount struct{} +type count struct{} // Frame 0c0200000001080008004e04000075c73301 -func (this *stockCount) Frame(exchange Exchange) *Frame { +func (this *count) Frame(exchange Exchange) *Frame { return &Frame{ Control: Control01, - Type: TypeStockCount, + Type: TypeCount, Data: []byte{exchange.Uint8(), 0x0, 0x75, 0xc7, 0x33, 0x01}, //后面的4字节不知道啥意思 } } -func (this *stockCount) Decode(bs []byte) (*StockCountResp, error) { +func (this *count) Decode(bs []byte) (*CountResp, error) { if len(bs) < 2 { return nil, errors.New("数据长度不足") } - return &StockCountResp{Count: Uint16(bs)}, nil + return &CountResp{Count: Uint16(bs)}, nil } diff --git a/protocol/model_history_minute_trade.go b/protocol/model_history_minute_trade.go new file mode 100644 index 0000000..1f84ae0 --- /dev/null +++ b/protocol/model_history_minute_trade.go @@ -0,0 +1,112 @@ +package protocol + +import ( + "errors" + "fmt" + "github.com/injoyai/conv" +) + +// HistoryMinuteTradeAllReq 获取指定日期全部数据的请求参数 +type HistoryMinuteTradeAllReq struct { + Date string //20241030 + Exchange Exchange + Code string +} + +// HistoryMinuteTradeReq 获取指定日期分页数据的请求参数 +type HistoryMinuteTradeReq struct { + Date string //20241030 + Exchange Exchange + Code string + Start uint16 + Count uint16 +} + +func (req HistoryMinuteTradeReq) Check() error { + if req.Count > 2000 { + return errors.New("数量不能超过2000") + } + return nil +} + +// HistoryMinuteTradeResp 历史分时交易比实时少了单量 +type HistoryMinuteTradeResp struct { + Count uint16 + List []*HistoryMinuteTrade +} + +type HistoryMinuteTrade struct { + Time string //时间 + Price Price //价格 + Volume int //成交量 + Status int //0是买,1是卖,2无效(汇总出现) +} + +func (this *HistoryMinuteTrade) String() string { + return fmt.Sprintf("%s \t%s \t%-6s \t%-6d(手) \t%-4s", this.Time, this.Price, this.Amount(), this.Volume, this.StatusString()) +} + +// Amount 成交额 +func (this *HistoryMinuteTrade) Amount() Price { + return this.Price * Price(this.Volume) * 100 +} + +func (this *HistoryMinuteTrade) StatusString() string { + switch this.Status { + case 0: + return "买入" + case 1: + return "卖出" + default: + return "" + } +} + +type historyMinuteTrade struct{} + +func (historyMinuteTrade) Frame(req HistoryMinuteTradeReq) (*Frame, error) { + if err := req.Check(); err != nil { + return nil, err + } + date := conv.Uint32(req.Date) //req.Time.Format("20060102")) + dataBs := Bytes(date) + dataBs = append(dataBs, req.Exchange.Uint8(), 0x0) + dataBs = append(dataBs, []byte(req.Code)...) + dataBs = append(dataBs, Bytes(req.Start)...) + dataBs = append(dataBs, Bytes(req.Count)...) + return &Frame{ + Control: Control01, + Type: TypeHistoryMinuteTrade, + Data: dataBs, + }, nil +} + +func (historyMinuteTrade) Decode(bs []byte, code string) (*HistoryMinuteTradeResp, error) { + if len(bs) < 2 { + return nil, errors.New("数据长度不足") + } + + resp := &HistoryMinuteTradeResp{ + Count: Uint16(bs[:2]), + } + + //第2-6字节不知道是啥 + bs = bs[2+4:] + + lastPrice := Price(0) + for i := uint16(0); i < resp.Count; i++ { + mt := &HistoryMinuteTrade{ + Time: GetHourMinute([2]byte(bs[:2])), + } + var sub Price + bs, sub = GetPrice(bs[2:]) + lastPrice += sub + mt.Price = lastPrice / basePrice(code) + bs, mt.Volume = CutInt(bs) + bs, mt.Status = CutInt(bs) + bs, _ = CutInt(bs) //这个得到的是0,不知道是啥 + resp.List = append(resp.List, mt) + } + + return resp, nil +} diff --git a/protocol/model_stock_history_minute_trade_test.go b/protocol/model_history_minute_trade_test.go similarity index 59% rename from protocol/model_stock_history_minute_trade_test.go rename to protocol/model_history_minute_trade_test.go index 75f6871..d3484c3 100644 --- a/protocol/model_stock_history_minute_trade_test.go +++ b/protocol/model_history_minute_trade_test.go @@ -8,8 +8,13 @@ import ( func Test_stockHistoryMinuteTrade_Frame(t *testing.T) { // 预期 0c 02000000 00 1200 1200 b50f 84da3401 0000 30303030303100006400 // 0c000000000112001200b50f84da3401000030303030303100006400 - ti := time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local) - f, err := MStockHistoryMinuteTrade.Frame(ti, ExchangeSH, "000001", 0, 100) + f, err := MStockHistoryMinuteTrade.Frame(StockHistoryMinuteTradeReq{ + Time: time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local), + Exchange: ExchangeSZ, + Code: "000001", + Start: 0, + Count: 100, + }) if err != nil { t.Error(err) return diff --git a/protocol/model_stock_kline.go b/protocol/model_kline.go similarity index 80% rename from protocol/model_stock_kline.go rename to protocol/model_kline.go index 1f9c0dc..a18b966 100644 --- a/protocol/model_stock_kline.go +++ b/protocol/model_kline.go @@ -7,14 +7,14 @@ import ( "time" ) -type StockKlineReq struct { +type KlineReq struct { Exchange Exchange Code string Start uint16 Count uint16 } -func (this *StockKlineReq) Bytes(Type TypeKline) (g.Bytes, error) { +func (this *KlineReq) Bytes(Type uint8) (g.Bytes, error) { if this.Count > 800 { return nil, errors.New("单次数量不能超过800") } @@ -23,7 +23,7 @@ func (this *StockKlineReq) Bytes(Type TypeKline) (g.Bytes, error) { } data := []byte{this.Exchange.Uint8(), 0x0} data = append(data, []byte(this.Code)...) //这里怎么是正序了? - data = append(data, Bytes(Type.Uint16())...) + data = append(data, Type, 0x0) data = append(data, 0x01, 0x0) data = append(data, Bytes(this.Start)...) data = append(data, Bytes(this.Count)...) @@ -31,12 +31,12 @@ func (this *StockKlineReq) Bytes(Type TypeKline) (g.Bytes, error) { return data, nil } -type StockKlineResp struct { +type KlineResp struct { Count uint16 - List []*StockKline + List []*Kline } -type StockKline struct { +type Kline struct { Last Price //昨日收盘价,这个是列表的上一条数据的收盘价,如果没有上条数据,那么这个值为0 Open Price //开盘价 High Price //最高价 @@ -47,7 +47,7 @@ type StockKline struct { Time time.Time //时间 } -func (this *StockKline) String() string { +func (this *Kline) String() string { return fmt.Sprintf("%s 昨收盘:%s 开盘价:%s 最高价:%s 最低价:%s 收盘价:%s 涨跌:%s 涨跌幅:%0.2f 成交量:%s 成交额:%s", this.Time.Format("2006-01-02 15:04:05"), this.Last, this.Open, this.High, this.Low, this.Close, @@ -57,12 +57,12 @@ func (this *StockKline) String() string { } // MaxDifference 最大差值,最高-最低 -func (this *StockKline) MaxDifference() Price { +func (this *Kline) MaxDifference() Price { return this.High - this.Low } // RisePrice 涨跌金额,第一个数据不准,仅做参考 -func (this *StockKline) RisePrice() Price { +func (this *Kline) RisePrice() Price { if this.Last == 0 { //稍微数据准确点,没减去0这么夸张,还是不准的 return this.Close - this.Open @@ -72,31 +72,31 @@ func (this *StockKline) RisePrice() Price { } // RiseRate 涨跌比例/涨跌幅,第一个数据不准,仅做参考 -func (this *StockKline) RiseRate() float64 { +func (this *Kline) RiseRate() float64 { return float64(this.RisePrice()) / float64(this.Open) * 100 } -type stockKline struct{} +type kline struct{} -func (stockKline) Frame(Type TypeKline, req *StockKlineReq) (*Frame, error) { +func (kline) Frame(Type uint8, req KlineReq) (*Frame, error) { bs, err := req.Bytes(Type) if err != nil { return nil, err } return &Frame{ Control: Control01, - Type: TypeStockKline, + Type: TypeKline, Data: bs, }, nil } -func (stockKline) Decode(bs []byte, Type TypeKline) (*StockKlineResp, error) { +func (kline) Decode(bs []byte, Type uint8) (*KlineResp, error) { if len(bs) < 2 { return nil, errors.New("数据长度不足") } - resp := &StockKlineResp{ + resp := &KlineResp{ Count: Uint16(bs[:2]), } @@ -104,7 +104,7 @@ func (stockKline) Decode(bs []byte, Type TypeKline) (*StockKlineResp, error) { var last Price //上条数据(昨天)的收盘价 for i := uint16(0); i < resp.Count; i++ { - k := &StockKline{ + k := &Kline{ Time: GetTime([4]byte(bs[:4]), Type), } diff --git a/protocol/model_stock_kline_test.go b/protocol/model_kline_test.go similarity index 100% rename from protocol/model_stock_kline_test.go rename to protocol/model_kline_test.go diff --git a/protocol/model_stock_minute.go b/protocol/model_minute.go similarity index 75% rename from protocol/model_stock_minute.go rename to protocol/model_minute.go index 8449964..9559fde 100644 --- a/protocol/model_stock_minute.go +++ b/protocol/model_minute.go @@ -4,7 +4,7 @@ import ( "errors" ) -type StockMinuteResp struct { +type MinuteResp struct { Count uint16 List []PriceNumber } @@ -14,9 +14,9 @@ type PriceNumber struct { Number int } -type stockMinute struct{} +type minute struct{} -func (this *stockMinute) Frame(exchange Exchange, code string) (*Frame, error) { +func (this *minute) Frame(exchange Exchange, code string) (*Frame, error) { if len(code) != 6 { return nil, errors.New("股票代码长度错误") } @@ -24,18 +24,18 @@ func (this *stockMinute) Frame(exchange Exchange, code string) (*Frame, error) { codeBs = append(codeBs, 0x0, 0x0, 0x0, 0x0) return &Frame{ Control: Control01, - Type: TypeStockMinute, + Type: TypeMinute, Data: append([]byte{exchange.Uint8(), 0x0}, codeBs...), }, nil } -func (this *stockMinute) Decode(bs []byte) (*StockMinuteResp, error) { +func (this *minute) Decode(bs []byte) (*MinuteResp, error) { if len(bs) < 6 { return nil, errors.New("数据长度不足") } - resp := &StockMinuteResp{ + resp := &MinuteResp{ Count: Uint16(bs[:2]), } //2-6字节是啥? diff --git a/protocol/model_minute_trade.go b/protocol/model_minute_trade.go new file mode 100644 index 0000000..7c4d90b --- /dev/null +++ b/protocol/model_minute_trade.go @@ -0,0 +1,125 @@ +package protocol + +import ( + "errors" + "fmt" +) + +type MinuteTradeReq struct { + Exchange Exchange + Code string + Start uint16 + Count uint16 +} + +func (req MinuteTradeReq) Check() error { + if len(req.Code) != 6 { + return errors.New("股票代码长度错误") + } + if req.Count > 1800 { + return errors.New("数量不能超过1800") + } + return nil +} + +type MinuteTradeResp struct { + Count uint16 + List []*MinuteTrade +} + +// MinuteTrade 分时成交,todo 时间没有到秒,客户端上也没有,东方客户端能显示秒 +type MinuteTrade struct { + Time string //时间 + Price Price //价格 + Volume int //成交量 + Number int //单数,历史数据改字段无效 + Status int //0是买,1是卖,2无效(汇总出现) +} + +func (this *MinuteTrade) String() string { + return fmt.Sprintf("%s \t%-6s \t%-6s \t%-6d(手) \t%-4d(单) \t%-4s", + this.Time, this.Price, this.Amount(), this.Volume, this.Number, this.StatusString()) +} + +// Amount 成交额 +func (this *MinuteTrade) Amount() Price { + return this.Price * Price(this.Volume) * 100 +} + +func (this *MinuteTrade) StatusString() string { + switch this.Status { + case 0: + return "买入" + case 1: + return "卖出" + default: + return "" + } +} + +// AvgVolume 平均每单成交量 +func (this *MinuteTrade) AvgVolume() float64 { + return float64(this.Volume) / float64(this.Number) +} + +// AvgPrice 平均每单成交金额 +func (this *MinuteTrade) AvgPrice() Price { + return Price(this.AvgVolume() * float64(this.Price) * 100) +} + +// IsBuy 是否是买单 +func (this *MinuteTrade) IsBuy() bool { + return this.Status == 0 +} + +// IsSell 是否是卖单 +func (this *MinuteTrade) IsSell() bool { + return this.Status == 1 +} + +type minuteTrade struct{} + +func (minuteTrade) Frame(req MinuteTradeReq) (*Frame, error) { + if err := req.Check(); err != nil { + return nil, err + } + codeBs := []byte(req.Code) + codeBs = append(codeBs, Bytes(req.Start)...) + codeBs = append(codeBs, Bytes(req.Count)...) + return &Frame{ + Control: Control01, + Type: TypeMinuteTrade, + Data: append([]byte{req.Exchange.Uint8(), 0x0}, codeBs...), + }, nil +} + +func (minuteTrade) Decode(bs []byte, code string) (*MinuteTradeResp, error) { + + if len(bs) < 2 { + return nil, errors.New("数据长度不足") + } + + resp := &MinuteTradeResp{ + Count: Uint16(bs[:2]), + } + + bs = bs[2:] + + lastPrice := Price(0) + for i := uint16(0); i < resp.Count; i++ { + mt := &MinuteTrade{ + Time: GetHourMinute([2]byte(bs[:2])), + } + var sub Price + bs, sub = GetPrice(bs[2:]) + lastPrice += sub + mt.Price = lastPrice / basePrice(code) + bs, mt.Volume = CutInt(bs) + bs, mt.Number = CutInt(bs) + bs, mt.Status = CutInt(bs) + bs, _ = CutInt(bs) //这个得到的是0,不知道是啥 + resp.List = append(resp.List, mt) + } + + return resp, nil +} diff --git a/protocol/model_stock_quote.go b/protocol/model_quote.go similarity index 91% rename from protocol/model_stock_quote.go rename to protocol/model_quote.go index c00b17f..f6f4748 100644 --- a/protocol/model_stock_quote.go +++ b/protocol/model_quote.go @@ -6,9 +6,9 @@ import ( "strings" ) -type StockQuotesResp []*StockQuote +type QuotesResp []*Quote -func (this StockQuotesResp) String() string { +func (this QuotesResp) String() string { ls := []string(nil) for _, v := range this { ls = append(ls, v.String()) @@ -16,7 +16,7 @@ func (this StockQuotesResp) String() string { return strings.Join(ls, "\n") } -type StockQuote struct { +type Quote struct { Exchange Exchange // 市场 Code string // 股票代码 6个ascii字符串 Active1 uint16 // 活跃度 @@ -45,7 +45,7 @@ type StockQuote struct { Active2 uint16 // 活跃度 } -func (this *StockQuote) String() string { +func (this *Quote) String() string { return fmt.Sprintf(`%s%s %s 总量:%s, 现量:%s, 总金额:%s, 内盘:%s, 外盘:%s @@ -58,12 +58,12 @@ func (this *StockQuote) String() string { ) } -type stockQuote struct{} +type quote struct{} -func (this stockQuote) Frame(m map[Exchange]string) (*Frame, error) { +func (this quote) Frame(m map[Exchange]string) (*Frame, error) { f := &Frame{ Control: Control01, - Type: TypeStockQuote, + Type: TypeQuote, Data: []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, } @@ -105,11 +105,11 @@ b212 昨天收盘价1186 8defd10c 服务时间 c005bed2668e05be15804d8ba12cb3b13a0083c3034100badc029d014201bc990384f70443029da503b7af074403a6e501b9db044504a6e2028dd5048d050000000000005909 */ -func (this stockQuote) Decode(bs []byte) StockQuotesResp { +func (this quote) Decode(bs []byte) QuotesResp { //logs.Debug(hex.EncodeToString(bs)) - resp := StockQuotesResp{} + resp := QuotesResp{} //前2字节是什么? bs = bs[2:] @@ -118,7 +118,7 @@ func (this stockQuote) Decode(bs []byte) StockQuotesResp { bs = bs[2:] for i := uint16(0); i < number; i++ { - sec := &StockQuote{ + sec := &Quote{ Exchange: Exchange(bs[0]), Code: string(UTF8ToGBK(bs[1:7])), Active1: Uint16(bs[7:9]), diff --git a/protocol/model_stock_history_minute_trade.go b/protocol/model_stock_history_minute_trade.go deleted file mode 100644 index ade908b..0000000 --- a/protocol/model_stock_history_minute_trade.go +++ /dev/null @@ -1,66 +0,0 @@ -package protocol - -import ( - "errors" - "github.com/injoyai/conv" - "time" -) - -// StockHistoryMinuteTradeResp 历史分时交易比实时少了单量 -type StockHistoryMinuteTradeResp struct { - Count uint16 - List []*StockMinuteTrade -} - -type StockHistoryMinuteTrade struct { - Time string //时间 - Price Price //价格 - Volume int //成交量 - Status int //0是买,1是卖,2无效(汇总出现) -} - -type stockHistoryMinuteTrade struct{} - -func (stockHistoryMinuteTrade) Frame(t time.Time, exchange Exchange, code string, start, count uint16) (*Frame, error) { - date := conv.Uint32(t.Format("20060102")) - dataBs := Bytes(date) - dataBs = append(dataBs, exchange.Uint8(), 0x0) - dataBs = append(dataBs, []byte(code)...) - dataBs = append(dataBs, Bytes(start)...) - dataBs = append(dataBs, Bytes(count)...) - return &Frame{ - Control: Control01, - Type: TypeStockHistoryMinuteTrade, - Data: dataBs, - }, nil -} - -func (stockHistoryMinuteTrade) Decode(bs []byte, code string) (*StockHistoryMinuteTradeResp, error) { - if len(bs) < 2 { - return nil, errors.New("数据长度不足") - } - - resp := &StockHistoryMinuteTradeResp{ - Count: Uint16(bs[:2]), - } - - //第2-6字节不知道是啥 - bs = bs[2+4:] - - lastPrice := Price(0) - for i := uint16(0); i < resp.Count; i++ { - mt := &StockMinuteTrade{ - Time: GetHourMinute([2]byte(bs[:2])), - } - var sub Price - bs, sub = GetPrice(bs[2:]) - lastPrice += sub - mt.Price = lastPrice / basePrice(code) - bs, mt.Volume = CutInt(bs) - bs, mt.Status = CutInt(bs) - bs, _ = CutInt(bs) //这个得到的是0,不知道是啥 - resp.List = append(resp.List, mt) - } - - return resp, nil -} diff --git a/protocol/model_stock_minute_trade.go b/protocol/model_stock_minute_trade.go deleted file mode 100644 index af0f903..0000000 --- a/protocol/model_stock_minute_trade.go +++ /dev/null @@ -1,107 +0,0 @@ -package protocol - -import ( - "errors" - "fmt" -) - -type StockMinuteTradeResp struct { - Count uint16 - List []*StockMinuteTrade -} - -// StockMinuteTrade 分时成交,todo 时间没有到秒,客户端上也没有,东方客户端能显示秒 -type StockMinuteTrade struct { - Time string //时间 - Price Price //价格 - Volume int //成交量 - Number int //单数 - Status int //0是买,1是卖,2无效(汇总出现) -} - -func (this *StockMinuteTrade) String() string { - return fmt.Sprintf("%s \t%s \t%-6s \t%-6d(手) \t%-4d(单) \t%-4s", this.Time, this.Price, this.Amount(), this.Volume, this.Number, this.StatusString()) -} - -// Amount 成交额 -func (this *StockMinuteTrade) Amount() Price { - return this.Price * Price(this.Volume) * 100 -} - -func (this *StockMinuteTrade) StatusString() string { - switch this.Status { - case 0: - return "买入" - case 1: - return "卖出" - default: - return "" - } -} - -// AvgVolume 平均每单成交量 -func (this *StockMinuteTrade) AvgVolume() float64 { - return float64(this.Volume) / float64(this.Number) -} - -// AvgPrice 平均每单成交金额 -func (this *StockMinuteTrade) AvgPrice() Price { - return Price(this.AvgVolume() * float64(this.Price) * 100) -} - -// IsBuy 是否是买单 -func (this *StockMinuteTrade) IsBuy() bool { - return this.Status == 0 -} - -// IsSell 是否是卖单 -func (this *StockMinuteTrade) IsSell() bool { - return this.Status == 1 -} - -type stockMinuteTrade struct{} - -func (stockMinuteTrade) Frame(exchange Exchange, code string, start, count uint16) (*Frame, error) { - if len(code) != 6 { - return nil, errors.New("股票代码长度错误") - } - codeBs := []byte(code) - codeBs = append(codeBs, Bytes(start)...) - codeBs = append(codeBs, Bytes(count)...) - return &Frame{ - Control: Control01, - Type: TypeStockMinuteTrade, - Data: append([]byte{exchange.Uint8(), 0x0}, codeBs...), - }, nil -} - -func (stockMinuteTrade) Decode(bs []byte, code string) (*StockMinuteTradeResp, error) { - - if len(bs) < 2 { - return nil, errors.New("数据长度不足") - } - - resp := &StockMinuteTradeResp{ - Count: Uint16(bs[:2]), - } - - bs = bs[2:] - - lastPrice := Price(0) - for i := uint16(0); i < resp.Count; i++ { - mt := &StockMinuteTrade{ - Time: GetHourMinute([2]byte(bs[:2])), - } - var sub Price - bs, sub = GetPrice(bs[2:]) - lastPrice += sub - mt.Price = lastPrice / basePrice(code) - bs, mt.Volume = CutInt(bs) - bs, mt.Number = CutInt(bs) - bs, mt.Status = CutInt(bs) - bs, _ = CutInt(bs) //这个得到的是0,不知道是啥 - resp.List = append(resp.List, mt) - } - - return resp, nil -} diff --git a/protocol/unit.go b/protocol/unit.go index a4e4f95..ab616cc 100644 --- a/protocol/unit.go +++ b/protocol/unit.go @@ -81,7 +81,7 @@ func GetHourMinute(bs [2]byte) string { return fmt.Sprintf("%02d:%02d", h, m) } -func GetTime(bs [4]byte, Type TypeKline) time.Time { +func GetTime(bs [4]byte, Type uint8) time.Time { switch Type { case TypeKlineDay2, TypeKlineMinute, TypeKlineMinute2: