mirror of
https://github.com/injoyai/tdx.git
synced 2025-11-26 21:25:35 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
66
client.go
66
client.go
@@ -233,6 +233,40 @@ func (this *Client) GetCodeAll(exchange protocol.Exchange) (*protocol.CodeResp,
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetStockAll 获取所有股票代码
|
||||
func (this *Client) GetStockAll() ([]string, error) {
|
||||
ls := []string(nil)
|
||||
for _, ex := range []protocol.Exchange{protocol.ExchangeSH, protocol.ExchangeSZ} {
|
||||
resp, err := this.GetCodeAll(ex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range resp.List {
|
||||
if protocol.IsStock(v.Code) {
|
||||
ls = append(ls, v.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ls, nil
|
||||
}
|
||||
|
||||
// GetETFAll 获取所有ETF代码
|
||||
func (this *Client) GetETFAll() ([]string, error) {
|
||||
ls := []string(nil)
|
||||
for _, ex := range []protocol.Exchange{protocol.ExchangeSH, protocol.ExchangeSZ} {
|
||||
resp, err := this.GetCodeAll(ex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range resp.List {
|
||||
if protocol.IsETF(v.Code) {
|
||||
ls = append(ls, v.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ls, nil
|
||||
}
|
||||
|
||||
// GetQuote 获取盘口五档报价
|
||||
func (this *Client) GetQuote(codes ...string) (protocol.QuotesResp, error) {
|
||||
for i := range codes {
|
||||
@@ -360,14 +394,14 @@ func (this *Client) GetMinuteTradeAll(code string) (*protocol.TradeResp, error)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (this *Client) GetHistoryTrade(date, code string, start, count uint16) (*protocol.HistoryTradeResp, error) {
|
||||
func (this *Client) GetHistoryTrade(date, code string, start, count uint16) (*protocol.TradeResp, error) {
|
||||
return this.GetHistoryMinuteTrade(date, code, start, count)
|
||||
}
|
||||
|
||||
// GetHistoryMinuteTrade 获取历史分时交易
|
||||
// 只能获取昨天及之前的数据,服务器最多返回2000条,count-start<=2000,如果日期输入错误,则返回0
|
||||
// 历史数据sz000001在20241116只能查到21111112,13年差几天,3141天,或者其他规则
|
||||
func (this *Client) GetHistoryMinuteTrade(date, code string, start, count uint16) (*protocol.HistoryTradeResp, error) {
|
||||
func (this *Client) GetHistoryMinuteTrade(date, code string, start, count uint16) (*protocol.TradeResp, error) {
|
||||
code = protocol.AddPrefix(code)
|
||||
f, err := protocol.MHistoryTrade.Frame(date, code, start, count)
|
||||
if err != nil {
|
||||
@@ -380,17 +414,17 @@ func (this *Client) GetHistoryMinuteTrade(date, code string, start, count uint16
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*protocol.HistoryTradeResp), nil
|
||||
return result.(*protocol.TradeResp), nil
|
||||
}
|
||||
|
||||
func (this *Client) GetHistoryTradeAll(date, code string) (*protocol.HistoryTradeResp, error) {
|
||||
func (this *Client) GetHistoryTradeAll(date, code string) (*protocol.TradeResp, error) {
|
||||
return this.GetHistoryMinuteTradeAll(date, code)
|
||||
}
|
||||
|
||||
// GetHistoryMinuteTradeAll 获取历史分时全部交易,通过多次请求来拼接,只能获取昨天及之前的数据
|
||||
// 历史数据sz000001在20241116只能查到21111112,13年差几天,3141天,或者其他规则
|
||||
func (this *Client) GetHistoryMinuteTradeAll(date, code string) (*protocol.HistoryTradeResp, error) {
|
||||
resp := &protocol.HistoryTradeResp{}
|
||||
func (this *Client) GetHistoryMinuteTradeAll(date, code string) (*protocol.TradeResp, error) {
|
||||
resp := &protocol.TradeResp{}
|
||||
size := uint16(2000)
|
||||
for start := uint16(0); ; start += size {
|
||||
r, err := this.GetHistoryMinuteTrade(date, code, start, size)
|
||||
@@ -603,18 +637,32 @@ func (this *Client) GetKline30MinuteUntil(code string, f func(k *protocol.Kline)
|
||||
return this.GetKlineUntil(protocol.TypeKline30Minute, code, f)
|
||||
}
|
||||
|
||||
// GetKline60Minute 获取60分钟k线数据
|
||||
func (this *Client) GetKline60Minute(code string, start, count uint16) (*protocol.KlineResp, error) {
|
||||
return this.GetKline(protocol.TypeKline60Minute, code, start, count)
|
||||
}
|
||||
|
||||
// GetKlineHour 获取小时k线数据
|
||||
func (this *Client) GetKlineHour(code string, start, count uint16) (*protocol.KlineResp, error) {
|
||||
return this.GetKline(protocol.TypeKlineHour, code, start, count)
|
||||
return this.GetKline(protocol.TypeKline60Minute, code, start, count)
|
||||
}
|
||||
|
||||
// GetKline60MinuteAll 获取60分钟k线全部数据
|
||||
func (this *Client) GetKline60MinuteAll(code string) (*protocol.KlineResp, error) {
|
||||
return this.GetKlineAll(protocol.TypeKline60Minute, code)
|
||||
}
|
||||
|
||||
// GetKlineHourAll 获取小时k线全部数据
|
||||
func (this *Client) GetKlineHourAll(code string) (*protocol.KlineResp, error) {
|
||||
return this.GetKlineAll(protocol.TypeKlineHour, code)
|
||||
return this.GetKlineAll(protocol.TypeKline60Minute, code)
|
||||
}
|
||||
|
||||
func (this *Client) GetKline60MinuteUntil(code string, f func(k *protocol.Kline) bool) (*protocol.KlineResp, error) {
|
||||
return this.GetKlineUntil(protocol.TypeKline60Minute, code, f)
|
||||
}
|
||||
|
||||
func (this *Client) GetKlineHourUntil(code string, f func(k *protocol.Kline) bool) (*protocol.KlineResp, error) {
|
||||
return this.GetKlineUntil(protocol.TypeKlineHour, code, f)
|
||||
return this.GetKlineUntil(protocol.TypeKline60Minute, code, f)
|
||||
}
|
||||
|
||||
// GetKlineDay 获取日k线数据
|
||||
|
||||
2
codes.go
2
codes.go
@@ -70,7 +70,7 @@ func NewCodes(c *Client, filenames ...string) (*Codes, error) {
|
||||
|
||||
{ //设置定时器,每天早上9点更新数据
|
||||
task := cron.New(cron.WithSeconds())
|
||||
task.AddFunc("0 0 9 * * *", func() {
|
||||
task.AddFunc("10 0 9 * * *", func() {
|
||||
for i := 0; i < 3; i++ {
|
||||
if err := cc.Update(); err == nil {
|
||||
return
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
func main() {
|
||||
ls := tdx.FastHosts(tdx.Hosts...)
|
||||
for _, v := range ls {
|
||||
logs.Debug(v)
|
||||
logs.Debug(v.Host, v.Spend)
|
||||
}
|
||||
logs.Debug("总数量:", len(ls))
|
||||
}
|
||||
|
||||
20
example/GetTrade/main.go
Normal file
20
example/GetTrade/main.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/injoyai/logs"
|
||||
"github.com/injoyai/tdx"
|
||||
"github.com/injoyai/tdx/example/common"
|
||||
)
|
||||
|
||||
func main() {
|
||||
common.Test(func(c *tdx.Client) {
|
||||
resp, err := c.GetTrade("sz000001", 0, 20)
|
||||
logs.PanicErr(err)
|
||||
|
||||
for _, v := range resp.List {
|
||||
logs.Debug(v)
|
||||
}
|
||||
|
||||
logs.Debug("总数:", resp.Count)
|
||||
})
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (this *PullTrade) PullYear(ctx context.Context, m *tdx.Manage, year int, co
|
||||
|
||||
date := t.Format("20060102")
|
||||
|
||||
var resp *protocol.HistoryTradeResp
|
||||
var resp *protocol.TradeResp
|
||||
err = m.Do(func(c *tdx.Client) error {
|
||||
resp, err = c.GetHistoryTradeAll(date, code)
|
||||
return err
|
||||
|
||||
6
go.mod
6
go.mod
@@ -5,9 +5,9 @@ go 1.20
|
||||
require (
|
||||
github.com/glebarez/go-sqlite v1.22.0
|
||||
github.com/go-sql-driver/mysql v1.7.0
|
||||
github.com/injoyai/base v1.2.7
|
||||
github.com/injoyai/conv v1.2.2
|
||||
github.com/injoyai/ios v0.0.7
|
||||
github.com/injoyai/base v1.2.8
|
||||
github.com/injoyai/conv v1.2.5
|
||||
github.com/injoyai/ios v0.0.10
|
||||
github.com/injoyai/logs v1.0.9
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
golang.org/x/text v0.16.0
|
||||
|
||||
12
go.sum
12
go.sum
@@ -27,12 +27,12 @@ github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/injoyai/base v1.2.7 h1:uYZoUIPGidkTNMfQfObsyHulu5VvNCOzuCh1DGn+Hz0=
|
||||
github.com/injoyai/base v1.2.7/go.mod h1:BsXiJ6/hXpswWxI4zLdKz+pW2Cwo+qhdfyaWDfR/vwg=
|
||||
github.com/injoyai/conv v1.2.2 h1:nxFD3zCYq/ZvVE6xAExBR+agi6gB+vc9O0si67VAsPk=
|
||||
github.com/injoyai/conv v1.2.2/go.mod h1:s05l3fQJQ4mT4VX+KIdbvCWQB0YzZHprmUfUu2uxd1k=
|
||||
github.com/injoyai/ios v0.0.7 h1:7k/brTmpnoqE6ajodyilkr2EJmJmcvSkpUD+LptgUVU=
|
||||
github.com/injoyai/ios v0.0.7/go.mod h1:9HemWSJTmhyJCnr+kH+lRfmvrEdABi1rkCBVsbqV5X8=
|
||||
github.com/injoyai/base v1.2.8 h1:voEPqxE5U+wI1RvcQStVbjUZJDLENbl1SsoQQWMn4s0=
|
||||
github.com/injoyai/base v1.2.8/go.mod h1:NfCQjml3z2pCvQ3J3YcOXtecqXD0xVPKjo4YTsMLhr8=
|
||||
github.com/injoyai/conv v1.2.5 h1:G4OCyF0NTZul5W1u9IgXDOhW4/zmIigdPKXFHQGmv1M=
|
||||
github.com/injoyai/conv v1.2.5/go.mod h1:s05l3fQJQ4mT4VX+KIdbvCWQB0YzZHprmUfUu2uxd1k=
|
||||
github.com/injoyai/ios v0.0.10 h1:Zd37Rwp90PYV5eFhirR0LJ+ni/aYLSCAYgHltk/ZzJA=
|
||||
github.com/injoyai/ios v0.0.10/go.mod h1:zLTmvQmIbdTf7zZxymOVxbxvvSeUMpcs4SCVPDT9BOc=
|
||||
github.com/injoyai/logs v1.0.9 h1:Wq7rCVIQKcPx+z+lzKQb2qyDK4TML/cgmaSZN9tx33c=
|
||||
github.com/injoyai/logs v1.0.9/go.mod h1:CLchJCGhb39Obyrci816R+KMtbxZhgPs0FuikhyixK4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
||||
27
hosts.go
27
hosts.go
@@ -1,10 +1,12 @@
|
||||
package tdx
|
||||
|
||||
import (
|
||||
"github.com/injoyai/base/types"
|
||||
"github.com/injoyai/logs"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -75,12 +77,12 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// FastHosts 通过tcp(ping不可用)的方式筛选可用的地址,并排序(有点误差)
|
||||
func FastHosts(hosts ...string) []string {
|
||||
// FastHosts 通过tcp(ping不可用)连接速度的方式筛选排序可用的地址
|
||||
func FastHosts(hosts ...string) []DialResult {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(hosts))
|
||||
mu := sync.Mutex{}
|
||||
ls := []string(nil)
|
||||
ls := types.List[DialResult](nil)
|
||||
for _, host := range hosts {
|
||||
go func(host string) {
|
||||
defer wg.Done()
|
||||
@@ -88,17 +90,30 @@ func FastHosts(hosts ...string) []string {
|
||||
if !strings.Contains(addr, ":") {
|
||||
addr += ":7709"
|
||||
}
|
||||
now := time.Now()
|
||||
c, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
logs.Err(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
spend := time.Since(now)
|
||||
c.Close()
|
||||
mu.Lock()
|
||||
ls = append(ls, host)
|
||||
ls = append(ls, DialResult{
|
||||
Host: host,
|
||||
Spend: spend,
|
||||
})
|
||||
mu.Unlock()
|
||||
}(host)
|
||||
}
|
||||
wg.Wait()
|
||||
return ls
|
||||
return ls.Sort(func(a, b DialResult) bool {
|
||||
return a.Spend < b.Spend
|
||||
})
|
||||
}
|
||||
|
||||
// DialResult 连接结果
|
||||
type DialResult struct {
|
||||
Host string
|
||||
Spend time.Duration
|
||||
}
|
||||
|
||||
41
manage.go
41
manage.go
@@ -25,13 +25,21 @@ func NewManage(cfg *ManageConfig, op ...client.Option) (*Manage, error) {
|
||||
cfg.Dial = DialDefault
|
||||
}
|
||||
|
||||
//代码
|
||||
codesClient, err := cfg.Dial(op...)
|
||||
//通用客户端
|
||||
commonClient, err := cfg.Dial(op...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
codesClient.Wait.SetTimeout(time.Second * 5)
|
||||
codes, err := NewCodes(codesClient, cfg.CodesFilename)
|
||||
commonClient.Wait.SetTimeout(time.Second * 5)
|
||||
|
||||
//代码管理
|
||||
codes, err := NewCodes(commonClient, cfg.CodesFilename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//工作日管理
|
||||
workday, err := NewWorkday(commonClient, cfg.WorkdayFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -44,17 +52,6 @@ func NewManage(cfg *ManageConfig, op ...client.Option) (*Manage, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//工作日
|
||||
workdayClient, err := cfg.Dial(op...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workdayClient.Wait.SetTimeout(time.Second * 5)
|
||||
workday, err := NewWorkday(workdayClient, cfg.WorkdayFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Manage{
|
||||
Pool: p,
|
||||
Config: cfg,
|
||||
@@ -72,6 +69,20 @@ type Manage struct {
|
||||
Cron *cron.Cron
|
||||
}
|
||||
|
||||
// RangeStocks 遍历所有股票
|
||||
func (this *Manage) RangeStocks(f func(code string)) {
|
||||
for _, v := range this.Codes.GetStocks() {
|
||||
f(v)
|
||||
}
|
||||
}
|
||||
|
||||
// RangeETFs 遍历所有ETF
|
||||
func (this *Manage) RangeETFs(f func(code string)) {
|
||||
for _, v := range this.Codes.GetETFs() {
|
||||
f(v)
|
||||
}
|
||||
}
|
||||
|
||||
// AddWorkdayTask 添加工作日任务
|
||||
func (this *Manage) AddWorkdayTask(spec string, f func(m *Manage)) {
|
||||
this.Cron.AddFunc(spec, func() {
|
||||
|
||||
@@ -6,11 +6,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// HistoryTradeResp 历史分时交易比实时少了单量
|
||||
type HistoryTradeResp struct {
|
||||
Count uint16
|
||||
List Trades
|
||||
}
|
||||
// HistoryTradeResp 兼容之前的版本
|
||||
type HistoryTradeResp = TradeResp
|
||||
|
||||
type historyTrade struct{}
|
||||
|
||||
@@ -31,7 +28,7 @@ func (historyTrade) Frame(date, code string, start, count uint16) (*Frame, error
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (historyTrade) Decode(bs []byte, c TradeCache) (*HistoryTradeResp, error) {
|
||||
func (historyTrade) Decode(bs []byte, c TradeCache) (*TradeResp, error) {
|
||||
if len(bs) < 2 {
|
||||
return nil, errors.New("数据长度不足")
|
||||
}
|
||||
@@ -41,7 +38,7 @@ func (historyTrade) Decode(bs []byte, c TradeCache) (*HistoryTradeResp, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &HistoryTradeResp{
|
||||
resp := &TradeResp{
|
||||
Count: Uint16(bs[:2]),
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ func (kline) Decode(bs []byte, c KlineCache) (*KlineResp, error) {
|
||||
k.Volume = int64(getVolume(Uint32(bs[:4])))
|
||||
bs = bs[4:]
|
||||
switch c.Type {
|
||||
case TypeKlineMinute, TypeKline5Minute, TypeKlineMinute2, TypeKline15Minute, TypeKline30Minute, TypeKlineHour, TypeKlineDay2:
|
||||
case TypeKlineMinute, TypeKline5Minute, TypeKlineMinute2, TypeKline15Minute, TypeKline30Minute, TypeKline60Minute, TypeKlineDay2:
|
||||
k.Volume /= 100
|
||||
}
|
||||
k.Amount = Price(getVolume(Uint32(bs[:4])) * 1000) //从元转为厘,并去除多余的小数
|
||||
|
||||
@@ -50,6 +50,7 @@ const (
|
||||
TypeKline5Minute uint8 = 0 // 5分钟K 线
|
||||
TypeKline15Minute uint8 = 1 // 15分钟K 线
|
||||
TypeKline30Minute uint8 = 2 // 30分钟K 线
|
||||
TypeKline60Minute uint8 = 3 // 60分钟K 线
|
||||
TypeKlineHour uint8 = 3 // 1小时K 线
|
||||
TypeKlineDay2 uint8 = 4 // 日K 线, 发现和Day的区别是这个要除以100,其他未知
|
||||
TypeKlineWeek uint8 = 5 // 周K 线
|
||||
|
||||
@@ -102,7 +102,7 @@ func GetHourMinute(bs [2]byte) string {
|
||||
|
||||
func GetTime(bs [4]byte, Type uint8) time.Time {
|
||||
switch Type {
|
||||
case TypeKlineMinute, TypeKlineMinute2, TypeKline5Minute, TypeKline15Minute, TypeKline30Minute, TypeKlineHour:
|
||||
case TypeKlineMinute, TypeKlineMinute2, TypeKline5Minute, TypeKline15Minute, TypeKline30Minute, TypeKline60Minute:
|
||||
|
||||
yearMonthDay := Uint16(bs[:2])
|
||||
hourMinute := Uint16(bs[2:4])
|
||||
|
||||
Reference in New Issue
Block a user