优化显示,yahoo API接口修复

master
yg070520@sina.com 1 year ago
parent a9f4de28d0
commit 56e6e0a711
  1. 193
      cmd/mop/main.go
  2. 297
      day.go
  3. 24
      line_editor.go
  4. 12
      screen.go
  5. 102
      yahoo_crumb.go
  6. 58
      yahoo_market.go
  7. 35
      yahoo_quotes.go

@ -55,54 +55,96 @@ Enter comma-delimited list of stock tickers when prompted.
<r> Press any key to continue </r> <r> Press any key to continue </r>
` `
func getuserinput() string{
func getuserinput(preset *Preset, sc mop.Stock) string{
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
var precondition string
var instrumentname string
var buyorsell string
// Prompt the user to enter the first date if sc.Ticker == "" {
fmt.Print("Enter Command: ") fmt.Print("Enter Command: ")
scanner.Scan() scanner.Scan()
cmdstr := scanner.Text() cmdstr := scanner.Text()
preset := Preset{}
inputcmd := strings.Split(cmdstr, " ") inputcmd := strings.Split(cmdstr, " ")
if len(inputcmd) == 2 { if len(inputcmd) == 2 {
if inputcmd[0] == "buy" { if inputcmd[0] == "buy" {
preset.Direction = 23 preset.Direction = 23
}else if inputcmd[0] == "sell" { }else if inputcmd[0] == "sell" {
preset.Direction = 24 preset.Direction = 24
}else{
return ""
}
}else{ }else{
return "" return ""
} }
preset.Scode = inputcmd[1] preset.Scode = inputcmd[1]
}else{
preset.Direction = 23
preset.Scode = sc.Dividend[2:]
f1, _ := strconv.ParseFloat(sc.LastTrade, 64)
f2, _ := strconv.ParseFloat(sc.Change, 64)
precondition = fmt.Sprintf("%s>%.2f", sc.LastTrade, f1-f2)
instrumentname = sc.Ticker[2:]
}
fmt.Print("Enter Condition: ") if preset.Direction == 23 {
scanner.Scan() buyorsell = "buy"
condition := scanner.Text() } else {
if strings.Contains(condition, ">") { buyorsell = "sell"
preset.Ifbelow = 0 }
preset.Ifabove, _ = strconv.ParseFloat(strings.Replace(condition, ">", "", -1), 64)
}else if strings.Contains(condition, "<") {
preset.Ifabove = 0
preset.Ifbelow, _ = strconv.ParseFloat(strings.Replace(condition, "<", "", -1), 64)
}
fmt.Print("Enter Vol: ")
scanner.Scan()
vol := scanner.Text()
preset.Vol, _ = strconv.ParseFloat(vol, 64)
//fmt.Print(preset) if preset.Ifbelow == 0 && preset.Ifabove == 0 {
jsonData, err := json.Marshal(preset)
if err != nil { }else if preset.Ifbelow == 0 {
fmt.Println(err) precondition = fmt.Sprintf(">%f", preset.Ifabove)
} }else{
extraField := `,"cmd": "preset"}` precondition = fmt.Sprintf("<%f", preset.Ifbelow)
jsonData = append(jsonData[:len(jsonData)-1], extraField...) }
message := string(jsonData)
fmt.Println(message)
return message fmt.Printf("Enter Condition[%s %s][%s]: ", buyorsell, preset.Scode+instrumentname, precondition)
scanner.Scan()
condition := scanner.Text()
if strings.Contains(condition, ">") {
preset.Ifbelow = 0
preset.Ifabove, _ = strconv.ParseFloat(strings.Replace(condition, ">", "", -1), 64)
}else if strings.Contains(condition, "<") {
preset.Ifabove = 0
preset.Ifbelow, _ = strconv.ParseFloat(strings.Replace(condition, "<", "", -1), 64)
}else{
return ""
}
if preset.Ifbelow == 0 && preset.Ifabove == 0 {
precondition = ""
}else if preset.Ifbelow == 0 {
precondition = fmt.Sprintf(">%.2f", preset.Ifabove)
}else{
precondition = fmt.Sprintf("<%.2f", preset.Ifbelow)
} }
return "" fmt.Printf("Enter Vol[%s %s][%s]: ", buyorsell, preset.Scode+instrumentname, precondition)
scanner.Scan()
vol := scanner.Text()
preset.Vol, _ = strconv.ParseFloat(vol, 64)
if preset.Vol == 0 {
return ""
}
//fmt.Print(preset)
jsonData, err := json.Marshal(preset)
if err != nil {
fmt.Println(err)
}
extraField := `,"cmd": "preset"}`
jsonData = append(jsonData[:len(jsonData)-1], extraField...)
message := string(jsonData)
fmt.Println(message)
return message
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -123,6 +165,8 @@ func mainLoop(screen *mop.Screen, profile *mop.Profile, mode string) {
upDownJump := profile.UpDownJump upDownJump := profile.UpDownJump
redrawQuotesFlag := false redrawQuotesFlag := false
redrawMarketFlag := false redrawMarketFlag := false
account := ""
var canstock mop.Stock
// 创建一个用于存储用户输入的缓冲区 // 创建一个用于存储用户输入的缓冲区
input := "" input := ""
@ -145,6 +189,12 @@ func mainLoop(screen *mop.Screen, profile *mop.Profile, mode string) {
// create a new MQTT client // create a new MQTT client
opts := mqtt.NewClientOptions() opts := mqtt.NewClientOptions()
opts.AddBroker("tcp://119.29.166.226:1883") opts.AddBroker("tcp://119.29.166.226:1883")
currentTime := time.Now().UnixNano() / int64(time.Millisecond)
millisecondsString := strconv.FormatInt(currentTime, 10)
opts.SetClientID("client-mop-"+millisecondsString)
opts.SetUsername("sandy")
opts.SetPassword("Abb123456.")
client := mqtt.NewClient(opts) client := mqtt.NewClient(opts)
// connect to the MQTT broker // connect to the MQTT broker
@ -230,11 +280,23 @@ loop:
redrawQuotesFlag = true redrawQuotesFlag = true
} else if event.Key == termbox.KeyArrowUp || event.Ch == 'k' { } else if event.Key == termbox.KeyArrowUp || event.Ch == 'k' {
screen.DecreaseOffset(1) screen.DecreaseOffset(1)
screen.Selectmoveup() screen.Selectmoveup(quotes)
selstock := quotes.Getselectedinfo(screen.Selectindex())
if selstock != nil {
canstock = *selstock
}else{
canstock = mop.Stock{}
}
redrawQuotesFlag = true redrawQuotesFlag = true
} else if event.Key == termbox.KeyArrowDown || event.Ch == 'j' { } else if event.Key == termbox.KeyArrowDown || event.Ch == 'j' {
screen.IncreaseOffset(1) screen.IncreaseOffset(1)
screen.Selectmovedown(quotes) screen.Selectmovedown(quotes)
selstock := quotes.Getselectedinfo(screen.Selectindex())
if selstock != nil {
canstock = *selstock
}else{
canstock = mop.Stock{}
}
redrawQuotesFlag = true redrawQuotesFlag = true
} else if event.Key == termbox.KeyHome { } else if event.Key == termbox.KeyHome {
screen.ScrollTop() screen.ScrollTop()
@ -242,6 +304,18 @@ loop:
} else if event.Key == termbox.KeyEnd { } else if event.Key == termbox.KeyEnd {
screen.ScrollBottom() screen.ScrollBottom()
redrawQuotesFlag = true redrawQuotesFlag = true
} else if event.Ch == 'b' {
data := map[string]string{
"cmd": "getaccount",
}
jsonData, err := json.Marshal(data)
if err != nil {
fmt.Println(err)
}
message := string(jsonData)
token := client.Publish("stock/request/470100037961", 0, false, message)
token.Wait()
account = "470100037961"
} else if event.Key == termbox.KeySpace { } else if event.Key == termbox.KeySpace {
data := map[string]string{ data := map[string]string{
"cmd": "getaccount", "cmd": "getaccount",
@ -251,21 +325,24 @@ loop:
fmt.Println(err) fmt.Println(err)
} }
message := string(jsonData) message := string(jsonData)
token := client.Publish("stock/request", 0, false, message) token := client.Publish("stock/request/620000301588", 0, false, message)
token.Wait() token.Wait()
account = "620000301588"
} else if event.Ch >= '0' && event.Ch <= '9' { } else if event.Ch >= '0' && event.Ch <= '9' {
input += string(event.Ch) input += string(event.Ch)
} else if event.Key == termbox.KeyEnter { } else if event.Key == termbox.KeyEnter {
indexnum, err := strconv.Atoi(input) indexnum, err := strconv.Atoi(input)
selectindex := screen.Selectindex() selectindex := screen.Selectindex()
if selectindex > 0 { if selectindex > 0 {
indexnum = selectindex selcode := canstock.Dividend
err = nil quotes.Sendstockgraphreq(selcode, false)
} quotes.Sendstockgraphreq(selcode, true)
}else{
//fmt.Println("indexnum:", indexnum) //fmt.Println("indexnum:", indexnum)
if err == nil && indexnum > 0 { if err == nil && indexnum > 0 {
quotes.Sendstockgraphreq(indexnum, false) quotes.Sendstockgraphreq(indexnum, false)
quotes.Sendstockgraphreq(indexnum, true) quotes.Sendstockgraphreq(indexnum, true)
}
} }
// 清空输入缓冲区 // 清空输入缓冲区
input = "" input = ""
@ -356,19 +433,21 @@ loop:
}else if strings.HasPrefix(msg.Topic(), "stock/image/time"){ }else if strings.HasPrefix(msg.Topic(), "stock/image/time"){
os.Stdout.Write(msg.Payload()) os.Stdout.Write(msg.Payload())
jsonstr := getuserinput() preset := &Preset{}
jsonstr := getuserinput(preset, canstock)
if jsonstr != "" { if jsonstr != "" {
token := client.Publish("stock/request", 0, false, jsonstr) token := client.Publish("stock/request/"+account, 0, false, jsonstr)
token.Wait() token.Wait()
} }
} }
}else if strings.HasPrefix(msg.Topic(), "stock/response"){ }else if strings.HasPrefix(msg.Topic(), "stock/response"){
fmt.Print("\033[2J") fmt.Print("\033[2J")
showposition(string(msg.Payload()) ,si) showposition(string(msg.Payload()) ,si)
jsonstr := getuserinput() preset := &Preset{}
jsonstr := getuserinput(preset, canstock)
if jsonstr != "" { if jsonstr != "" {
token := client.Publish("stock/request", 0, false, jsonstr) token := client.Publish("stock/request/"+account, 0, false, jsonstr)
token.Wait() token.Wait()
} }
} }
@ -412,6 +491,10 @@ type Positions struct {
Latestinfo string `json:"lastinfo"` Latestinfo string `json:"lastinfo"`
} }
func float2Str(f float64) string {
return fmt.Sprintf("%.2f", f)
}
func showposition(payload string,si map[string]*stock.Stock) string{ func showposition(payload string,si map[string]*stock.Stock) string{
var positions Positions var positions Positions
@ -422,10 +505,14 @@ func showposition(payload string,si map[string]*stock.Stock) string{
} }
var data [][]string var data [][]string
var totalFloatProfit float64 = 0.0
var totalMarketValue float64 = 0.0
//fmt.Println(positions.Position) //fmt.Println(positions.Position)
for _, pos := range positions.Position { for _, pos := range positions.Position {
row := []string{pos.Scode + " " +pos.Sname, fmt.Sprintf("%.2f", pos.Openprice), fmt.Sprintf("%.2f", pos.Floatprofit), fmt.Sprintf("%.2f", pos.Marketvalue)} row := []string{pos.Scode + " " +pos.Sname, fmt.Sprintf("%.2f", pos.Openprice), fmt.Sprintf("%.2f", pos.Floatprofit), fmt.Sprintf("%.2f", pos.Marketvalue)}
data = append(data, row) data = append(data, row)
totalFloatProfit += pos.Floatprofit
totalMarketValue += pos.Marketvalue
} }
for _, pos := range positions.Preset { for _, pos := range positions.Preset {
@ -455,8 +542,8 @@ func showposition(payload string,si map[string]*stock.Stock) string{
tableString := &strings.Builder{} tableString := &strings.Builder{}
table := tablewriter.NewWriter(tableString) table := tablewriter.NewWriter(tableString)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) table.SetHeader([]string{"Instrument", "Avg. Price", "Float Profit", "Market Value"})
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer table.SetFooter([]string{"", "Total", float2Str(totalFloatProfit), float2Str(totalMarketValue)}) // Add Footer
//table.EnableBorder(false) // Set Border to false //table.EnableBorder(false) // Set Border to false
table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor}, table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor},

297
day.go

@ -0,0 +1,297 @@
package mop
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
//"github.com/markcheno/go-talib"
)
type KLineData struct {
Day string `json:"day"`
Open float64 `json:"open,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Close float64 `json:"close,string"`
Volume float64 `json:"volume,string"`
}
func getURL(code string, ts int, count int) string {
return fmt.Sprintf("http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=%s&scale=%d&ma=5&datalen=%d", code, ts, count)
}
func getKLineData(url string) ([]KLineData, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var data []KLineData
err = json.Unmarshal(body, &data)
if err != nil {
return nil, err
}
return data, nil
}
func get_price_sina(code string, end_date string, count int, frequency string, startdate string) ([]KLineData, error) {
frequency = strings.Replace(frequency, "1d", "240m", 1)
frequency = strings.Replace(frequency, "1w", "1200m", 1)
frequency = strings.Replace(frequency, "1M", "7200m", 1)
ts, err := strconv.Atoi(strings.TrimSuffix(frequency, "m"))
if err != nil {
return nil, err
}
if end_date != "" && (frequency == "240m" || frequency == "1200m" || frequency == "7200m") {
endDate, err := time.Parse("2006-01-02", end_date)
if err != nil {
return nil, err
}
unit := 1
if frequency == "1200m" {
unit = 4
} else if frequency == "7200m" {
unit = 29
}
days := int(time.Since(endDate).Hours() / 24)
count = count + days/unit
}
url := getURL(code, ts, count)
//fmt.Printf("url: %s\n", url)
data, err := getKLineData(url)
if err != nil {
return nil, err
}
//fmt.Printf("data: %v\n", data)
if startdate != "" && (frequency == "240m" || frequency == "1200m" || frequency == "7200m") {
endDate := time.Now()
//endDate, err := time.Parse("2006-01-02", end_date)
//if err != nil {
// return nil, err
//}
start_date, err := time.Parse("2006-01-02", startdate)
if err != nil {
return nil, err
}
filteredData := []KLineData{}
for _, d := range data {
day, err := time.Parse("2006-01-02", d.Day)
if err != nil {
return nil, err
}
if day.After(start_date) && (day.Before(endDate) || day.Equal(endDate)) {
filteredData = append(filteredData, d)
}
}
return filteredData, nil
}
return data, nil
}
func findMaxHighAndMinLow(data []KLineData) (float64, float64) {
maxHigh := data[0].High
minLow := data[0].Low
for _, d := range data {
if d.High > maxHigh {
maxHigh = d.High
}
if d.Low < minLow {
minLow = d.Low
}
}
return maxHigh, minLow
}
// 将interface{}类型转换为float64类型
func convertToFloat64(value interface{}) float64 {
if floatValue, ok := value.(float64); ok {
return floatValue
}
if stringValue, ok := value.(string); ok {
floatValue, err := strconv.ParseFloat(stringValue, 64)
if err == nil {
return floatValue
}
}
return 0
}
func getURLTencent(code string, start string, count int) string {
// 给定的日期
datestr := ""
date, err := time.Parse("2006-01-02", start)
if err != nil {
fmt.Println("解析日期失败:", err)
}else{
futureDate := date.AddDate(0, 0, 10)
if futureDate.Before(time.Now()){
datestr = futureDate.Format("2006-01-02")
fmt.Println(datestr)
}
}
return fmt.Sprintf("https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=%s,day,,%s,%d,qfq", code, datestr, count)
}
func getKLineTencent(url string, code string)([]KLineData, error){
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var dataMap map[string]interface{}
err = json.Unmarshal(body, &dataMap)
if err != nil {
fmt.Println("解析JSON字符串失败", err)
return nil, err
}
klineData := make([]KLineData, 0)
// 获取K线数据
if shData, ok := dataMap["data"].(map[string]interface{})[code].(map[string]interface{}); ok {
if qfqday, ok := shData["qfqday"].([]interface{}); ok {
for _, item := range qfqday {
if data, ok := item.([]interface{}); ok {
klineData = append(klineData, KLineData{
Day: data[0].(string),
Open: convertToFloat64(data[1]),
High: convertToFloat64(data[3]),
Low: convertToFloat64(data[4]),
Close: convertToFloat64(data[2]),
Volume: convertToFloat64(data[5]),
})
}
}
//fmt.Println(klineData)
return klineData,nil
}else if day, ok := shData["day"].([]interface{}); ok {
for _, item := range day {
if data, ok := item.([]interface{}); ok {
klineData = append(klineData, KLineData{
Day: data[0].(string),
Open: convertToFloat64(data[1]),
High: convertToFloat64(data[3]),
Low: convertToFloat64(data[4]),
Close: convertToFloat64(data[2]),
Volume: convertToFloat64(data[5]),
})
}
}
return klineData,nil
}
}
return klineData,nil
}
func get_price_tencent(code string, end_date string, count int, frequency string, startdate string) ([]KLineData, error) {
frequency = strings.Replace(frequency, "1d", "240m", 1)
frequency = strings.Replace(frequency, "1w", "1200m", 1)
frequency = strings.Replace(frequency, "1M", "7200m", 1)
if end_date != "" && (frequency == "240m" || frequency == "1200m" || frequency == "7200m") {
endDate, err := time.Parse("2006-01-02", end_date)
if err != nil {
return nil, err
}
unit := 1
if frequency == "1200m" {
unit = 4
} else if frequency == "7200m" {
unit = 29
}
days := int(time.Since(endDate).Hours() / 24)
count = count + days/unit
}
/*
url := getURL(code, ts, count)
fmt.Printf("url: %s\n", url)
data, err := getKLineData(url)
*/
url := getURLTencent(code, startdate, 10)
//fmt.Printf("url: %s\n", url)
data, err := getKLineTencent(url, code)
if err != nil {
return nil, err
}
//fmt.Printf("data: %v\n", data)
if startdate != "" && (frequency == "240m" || frequency == "1200m" || frequency == "7200m") {
endDate := time.Now()
//endDate, err := time.Parse("2006-01-02", end_date)
//if err != nil {
// return nil, err
//}
start_date, err := time.Parse("2006-01-02", startdate)
if err != nil {
return nil, err
}
filteredData := []KLineData{}
for _, d := range data {
day, err := time.Parse("2006-01-02", d.Day)
if err != nil {
return nil, err
}
//fmt.Println(start_date, endDate, day)
if day.After(start_date) && (day.Before(endDate) || day.Equal(endDate)) {
filteredData = append(filteredData, d)
}
}
return filteredData, nil
}
return data, nil
}
func getnextdaysHL(code string, start_date string) (float64, float64, float64, float64 ,int) {
//data, err := get_price_sina(code, "", 30, "240m", start_date)
data, err := get_price_tencent(code, "", 30, "240m", start_date)
if err != nil {
return 0, 0, 0, 0, 0
}
pre := 3
if len(data) < 3 {
pre = len(data)
}
//fmt.Printf("data: %v\n", data[:3])
caldata := data[:pre]
maxHigh, minLow := findMaxHighAndMinLow(caldata)
//fmt.Println(maxHigh, minLow)
return caldata[0].Open, caldata[pre-1].Close, maxHigh, minLow, pre
}

@ -64,6 +64,30 @@ func (editor *LineEditor) Prompt(command rune) *LineEditor {
return editor return editor
} }
func (editor *LineEditor) PromptInstrumet(command rune) *LineEditor {
filterPrompt := `Set filter: `
if filter := editor.quotes.profile.Filter; len(filter) > 0 {
filterPrompt = `Set filter (` + filter + `): `
}
prompts := map[rune]string{
'+': `Add tickers: `, '-': `Remove tickers: `,
'f': filterPrompt,
}
if prompt, ok := prompts[command]; ok {
editor.prompt = prompt
editor.command = command
editor.screen.DrawLine(0, 3, `<white>`+editor.prompt+`</>`)
termbox.SetCursor(len(editor.prompt), 3)
termbox.Flush()
}
return editor
}
func (editor *LineEditor) insertString(str string) { func (editor *LineEditor) insertString(str string) {
for _, ch := range str { for _, ch := range str {
editor.insertCharacter(ch) editor.insertCharacter(ch)

@ -117,22 +117,32 @@ func (screen *Screen) DecreaseOffset(n int) {
} }
} }
func (screen *Screen) Selectmoveup() { func (screen *Screen) Selectmoveup(quotes *Quotes) {
if screen.selectindex >= 5 { if screen.selectindex >= 5 {
screen.selectindex -= 1 screen.selectindex -= 1
} }
if screen.selectindex == 4 {
screen.DrawLine(0, 3, `<white>`+" "+`</>`)
}else{
screen.DrawLine(0, 3, `<white>`+quotes.stocks[screen.selectindex-5].Ticker+`</>`)
}
} }
func (screen *Screen) Selectmovedown(quotes *Quotes) { func (screen *Screen) Selectmovedown(quotes *Quotes) {
if screen.selectindex < len(quotes.stocks) + 4 { if screen.selectindex < len(quotes.stocks) + 4 {
screen.selectindex += 1 screen.selectindex += 1
} }
screen.DrawLine(0, 3, `<white>`+quotes.stocks[screen.selectindex-5].Ticker+`</>`)
} }
func (screen *Screen) Selectindex() int { func (screen *Screen) Selectindex() int {
return screen.selectindex - 4 return screen.selectindex - 4
} }
func (screen *Screen) Selectpreset() int {
return screen.selectindex - 4
}
func (screen *Screen) ScrollTop() { func (screen *Screen) ScrollTop() {
screen.offset = 0 screen.offset = 0
} }

@ -0,0 +1,102 @@
// Copyright (c) 2013-2023 by Michael Dvorkin and contributors. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.
package mop
import (
"io/ioutil"
"net/http"
"strings"
"net/url"
)
const crumbURL = "https://query1.finance.yahoo.com/v1/test/getcrumb"
const cookieURL = "https://login.yahoo.com"
const userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0"
func fetchCrumb(cookies string) string {
proxyUrl, err := url.Parse("http://172.29.100.107:28888")
if err != nil {
panic(err)
}
transport := &http.Transport{
Proxy: http.ProxyURL(proxyUrl),
}
client := &http.Client{
Transport: transport,
}
//client := http.Client{}
request, err := http.NewRequest("GET", crumbURL, nil)
if err != nil {
panic(err)
}
request.Header = http.Header{
"Accept": {"*/*"},
"Accept-Encoding": {"gzip, deflate, br"},
"Accept-Language": {"en-US,en;q=0.5"},
"Connection": {"keep-alive"},
"Content-Type": {"text/plain"},
"Cookie": {cookies},
"Host": {"query1.finance.yahoo.com"},
"Sec-Fetch-Dest": {"empty"},
"Sec-Fetch-Mode": {"cors"},
"Sec-Fetch-Site": {"same-site"},
"TE": {"trailers"},
"User-Agent": {userAgent},
}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}
return string(body[:])
}
func fetchCookies() string {
client := http.Client{}
request, err := http.NewRequest("GET", cookieURL, nil)
if err != nil {
panic(err)
}
request.Header = http.Header{
"Accept": {"*/*"},
"Accept-Encoding": {"gzip, deflate, br"},
"Accept-Language": {"en-US,en;q=0.5"},
"Connection": {"keep-alive"},
"Host": {"login.yahoo.com"},
"Sec-Fetch-Dest": {"document"},
"Sec-Fetch-Mode": {"navigate"},
"Sec-Fetch-Site": {"none"},
"Sec-Fetch-User": {"?1"},
"TE": {"trailers"},
"Update-Insecure-Requests": {"1"},
"User-Agent": {userAgent},
}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
var result string
for _, cookie := range response.Cookies() {
if cookie.Name != "AS" {
result += cookie.Name + "=" + cookie.Value + "; "
}
}
result = strings.TrimSuffix(result, "; ")
return result
}

@ -5,16 +5,16 @@
package mop package mop
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"encoding/json" "net/url"
//"net/url"
"easyquotation/stock" "easyquotation/stock"
) )
const marketURL = `https://query1.finance.yahoo.com/v6/finance/quote?symbols=%s` const marketURL = `https://query1.finance.yahoo.com/v7/finance/quote?crumb=%s&symbols=%s`
const marketURLQueryParts = `&range=1d&interval=5m&indicators=close&includeTimestamps=false&includePrePost=false&corsDomain=finance.yahoo.com&.tsrc=finance` const marketURLQueryParts = `&range=1d&interval=5m&indicators=close&includeTimestamps=false&includePrePost=false&corsDomain=finance.yahoo.com&.tsrc=finance`
// Market stores current market information displayed in the top three lines of // Market stores current market information displayed in the top three lines of
@ -38,6 +38,8 @@ type Market struct {
res map[string]*stock.Stock res map[string]*stock.Stock
watchlist *Watchlist watchlist *Watchlist
cookies string // cookies for auth
crumb string // crumb for the cookies, to be applied as a query param
} }
// Returns new initialized Market struct. // Returns new initialized Market struct.
@ -59,7 +61,9 @@ func NewMarket(res map[string]*stock.Stock, watchlist *Watchlist) *Market {
market.Euro = make(map[string]string) market.Euro = make(map[string]string)
market.Gold = make(map[string]string) market.Gold = make(map[string]string)
market.url = fmt.Sprintf(marketURL, `^DJI,^IXIC,^GSPC,^N225,^HSI,^FTSE,^GDAXI,^TNX,CL=F,CNH=X,EUR=X,GC=F`) + marketURLQueryParts market.cookies = fetchCookies()
market.crumb = fetchCrumb(market.cookies)
market.url = fmt.Sprintf(marketURL, market.crumb, `^DJI,^IXIC,^GSPC,^N225,^HSI,^FTSE,^GDAXI,^TNX,CL=F,CNH=X,EUR=X,GC=F`) + marketURLQueryParts
market.errors = `` market.errors = ``
market.res = res market.res = res
@ -78,6 +82,7 @@ func (market *Market) Fetch() (self *Market) {
market.errors = "" market.errors = ""
} }
}() }()
/*
// Define the proxy URL // Define the proxy URL
//proxyUrl, err := url.Parse("http://172.29.100.107:28888") //proxyUrl, err := url.Parse("http://172.29.100.107:28888")
//if err != nil { //if err != nil {
@ -98,12 +103,55 @@ func (market *Market) Fetch() (self *Market) {
panic(err) panic(err)
} }
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}*/
proxyUrl, err := url.Parse("http://172.29.100.107:28888")
if err != nil {
panic(err)
}
transport := &http.Transport{
Proxy: http.ProxyURL(proxyUrl),
}
client := &http.Client{
Transport: transport,
}
//client := http.Client{}
request, err := http.NewRequest("GET", market.url, nil)
if err != nil {
panic(err)
}
request.Header = http.Header{
"Accept": {"*/*"},
"Accept-Language": {"en-US,en;q=0.5"},
"Connection": {"keep-alive"},
"Content-Type": {"application/json"},
"Cookie": {market.cookies},
"Host": {"query1.finance.yahoo.com"},
"Origin": {"https://finance.yahoo.com"},
"Referer": {"https://finance.yahoo.com"},
"Sec-Fetch-Dest": {"empty"},
"Sec-Fetch-Mode": {"cors"},
"Sec-Fetch-Site": {"same-site"},
"TE": {"trailers"},
"User-Agent": {userAgent},
}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close() defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
panic(err) panic(err)
} }
//fmt.Println(string(body))
body = market.isMarketOpen(body) body = market.isMarketOpen(body)
return market.extract(body) return market.extract(body)
} }

