frist commit

master
xuebing zhang 4 years ago
parent 5681ec638d
commit 86036645ee
  1. 43
      decode/decode.go
  2. 7
      decode/decode_test.go
  3. 31
      quotation.go
  4. 26
      quotation_test.go
  5. 19
      sina/sina.go
  6. 63
      sina/sinaindex.go
  7. 104
      sina/sinastock.go
  8. 2
      sina/sinastock_test.go
  9. 47
      stock/stock.go
  10. 66
      stock/stockmanager.go
  11. 6
      stock/stockmanager_test.go
  12. 131
      utils/helper.go
  13. 20
      utils/helper_test.go

@ -0,0 +1,43 @@
package decode
import (
"easyquotation/stock"
"easyquotation/utils"
"fmt"
"reflect"
"strings"
)
var str string = "var hq_str_sz161505=\"银河通利,0.000,1.258,0.000,0.000,0.000,1.239,1.280,0,0.000,3000,1.239,8100,1.234,1000,1.233,1000,1.198,900,1.188,5548,1.280,900,1.300,1000,1.314,1000,1.326,1600,1.330,2020-07-24,10:58:12,00\""
func Split(r rune) bool {
return r == ' ' || r == '_' || r == '='
}
func DecodeMarket() {
l := utils.SplitString(str, Split)
symbol := l[3]
market := l[4][1 : len(l[4])-1]
marketList := strings.Split(market, ",")
a := stock.Market{}
eleVals := reflect.ValueOf(&a).Elem()
utils.DecodeStock(marketList[:10], eleVals)
for i := 0; i < 10; i += 2 {
bEntry := stock.Entry{}
vals := reflect.ValueOf(&bEntry).Elem()
utils.DecodeStock(marketList[10+i:10+i+2], vals)
a.BuyEntryList = append(a.BuyEntryList, bEntry)
}
for i := 0; i < 10; i += 2 {
bEntry := stock.Entry{}
vals := reflect.ValueOf(&bEntry).Elem()
utils.DecodeStock(marketList[20+i:20+i+2], vals)
a.SellEntryList = append(a.SellEntryList, bEntry)
}
a.Date = marketList[30]
a.Time = marketList[31]
a.Flag = marketList[32]
fmt.Println(a)
}

@ -0,0 +1,7 @@
package decode
import "testing"
func TestDecodeMarket(t *testing.T) {
DecodeMarket()
}

@ -0,0 +1,31 @@
package easyquotation
import (
. "easyquotation/stock"
"easyquotation/utils"
"log"
"os"
)
func Init() {
path, err := os.Getwd()
file := path + "/message" + ".txt"
logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
if err != nil {
panic(err)
}
log.SetOutput(logFile) // 将文件设置为log输出的文件
log.SetPrefix("[quotation]")
log.SetFlags(log.LstdFlags | log.Lshortfile | log.LUTC)
// 获取新浪股票代码信息
utils.UpdateStockCodes()
//
G_STOCK_MANAGER = &StockManager{
make(map[string]*Stock),
make(map[string]*Stock),
make(map[string]*Stock),
make(map[string]*Stock),
}
G_STOCK_MANAGER.Load()
}

@ -0,0 +1,26 @@
package easyquotation
import (
"easyquotation/sina"
"easyquotation/stock"
"fmt"
"github.com/gocolly/colly"
"testing"
"time"
)
func TestInit(t *testing.T) {
Init()
c := colly.NewCollector()
SinaStock_spider := sina.NewSinaStock(c)
SinaStock_spider.Start()
tt := time.NewTicker(time.Second * 3)
for {
select {
case <- tt.C:
fmt.Println(stock.G_STOCK_MANAGER.StockList["sh600000"])
}
}
}

@ -0,0 +1,19 @@
package sina
import (
"github.com/gocolly/colly"
"time"
)
type ISpiderIntface interface {
Url() string
Collector(c *colly.Collector)
OnRequest(r *colly.Request)
OnResponse(res *colly.Response)
Start()
}
type Spider struct {
C *colly.Collector
Timer *time.Ticker // 个股
}

@ -0,0 +1,63 @@
package sina
import (
"easyquotation/stock"
"easyquotation/utils"
"fmt"
"github.com/gocolly/colly"
"log"
"time"
)
type SinaIndex struct {
Spider
}
func (s *SinaIndex) Url() string {
return fmt.Sprintf("http://hq.sinajs.cn/rn=%s&list=", utils.Random(5))
}
func NewSinaIndex(c *colly.Collector) *SinaIndex {
s := &SinaIndex{Spider{Timer:time.NewTicker(time.Second * 10)}}
s.Collector(c)
s.C.OnRequest(s.OnRequest)
s.C.OnResponse(s.OnResponse)
return s
}
func (s *SinaIndex) Collector(c *colly.Collector) {
s.Spider.C = c.Clone()
}
func (s *SinaIndex) OnRequest(r *colly.Request) {
}
func (s *SinaIndex) OnResponse(res *colly.Response) {
log.Println(string(res.Body))
}
func (s *SinaIndex) Start() {
go func() {
for {
select {
case <- s.Spider.Timer.C:
ipos := 1
params := make([]string, 0)
param := ""
for k, _ := range stock.G_STOCK_MANAGER.StockList {
if ipos%800 == 0 {
params = append(params, param)
param = ""
}
param += k
param += ","
ipos++
}
params = append(params, param)
for _, str := range params {
url := s.Url() + str
go s.C.Visit(url)
}
}
}
}()
}

