减少方法名称长度,去掉固定前缀Stock

This commit is contained in:
injoyai
2024-10-31 10:16:49 +08:00
parent fc604d1eff
commit c6e701af1b
27 changed files with 502 additions and 390 deletions

View File

@@ -16,7 +16,8 @@
### 数据校对 ### 数据校对
* 日K线校对 * 日K线校对
![](docs/check_kline.png) ![](docs/check_kline_right.png) ![](docs/check_kline.png)
![](docs/check_kline_right.png)
* 校对分时成交 * 校对分时成交
![](docs/check_trade.png) ![](docs/check_trade.png)
@@ -40,7 +41,7 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
resp, err := c.GetStockQuotes(map[protocol.Exchange]string{ resp, err := c.GetQuote(map[protocol.Exchange]string{
protocol.ExchangeSH: "000001", protocol.ExchangeSH: "000001",
protocol.ExchangeSZ: "600008", protocol.ExchangeSZ: "600008",
}) })

266
client.go
View File

@@ -1,7 +1,6 @@
package tdx package tdx
import ( import (
"errors"
"fmt" "fmt"
"github.com/injoyai/base/maps" "github.com/injoyai/base/maps"
"github.com/injoyai/base/maps/wait/v2" "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.TypeHeart:
case protocol.TypeStockCount: case protocol.TypeCount:
resp, err = protocol.MStockCount.Decode(f.Data) resp, err = protocol.MCount.Decode(f.Data)
case protocol.TypeStockList: case protocol.TypeCode:
resp, err = protocol.MStockList.Decode(f.Data) resp, err = protocol.MCode.Decode(f.Data)
case protocol.TypeStockQuote: case protocol.TypeQuote:
resp = protocol.MStockQuote.Decode(f.Data) resp = protocol.MQuote.Decode(f.Data)
case protocol.TypeStockMinute: case protocol.TypeMinute:
resp, err = protocol.MStockMinute.Decode(f.Data) resp, err = protocol.MMinute.Decode(f.Data)
case protocol.TypeStockMinuteTrade: case protocol.TypeMinuteTrade:
resp, err = protocol.MStockMinuteTrade.Decode(f.Data, conv.String(val)) //todo resp, err = protocol.MMinuteTrade.Decode(f.Data, conv.String(val)) //todo
case protocol.TypeStockHistoryMinuteTrade: case protocol.TypeHistoryMinuteTrade:
resp, err = protocol.MStockHistoryMinuteTrade.Decode(f.Data, conv.String(val)) resp, err = protocol.MHistoryMinuteTrade.Decode(f.Data, conv.String(val))
case protocol.TypeStockKline: case protocol.TypeKline:
resp, err = protocol.MStockKline.Decode(f.Data, protocol.TypeKline(conv.Uint16(val))) resp, err = protocol.MKline.Decode(f.Data, conv.Uint8(val))
default: default:
err = fmt.Errorf("通讯类型未解析:0x%X", f.Type) 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)) return this.Wait.Wait(conv.String(this.msgID))
} }
// GetStockCount 获取市场内的股票数量 // GetCount 获取市场内的股票数量
func (this *Client) GetStockCount(exchange protocol.Exchange) (*protocol.StockCountResp, error) { func (this *Client) GetCount(exchange protocol.Exchange) (*protocol.CountResp, error) {
f := protocol.MStockCount.Frame(exchange) f := protocol.MCount.Frame(exchange)
result, err := this.SendFrame(f) result, err := this.SendFrame(f)
if err != nil { if err != nil {
return nil, err 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开头的国债 // 上证前370只是395/399开头的(中证500/总交易等辅助类),在后面的话是一些100开头的国债
// 600开头的股票是上证A股属于大盘股其中6006开头的股票是最早上市的股票 6016开头的股票为大盘蓝筹股900开头的股票是上证B股 // 600开头的股票是上证A股属于大盘股其中6006开头的股票是最早上市的股票 6016开头的股票为大盘蓝筹股900开头的股票是上证B股
// 000开头的股票是深证A股001、002开头的股票也都属于深证A股 其中002开头的股票是深证A股中小企业股票200开头的股票是深证B股 // 000开头的股票是深证A股001、002开头的股票也都属于深证A股 其中002开头的股票是深证A股中小企业股票200开头的股票是深证B股
// 300开头的股票是创业板股票400开头的股票是三板市场股票。 // 300开头的股票是创业板股票400开头的股票是三板市场股票。
func (this *Client) GetStockList(exchange protocol.Exchange, start uint16) (*protocol.StockListResp, error) { func (this *Client) GetCode(exchange protocol.Exchange, start uint16) (*protocol.CodeResp, error) {
f := protocol.MStockList.Frame(exchange, start) f := protocol.MCode.Frame(exchange, start)
result, err := this.SendFrame(f) result, err := this.SendFrame(f)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(*protocol.StockListResp), nil return result.(*protocol.CodeResp), nil
} }
// GetStockAll 通过多次请求的方式获取全部证券代码 // GetCodeAll 通过多次请求的方式获取全部证券代码
func (this *Client) GetStockAll(exchange protocol.Exchange) (*protocol.StockListResp, error) { func (this *Client) GetCodeAll(exchange protocol.Exchange) (*protocol.CodeResp, error) {
resp := &protocol.StockListResp{} resp := &protocol.CodeResp{}
size := uint16(1000) size := uint16(1000)
for start := uint16(0); ; start += size { for start := uint16(0); ; start += size {
r, err := this.GetStockList(exchange, start) r, err := this.GetCode(exchange, start)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -191,9 +190,9 @@ func (this *Client) GetStockAll(exchange protocol.Exchange) (*protocol.StockList
return resp, nil return resp, nil
} }
// GetStockQuotes 获取盘口五档报价 // GetQuote 获取盘口五档报价
func (this *Client) GetStockQuotes(m map[protocol.Exchange]string) (protocol.StockQuotesResp, error) { func (this *Client) GetQuote(m map[protocol.Exchange]string) (protocol.QuotesResp, error) {
f, err := protocol.MStockQuote.Frame(m) f, err := protocol.MQuote.Frame(m)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -201,12 +200,12 @@ func (this *Client) GetStockQuotes(m map[protocol.Exchange]string) (protocol.Sto
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(protocol.StockQuotesResp), nil return result.(protocol.QuotesResp), nil
} }
// GetStockMinute 获取分时数据,todo 解析好像不对 // GetMinute 获取分时数据,todo 解析好像不对
func (this *Client) GetStockMinute(exchange protocol.Exchange, code string) (*protocol.StockMinuteResp, error) { func (this *Client) GetMinute(exchange protocol.Exchange, code string) (*protocol.MinuteResp, error) {
f, err := protocol.MStockMinute.Frame(exchange, code) f, err := protocol.MMinute.Frame(exchange, code)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -214,31 +213,33 @@ func (this *Client) GetStockMinute(exchange protocol.Exchange, code string) (*pr
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(*protocol.StockMinuteResp), nil return result.(*protocol.MinuteResp), nil
} }
// GetStockMinuteTrade 获取分时交易详情,服务器最多返回1800条,count-start<=1800 // GetMinuteTrade 获取分时交易详情,服务器最多返回1800条,count-start<=1800
func (this *Client) GetStockMinuteTrade(exchange protocol.Exchange, code string, start, count uint16) (*protocol.StockMinuteTradeResp, error) { func (this *Client) GetMinuteTrade(req protocol.MinuteTradeReq) (*protocol.MinuteTradeResp, error) {
if count > 1800 { f, err := protocol.MMinuteTrade.Frame(req)
return nil, errors.New("数量不能超过1800")
}
f, err := protocol.MStockMinuteTrade.Frame(exchange, code, start, count)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result, err := this.SendFrame(f, code) result, err := this.SendFrame(f, req.Code)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(*protocol.StockMinuteTradeResp), nil return result.(*protocol.MinuteTradeResp), nil
} }
// GetStockMinuteTradeAll 获取分时全部交易详情,todo 只做参考 因为交易实时在进行,然后又是分页读取的,所以会出现读取间隔内产生的交易会丢失 // GetMinuteTradeAll 获取分时全部交易详情,todo 只做参考 因为交易实时在进行,然后又是分页读取的,所以会出现读取间隔内产生的交易会丢失
func (this *Client) GetStockMinuteTradeAll(exchange protocol.Exchange, code string) (*protocol.StockMinuteTradeResp, error) { func (this *Client) GetMinuteTradeAll(exchange protocol.Exchange, code string) (*protocol.MinuteTradeResp, error) {
resp := &protocol.StockMinuteTradeResp{} resp := &protocol.MinuteTradeResp{}
size := uint16(1800) size := uint16(1800)
for i := uint16(0); ; i += size { for start := uint16(0); ; start += size {
r, err := this.GetStockMinuteTrade(exchange, code, i, size) r, err := this.GetMinuteTrade(protocol.MinuteTradeReq{
Exchange: exchange,
Code: code,
Start: start,
Count: size,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -252,33 +253,36 @@ func (this *Client) GetStockMinuteTradeAll(exchange protocol.Exchange, code stri
return resp, nil return resp, nil
} }
// GetStockHistoryMinuteTrade 获取历史分时交易,,只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000 // GetHistoryMinuteTrade 获取历史分时交易,,只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000,如果日期输入错误,则返回0
func (this *Client) GetStockHistoryMinuteTrade(t time.Time, exchange protocol.Exchange, code string, start, count uint16) (*protocol.StockHistoryMinuteTradeResp, error) { func (this *Client) GetHistoryMinuteTrade(req protocol.HistoryMinuteTradeReq) (*protocol.HistoryMinuteTradeResp, error) {
if count > 2000 { f, err := protocol.MHistoryMinuteTrade.Frame(req)
return nil, errors.New("数量不能超过2000")
}
f, err := protocol.MStockHistoryMinuteTrade.Frame(t, exchange, code, start, count)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result, err := this.SendFrame(f, code) result, err := this.SendFrame(f, req.Code)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(*protocol.StockHistoryMinuteTradeResp), nil return result.(*protocol.HistoryMinuteTradeResp), nil
} }
// GetStockHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据 // GetHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据
func (this *Client) GetStockHistoryMinuteTradeAll(exchange protocol.Exchange, code string) (*protocol.StockMinuteTradeResp, error) { func (this *Client) GetHistoryMinuteTradeAll(req protocol.HistoryMinuteTradeAllReq) (*protocol.HistoryMinuteTradeResp, error) {
resp := &protocol.StockMinuteTradeResp{} resp := &protocol.HistoryMinuteTradeResp{}
size := uint16(2000) size := uint16(2000)
for i := uint16(0); ; i += size { for start := uint16(0); ; start += size {
r, err := this.GetStockMinuteTrade(exchange, code, i, size) r, err := this.GetHistoryMinuteTrade(protocol.HistoryMinuteTradeReq{
Date: req.Date,
Exchange: req.Exchange,
Code: req.Code,
Start: start,
Count: size,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp.Count += r.Count resp.Count += r.Count
resp.List = append(resp.List, r.List...) resp.List = append(r.List, resp.List...)
if r.Count < size { if r.Count < size {
break break
} }
@@ -286,26 +290,26 @@ func (this *Client) GetStockHistoryMinuteTradeAll(exchange protocol.Exchange, co
return resp, nil return resp, nil
} }
// GetStockKline 获取k线数据 // GetKline 获取k线数据
func (this *Client) GetStockKline(Type protocol.TypeKline, req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKline(Type uint8, req protocol.KlineReq) (*protocol.KlineResp, error) {
f, err := protocol.MStockKline.Frame(Type, req) f, err := protocol.MKline.Frame(Type, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result, err := this.SendFrame(f, Type.Uint16()) result, err := this.SendFrame(f, Type)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result.(*protocol.StockKlineResp), nil return result.(*protocol.KlineResp), nil
} }
// GetStockKlineAll 获取全部k线数据 // GetKlineAll 获取全部k线数据
func (this *Client) GetStockKlineAll(Type protocol.TypeKline, exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineAll(Type uint8, exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
resp := &protocol.StockKlineResp{} resp := &protocol.KlineResp{}
size := uint16(800) size := uint16(800)
var last *protocol.StockKline var last *protocol.Kline
for i := uint16(0); ; i += size { for i := uint16(0); ; i += size {
r, err := this.GetStockKline(Type, &protocol.StockKlineReq{ r, err := this.GetKline(Type, protocol.KlineReq{
Exchange: exchange, Exchange: exchange,
Code: code, Code: code,
Start: i, Start: i,
@@ -329,102 +333,102 @@ func (this *Client) GetStockKlineAll(Type protocol.TypeKline, exchange protocol.
return resp, nil return resp, nil
} }
// GetStockKlineMinute 获取一分钟k线数据 // GetKlineMinute 获取一分钟k线数据
func (this *Client) GetStockKlineMinute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineMinute(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineMinute, req) return this.GetKline(protocol.TypeKlineMinute, req)
} }
// GetStockKlineMinuteAll 获取一分钟k线全部数据 // GetKlineMinuteAll 获取一分钟k线全部数据
func (this *Client) GetStockKlineMinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineMinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineMinute, exchange, code) return this.GetKlineAll(protocol.TypeKlineMinute, exchange, code)
} }
// GetStockKline5Minute 获取五分钟k线数据 // GetKline5Minute 获取五分钟k线数据
func (this *Client) GetStockKline5Minute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKline5Minute(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKline5Minute, req) return this.GetKline(protocol.TypeKline5Minute, req)
} }
// GetStockKline5MinuteAll 获取5分钟k线全部数据 // GetKline5MinuteAll 获取5分钟k线全部数据
func (this *Client) GetStockKline5MinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKline5MinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKline5Minute, exchange, code) return this.GetKlineAll(protocol.TypeKline5Minute, exchange, code)
} }
// GetStockKline15Minute 获取十五分钟k线数据 // GetKline15Minute 获取十五分钟k线数据
func (this *Client) GetStockKline15Minute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKline15Minute(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKline15Minute, req) return this.GetKline(protocol.TypeKline15Minute, req)
} }
// GetStockKline15MinuteAll 获取十五分钟k线全部数据 // GetKline15MinuteAll 获取十五分钟k线全部数据
func (this *Client) GetStockKline15MinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKline15MinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKline15Minute, exchange, code) return this.GetKlineAll(protocol.TypeKline15Minute, exchange, code)
} }
// GetStockKline30Minute 获取三十分钟k线数据 // GetKline30Minute 获取三十分钟k线数据
func (this *Client) GetStockKline30Minute(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKline30Minute(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKline30Minute, req) return this.GetKline(protocol.TypeKline30Minute, req)
} }
// GetStockKline30MinuteAll 获取三十分钟k线全部数据 // GetKline30MinuteAll 获取三十分钟k线全部数据
func (this *Client) GetStockKline30MinuteAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKline30MinuteAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKline30Minute, exchange, code) return this.GetKlineAll(protocol.TypeKline30Minute, exchange, code)
} }
// GetStockKlineHour 获取小时k线数据 // GetKlineHour 获取小时k线数据
func (this *Client) GetStockKlineHour(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineHour(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineHour, req) return this.GetKline(protocol.TypeKlineHour, req)
} }
// GetStockKlineHourAll 获取小时k线全部数据 // GetKlineHourAll 获取小时k线全部数据
func (this *Client) GetStockKlineHourAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineHourAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineHour, exchange, code) return this.GetKlineAll(protocol.TypeKlineHour, exchange, code)
} }
// GetStockKlineDay 获取日k线数据 // GetKlineDay 获取日k线数据
func (this *Client) GetStockKlineDay(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineDay(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineDay, req) return this.GetKline(protocol.TypeKlineDay, req)
} }
// GetStockKlineDayAll 获取日k线全部数据 // GetKlineDayAll 获取日k线全部数据
func (this *Client) GetStockKlineDayAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineDayAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineDay, exchange, code) return this.GetKlineAll(protocol.TypeKlineDay, exchange, code)
} }
// GetStockKlineWeek 获取周k线数据 // GetKlineWeek 获取周k线数据
func (this *Client) GetStockKlineWeek(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineWeek(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineWeek, req) return this.GetKline(protocol.TypeKlineWeek, req)
} }
// GetStockKlineWeekAll 获取周k线全部数据 // GetKlineWeekAll 获取周k线全部数据
func (this *Client) GetStockKlineWeekAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineWeekAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineWeek, exchange, code) return this.GetKlineAll(protocol.TypeKlineWeek, exchange, code)
} }
// GetStockKlineMonth 获取月k线数据 // GetStockKlineMonth 获取月k线数据
func (this *Client) GetStockKlineMonth(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetStockKlineMonth(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineMonth, req) return this.GetKline(protocol.TypeKlineMonth, req)
} }
// GetStockKlineMonthAll 获取月k线全部数据 // GetKlineMonthAll 获取月k线全部数据
func (this *Client) GetStockKlineMonthAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineMonthAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineMonth, exchange, code) return this.GetKlineAll(protocol.TypeKlineMonth, exchange, code)
} }
// GetStockKlineQuarter 获取季k线数据 // GetKlineQuarter 获取季k线数据
func (this *Client) GetStockKlineQuarter(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineQuarter(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineQuarter, req) return this.GetKline(protocol.TypeKlineQuarter, req)
} }
// GetStockKlineQuarterAll 获取季k线全部数据 // GetKlineQuarterAll 获取季k线全部数据
func (this *Client) GetStockKlineQuarterAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineQuarterAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineQuarter, exchange, code) return this.GetKlineAll(protocol.TypeKlineQuarter, exchange, code)
} }
// GetStockKlineYear 获取年k线数据 // GetKlineYear 获取年k线数据
func (this *Client) GetStockKlineYear(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineYear(req protocol.KlineReq) (*protocol.KlineResp, error) {
return this.GetStockKline(protocol.TypeKlineYear, req) return this.GetKline(protocol.TypeKlineYear, req)
} }
// GetStockKlineYearAll 获取年k线数据 // GetKlineYearAll 获取年k线数据
func (this *Client) GetStockKlineYearAll(exchange protocol.Exchange, code string) (*protocol.StockKlineResp, error) { func (this *Client) GetKlineYearAll(exchange protocol.Exchange, code string) (*protocol.KlineResp, error) {
return this.GetStockKlineAll(protocol.TypeKlineYear, exchange, code) return this.GetKlineAll(protocol.TypeKlineYear, exchange, code)
} }

