mirror of
https://github.com/bensema/gotdx.git
synced 2025-11-21 02:45:33 +08:00
285 lines
7.0 KiB
Go
285 lines
7.0 KiB
Go
package proto
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/binary"
|
||
"math"
|
||
"sync/atomic"
|
||
"time"
|
||
)
|
||
|
||
const (
|
||
MessageHeaderBytes = 0x10
|
||
MessageMaxBytes = 1 << 15
|
||
)
|
||
|
||
const (
|
||
KMSG_CMD1 = 0x000d // 建立链接
|
||
KMSG_CMD2 = 0x0fdb // 建立链接
|
||
KMSG_PING = 0x0015 // 测试连接
|
||
KMSG_HEARTBEAT = 0xFFFF // 心跳(自定义)
|
||
KMSG_SECURITYCOUNT = 0x044e // 证券数量
|
||
KMSG_BLOCKINFOMETA = 0x02c5 // 板块文件信息
|
||
KMSG_BLOCKINFO = 0x06b9 // 板块文件
|
||
KMSG_COMPANYCATEGORY = 0x02cf // 公司信息文件信息
|
||
KMSG_COMPANYCONTENT = 0x02d0 // 公司信息描述
|
||
KMSG_FINANCEINFO = 0x0010 // 财务信息
|
||
KMSG_HISTORYMINUTETIMEDATE = 0x0fb4 // 历史分时信息
|
||
KMSG_HISTORYTRANSACTIONDATA = 0x0fb5 // 历史分笔成交信息
|
||
KMSG_INDEXBARS = 0x052d // 指数K线
|
||
KMSG_SECURITYBARS = 0x052d // 股票K线
|
||
KMSG_MINUTETIMEDATA = 0x0537 // 分时数据
|
||
KMSG_SECURITYLIST = 0x0450 // 证券列表
|
||
KMSG_SECURITYQUOTES = 0x053e // 行情信息
|
||
KMSG_TRANSACTIONDATA = 0x0fc5 // 分笔成交信息
|
||
KMSG_XDXRINFO = 0x000f // 除权除息信息
|
||
|
||
)
|
||
|
||
const (
|
||
KLINE_TYPE_5MIN = 0 // 5 分钟K 线
|
||
KLINE_TYPE_15MIN = 1 // 15 分钟K 线
|
||
KLINE_TYPE_30MIN = 2 // 30 分钟K 线
|
||
KLINE_TYPE_1HOUR = 3 // 1 小时K 线
|
||
KLINE_TYPE_DAILY = 4 // 日K 线
|
||
KLINE_TYPE_WEEKLY = 5 // 周K 线
|
||
KLINE_TYPE_MONTHLY = 6 // 月K 线
|
||
KLINE_TYPE_EXHQ_1MIN = 7 // 1 分钟
|
||
KLINE_TYPE_1MIN = 8 // 1 分钟K 线
|
||
KLINE_TYPE_RI_K = 9 // 日K 线
|
||
KLINE_TYPE_3MONTH = 10 // 季K 线
|
||
KLINE_TYPE_YEARLY = 11 // 年K 线
|
||
)
|
||
|
||
type Msg interface {
|
||
Serialize() ([]byte, error)
|
||
UnSerialize(head interface{}, in []byte) error
|
||
}
|
||
|
||
var _seqId uint32
|
||
|
||
/*
|
||
0c 02000000 00 1c00 1c00 2d05 0100363030303030080001000000140000000000000000000000
|
||
0c 02189300 01 0300 0300 0d00 01
|
||
0c 00000000 00 0200 0200 1500
|
||
*/
|
||
type ReqHeader struct {
|
||
Zip uint8 // ZipFlag
|
||
SeqID uint32 // 请求编号
|
||
PacketType uint8
|
||
PkgLen1 uint16
|
||
PkgLen2 uint16
|
||
Method uint16 // method 请求方法
|
||
}
|
||
|
||
type RespHeader struct {
|
||
I1 uint32
|
||
I2 uint8
|
||
SeqID uint32 // 请求编号
|
||
I3 uint8
|
||
Method uint16 // method
|
||
ZipSize uint16 // 长度
|
||
UnZipSize uint16 // 未压缩长度
|
||
}
|
||
|
||
func seqID() uint32 {
|
||
atomic.AddUint32(&_seqId, 1)
|
||
return _seqId
|
||
}
|
||
|
||
// pytdx : 类似utf-8的编码方式保存有符号数字
|
||
func getprice(b []byte, pos *int) int {
|
||
/*
|
||
0x7f与常量做与运算实质是保留常量(转换为二进制形式)的后7位数,既取值区间为[0,127]
|
||
0x3f与常量做与运算实质是保留常量(转换为二进制形式)的后6位数,既取值区间为[0,63]
|
||
|
||
0x80 1000 0000
|
||
0x7f 0111 1111
|
||
0x40 100 0000
|
||
0x3f 011 1111
|
||
*/
|
||
posByte := 6
|
||
bData := b[*pos]
|
||
data := int(bData & 0x3f)
|
||
bSign := false
|
||
if (bData & 0x40) > 0 {
|
||
bSign = true
|
||
}
|
||
|
||
if (bData & 0x80) > 0 {
|
||
for {
|
||
*pos += 1
|
||
bData = b[*pos]
|
||
data += (int(bData&0x7f) << posByte)
|
||
|
||
posByte += 7
|
||
|
||
if (bData & 0x80) <= 0 {
|
||
break
|
||
}
|
||
}
|
||
}
|
||
*pos++
|
||
|
||
if bSign {
|
||
data = -data
|
||
}
|
||
return data
|
||
}
|
||
|
||
func gettime(b []byte, pos *int) (h uint16, m uint16) {
|
||
var sec uint16
|
||
binary.Read(bytes.NewBuffer(b[*pos:*pos+2]), binary.LittleEndian, &sec)
|
||
h = sec / 60
|
||
m = sec % 60
|
||
(*pos) += 2
|
||
return
|
||
}
|
||
|
||
func getdatetime(category int, b []byte, pos *int) (year int, month int, day int, hour int, minute int) {
|
||
hour = 15
|
||
if category < 4 || category == 7 || category == 8 {
|
||
var zipday, tminutes uint16
|
||
binary.Read(bytes.NewBuffer(b[*pos:*pos+2]), binary.LittleEndian, &zipday)
|
||
(*pos) += 2
|
||
binary.Read(bytes.NewBuffer(b[*pos:*pos+2]), binary.LittleEndian, &tminutes)
|
||
(*pos) += 2
|
||
|
||
year = int((zipday >> 11) + 2004)
|
||
month = int((zipday % 2048) / 100)
|
||
day = int((zipday % 2048) % 100)
|
||
hour = int(tminutes / 60)
|
||
minute = int(tminutes % 60)
|
||
} else {
|
||
var zipday uint32
|
||
binary.Read(bytes.NewBuffer(b[*pos:*pos+4]), binary.LittleEndian, &zipday)
|
||
(*pos) += 4
|
||
year = int(zipday / 10000)
|
||
month = int((zipday % 10000) / 100)
|
||
day = int(zipday % 100)
|
||
}
|
||
return
|
||
}
|
||
|
||
func getdatetimenow(category int, lasttime string) (year int, month int, day int, hour int, minute int) {
|
||
utime, _ := time.Parse("2006-01-02 15:04:05", lasttime)
|
||
switch category {
|
||
case KLINE_TYPE_5MIN:
|
||
utime = utime.Add(time.Minute * 5)
|
||
case KLINE_TYPE_15MIN:
|
||
utime = utime.Add(time.Minute * 15)
|
||
case KLINE_TYPE_30MIN:
|
||
utime = utime.Add(time.Minute * 30)
|
||
case KLINE_TYPE_1HOUR:
|
||
utime = utime.Add(time.Hour)
|
||
case KLINE_TYPE_DAILY:
|
||
utime = utime.AddDate(0, 0, 1)
|
||
case KLINE_TYPE_WEEKLY:
|
||
utime = utime.Add(time.Hour * 24 * 7)
|
||
case KLINE_TYPE_MONTHLY:
|
||
utime = utime.AddDate(0, 1, 0)
|
||
case KLINE_TYPE_EXHQ_1MIN:
|
||
utime = utime.Add(time.Minute)
|
||
case KLINE_TYPE_1MIN:
|
||
utime = utime.Add(time.Minute)
|
||
case KLINE_TYPE_RI_K:
|
||
utime = utime.AddDate(0, 0, 1)
|
||
case KLINE_TYPE_3MONTH:
|
||
utime = utime.AddDate(0, 3, 0)
|
||
case KLINE_TYPE_YEARLY:
|
||
utime = utime.AddDate(1, 0, 0)
|
||
}
|
||
|
||
if category < 4 || category == 7 || category == 8 {
|
||
if (utime.Hour() >= 15 && utime.Minute() > 0) || (utime.Hour() > 15) {
|
||
utime = utime.AddDate(0, 0, 1)
|
||
utime = utime.Add(time.Minute * 30)
|
||
hour = (utime.Hour() + 18) % 24
|
||
} else {
|
||
hour = utime.Hour()
|
||
}
|
||
minute = utime.Minute()
|
||
} else {
|
||
if utime.Unix() > time.Now().Unix() {
|
||
utime = time.Now()
|
||
}
|
||
hour = utime.Hour()
|
||
minute = utime.Minute()
|
||
if utime.Hour() > 15 {
|
||
hour = 15
|
||
minute = 0
|
||
}
|
||
}
|
||
year = utime.Year()
|
||
month = int(utime.Month())
|
||
day = utime.Day()
|
||
return
|
||
}
|
||
|
||
func getvolume(ivol int) (volume float64) {
|
||
logpoint := ivol >> (8 * 3)
|
||
//hheax := ivol >> (8 * 3) // [3]
|
||
hleax := (ivol >> (8 * 2)) & 0xff // [2]
|
||
lheax := (ivol >> 8) & 0xff //[1]
|
||
lleax := ivol & 0xff //[0]
|
||
|
||
//dbl_1 := 1.0
|
||
//dbl_2 := 2.0
|
||
//dbl_128 := 128.0
|
||
|
||
dwEcx := logpoint*2 - 0x7f
|
||
dwEdx := logpoint*2 - 0x86
|
||
dwEsi := logpoint*2 - 0x8e
|
||
dwEax := logpoint*2 - 0x96
|
||
tmpEax := dwEcx
|
||
if dwEcx < 0 {
|
||
tmpEax = -dwEcx
|
||
} else {
|
||
tmpEax = dwEcx
|
||
}
|
||
|
||
dbl_xmm6 := 0.0
|
||
dbl_xmm6 = math.Pow(2.0, float64(tmpEax))
|
||
if dwEcx < 0 {
|
||
dbl_xmm6 = 1.0 / dbl_xmm6
|
||
}
|
||
|
||
dbl_xmm4 := 0.0
|
||
dbl_xmm0 := 0.0
|
||
|
||
if hleax > 0x80 {
|
||
tmpdbl_xmm3 := 0.0
|
||
//tmpdbl_xmm1 := 0.0
|
||
dwtmpeax := dwEdx + 1
|
||
tmpdbl_xmm3 = math.Pow(2.0, float64(dwtmpeax))
|
||
dbl_xmm0 = math.Pow(2.0, float64(dwEdx)) * 128.0
|
||
dbl_xmm0 += float64(hleax&0x7f) * tmpdbl_xmm3
|
||
dbl_xmm4 = dbl_xmm0
|
||
} else {
|
||
if dwEdx >= 0 {
|
||
dbl_xmm0 = math.Pow(2.0, float64(dwEdx)) * float64(hleax)
|
||
} else {
|
||
dbl_xmm0 = (1 / math.Pow(2.0, float64(dwEdx))) * float64(hleax)
|
||
}
|
||
dbl_xmm4 = dbl_xmm0
|
||
}
|
||
|
||
dbl_xmm3 := math.Pow(2.0, float64(dwEsi)) * float64(lheax)
|
||
dbl_xmm1 := math.Pow(2.0, float64(dwEax)) * float64(lleax)
|
||
if (hleax & 0x80) > 0 {
|
||
dbl_xmm3 *= 2.0
|
||
dbl_xmm1 *= 2.0
|
||
}
|
||
volume = dbl_xmm6 + dbl_xmm4 + dbl_xmm3 + dbl_xmm1
|
||
return
|
||
}
|
||
|
||
func baseUnit(code string) float64 {
|
||
switch code[:2] {
|
||
case "60", "30", "68", "00":
|
||
return 100.0
|
||
default:
|
||
return 1000.0
|
||
}
|
||
}
|