@ -0,0 +1,104 @@
package sina
import (
"easyquotation/stock"
"easyquotation/utils"
"fmt"
"github.com/gocolly/colly"
"reflect"
"strings"
"time"
)
type SinaStock struct {
Spider
}
func NewSinaStock(c *colly.Collector) *SinaStock {
s := &SinaStock{Spider{Timer: time.NewTicker(time.Second * 3)}}
s.Collector(c)
s.C.OnRequest(s.OnRequest)
s.C.OnResponse(s.OnResponse)
return s
}
func (s *SinaStock) Collector(c *colly.Collector) {
s.Spider.C = c.Clone()
}
func (s *SinaStock) Url() string {
return fmt.Sprintf("http://hq.sinajs.cn/rn=%d&list=", time.Now().Unix())
}
func (s *SinaStock) OnRequest(r *colly.Request) {
// fmt.Println(r.URL)
}
func (s *SinaStock) Split(r rune) bool {
return r == ' ' || r == '_' || r == '='
}
func (s *SinaStock) DecodeMarket(str string) {
l := utils.SplitString(str, s.Split)
if (len(l) < 5){
return
}
symbol := l[3] // 代码
market := l[4][1 : len(l[4])-1] // 去除左右" "
marketList := strings.Split(market, ",")
if (len(marketList) < 33) {
return
}
a := stock.Market{}
eleVals := reflect.ValueOf(&a).Elem()
utils.DecodeStock(marketList[:10], eleVals)
// 买五档
for i := 0; i < 10; i += 2 {
bEntry := stock.Entry{}
vals := reflect.ValueOf(&bEntry).Elem()
utils.DecodeStock(marketList[10+i:10+i+2], vals)
a.BuyEntryList = append(a.BuyEntryList, bEntry)
}
// 卖五档
for i := 0; i < 10; i += 2 {
bEntry := stock.Entry{}
vals := reflect.ValueOf(&bEntry).Elem()
utils.DecodeStock(marketList[20+i:20+i+2], vals)
a.SellEntryList = append(a.SellEntryList, bEntry)
}
a.Date = marketList[30]
a.Time = marketList[31]
a.Flag = marketList[32]
stock.G_STOCK_MANAGER.StockList[symbol].Market = a
}
func (s *SinaStock) OnResponse(res *colly.Response) {
l := strings.Split(string(res.Body), ";")
for _, str := range l {
s.DecodeMarket(str)
}
}
func (s *SinaStock) Start() {
go func() {
for {
select {
case <-s.Spider.Timer.C:
ipos := 1
params := make([]string, 0)
param := ""
for k, _ := range stock.G_STOCK_MANAGER.StockList {
if ipos%800 == 0 {
params = append(params, param)
param = ""
}
param += k
param += ","
ipos++
}
params = append(params, param)
for _, str := range params {
url := s.Url() + str
go s.C.Visit(url)
}
}
}
}()
}

@ -0,0 +1,2 @@
package sina

@ -0,0 +1,47 @@
package stock
const (
TICK_DAY_NUM = 4*60 + 2 // 分时数据量
)
type Base struct {
Symbol string // 代码
Name string // 全称
Short string // 简称
}
type Entry struct {
Qty float64 `json:"qty"` // 数量
Price float64 `json:"price"` // 价格
}
type Tick struct {
Time string // 时间
LastPrice float64 // 最新价
AvgPrice float64 // 均价
Volumn float64 // 成交量
Value float64 // 成交额
}
type Market struct {
Name string `json:"name"` // 名称
Open float64 `json:"open"` // 开盘
PreClose float64 `json:"pre_close"` // 昨收
LastPrice float64 `json:"last_price"` // 最新价
High float64 `json:"high"` // 最高价
Low float64 `json:"low"` // 最低价
BidPice float64 `json:"bid_pice"` // 竞买价
OfferPice float64 `json:"offer_pice"` // 竞卖价
Volumn float64 `json:"volumn"` // 成交量(股)
Value float64 `json:"value"` // 成交额(元)
BuyEntryList []Entry `json:"buy_entry_list"` // 买5档
SellEntryList []Entry `json:"sell_entry_list"` // 卖5档
Date string `json:"date"` // 日期
Time string `json:"time"` // 时间
Flag string `json:"flag"` // 状态
}
type Stock struct {
Base
Market
}