View File

@@ -23,9 +23,14 @@ func init() {
} }
func TestClient_GetStockHistoryMinuteTrade(t *testing.T) { func TestClient_GetStockHistoryMinuteTrade(t *testing.T) {
ti := time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local)
do(func(c *Client) { 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 { if err != nil {
t.Error(err) t.Error(err)
return return

View File

@@ -10,7 +10,7 @@ func main() {
c, err := tdx.Dial("124.71.187.122:7709") c, err := tdx.Dial("124.71.187.122:7709")
logs.PanicErr(err) logs.PanicErr(err)
resp, err := c.GetStockList(protocol.ExchangeSH, 369) resp, err := c.GetCode(protocol.ExchangeSH, 369)
logs.PanicErr(err) logs.PanicErr(err)
for i, v := range resp.List { for i, v := range resp.List {

View File

@@ -9,7 +9,7 @@ import (
func main() { func main() {
common.Test(func(c *tdx.Client) { common.Test(func(c *tdx.Client) {
resp, err := c.GetStockAll(protocol.ExchangeSZ) resp, err := c.GetCodeAll(protocol.ExchangeSZ)
logs.PanicErr(err) logs.PanicErr(err)
for _, v := range resp.List { for _, v := range resp.List {

View File

@@ -10,7 +10,7 @@ func main() {
c, err := tdx.Dial("124.71.187.122:7709") c, err := tdx.Dial("124.71.187.122:7709")
logs.PanicErr(err) logs.PanicErr(err)
resp, err := c.GetStockCount(protocol.ExchangeSH) resp, err := c.GetCount(protocol.ExchangeSH)
logs.PanicErr(err) logs.PanicErr(err)
logs.Debug(resp.Count) logs.Debug(resp.Count)

View File

@@ -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)
})
}

View File

@@ -5,13 +5,15 @@ import (
"github.com/injoyai/tdx" "github.com/injoyai/tdx"
"github.com/injoyai/tdx/example/common" "github.com/injoyai/tdx/example/common"
"github.com/injoyai/tdx/protocol" "github.com/injoyai/tdx/protocol"
"time"
) )
func main() { func main() {
common.Test(func(c *tdx.Client) { common.Test(func(c *tdx.Client) {
t := time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local) resp, err := c.GetHistoryMinuteTradeAll(protocol.HistoryMinuteTradeAllReq{
resp, err := c.GetStockHistoryMinuteTrade(t, protocol.ExchangeSH, "000001", 0, 2000) Date: "20241027",
Exchange: protocol.ExchangeSZ,
Code: "000001",
})
logs.PanicErr(err) logs.PanicErr(err)
for _, v := range resp.List { for _, v := range resp.List {

View File

@@ -9,7 +9,7 @@ import (
func main() { func main() {
common.Test(func(c *tdx.Client) { common.Test(func(c *tdx.Client) {
resp, err := c.GetStockKlineDayAll(protocol.ExchangeSH, "000001") resp, err := c.GetKlineDayAll(protocol.ExchangeSH, "000001")
logs.PanicErr(err) logs.PanicErr(err)
for _, v := range resp.List { for _, v := range resp.List {

View File

@@ -10,7 +10,7 @@ func main() {
c, err := tdx.Dial("124.71.187.122:7709") c, err := tdx.Dial("124.71.187.122:7709")
logs.PanicErr(err) logs.PanicErr(err)
resp, err := c.GetStockMinute(protocol.ExchangeSH, "000001") resp, err := c.GetMinute(protocol.ExchangeSH, "000001")
logs.PanicErr(err) logs.PanicErr(err)
for _, v := range resp.List { for _, v := range resp.List {

View File

@@ -10,7 +10,12 @@ import (
func main() { func main() {
common.Test(func(c *tdx.Client) { 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) logs.PanicErr(err)
for _, v := range resp.List { for _, v := range resp.List {

View File

@@ -21,9 +21,9 @@ func main() {
b1cb74001c00000000000d005100bd00789c6378c1cecb252ace6066c5b4898987b9050ed1f90cc5b74c18a5bc18c1b43490fecff09c81819191f13fc3c9f3bb169f5e7dfefeb5ef57f7199a305009308208e5b32bb6bcbf70148712002d7f1e13 b1cb74001c00000000000d005100bd00789c6378c1cecb252ace6066c5b4898987b9050ed1f90cc5b74c18a5bc18c1b43490fecff09c81819191f13fc3c9f3bb169f5e7dfefeb5ef57f7199a305009308208e5b32bb6bcbf70148712002d7f1e13
b1cb74000c02000000003e05ac00ac000102020000303030303031601294121a1c2d4eadabcf0ed412aae5fc01afb0024561124fbcc08301afa47900b2e3174100bf68871a4201b741b6144302bb09af334403972e96354504ac09b619560e00000000f8ff601201363030303038b60fba04060607429788a70efa04ada37ab2531c12974d91e7449dbc354184b6010001844bad324102b5679ea1014203a65abd8d0143048a6ba4dd01440587e101b3d2029613000000000000b60f b1cb74000c02000000003e05ac00ac000102020000303030303031601294121a1c2d4eadabcf0ed412aae5fc01afb0024561124fbcc08301afa47900b2e3174100bf68871a4201b741b6144302bb09af334403972e96354504ac09b619560e00000000f8ff601201363030303038b60fba04060607429788a70efa04ada37ab2531c12974d91e7449dbc354184b6010001844bad324102b5679ea1014203a65abd8d0143048a6ba4dd01440587e101b3d2029613000000000000b60f
*/ */
resp, err := c.GetStockQuotes(map[protocol.Exchange]string{ resp, err := c.GetQuote(map[protocol.Exchange]string{
protocol.ExchangeSH: "000001", protocol.ExchangeSZ: "000001",
protocol.ExchangeSZ: "600008", protocol.ExchangeSH: "600008",
}) })
logs.PanicErr(err) logs.PanicErr(err)

View File

@@ -1,15 +1,15 @@
package protocol package protocol
const ( const (
TypeConnect = 0x000D //建立连接 TypeConnect = 0x000D //建立连接
TypeHeart = 0x0004 //心跳 TypeHeart = 0x0004 //心跳
TypeStockCount = 0x044E //获取股票数量 TypeCount = 0x044E //获取股票数量
TypeStockList = 0x0450 //获取股票代码 TypeCode = 0x0450 //获取股票代码
TypeStockQuote = 0x053E //行情信息 TypeQuote = 0x053E //行情信息
TypeStockMinute = 0x051D //分时数据 TypeMinute = 0x051D //分时数据
TypeStockMinuteTrade = 0x0FC5 //分时交易 TypeMinuteTrade = 0x0FC5 //分时交易
TypeStockHistoryMinuteTrade = 0x0FB5 //历史分时交易 TypeHistoryMinuteTrade = 0x0FB5 //历史分时交易
TypeStockKline = 0x052D //K线图 TypeKline = 0x052D //K线图
) )
/* /*

View File

@@ -84,7 +84,7 @@ func Decode(bs []byte) (*Response, error) {
} }
if resp.Control&0x10 != 0x10 { 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:]) { if int(resp.ZipLength) != len(bs[16:]) {

View File

@@ -5,12 +5,12 @@ import (
"fmt" "fmt"
) )
type StockListResp struct { type CodeResp struct {
Count uint16 Count uint16
List []*Stock List []*Code
} }
type Stock struct { type Code struct {
Name string //股票名称 Name string //股票名称
Code string //股票代码 Code string //股票代码
Multiple uint16 //倍数,基本是0x64=100 Multiple uint16 //倍数,基本是0x64=100
@@ -18,33 +18,33 @@ type Stock struct {
PreClose float64 //未知 PreClose float64 //未知
} }
func (this *Stock) String() string { func (this *Code) String() string {
return fmt.Sprintf("%s(%s)", this.Code, this.Name) 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{ return &Frame{
Control: Control01, Control: Control01,
Type: TypeStockList, Type: TypeCode,
Data: []byte{exchange.Uint8(), 0x0, uint8(start), uint8(start >> 8)}, 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 { if len(bs) < 2 {
return nil, errors.New("数据长度不足") return nil, errors.New("数据长度不足")
} }
resp := &StockListResp{ resp := &CodeResp{
Count: Uint16(bs[:2]), Count: Uint16(bs[:2]),
} }
bs = bs[2:] bs = bs[2:]
for i := uint16(0); i < resp.Count; i++ { for i := uint16(0); i < resp.Count; i++ {
sec := &Stock{ sec := &Code{
Code: string(bs[:6]), Code: string(bs[:6]),
Multiple: Uint16(bs[6:8]), Multiple: Uint16(bs[6:8]),
Name: string(UTF8ToGBK(bs[8:16])), Name: string(UTF8ToGBK(bs[8:16])),

View File

@@ -5,15 +5,15 @@ import (
) )
var ( var (
MConnect = connect{} MConnect = connect{}
MHeart = heart{} MHeart = heart{}
MStockCount = stockCount{} MCount = count{}
MStockQuote = stockQuote{} MQuote = quote{}
MStockList = stockList{} MCode = code{}
MStockMinute = stockMinute{} MMinute = minute{}
MStockMinuteTrade = stockMinuteTrade{} MMinuteTrade = minuteTrade{}
MStockHistoryMinuteTrade = stockHistoryMinuteTrade{} MHistoryMinuteTrade = historyMinuteTrade{}
MStockKline = stockKline{} MKline = kline{}
) )
type ConnectResp struct { type ConnectResp struct {

View File

@@ -2,24 +2,24 @@ package protocol
import "errors" import "errors"
type StockCountResp struct { type CountResp struct {
Count uint16 Count uint16
} }
type stockCount struct{} type count struct{}
// Frame 0c0200000001080008004e04000075c73301 // Frame 0c0200000001080008004e04000075c73301
func (this *stockCount) Frame(exchange Exchange) *Frame { func (this *count) Frame(exchange Exchange) *Frame {
return &Frame{ return &Frame{
Control: Control01, Control: Control01,
Type: TypeStockCount, Type: TypeCount,
Data: []byte{exchange.Uint8(), 0x0, 0x75, 0xc7, 0x33, 0x01}, //后面的4字节不知道啥意思 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 { if len(bs) < 2 {
return nil, errors.New("数据长度不足") return nil, errors.New("数据长度不足")
} }
return &StockCountResp{Count: Uint16(bs)}, nil return &CountResp{Count: Uint16(bs)}, nil
} }

View File

@@ -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
}

View File

@@ -8,8 +8,13 @@ import (
func Test_stockHistoryMinuteTrade_Frame(t *testing.T) { func Test_stockHistoryMinuteTrade_Frame(t *testing.T) {
// 预期 0c 02000000 00 1200 1200 b50f 84da3401 0000 30303030303100006400 // 预期 0c 02000000 00 1200 1200 b50f 84da3401 0000 30303030303100006400
// 0c000000000112001200b50f84da3401000030303030303100006400 // 0c000000000112001200b50f84da3401000030303030303100006400
ti := time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local) f, err := MStockHistoryMinuteTrade.Frame(StockHistoryMinuteTradeReq{
f, err := MStockHistoryMinuteTrade.Frame(ti, ExchangeSH, "000001", 0, 100) Time: time.Date(2024, 10, 28, 0, 0, 0, 0, time.Local),
Exchange: ExchangeSZ,
Code: "000001",
Start: 0,
Count: 100,
})
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return

View File

@@ -7,14 +7,14 @@ import (
"time" "time"
) )
type StockKlineReq struct { type KlineReq struct {
Exchange Exchange Exchange Exchange
Code string Code string
Start uint16 Start uint16
Count 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 { if this.Count > 800 {
return nil, errors.New("单次数量不能超过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 := []byte{this.Exchange.Uint8(), 0x0}
data = append(data, []byte(this.Code)...) //这里怎么是正序了? 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, 0x01, 0x0)
data = append(data, Bytes(this.Start)...) data = append(data, Bytes(this.Start)...)
data = append(data, Bytes(this.Count)...) data = append(data, Bytes(this.Count)...)
@@ -31,12 +31,12 @@ func (this *StockKlineReq) Bytes(Type TypeKline) (g.Bytes, error) {
return data, nil return data, nil
} }
type StockKlineResp struct { type KlineResp struct {
Count uint16 Count uint16
List []*StockKline List []*Kline
} }
type StockKline struct { type Kline struct {
Last Price //昨日收盘价,这个是列表的上一条数据的收盘价如果没有上条数据那么这个值为0 Last Price //昨日收盘价,这个是列表的上一条数据的收盘价如果没有上条数据那么这个值为0
Open Price //开盘价 Open Price //开盘价
High Price //最高价 High Price //最高价
@@ -47,7 +47,7 @@ type StockKline struct {
Time time.Time //时间 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", return fmt.Sprintf("%s 昨收盘:%s 开盘价:%s 最高价:%s 最低价:%s 收盘价:%s 涨跌:%s 涨跌幅:%0.2f 成交量:%s 成交额:%s",
this.Time.Format("2006-01-02 15:04:05"), this.Time.Format("2006-01-02 15:04:05"),
this.Last, this.Open, this.High, this.Low, this.Close, this.Last, this.Open, this.High, this.Low, this.Close,
@@ -57,12 +57,12 @@ func (this *StockKline) String() string {
} }
// MaxDifference 最大差值,最高-最低 // MaxDifference 最大差值,最高-最低
func (this *StockKline) MaxDifference() Price { func (this *Kline) MaxDifference() Price {
return this.High - this.Low return this.High - this.Low
} }
// RisePrice 涨跌金额,第一个数据不准,仅做参考 // RisePrice 涨跌金额,第一个数据不准,仅做参考
func (this *StockKline) RisePrice() Price { func (this *Kline) RisePrice() Price {
if this.Last == 0 { if this.Last == 0 {
//稍微数据准确点没减去0这么夸张还是不准的 //稍微数据准确点没减去0这么夸张还是不准的
return this.Close - this.Open return this.Close - this.Open
@@ -72,31 +72,31 @@ func (this *StockKline) RisePrice() Price {
} }
// RiseRate 涨跌比例/涨跌幅,第一个数据不准,仅做参考 // RiseRate 涨跌比例/涨跌幅,第一个数据不准,仅做参考
func (this *StockKline) RiseRate() float64 { func (this *Kline) RiseRate() float64 {
return float64(this.RisePrice()) / float64(this.Open) * 100 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) bs, err := req.Bytes(Type)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Frame{ return &Frame{
Control: Control01, Control: Control01,
Type: TypeStockKline, Type: TypeKline,
Data: bs, Data: bs,
}, nil }, nil
} }
func (stockKline) Decode(bs []byte, Type TypeKline) (*StockKlineResp, error) { func (kline) Decode(bs []byte, Type uint8) (*KlineResp, error) {
if len(bs) < 2 { if len(bs) < 2 {
return nil, errors.New("数据长度不足") return nil, errors.New("数据长度不足")
} }
resp := &StockKlineResp{ resp := &KlineResp{
Count: Uint16(bs[:2]), Count: Uint16(bs[:2]),
} }
@@ -104,7 +104,7 @@ func (stockKline) Decode(bs []byte, Type TypeKline) (*StockKlineResp, error) {
var last Price //上条数据(昨天)的收盘价 var last Price //上条数据(昨天)的收盘价
for i := uint16(0); i < resp.Count; i++ { for i := uint16(0); i < resp.Count; i++ {
k := &StockKline{ k := &Kline{
Time: GetTime([4]byte(bs[:4]), Type), Time: GetTime([4]byte(bs[:4]), Type),
} }

View File

@@ -4,7 +4,7 @@ import (
"errors" "errors"
) )
type StockMinuteResp struct { type MinuteResp struct {
Count uint16 Count uint16
List []PriceNumber List []PriceNumber
} }
@@ -14,9 +14,9 @@ type PriceNumber struct {
Number int 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 { if len(code) != 6 {
return nil, errors.New("股票代码长度错误") 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) codeBs = append(codeBs, 0x0, 0x0, 0x0, 0x0)
return &Frame{ return &Frame{
Control: Control01, Control: Control01,
Type: TypeStockMinute, Type: TypeMinute,
Data: append([]byte{exchange.Uint8(), 0x0}, codeBs...), Data: append([]byte{exchange.Uint8(), 0x0}, codeBs...),
}, nil }, nil
} }
func (this *stockMinute) Decode(bs []byte) (*StockMinuteResp, error) { func (this *minute) Decode(bs []byte) (*MinuteResp, error) {
if len(bs) < 6 { if len(bs) < 6 {
return nil, errors.New("数据长度不足") return nil, errors.New("数据长度不足")
} }
resp := &StockMinuteResp{ resp := &MinuteResp{
Count: Uint16(bs[:2]), Count: Uint16(bs[:2]),
} }
//2-6字节是啥? //2-6字节是啥?

View File

@@ -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
}

View File

@@ -6,9 +6,9 @@ import (
"strings" "strings"
) )
type StockQuotesResp []*StockQuote type QuotesResp []*Quote
func (this StockQuotesResp) String() string { func (this QuotesResp) String() string {
ls := []string(nil) ls := []string(nil)
for _, v := range this { for _, v := range this {
ls = append(ls, v.String()) ls = append(ls, v.String())
@@ -16,7 +16,7 @@ func (this StockQuotesResp) String() string {
return strings.Join(ls, "\n") return strings.Join(ls, "\n")
} }
type StockQuote struct { type Quote struct {
Exchange Exchange // 市场 Exchange Exchange // 市场
Code string // 股票代码 6个ascii字符串 Code string // 股票代码 6个ascii字符串
Active1 uint16 // 活跃度 Active1 uint16 // 活跃度
@@ -45,7 +45,7 @@ type StockQuote struct {
Active2 uint16 // 活跃度 Active2 uint16 // 活跃度
} }
func (this *StockQuote) String() string { func (this *Quote) String() string {
return fmt.Sprintf(`%s%s return fmt.Sprintf(`%s%s
%s %s
总量%s, 现量%s, 总金额%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{ f := &Frame{
Control: Control01, Control: Control01,
Type: TypeStockQuote, Type: TypeQuote,
Data: []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, Data: []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
} }
@@ -105,11 +105,11 @@ b212 昨天收盘价1186
8defd10c 服务时间 8defd10c 服务时间
c005bed2668e05be15804d8ba12cb3b13a0083c3034100badc029d014201bc990384f70443029da503b7af074403a6e501b9db044504a6e2028dd5048d050000000000005909 c005bed2668e05be15804d8ba12cb3b13a0083c3034100badc029d014201bc990384f70443029da503b7af074403a6e501b9db044504a6e2028dd5048d050000000000005909
*/ */
func (this stockQuote) Decode(bs []byte) StockQuotesResp { func (this quote) Decode(bs []byte) QuotesResp {
//logs.Debug(hex.EncodeToString(bs)) //logs.Debug(hex.EncodeToString(bs))
resp := StockQuotesResp{} resp := QuotesResp{}
//前2字节是什么? //前2字节是什么?
bs = bs[2:] bs = bs[2:]
@@ -118,7 +118,7 @@ func (this stockQuote) Decode(bs []byte) StockQuotesResp {
bs = bs[2:] bs = bs[2:]
for i := uint16(0); i < number; i++ { for i := uint16(0); i < number; i++ {
sec := &StockQuote{ sec := &Quote{
Exchange: Exchange(bs[0]), Exchange: Exchange(bs[0]),
Code: string(UTF8ToGBK(bs[1:7])), Code: string(UTF8ToGBK(bs[1:7])),
Active1: Uint16(bs[7:9]), Active1: Uint16(bs[7:9]),

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -81,7 +81,7 @@ func GetHourMinute(bs [2]byte) string {
return fmt.Sprintf("%02d:%02d", h, m) 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 { switch Type {
case TypeKlineDay2, TypeKlineMinute, TypeKlineMinute2: case TypeKlineDay2, TypeKlineMinute, TypeKlineMinute2: