日线数据对上了,其它k线待校对

This commit is contained in:
injoyai
2024-10-30 10:14:01 +08:00
parent d0ae22fb84
commit 060cbbf301
9 changed files with 116 additions and 90 deletions

View File

@@ -10,4 +10,19 @@
* 分时成交 * 分时成交
![](docs/plan20241028-2.png) ![](docs/plan20241028-2.png)
* K线 * K线
![](docs/plan20241029.png) ![](docs/plan20241029.png)
### 其它信息
* 中国的股市开盘时间为每周一至周五的上午9:30——1130 下午13:00——15:00。中国股市收盘时间为每周一至周五的下午3点。
* 600开头的股票是上证A股属于大盘股其中6006开头的股票是最早上市的股票 6016开头的股票为大盘蓝筹股900开头的股票是上证B股 000开头的股票是深证A股001、002开头的股票也都属于深证A股 其中002开头的股票是深证A股中小企业股票200开头的股票是深证B股 300开头的股票是创业板股票400开头的股票是三板市场股票。
### 数据接口
* 实时行情数据 http://vip.stock.finance.sina.com.cn/mkt/#hs_a
描述: A 股数据是从新浪财经获取的数据, 重复运行本函数会被新浪暂时封 IP, 建议增加时间间隔 限量: 单次返回所有 A 股上市公司的实时行情数据
* 历史行情数据 https://finance.sina.com.cn/realstock/company/sh600006/nc.shtml
描述: A 股数据是从新浪财经获取的数据, 历史数据按日频率更新; 注意其中的 sh689009 为 CDR, 请 通过 stock_zh_a_cdr_daily 接口获取 限量: 单次返回指定 A 股上市公司指定日期间的历史行情日频率数据

View File

@@ -10,6 +10,7 @@ import (
"github.com/injoyai/ios/client/dial" "github.com/injoyai/ios/client/dial"
"github.com/injoyai/logs" "github.com/injoyai/logs"
"github.com/injoyai/tdx/protocol" "github.com/injoyai/tdx/protocol"
"sync/atomic"
"time" "time"
) )
@@ -128,21 +129,15 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) {
} }
// SendFrame 发送数据,并等待响应
func (this *Client) SendFrame(f *protocol.Frame) (any, error) { func (this *Client) SendFrame(f *protocol.Frame) (any, error) {
this.msgID++ f.MsgID = atomic.AddUint32(&this.msgID, 1)
f.MsgID = this.msgID
if _, err := this.Client.Write(f.Bytes()); err != nil { if _, err := this.Client.Write(f.Bytes()); err != nil {
return nil, err return nil, err
} }
return this.Wait.Wait(conv.String(this.msgID)) return this.Wait.Wait(conv.String(this.msgID))
} }
func (this *Client) connect() error {
f := protocol.MConnect.Frame()
_, err := this.Write(f.Bytes())
return err
}
// GetStockCount 获取市场内的股票数量 // GetStockCount 获取市场内的股票数量
func (this *Client) GetStockCount(exchange protocol.Exchange) (*protocol.StockCountResp, error) { func (this *Client) GetStockCount(exchange protocol.Exchange) (*protocol.StockCountResp, error) {
f := protocol.MStockCount.Frame(exchange) f := protocol.MStockCount.Frame(exchange)
@@ -155,6 +150,9 @@ func (this *Client) GetStockCount(exchange protocol.Exchange) (*protocol.StockCo
// GetStockList 获取市场内指定范围内的所有证券代码,一次固定返回1000只,上证股票有效范围370-1480 // GetStockList 获取市场内指定范围内的所有证券代码,一次固定返回1000只,上证股票有效范围370-1480
// 上证前370只是395/399开头的(中证500/总交易等辅助类),在后面的话是一些100开头的国债 // 上证前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) { func (this *Client) GetStockList(exchange protocol.Exchange, start uint16) (*protocol.StockListResp, error) {
f := protocol.MStockList.Frame(exchange, start) f := protocol.MStockList.Frame(exchange, start)
result, err := this.SendFrame(f) result, err := this.SendFrame(f)
@@ -164,6 +162,24 @@ func (this *Client) GetStockList(exchange protocol.Exchange, start uint16) (*pro
return result.(*protocol.StockListResp), nil return result.(*protocol.StockListResp), nil
} }
// GetStockAll 通过多次请求的方式获取全部证券代码
func (this *Client) GetStockAll(exchange protocol.Exchange) (*protocol.StockListResp, error) {
resp := &protocol.StockListResp{}
maxSize := uint16(1000)
for start := uint16(0); ; start += maxSize {
r, err := this.GetStockList(exchange, start)
if err != nil {
return nil, err
}
resp.Count += r.Count
resp.List = append(resp.List, r.List...)
if r.Count < maxSize {
break
}
}
return resp, nil
}
// GetStockQuotes 获取盘口五档报价 // GetStockQuotes 获取盘口五档报价
func (this *Client) GetStockQuotes(m map[protocol.Exchange]string) (protocol.StockQuotesResp, error) { func (this *Client) GetStockQuotes(m map[protocol.Exchange]string) (protocol.StockQuotesResp, error) {
f, err := protocol.MStockQuote.Frame(m) f, err := protocol.MStockQuote.Frame(m)
@@ -286,6 +302,11 @@ func (this *Client) GetStockKline30Minute(req *protocol.StockKlineReq) (*protoco
return this.GetStockKline(protocol.TypeKline30Minute, req) return this.GetStockKline(protocol.TypeKline30Minute, req)
} }
// GetStockKlineHour 获取小时k线数据
func (this *Client) GetStockKlineHour(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) {
return this.GetStockKline(protocol.TypeKlineHour, req)
}
// GetStockKlineDay 获取日k线数据 // GetStockKlineDay 获取日k线数据
func (this *Client) GetStockKlineDay(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) { func (this *Client) GetStockKlineDay(req *protocol.StockKlineReq) (*protocol.StockKlineResp, error) {
return this.GetStockKline(protocol.TypeKlineDay, req) return this.GetStockKline(protocol.TypeKlineDay, req)

View File

@@ -37,7 +37,7 @@ type StockKline struct {
Open Price //开盘价 Open Price //开盘价
High Price //最高价 High Price //最高价
Low Price //最低价 Low Price //最低价
Close Price //收盘价 Close Price //收盘价,如果是当天,则是最新价/实时价
Volume float64 //成交量 Volume float64 //成交量
Amount float64 //成交额 Amount float64 //成交额
Time time.Time //时间 Time time.Time //时间
@@ -100,9 +100,7 @@ func (stockKline) Decode(bs []byte, Type TypeKline) (*StockKlineResp, error) {
last = last + open + _close last = last + open + _close
//logs.Debug(Reverse(bs[:4]), getVolume(Uint32(bs[:4]))) k.Volume = getVolume(Uint32(bs[:4]))
//logs.Debug(Reverse(bs[4:8]), getVolume(Uint32(bs[4:8])))
k.Volume = getVolume(Uint32(bs[:4])) / 100
k.Amount = getVolume(Uint32(bs[4:8])) k.Amount = getVolume(Uint32(bs[4:8]))
bs = bs[8:] bs = bs[8:]

View File

@@ -8,7 +8,7 @@ import (
func Test_stockKline_Frame(t *testing.T) { func Test_stockKline_Frame(t *testing.T) {
//预期0c02000000001c001c002d050000303030303031 0900 0100 0000 0a00 00000000000000000000 //预期0c02000000001c001c002d050000303030303031 0900 0100 0000 0a00 00000000000000000000
// 0c00000000011c001c002d050000313030303030 0900 0000 0000 0a00 00000000000000000000 // 0c00000000011c001c002d050000313030303030 0900 0000 0000 0a00 00000000000000000000
f, _ := MStockKline.Frame(TypeKlineDay2, &StockKlineReq{ f, _ := MStockKline.Frame(TypeKlineDay, &StockKlineReq{
Exchange: ExchangeSH, Exchange: ExchangeSH,
Code: "000001", Code: "000001",
Start: 0, Start: 0,

View File

@@ -55,12 +55,12 @@ const (
TypeKline15Minute TypeKline = 1 // 15分钟K 线 TypeKline15Minute TypeKline = 1 // 15分钟K 线
TypeKline30Minute TypeKline = 2 // 30分钟K 线 TypeKline30Minute TypeKline = 2 // 30分钟K 线
TypeKlineHour TypeKline = 3 // 1小时K 线 TypeKlineHour TypeKline = 3 // 1小时K 线
TypeKlineDay TypeKline = 4 // 日K 线 TypeKlineDay2 TypeKline = 4 // 日K 线
TypeKlineWeek TypeKline = 5 // 周K 线 TypeKlineWeek TypeKline = 5 // 周K 线
TypeKlineMonth TypeKline = 6 // 月K 线 TypeKlineMonth TypeKline = 6 // 月K 线
TypeKlineMinute TypeKline = 7 // 1分钟 TypeKlineMinute TypeKline = 7 // 1分钟
TypeKlineMinute2 TypeKline = 8 // 1分钟K 线 TypeKlineMinute2 TypeKline = 8 // 1分钟K 线
TypeKlineDay2 TypeKline = 9 // 日K 线 TypeKlineDay TypeKline = 9 // 日K 线
TypeKlineQuarter TypeKline = 10 // 季K 线 TypeKlineQuarter TypeKline = 10 // 季K 线
TypeKlineYear TypeKline = 11 // 年K 线 TypeKlineYear TypeKline = 11 // 年K 线
) )

View File

@@ -2,7 +2,6 @@ package protocol
import ( import (
"fmt" "fmt"
"math"
) )
// Price 价格,单位分 // Price 价格,单位分
@@ -158,61 +157,3 @@ func getData(bs []byte) (data int) {
return return
} }
func getVolume(ivol uint32) (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
}

View File

@@ -1,14 +0,0 @@
package protocol
import (
"math"
"testing"
)
func Test_getVolume(t *testing.T) {
f := float32(1.03)
n := math.Float32bits(f)
t.Log(n)
t.Log(getVolume(n))
}

View File

@@ -8,6 +8,7 @@ import (
"golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform" "golang.org/x/text/transform"
"io" "io"
"math"
"time" "time"
) )
@@ -82,7 +83,7 @@ func GetDate(bs [2]byte) string {
func GetTime(bs [4]byte, Type TypeKline) time.Time { func GetTime(bs [4]byte, Type TypeKline) time.Time {
switch Type { switch Type {
case TypeKlineDay, TypeKlineMinute, TypeKlineMinute2: case TypeKlineDay2, TypeKlineMinute, TypeKlineMinute2:
yearMonthDay := Uint16(bs[:2]) yearMonthDay := Uint16(bs[:2])
hourMinute := Uint16(bs[:2]) hourMinute := Uint16(bs[:2])
@@ -115,3 +116,62 @@ func basePrice(code string) Price {
return 10 return 10
} }
} }
func getVolume(val uint32) (volume float64) {
ivol := int32(val)
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
}

View File

@@ -17,3 +17,8 @@ func TestUTF8ToGBK(t *testing.T) {
bs = UTF8ToGBK(bs) bs = UTF8ToGBK(bs)
t.Log(string(bs)) t.Log(string(bs))
} }
func Test_getVolume(t *testing.T) {
t.Log(getVolume(1237966432))
t.Log(getVolume(1237966432))
}