You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
7.5 KiB
297 lines
7.5 KiB
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
|
|
}
|
|
|
|
|
|
|