@ -204,9 +204,10 @@ func (quotes *Quotes) Fetch() (self *Quotes) {
//write a function to save the slice of quotes.stocks to file //write a function to save the slice of quotes.stocks to file
func (quotes *Quotes) SaveStocks() { func (quotes *Quotes) SaveStocks() {
//fmt.Println("save") if quotes.profile.mode == "review"{
//fmt.Println(quotes.stocks) return
//fmt.Println(quotes.profile.mode) }
filedata, err := json.MarshalIndent(quotes.totalstocks, "", " ") filedata, err := json.MarshalIndent(quotes.totalstocks, "", " ")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
@ -383,18 +384,27 @@ func padString(str string, length int) string {
return str return str
} }
func (quotes *Quotes) Sendstockgraphreq(index int, istime bool) { func (quotes *Quotes) Sendstockgraphreq(index interface{}, istime bool) {
if index > len(quotes.totalstocks){ var selcode string
return if intvalue, ok := index.(int); ok {
if intvalue > len(quotes.totalstocks){
return
}
selcode = quotes.totalstocks[intvalue-1].Scode
}
if stringValue, ok := index.(string); ok {
selcode = stringValue
} }
topic := "my/topic" topic := "my/topic"
itemsel := quotes.getitembyscode(quotes.totalstocks[index-1].Scode) itemsel := quotes.getitembyscode(selcode)
data := map[string]interface{}{ data := map[string]interface{}{
"scode": quotes.totalstocks[index-1].Scode, "scode": selcode,//quotes.totalstocks[index-1].Scode,
"tier": 0, "tier": 0,
"daysback": itemsel.Daysback, "daysback": itemsel.Daysback,
"stdprice": itemsel.Enterprice, "stdprice": itemsel.Enterprice,
"name": strings.TrimSpace(quotes.totalstocks[index-1].Sname), "name": quotes.res[selcode].Base.Name, //strings.TrimSpace(quotes.totalstocks[index-1].Sname),
"ed": itemsel.AnalyseDay, "ed": itemsel.AnalyseDay,
} }
if istime { if istime {
@ -410,6 +420,13 @@ func (quotes *Quotes) Sendstockgraphreq(index int, istime bool) {
token.Wait() token.Wait()
} }
func (quotes *Quotes) Getselectedinfo(index int) *Stock {
if index > len(quotes.totalstocks) || index < 1 {
return nil
}
return &quotes.stocks[index-1]
}
func (quotes *Quotes) parsereview(res map[string]*stock.Stock) (*Quotes, error) { func (quotes *Quotes) parsereview(res map[string]*stock.Stock) (*Quotes, error) {
var scodes []string var scodes []string
fmt.Println("Start parsing review") fmt.Println("Start parsing review")

Loading…
Cancel
Save