parent
a9f4de28d0
commit
56e6e0a711
@ -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 |
||||
} |
||||
|
||||
|
@ -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 |
||||
} |
Loading…
Reference in new issue