@ -0,0 +1,66 @@
package stock
import (
"bufio"
"easyquotation/utils"
"fmt"
"os"
"reflect"
"strings"
)
var G_STOCK_MANAGER *StockManager
type StockManager struct {
StockList map[string]*Stock //个股
IndexList map[string]*Stock //指数
BKkList map[string]*Stock //板块
ZZIndexList map[string]*Stock //中证指数
}
func (s *StockManager) SetBase(list []string) *Stock {
b := Base{}
eleVals := reflect.ValueOf(&b).Elem()
utils.DecodeStock(list, eleVals)
return &Stock{Base: b}
}
// 加载股票信息
func (s *StockManager) Load() {
path, err := os.Getwd()
if err != nil {
path = "./"
}
if file, err := os.Open(path + "/stock_codes"); err != nil {
panic(err)
} else {
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
eleList := strings.Split(line, " ")
if len(eleList) < 3 {
continue
} else {
if strings.HasPrefix(eleList[0], "zz") {
s.ZZIndexList[eleList[0]] = s.SetBase(eleList)
} else {
if utils.EndSwitch(eleList[1], []string{".沪指数", ".深指数"}) {
if !strings.HasPrefix(eleList[0], "sh") {
eleList[0] = fmt.Sprintf("sz%s", eleList[0])
}
s.IndexList[eleList[0]] = s.SetBase(eleList)
} else if strings.HasSuffix(eleList[1], ".板块") {
s.BKkList[eleList[0]] = s.SetBase(eleList)
} else {
if utils.StartSwitch(eleList[0], []string{"5", "6", "9"}) {
eleList[0] = fmt.Sprintf("sh%s", eleList[0])
} else {
eleList[0] = fmt.Sprintf("sz%s", eleList[0])
}
s.StockList[eleList[0]] = s.SetBase(eleList)
}
}
}
}
}
}

@ -0,0 +1,6 @@
package stock
import "testing"
func TestStockManager_Load(t *testing.T) {
}

@ -0,0 +1,131 @@
package utils
import (
"io/ioutil"
"math/rand"
"net/http"
"os"
"reflect"
"strconv"
"strings"
"time"
"unsafe"
"errors"
)
func UpdateStockCodes() {
path, err := os.Getwd()
if err != nil {
path = "./"
}
req, err := http.NewRequest("GET", "http://www.shdjt.com/js/lib/astock.js", nil)
if err != nil {
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
list := strings.Split(string(respBody), "=")
list = strings.Split(list[1][1:len(list[1])-1], "~")
if fileObj, err := os.OpenFile(path+"/stock_codes", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666); err == nil {
defer fileObj.Close()
realList := list[1:]
realLen := len(realList)
for index0, item := range realList {
l := strings.Split(item, "`")
for _, s := range l {
fileObj.WriteString(s + " ")
}
if index0 != realLen-1 {
fileObj.WriteString("\n")
}
}
}
}
func StartSwitch(s string, prefixs []string) bool {
for _, prefix := range prefixs {
if strings.HasPrefix(s, prefix) == true {
return true
}
}
return false
}
func EndSwitch(s string, suffixs []string) bool {
for _, suffix := range suffixs {
if strings.HasSuffix(s, suffix) == true {
return true
}
}
return false
}
// 生成随机串
// ref:https://cloud.tencent.com/developer/article/1580647
var src = rand.NewSource(time.Now().UnixNano())
const letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
func Random(n int) (s string) {
b := make([]byte, n)
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return *(*string)(unsafe.Pointer(&b))
}
func Min(a ...int) int {
m := int(^uint(0) >> 1)
for _, i := range a {
if i < m {
m = i
}
}
return m
}
func SplitString(s string, f func(rune) bool) []string {
a := strings.FieldsFunc(s, f)
return a
}
func DecodeStock(list []string, data reflect.Value) {
length := Min(len(list), data.NumField())
for i := 0; i < length; i++ {
switch data.Field(i).Kind() {
case reflect.String:
data.Field(i).SetString(list[i])
case reflect.Int:
i64, _ := strconv.ParseInt(list[i], 10,64)
data.Field(i).SetInt(i64)
case reflect.Float64:
f, _ := strconv.ParseFloat(list[i], 64)
data.Field(i).SetFloat(f)
default:
panic(errors.New("Decode error"))
}
}
}

@ -0,0 +1,20 @@
package utils
import (
"fmt"
"testing"
)
func TestUpdateStockCodes(t *testing.T) {
UpdateStockCodes()
}
func TestStockMarket(t *testing.T) {
}
func TestRandom(t *testing.T) {
for i:=0; i< 100; i++ {
fmt.Println(Random(5))
}
}
Loading…
Cancel
Save