mirror of
https://github.com/injoyai/tdx.git
synced 2025-11-26 21:25:35 +08:00
统一分时成交的结构名称为Trade,和K线Kline一样简洁
This commit is contained in:
50
client.go
50
client.go
@@ -157,10 +157,10 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) {
|
|||||||
resp, err = protocol.MHistoryMinute.Decode(f.Data)
|
resp, err = protocol.MHistoryMinute.Decode(f.Data)
|
||||||
|
|
||||||
case protocol.TypeMinuteTrade:
|
case protocol.TypeMinuteTrade:
|
||||||
resp, err = protocol.MMinuteTrade.Decode(f.Data, conv.String(val))
|
resp, err = protocol.MTrade.Decode(f.Data, val.(protocol.TradeCache))
|
||||||
|
|
||||||
case protocol.TypeHistoryMinuteTrade:
|
case protocol.TypeHistoryMinuteTrade:
|
||||||
resp, err = protocol.MHistoryMinuteTrade.Decode(f.Data, conv.String(val))
|
resp, err = protocol.MHistoryTrade.Decode(f.Data, val.(protocol.TradeCache))
|
||||||
|
|
||||||
case protocol.TypeKline:
|
case protocol.TypeKline:
|
||||||
resp, err = protocol.MKline.Decode(f.Data, val.(protocol.KlineCache))
|
resp, err = protocol.MKline.Decode(f.Data, val.(protocol.KlineCache))
|
||||||
@@ -316,23 +316,34 @@ func (this *Client) GetHistoryMinute(date, code string) (*protocol.MinuteResp, e
|
|||||||
return result.(*protocol.MinuteResp), nil
|
return result.(*protocol.MinuteResp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Client) GetTrade(code string, start, count uint16) (*protocol.TradeResp, error) {
|
||||||
|
return this.GetMinuteTrade(code, start, count)
|
||||||
|
}
|
||||||
|
|
||||||
// GetMinuteTrade 获取分时交易详情,服务器最多返回1800条,count-start<=1800
|
// GetMinuteTrade 获取分时交易详情,服务器最多返回1800条,count-start<=1800
|
||||||
func (this *Client) GetMinuteTrade(code string, start, count uint16) (*protocol.MinuteTradeResp, error) {
|
func (this *Client) GetMinuteTrade(code string, start, count uint16) (*protocol.TradeResp, error) {
|
||||||
code = protocol.AddPrefix(code)
|
code = protocol.AddPrefix(code)
|
||||||
f, err := protocol.MMinuteTrade.Frame(code, start, count)
|
f, err := protocol.MTrade.Frame(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, protocol.TradeCache{
|
||||||
|
Date: time.Now().Format("20060102"),
|
||||||
|
Code: code,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return result.(*protocol.MinuteTradeResp), nil
|
return result.(*protocol.TradeResp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) GetTradeAll(code string) (*protocol.TradeResp, error) {
|
||||||
|
return this.GetMinuteTradeAll(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMinuteTradeAll 获取分时全部交易详情,todo 只做参考 因为交易实时在进行,然后又是分页读取的,所以会出现读取间隔内产生的交易会丢失
|
// GetMinuteTradeAll 获取分时全部交易详情,todo 只做参考 因为交易实时在进行,然后又是分页读取的,所以会出现读取间隔内产生的交易会丢失
|
||||||
func (this *Client) GetMinuteTradeAll(code string) (*protocol.MinuteTradeResp, error) {
|
func (this *Client) GetMinuteTradeAll(code string) (*protocol.TradeResp, error) {
|
||||||
resp := &protocol.MinuteTradeResp{}
|
resp := &protocol.TradeResp{}
|
||||||
size := uint16(1800)
|
size := uint16(1800)
|
||||||
for start := uint16(0); ; start += size {
|
for start := uint16(0); ; start += size {
|
||||||
r, err := this.GetMinuteTrade(code, start, size)
|
r, err := this.GetMinuteTrade(code, start, size)
|
||||||
@@ -349,26 +360,37 @@ func (this *Client) GetMinuteTradeAll(code string) (*protocol.MinuteTradeResp, e
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Client) GetHistoryTrade(date, code string, start, count uint16) (*protocol.HistoryTradeResp, error) {
|
||||||
|
return this.GetHistoryMinuteTrade(date, code, start, count)
|
||||||
|
}
|
||||||
|
|
||||||
// GetHistoryMinuteTrade 获取历史分时交易
|
// GetHistoryMinuteTrade 获取历史分时交易
|
||||||
// 只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000,如果日期输入错误,则返回0
|
// 只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000,如果日期输入错误,则返回0
|
||||||
// 历史数据sz000001在20241116只能查到21111112,13年差几天,3141天,或者其他规则
|
// 历史数据sz000001在20241116只能查到21111112,13年差几天,3141天,或者其他规则
|
||||||
func (this *Client) GetHistoryMinuteTrade(date, code string, start, count uint16) (*protocol.HistoryMinuteTradeResp, error) {
|
func (this *Client) GetHistoryMinuteTrade(date, code string, start, count uint16) (*protocol.HistoryTradeResp, error) {
|
||||||
code = protocol.AddPrefix(code)
|
code = protocol.AddPrefix(code)
|
||||||
f, err := protocol.MHistoryMinuteTrade.Frame(date, code, start, count)
|
f, err := protocol.MHistoryTrade.Frame(date, 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, protocol.TradeCache{
|
||||||
|
Date: date,
|
||||||
|
Code: code,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return result.(*protocol.HistoryMinuteTradeResp), nil
|
return result.(*protocol.HistoryTradeResp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) GetHistoryTradeAll(date, code string) (*protocol.HistoryTradeResp, error) {
|
||||||
|
return this.GetHistoryMinuteTradeAll(date, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据
|
// GetHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据
|
||||||
// 历史数据sz000001在20241116只能查到21111112,13年差几天,3141天,或者其他规则
|
// 历史数据sz000001在20241116只能查到21111112,13年差几天,3141天,或者其他规则
|
||||||
func (this *Client) GetHistoryMinuteTradeAll(date, code string) (*protocol.HistoryMinuteTradeResp, error) {
|
func (this *Client) GetHistoryMinuteTradeAll(date, code string) (*protocol.HistoryTradeResp, error) {
|
||||||
resp := &protocol.HistoryMinuteTradeResp{}
|
resp := &protocol.HistoryTradeResp{}
|
||||||
size := uint16(2000)
|
size := uint16(2000)
|
||||||
for start := uint16(0); ; start += size {
|
for start := uint16(0); ; start += size {
|
||||||
r, err := this.GetHistoryMinuteTrade(date, code, start, size)
|
r, err := this.GetHistoryMinuteTrade(date, code, start, size)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ var (
|
|||||||
MCode = code{}
|
MCode = code{}
|
||||||
MMinute = minute{}
|
MMinute = minute{}
|
||||||
MHistoryMinute = historyMinute{}
|
MHistoryMinute = historyMinute{}
|
||||||
MMinuteTrade = minuteTrade{}
|
MTrade = trade{}
|
||||||
MHistoryMinuteTrade = historyMinuteTrade{}
|
MHistoryTrade = historyTrade{}
|
||||||
MKline = kline{}
|
MKline = kline{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
package protocol
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/injoyai/conv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HistoryMinuteTradeResp 历史分时交易比实时少了单量
|
|
||||||
type HistoryMinuteTradeResp struct {
|
|
||||||
Count uint16
|
|
||||||
List HistoryMinuteTrades
|
|
||||||
//List []*HistoryMinuteTrade
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryMinuteTrade struct {
|
|
||||||
Time string //时间
|
|
||||||
Price Price //价格
|
|
||||||
Volume int //成交量
|
|
||||||
Status int //0是买,1是卖,2无效(汇总出现)中途也可能出现2,例20241115(sz000001)的14:56
|
|
||||||
}
|
|
||||||
|
|
||||||
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(date, code string, start, count uint16) (*Frame, error) {
|
|
||||||
exchange, number, err := DecodeCode(code)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dataBs := Bytes(conv.Uint32(date)) //req.Time.Format("20060102"))
|
|
||||||
dataBs = append(dataBs, exchange.Uint8(), 0x0)
|
|
||||||
dataBs = append(dataBs, []byte(number)...)
|
|
||||||
dataBs = append(dataBs, Bytes(start)...)
|
|
||||||
dataBs = append(dataBs, Bytes(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("数据长度不足")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, number, err := DecodeCode(code)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
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 * 10 //把分转成厘
|
|
||||||
mt.Price = lastPrice / basePrice(number)
|
|
||||||
bs, mt.Volume = CutInt(bs)
|
|
||||||
bs, mt.Status = CutInt(bs)
|
|
||||||
bs, _ = CutInt(bs) //这个得到的是0,不知道是啥
|
|
||||||
resp.List = append(resp.List, mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryMinuteTrades []*HistoryMinuteTrade
|
|
||||||
|
|
||||||
func (this HistoryMinuteTrades) Kline(date string) (k *Kline, err error) {
|
|
||||||
k = &Kline{}
|
|
||||||
for i, v := range this {
|
|
||||||
switch i {
|
|
||||||
case 0:
|
|
||||||
k.Time, err = time.Parse("2006010215:04", date+v.Time)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
k.Open = v.Price
|
|
||||||
k.High = v.Price
|
|
||||||
k.Low = v.Price
|
|
||||||
k.Close = v.Price
|
|
||||||
case len(this) - 1:
|
|
||||||
k.Close = v.Price
|
|
||||||
}
|
|
||||||
k.High = conv.Select(v.Price > k.High, v.Price, k.High)
|
|
||||||
k.Low = conv.Select(v.Price < k.Low, v.Price, k.Low)
|
|
||||||
k.Volume += int64(v.Volume)
|
|
||||||
k.Amount += v.Amount()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinuteKline 分时K线
|
|
||||||
func (this HistoryMinuteTrades) MinuteKline(date string) (Klines, error) {
|
|
||||||
m := make(map[string]HistoryMinuteTrades)
|
|
||||||
for _, v := range this {
|
|
||||||
v.Time = conv.Select(v.Time > "09:00", v.Time, "09:00")
|
|
||||||
m[v.Time] = append(m[v.Time], v)
|
|
||||||
}
|
|
||||||
|
|
||||||
ls := Klines(nil)
|
|
||||||
for _, v := range m {
|
|
||||||
k, err := v.Kline(date)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ls = append(ls, k)
|
|
||||||
}
|
|
||||||
ls.Sort()
|
|
||||||
return ls, nil
|
|
||||||
}
|
|
||||||
70
protocol/model_history_trade.go
Normal file
70
protocol/model_history_trade.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/injoyai/conv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HistoryTradeResp 历史分时交易比实时少了单量
|
||||||
|
type HistoryTradeResp struct {
|
||||||
|
Count uint16
|
||||||
|
List Trades
|
||||||
|
}
|
||||||
|
|
||||||
|
type historyTrade struct{}
|
||||||
|
|
||||||
|
func (historyTrade) Frame(date, code string, start, count uint16) (*Frame, error) {
|
||||||
|
exchange, number, err := DecodeCode(code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataBs := Bytes(conv.Uint32(date)) //req.Time.Format("20060102"))
|
||||||
|
dataBs = append(dataBs, exchange.Uint8(), 0x0)
|
||||||
|
dataBs = append(dataBs, []byte(number)...)
|
||||||
|
dataBs = append(dataBs, Bytes(start)...)
|
||||||
|
dataBs = append(dataBs, Bytes(count)...)
|
||||||
|
return &Frame{
|
||||||
|
Control: Control01,
|
||||||
|
Type: TypeHistoryMinuteTrade,
|
||||||
|
Data: dataBs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (historyTrade) Decode(bs []byte, c TradeCache) (*HistoryTradeResp, error) {
|
||||||
|
if len(bs) < 2 {
|
||||||
|
return nil, errors.New("数据长度不足")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, number, err := DecodeCode(c.Code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &HistoryTradeResp{
|
||||||
|
Count: Uint16(bs[:2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
//第2-6字节不知道是啥
|
||||||
|
bs = bs[2+4:]
|
||||||
|
|
||||||
|
lastPrice := Price(0)
|
||||||
|
for i := uint16(0); i < resp.Count; i++ {
|
||||||
|
timeStr := GetHourMinute([2]byte(bs[:2]))
|
||||||
|
t, err := time.Parse("2006010215:04", c.Date+timeStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mt := &Trade{Time: t}
|
||||||
|
var sub Price
|
||||||
|
bs, sub = GetPrice(bs[2:])
|
||||||
|
lastPrice += sub * 10 //把分转成厘
|
||||||
|
mt.Price = lastPrice / basePrice(number)
|
||||||
|
bs, mt.Volume = CutInt(bs)
|
||||||
|
bs, mt.Status = CutInt(bs)
|
||||||
|
bs, _ = CutInt(bs) //这个得到的是0,不知道是啥
|
||||||
|
resp.List = append(resp.List, mt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ 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
|
||||||
f, err := MHistoryMinuteTrade.Frame("20241028", "sz000001", 0, 100)
|
f, err := MHistoryTrade.Frame("20241028", "sz000001", 0, 100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
package protocol
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
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(code string, start, count uint16) (*Frame, error) {
|
|
||||||
exchange, number, err := DecodeCode(code)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
codeBs := []byte(number)
|
|
||||||
codeBs = append(codeBs, Bytes(start)...)
|
|
||||||
codeBs = append(codeBs, Bytes(count)...)
|
|
||||||
return &Frame{
|
|
||||||
Control: Control01,
|
|
||||||
Type: TypeMinuteTrade,
|
|
||||||
Data: append([]byte{exchange.Uint8(), 0x0}, codeBs...),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (minuteTrade) Decode(bs []byte, code string) (*MinuteTradeResp, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
_, code, err = DecodeCode(code)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
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 * 10 //把分转换成厘
|
|
||||||
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
|
|
||||||
}
|
|
||||||
171
protocol/model_trade.go
Normal file
171
protocol/model_trade.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/injoyai/conv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TradeResp struct {
|
||||||
|
Count uint16
|
||||||
|
List Trades
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trade 分时成交,todo 时间没有到秒,客户端上也没有,东方客户端能显示秒
|
||||||
|
type Trade struct {
|
||||||
|
Time time.Time //时间, 09:30
|
||||||
|
Price Price //价格
|
||||||
|
Volume int //成交量,手
|
||||||
|
Status int //0是买,1是卖,2中性/汇总 中途也可能出现2,例20241115(sz000001)的14:56
|
||||||
|
Number int //单数,历史数据该字段无效
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Trade) 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 *Trade) Amount() Price {
|
||||||
|
return this.Price * Price(this.Volume*100)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Trade) StatusString() string {
|
||||||
|
switch this.Status {
|
||||||
|
case 0:
|
||||||
|
return "买入"
|
||||||
|
case 1:
|
||||||
|
return "卖出"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvgVolume 平均每单成交量
|
||||||
|
func (this *Trade) AvgVolume() float64 {
|
||||||
|
return float64(this.Volume) / float64(this.Number)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvgPrice 平均每单成交金额
|
||||||
|
func (this *Trade) AvgPrice() Price {
|
||||||
|
return Price(this.AvgVolume() * float64(this.Price) * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBuy 是否是买单
|
||||||
|
func (this *Trade) IsBuy() bool {
|
||||||
|
return this.Status == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSell 是否是卖单
|
||||||
|
func (this *Trade) IsSell() bool {
|
||||||
|
return this.Status == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
type trade struct{}
|
||||||
|
|
||||||
|
func (trade) Frame(code string, start, count uint16) (*Frame, error) {
|
||||||
|
exchange, number, err := DecodeCode(code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
codeBs := []byte(number)
|
||||||
|
codeBs = append(codeBs, Bytes(start)...)
|
||||||
|
codeBs = append(codeBs, Bytes(count)...)
|
||||||
|
return &Frame{
|
||||||
|
Control: Control01,
|
||||||
|
Type: TypeMinuteTrade,
|
||||||
|
Data: append([]byte{exchange.Uint8(), 0x0}, codeBs...),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trade) Decode(bs []byte, c TradeCache) (*TradeResp, error) {
|
||||||
|
|
||||||
|
_, code, err := DecodeCode(c.Code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(bs) < 2 {
|
||||||
|
return nil, errors.New("数据长度不足")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &TradeResp{
|
||||||
|
Count: Uint16(bs[:2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = bs[2:]
|
||||||
|
|
||||||
|
lastPrice := Price(0)
|
||||||
|
for i := uint16(0); i < resp.Count; i++ {
|
||||||
|
timeStr := GetHourMinute([2]byte(bs[:2]))
|
||||||
|
t, err := time.Parse("2006010215:04", c.Date+timeStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mt := &Trade{Time: t}
|
||||||
|
var sub Price
|
||||||
|
bs, sub = GetPrice(bs[2:])
|
||||||
|
lastPrice += sub * 10 //把分转换成厘
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type Trades []*Trade
|
||||||
|
|
||||||
|
func (this Trades) Kline() (k *Kline, err error) {
|
||||||
|
k = &Kline{}
|
||||||
|
for i, v := range this {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
k.Time = v.Time
|
||||||
|
k.Open = v.Price
|
||||||
|
k.High = v.Price
|
||||||
|
k.Low = v.Price
|
||||||
|
k.Close = v.Price
|
||||||
|
case len(this) - 1:
|
||||||
|
k.Close = v.Price
|
||||||
|
}
|
||||||
|
k.High = conv.Select(v.Price > k.High, v.Price, k.High)
|
||||||
|
k.Low = conv.Select(v.Price < k.Low, v.Price, k.Low)
|
||||||
|
k.Volume += int64(v.Volume)
|
||||||
|
k.Amount += v.Amount()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Klines1 1分K线
|
||||||
|
func (this Trades) Klines1() (Klines, error) {
|
||||||
|
m := make(map[int64]Trades)
|
||||||
|
for _, v := range this {
|
||||||
|
//小于9点30的数据归类到9点30
|
||||||
|
if v.Time.Hour() == 9 && v.Time.Minute() < 30 {
|
||||||
|
v.Time = time.Date(v.Time.Year(), v.Time.Month(), v.Time.Day(), 9, 30, 0, 0, v.Time.Location())
|
||||||
|
}
|
||||||
|
m[v.Time.Unix()] = append(m[v.Time.Unix()], v)
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := Klines(nil)
|
||||||
|
for _, v := range m {
|
||||||
|
k, err := v.Kline()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ls = append(ls, k)
|
||||||
|
}
|
||||||
|
ls.Sort()
|
||||||
|
return ls, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TradeCache struct {
|
||||||
|
Date string //日期
|
||||||
|
Code string //计算倍数
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user