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.
1214 lines
43 KiB
1214 lines
43 KiB
2 months ago
|
package processor
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"github.com/360EntSecGroup-Skylar/excelize"
|
||
|
"github.com/gin-gonic/gin"
|
||
|
"github.com/shopspring/decimal"
|
||
|
"go.mongodb.org/mongo-driver/bson"
|
||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
|
"go.mongodb.org/mongo-driver/mongo"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
"wss-pool/cmd/common"
|
||
|
"wss-pool/config"
|
||
|
"wss-pool/internal"
|
||
|
"wss-pool/internal/data"
|
||
|
"wss-pool/internal/data/business"
|
||
|
"wss-pool/internal/data/mysqlbusiness"
|
||
|
red "wss-pool/internal/redis"
|
||
|
"wss-pool/logging/applogger"
|
||
|
"wss-pool/pkg/model"
|
||
|
"wss-pool/pkg/model/stock"
|
||
|
)
|
||
|
|
||
|
var topIc = "https://"
|
||
|
var TotalSize int = 10
|
||
|
var FreeSymbolKey = "USER:MARKET:"
|
||
|
var MarketType = map[int]string{
|
||
|
1: "spots",
|
||
|
2: "contract",
|
||
|
3: "US",
|
||
|
4: "Indonesia",
|
||
|
5: "Malaysia",
|
||
|
6: "Thailand",
|
||
|
7: "India",
|
||
|
9: "Singapore",
|
||
|
12: "HongKong",
|
||
|
14: "UK",
|
||
|
15: "France",
|
||
|
16: "Germany",
|
||
|
17: "Brazil",
|
||
|
18: "Japan",
|
||
|
19: "Forex",
|
||
|
}
|
||
|
|
||
|
type StockSymbol struct {
|
||
|
Code string `json:"code"`
|
||
|
Name string `json:"name"`
|
||
|
MarketType int `json:"market_type"`
|
||
|
TradeNumericCode string `json:"trade_numeric_code"`
|
||
|
}
|
||
|
|
||
|
// ExchangeSymbolList Obtain stock list data
|
||
|
func ExchangeSymbolList(c *gin.Context) {
|
||
|
/* 股票代码查询业务逻辑
|
||
|
1、列表查询传入交易所代码
|
||
|
2、搜索
|
||
|
1、带有交易所代码--模糊查询当前交易所的股票
|
||
|
2、不带有交易所代码--模糊查询所有股票
|
||
|
3、查询股票列表不排序,搜索排序(通过code排序)
|
||
|
*/
|
||
|
symbol := internal.ReplaceStr(c.Query("symbol")) // 国家(美股,马股)
|
||
|
pageSize := internal.IntegerInit(internal.ReplaceStr(c.Query("pageSize"))) // 每页显示多少条数据
|
||
|
pageNumber := internal.IntegerInit(internal.ReplaceStr(c.Query("pageNumber"))) // 第几页
|
||
|
sort := internal.IntegerInit(internal.ReplaceStr(c.Query("sort"))) // Code排序
|
||
|
search := internal.ReplaceStr(c.Query("search")) // 搜索数据(模糊
|
||
|
code := internal.ReplaceStr(c.Query("code")) // 多个代码
|
||
|
primaryExchange := internal.ReplaceStr(c.Query("primaryExchange")) // 交易所
|
||
|
if pageSize <= 0 || pageNumber <= 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "分页参数不能为零", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
var condition = symbol
|
||
|
var filter bson.M
|
||
|
if len(search) > 0 {
|
||
|
//香港股票代码特殊处理
|
||
|
if symbol == "HongKong" {
|
||
|
numberWithoutLeadingZeros := strings.TrimLeft(search, "0")
|
||
|
if numberWithoutLeadingZeros == "" {
|
||
|
numberWithoutLeadingZeros = "0"
|
||
|
}
|
||
|
search = numberWithoutLeadingZeros
|
||
|
}
|
||
|
if len(primaryExchange) > 0 {
|
||
|
filter = bson.M{"Country": condition, "Exchange": primaryExchange, "$or": []bson.M{{"Code": bson.M{"$regex": search}}, {"Name": bson.M{"$regex": search}}, {"NumericCode": bson.M{"$regex": search}}}, "YesterdayClose": bson.M{"$ne": ""}}
|
||
|
} else {
|
||
|
filter = bson.M{"Country": condition, "$or": []bson.M{{"Code": bson.M{"$regex": search}}, {"Name": bson.M{"$regex": search}}, {"NumericCode": bson.M{"$regex": search}}}, "YesterdayClose": bson.M{"$ne": ""}, "Exchange": bson.M{"$exists": true}}
|
||
|
}
|
||
|
} else {
|
||
|
if len(primaryExchange) > 0 {
|
||
|
filter = bson.M{"Country": condition, "Exchange": primaryExchange, "YesterdayClose": bson.M{"$ne": ""}}
|
||
|
} else {
|
||
|
filter = bson.M{"Country": condition, "YesterdayClose": bson.M{"$ne": ""}, "Exchange": bson.M{"$exists": true}}
|
||
|
}
|
||
|
}
|
||
|
codeSearch := "Code"
|
||
|
if symbol == "Malaysia" {
|
||
|
codeSearch = "NumericCode"
|
||
|
}
|
||
|
str_s := strings.Split(code, "-")
|
||
|
if len(code) > 0 {
|
||
|
if len(primaryExchange) > 0 {
|
||
|
filter = bson.M{"Country": condition, "Exchange": primaryExchange, "YesterdayClose": bson.M{"$ne": ""}, codeSearch: bson.M{"$in": str_s}}
|
||
|
} else {
|
||
|
filter = bson.M{"Country": condition, "YesterdayClose": bson.M{"$ne": ""}, codeSearch: bson.M{"$in": str_s}, "Exchange": bson.M{"$exists": true}}
|
||
|
}
|
||
|
}
|
||
|
total, err := data.MgoFindTotal(data.StockList, filter)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
//applogger.Debug("查询数据表: %v", data.StockList)
|
||
|
//applogger.Debug("查询数据总数: %v", total)
|
||
|
pageData := make([]stock.StockPolygon, 0)
|
||
|
if sort == 0 {
|
||
|
sort = -1
|
||
|
}
|
||
|
sortField := "Vol"
|
||
|
if symbol == "US" {
|
||
|
sortField = "DP"
|
||
|
}
|
||
|
//applogger.Debug("查询条件: %v", filter)
|
||
|
var md stock.MgoPageSize
|
||
|
md.PageSize = pageSize
|
||
|
md.PageNumber = pageNumber
|
||
|
md.Total = total
|
||
|
if err = data.MgoPagingFindStruct(data.StockList, filter, int64(pageSize), int64(pageNumber), sortField, sort, &pageData); err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
||
|
}
|
||
|
//applogger.Debug("查询数据: %", len(pageData))
|
||
|
if len(pageData) <= 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
||
|
return
|
||
|
}
|
||
|
var dataStockPolygon = make([]stock.StockPolygon, 0)
|
||
|
for k, v := range pageData {
|
||
|
key := business.StockClosingPrice[fmt.Sprintf("%sNew", v.Locale)]
|
||
|
pageData[k].ClosePrice, err = red.Hget(key, v.Code)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
if common.IsExistStock(v.Locale, v.Code) {
|
||
|
dataStockPolygon = append(dataStockPolygon, pageData[k])
|
||
|
}
|
||
|
}
|
||
|
md.Data = dataStockPolygon
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// ExchangeFreeSymbolList exchange free symbol list
|
||
|
func ExchangeFreeSymbolList(c *gin.Context) {
|
||
|
id := internal.ReplaceStr(c.Query("id")) // 用户ID
|
||
|
market_type := internal.IntegerInit(internal.ReplaceStr(c.Query("market_type"))) // 市场
|
||
|
pageSize := internal.IntegerInit(internal.ReplaceStr(c.Query("pageSize"))) // 每页显示多少条数据
|
||
|
pageNumber := internal.IntegerInit(internal.ReplaceStr(c.Query("pageNumber"))) // 第几页
|
||
|
if pageSize <= 0 || pageNumber <= 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "分页参数不能为零", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
if len(id) <= 0 || market_type <= 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "参数不能为空", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
var md stock.MgoPageSize
|
||
|
var dataStockPolygon = make([]stock.StockPolygon, 0)
|
||
|
md.PageSize = pageSize
|
||
|
md.PageNumber = pageNumber
|
||
|
|
||
|
userIdKey := fmt.Sprintf("%v%v", FreeSymbolKey, id)
|
||
|
result, err := red.Get_Cache_Byte(userIdKey)
|
||
|
if err != nil {
|
||
|
md.Data = dataStockPolygon
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
var freeList []StockSymbol
|
||
|
if err = json.Unmarshal(result, &freeList); err != nil {
|
||
|
md.Data = dataStockPolygon
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
// 组合需要查询自选缓存股票code
|
||
|
var symbolList []string
|
||
|
var condition = MarketType[market_type]
|
||
|
for _, value := range freeList {
|
||
|
if market_type == value.MarketType {
|
||
|
symbolList = append(symbolList, value.Code)
|
||
|
}
|
||
|
}
|
||
|
//applogger.Debug("查询自选股票列表: %v", symbolList)
|
||
|
codeSearch := "Code"
|
||
|
if condition == "Malaysia" {
|
||
|
codeSearch = "NumericCode"
|
||
|
}
|
||
|
filter := bson.M{"Country": condition, "YesterdayClose": bson.M{"$ne": ""}, codeSearch: bson.M{"$in": symbolList}, "Exchange": bson.M{"$exists": true}}
|
||
|
total, err := data.MgoFindTotal(data.StockList, filter)
|
||
|
if err != nil {
|
||
|
md.Total = int64(len(symbolList))
|
||
|
md.Data = dataStockPolygon
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
//applogger.Debug("查询数据表: %v", data.StockList)
|
||
|
//applogger.Debug("查询数据总数: %v", total)
|
||
|
//applogger.Debug("查询条件: %v", filter)
|
||
|
md.Total = total
|
||
|
var pageData = make([]stock.StockPolygon, 0)
|
||
|
sortField := "Vol"
|
||
|
if condition == "US" {
|
||
|
sortField = "DP"
|
||
|
}
|
||
|
if err = data.MgoPagingFindStruct(data.StockList, filter, int64(pageSize), int64(pageNumber), sortField, -1, &pageData); err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
||
|
return
|
||
|
}
|
||
|
if len(pageData) <= 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
||
|
return
|
||
|
}
|
||
|
for k, v := range pageData {
|
||
|
key := business.StockClosingPrice[fmt.Sprintf("%sNew", v.Locale)]
|
||
|
pageData[k].ClosePrice, err = red.Hget(key, v.Code)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
if common.IsExistStock(v.Locale, v.Code) {
|
||
|
dataStockPolygon = append(dataStockPolygon, pageData[k])
|
||
|
}
|
||
|
}
|
||
|
md.Data = dataStockPolygon
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
func UpdateKeepDecimal(c *gin.Context) {
|
||
|
param := model.Data{}
|
||
|
err := c.BindJSON(¶m)
|
||
|
if err != nil {
|
||
|
applogger.Error("BindJSON", err.Error())
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "param error", internal.QueryError))
|
||
|
return
|
||
|
} else if param.StockCode == "" {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "stock_code null", internal.QueryError))
|
||
|
return
|
||
|
} else if param.KeepDecimal == 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "keep_decimal error", internal.QueryError))
|
||
|
return
|
||
|
} else if param.Currency == "" {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "currency error", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
filterS := bson.D{{"Code", bson.M{
|
||
|
"$eq": param.StockCode,
|
||
|
}}, {"Currency", bson.M{
|
||
|
"$eq": param.Currency,
|
||
|
}}}
|
||
|
updateData := bson.M{
|
||
|
"$set": bson.M{
|
||
|
"Code": param.StockCode,
|
||
|
"KeepDecimal": param.KeepDecimal,
|
||
|
}}
|
||
|
if err := data.MgoUpdateOne(data.StockList, filterS, updateData); err != nil {
|
||
|
applogger.Error("MgoBulkWrite update err:%v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err.Error(), internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "ok", internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
func SymbolToExcel(c *gin.Context) {
|
||
|
country := internal.ReplaceStr(c.Query("country"))
|
||
|
filter := bson.M{}
|
||
|
if country != "" {
|
||
|
filter = bson.M{"Country": country}
|
||
|
} else {
|
||
|
country = "total"
|
||
|
}
|
||
|
res := make([]stock.StockPolygon, 0)
|
||
|
data.MgoFindRes(data.StockList, filter, &res)
|
||
|
// 创建Excel文件
|
||
|
file := excelize.NewFile()
|
||
|
sheetName := "Sheet1"
|
||
|
// 写入表头
|
||
|
file.SetCellValue(sheetName, "A1", "Code")
|
||
|
file.SetCellValue(sheetName, "B1", "Name")
|
||
|
file.SetCellValue(sheetName, "C1", "Country")
|
||
|
file.SetCellValue(sheetName, "D1", "PrimaryExchange")
|
||
|
file.SetCellValue(sheetName, "E1", "Symbol")
|
||
|
file.SetCellValue(sheetName, "F1", "NumericCode")
|
||
|
file.SetCellValue(sheetName, "G1", "Intro")
|
||
|
file.SetCellValue(sheetName, "H1", "JapanIntro")
|
||
|
file.SetCellValue(sheetName, "I1", "JapanName")
|
||
|
// 写入数据
|
||
|
row := 2 // 从第二行开始写入数据
|
||
|
for _, val := range res {
|
||
|
if val.PrimaryExchange == "" {
|
||
|
applogger.Error(val.Locale, val.Code, " not Exchange")
|
||
|
continue
|
||
|
}
|
||
|
file.SetCellValue(sheetName, "A"+strconv.Itoa(row), val.Code)
|
||
|
file.SetCellValue(sheetName, "B"+strconv.Itoa(row), val.Name)
|
||
|
file.SetCellValue(sheetName, "C"+strconv.Itoa(row), val.Locale)
|
||
|
file.SetCellValue(sheetName, "D"+strconv.Itoa(row), val.PrimaryExchange)
|
||
|
file.SetCellValue(sheetName, "E"+strconv.Itoa(row), val.Symbol)
|
||
|
file.SetCellValue(sheetName, "F"+strconv.Itoa(row), val.NumericCode)
|
||
|
file.SetCellValue(sheetName, "G"+strconv.Itoa(row), val.Intro)
|
||
|
file.SetCellValue(sheetName, "H"+strconv.Itoa(row), val.JapanIntro)
|
||
|
file.SetCellValue(sheetName, "I"+strconv.Itoa(row), val.JapanName)
|
||
|
row++
|
||
|
}
|
||
|
// 保存文件
|
||
|
err := file.SaveAs(fmt.Sprintf("/home/ubuntu/wss-server/%s.xlsx", country))
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
func ExcelToSymbolByJapanJson(c *gin.Context) {
|
||
|
data.Mgo_init(config.Config.Mongodb)
|
||
|
f, err := excelize.OpenFile("/home/ubuntu/wss-server/Japan.xlsx")
|
||
|
if err != nil {
|
||
|
applogger.Error("ExcelToSymbol err:%v", err)
|
||
|
return
|
||
|
}
|
||
|
var dataList []mongo.WriteModel
|
||
|
// 获取 Sheet1 上所有单元格
|
||
|
rows := f.GetRows("Sheet1")
|
||
|
for k, row := range rows {
|
||
|
if k == 0 {
|
||
|
continue
|
||
|
}
|
||
|
applogger.Debug("Code:%v", row[0])
|
||
|
applogger.Debug("Name:%v", row[1])
|
||
|
applogger.Debug("Country:%v", row[2])
|
||
|
applogger.Debug("PrimaryExchange:%v", row[3])
|
||
|
applogger.Debug("Symbol:%v", row[4])
|
||
|
applogger.Debug("NumericCode:%v", row[5])
|
||
|
applogger.Debug("Intro:%v", row[6])
|
||
|
applogger.Debug("JapanIntro:%v", row[7])
|
||
|
applogger.Debug("JapanName:%v", row[8])
|
||
|
|
||
|
filter := bson.D{{"Code", bson.M{
|
||
|
"$eq": row[0],
|
||
|
}}, {"Country", bson.M{
|
||
|
"$eq": row[2],
|
||
|
}}}
|
||
|
|
||
|
update := bson.D{{"$set", bson.D{
|
||
|
{"Code", row[0]},
|
||
|
{"Name", row[1]},
|
||
|
{"Country", row[2]},
|
||
|
{"PrimaryExchange", row[3]},
|
||
|
{"Symbol", row[4]},
|
||
|
{"NumericCode", row[5]},
|
||
|
{"Intro", row[6]},
|
||
|
{"JapanIntro", row[7]},
|
||
|
{"JapanName", row[8]},
|
||
|
}}}
|
||
|
|
||
|
models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true)
|
||
|
dataList = append(dataList, models)
|
||
|
}
|
||
|
if len(dataList) > 0 {
|
||
|
if err = data.MgoBulkWrite(data.StockList, dataList); err != nil {
|
||
|
applogger.Error("MgoInsertMany err:%v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "operation failure", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", "ok"))
|
||
|
}
|
||
|
func ExcelToSymbolByJapan(c *gin.Context) {
|
||
|
data.Mgo_init(config.Config.Mongodb)
|
||
|
f, err := excelize.OpenFile("/home/ubuntu/wss-server/Japan_edited.xlsx")
|
||
|
if err != nil {
|
||
|
applogger.Error("ExcelToSymbol err:%v", err)
|
||
|
return
|
||
|
}
|
||
|
var dataList []mongo.WriteModel
|
||
|
// 获取 Sheet1 上所有单元格
|
||
|
rows := f.GetRows("Sheet1")
|
||
|
for k, row := range rows {
|
||
|
if k == 0 {
|
||
|
continue
|
||
|
}
|
||
|
applogger.Debug("Name:%v", row[0])
|
||
|
applogger.Debug("Symbol:%v", row[1])
|
||
|
applogger.Debug("JapanName:%v", row[2])
|
||
|
|
||
|
filter := bson.D{{"Symbol", bson.M{"$eq": row[1]}}}
|
||
|
update := bson.D{{"$set", bson.D{{"JapanName", row[2]}}}}
|
||
|
models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true)
|
||
|
dataList = append(dataList, models)
|
||
|
}
|
||
|
if len(dataList) > 0 {
|
||
|
if err = data.MgoBulkWrite(data.StockList, dataList); err != nil {
|
||
|
applogger.Error("MgoInsertMany err:%v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "operation failure", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", "ok"))
|
||
|
}
|
||
|
func ExcelToForexCode(c *gin.Context) {
|
||
|
data.Mgo_init(config.Config.Mongodb)
|
||
|
f, err := excelize.OpenFile("/home/ubuntu/wss-server/forex_code.xlsx")
|
||
|
if err != nil {
|
||
|
applogger.Error("ExcelToSymbol err:%v", err)
|
||
|
return
|
||
|
}
|
||
|
var dataList []mongo.WriteModel
|
||
|
applogger.Debug("这里执行了。。。。。")
|
||
|
// 获取 Sheet1 上所有单元格
|
||
|
rows := f.GetRows("Sheet1")
|
||
|
for k, row := range rows {
|
||
|
if k == 0 {
|
||
|
continue
|
||
|
}
|
||
|
applogger.Debug("code:%v", row[0])
|
||
|
applogger.Debug("name:%v", row[1])
|
||
|
applogger.Debug("category:%v", row[2])
|
||
|
applogger.Debug("symbol:%v", row[3])
|
||
|
|
||
|
filter := bson.D{{"code", bson.M{"$eq": row[0]}}}
|
||
|
update := bson.D{{"$set", bson.D{
|
||
|
{"code", row[0]},
|
||
|
{"name", row[1]},
|
||
|
{"category", row[2]},
|
||
|
{"symbol", row[3]},
|
||
|
}}}
|
||
|
models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true)
|
||
|
dataList = append(dataList, models)
|
||
|
}
|
||
|
applogger.Debug("这里执行了。。。。。111111")
|
||
|
if len(dataList) > 0 {
|
||
|
if err = data.MgoBulkWrite(data.ForexListBak, dataList); err != nil {
|
||
|
applogger.Error("MgoInsertMany err:%v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "operation failure", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", "ok"))
|
||
|
}
|
||
|
|
||
|
func TickerToExcel(c *gin.Context) {
|
||
|
filter := bson.M{}
|
||
|
res := make([]stock.ForexData, 0)
|
||
|
data.MgoFindRes(data.StockList, filter, &res)
|
||
|
// 创建Excel文件
|
||
|
file := excelize.NewFile()
|
||
|
sheetName := "Sheet1"
|
||
|
// 写入表头
|
||
|
file.SetCellValue(sheetName, "A1", "code")
|
||
|
file.SetCellValue(sheetName, "B1", "Name")
|
||
|
file.SetCellValue(sheetName, "C1", "Country")
|
||
|
file.SetCellValue(sheetName, "D1", "PrimaryExchange")
|
||
|
file.SetCellValue(sheetName, "E1", "Symbol")
|
||
|
file.SetCellValue(sheetName, "F1", "NumericCode")
|
||
|
// 写入数据
|
||
|
row := 2 // 从第二行开始写入数据
|
||
|
for _, val := range res {
|
||
|
file.SetCellValue(sheetName, "A"+strconv.Itoa(row), val.Ticker)
|
||
|
file.SetCellValue(sheetName, "B"+strconv.Itoa(row), "")
|
||
|
file.SetCellValue(sheetName, "C"+strconv.Itoa(row), "")
|
||
|
file.SetCellValue(sheetName, "D"+strconv.Itoa(row), "")
|
||
|
file.SetCellValue(sheetName, "E"+strconv.Itoa(row), "")
|
||
|
file.SetCellValue(sheetName, "F"+strconv.Itoa(row), "")
|
||
|
row++
|
||
|
}
|
||
|
// 保存文件
|
||
|
//err := file.SaveAs(fmt.Sprintf("/home/ubuntu/wss-server/%s.xlsx", "forex"))
|
||
|
err := file.SaveAs(fmt.Sprintf("./cmd/%s.xlsx", "forex"))
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
func OptionToExcel(c *gin.Context) {
|
||
|
symbol := internal.ReplaceStr(c.Query("option"))
|
||
|
filter := bson.M{"Country": symbol}
|
||
|
res := make([]model.OptionPolygon, 0)
|
||
|
data.MgoFindRes(data.OptionList, filter, &res)
|
||
|
// 创建Excel文件
|
||
|
file := excelize.NewFile()
|
||
|
sheetName := "Sheet1"
|
||
|
// 写入表头
|
||
|
file.SetCellValue(sheetName, "A1", "Code")
|
||
|
file.SetCellValue(sheetName, "B1", "Name")
|
||
|
file.SetCellValue(sheetName, "C1", "Country")
|
||
|
file.SetCellValue(sheetName, "D1", "Tape")
|
||
|
// 写入数据
|
||
|
row := 2 // 从第二行开始写入数据
|
||
|
for _, val := range res {
|
||
|
file.SetCellValue(sheetName, "A"+strconv.Itoa(row), val.Stock)
|
||
|
file.SetCellValue(sheetName, "B"+strconv.Itoa(row), val.Stock)
|
||
|
file.SetCellValue(sheetName, "C"+strconv.Itoa(row), val.Country)
|
||
|
file.SetCellValue(sheetName, "D"+strconv.Itoa(row), val.PrimaryExchange)
|
||
|
row++
|
||
|
}
|
||
|
// 保存文件
|
||
|
err := file.SaveAs(fmt.Sprintf("%s.xlsx", symbol))
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// IntraDisCal IntraDisCal data
|
||
|
func IntraDisCal(c *gin.Context) {
|
||
|
symbol := strings.ToUpper(internal.ReplaceStr(c.Query("symbol"))) // 股票代码
|
||
|
intMin := internal.IntegerInit(internal.ReplaceStr(c.Query("interval"))) // 查询间隔
|
||
|
from := internal.IntegerInit(internal.ReplaceStr(c.Query("from"))) // 开始时间
|
||
|
applogger.Debug("Incoming parameters:%v", symbol, intMin)
|
||
|
|
||
|
if from <= 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusUnauthorized, "parameter error", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//filter := bson.M{"Code": symbol, "YesterdayClose": bson.M{"$ne": ""}, "BeforeClose": bson.M{"$ne": ""}}
|
||
|
intTime := intMin * 60 * 1000
|
||
|
match := bson.D{
|
||
|
{"$match", bson.D{
|
||
|
{"s", symbol},
|
||
|
{"t", bson.D{{"$gte", from}}}},
|
||
|
}}
|
||
|
group := bson.D{{
|
||
|
"$group", bson.D{
|
||
|
{"_id", bson.D{{"$subtract", bson.A{"$t", bson.D{{"$mod", bson.A{"$t", intTime}}}}}}},
|
||
|
{"fisrtTime", bson.D{{"$first", "$t"}}},
|
||
|
{"lastTime", bson.D{{"$last", "$t"}}},
|
||
|
{"datetime", bson.D{{"$first", bson.D{{"$dateToString",
|
||
|
bson.D{{"format", "%Y-%m-%d %H:%M:%S"},
|
||
|
{"date", bson.D{{"$add", bson.A{time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), "$t", 28800000}}}}}}}}}},
|
||
|
{"timestamp", bson.D{{"$first", "$t"}}},
|
||
|
{"open", bson.D{{"$max", bson.D{{"$toDouble", "$p"}}}}},
|
||
|
{"high", bson.D{{"$max", bson.D{{"$toDouble", "$h"}}}}},
|
||
|
{"low", bson.D{{"$min", bson.D{{"$toDouble", "$l"}}}}},
|
||
|
{"close", bson.D{{"$min", bson.D{{"$toDouble", "$cl"}}}}},
|
||
|
{"volume", bson.D{{"$sum", "$v"}}},
|
||
|
}}}
|
||
|
sort := bson.D{{"$sort", bson.D{{"timestamp", 1}}}}
|
||
|
|
||
|
operations := mongo.Pipeline{match, group, sort}
|
||
|
applogger.Debug("mongodb filter info: %v", operations)
|
||
|
|
||
|
mapList, err := data.MgoAggregate(data.StockUs, operations)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusUnauthorized, "MgoAggregate err", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
applogger.Debug("data info: %v", mapList)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, mapList, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// FindShareBySymbol 自选列表查询服务
|
||
|
func FindShareBySymbol(c *gin.Context) {
|
||
|
auth := internal.ReplaceStr(c.Query("auth"))
|
||
|
systemBoursesId := internal.IntegerInit(internal.ReplaceStr(c.Query("systemBoursesId")))
|
||
|
bourseType := internal.IntegerInit(internal.ReplaceStr(c.Query("bourseType")))
|
||
|
|
||
|
if len(auth) == 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusUnauthorized, internal.QueryToken, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
check, userId, err := mysqlbusiness.GetBoUsers(auth)
|
||
|
if err != nil {
|
||
|
applogger.Error("GetBoUsers err: %v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusUnauthorized, internal.QueryToken, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if !check {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusUnauthorized, internal.QueryToken, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
usList, err := mysqlbusiness.GetBoUserOptionalStocksNew(bourseType, systemBoursesId, userId)
|
||
|
if err != nil {
|
||
|
applogger.Error("GetBoUserOptionalStocks err : %v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusUnauthorized, "", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var keys []bson.M
|
||
|
for _, value := range usList {
|
||
|
code := value.Stockcode
|
||
|
keys = append(keys, bson.M{"Code": code})
|
||
|
}
|
||
|
|
||
|
filter := bson.M{"$or": keys}
|
||
|
pagedData, err := data.MgoFind(data.StockList, filter)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusInternalServerError, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
pagedDataMap := make(map[string]stock.StockShare)
|
||
|
for _, vue := range pagedData.([]primitive.M) {
|
||
|
var stockM stock.StockShare
|
||
|
code := vue["Code"]
|
||
|
beforeClose := vue["BeforeClose"]
|
||
|
yesterdayClose := vue["YesterdayClose"]
|
||
|
fullName := vue["Name"]
|
||
|
stockM.BeforeClose = beforeClose.(string)
|
||
|
stockM.YesterdayClose = yesterdayClose.(string)
|
||
|
stockM.Name = fullName.(string)
|
||
|
pagedDataMap[code.(string)] = stockM
|
||
|
}
|
||
|
|
||
|
applogger.Debug("")
|
||
|
|
||
|
var dataList []model.Data
|
||
|
for _, value := range usList {
|
||
|
var md model.Data
|
||
|
dataBool := false
|
||
|
vue, ok := pagedDataMap[value.Stockcode]
|
||
|
if ok {
|
||
|
md.BeforeClose = decimal.RequireFromString(vue.BeforeClose)
|
||
|
md.YesterdayClose = decimal.RequireFromString(vue.YesterdayClose)
|
||
|
md.FullName = vue.Name
|
||
|
|
||
|
md.Id = value.Id
|
||
|
md.BourseType = value.Boursetype
|
||
|
md.SystemBoursesId = value.Systemboursesid
|
||
|
md.UserId = value.Userid
|
||
|
md.StockCode = value.Stockcode
|
||
|
|
||
|
dataList = append(dataList, md)
|
||
|
|
||
|
dataBool = true
|
||
|
}
|
||
|
if !dataBool {
|
||
|
md.Id = value.Id
|
||
|
md.BourseType = value.Boursetype
|
||
|
md.SystemBoursesId = value.Systemboursesid
|
||
|
md.UserId = value.Userid
|
||
|
md.StockCode = value.Stockcode
|
||
|
md.FullName = ""
|
||
|
dataList = append(dataList, md)
|
||
|
}
|
||
|
dataBool = false
|
||
|
}
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, dataList, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// Fundamentals 获取个人股票信息
|
||
|
func Fundamentals(c *gin.Context) {
|
||
|
// https://eodhistoricaldata.com/api/fundamentals/AAPL.US?api_token=demo
|
||
|
symbol := internal.ReplaceStr(c.Query("symbol"))
|
||
|
region := internal.ReplaceStr(c.Query("region"))
|
||
|
filter := internal.ReplaceStr(c.Query("filter"))
|
||
|
|
||
|
var param string
|
||
|
param = fmt.Sprintf("api_token=%v", config.Config.ShareGather.FinancialKey)
|
||
|
if len(filter) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("filter=%v", filter)
|
||
|
}
|
||
|
if len(symbol) == 0 {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "参数错误", internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
qe := fmt.Sprintf("%v.%v", symbol, region)
|
||
|
url := fmt.Sprintf("%v%v/api/fundamentals/%v?%v", topIc, config.Config.ShareGather.FinancialHost, qe, param)
|
||
|
|
||
|
applogger.Debug("url info:%v", url)
|
||
|
|
||
|
bodyStr := make(map[string]interface{})
|
||
|
data, err := red.Get_Cache_Data(symbol)
|
||
|
applogger.Debug("数据信息:%v", data)
|
||
|
if err != nil {
|
||
|
applogger.Error("Get_Cache_Data err: %v", err)
|
||
|
}
|
||
|
if len(data) == 0 {
|
||
|
bodyStr, err = internal.HttpGetDoNew(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
//applogger.Debug("bodyStr info:%v", bodyStr)
|
||
|
jsonStr, err := json.Marshal(bodyStr)
|
||
|
if err != nil {
|
||
|
applogger.Debug("http data json Marshal err: %v", bodyStr)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
if err = red.Set_Cache_Data(symbol, jsonStr, 1440); err != nil {
|
||
|
applogger.Error("write Set_Cache_Data info err: %v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
} else {
|
||
|
if err := json.Unmarshal([]byte(data), &bodyStr); err != nil {
|
||
|
applogger.Error("select redis data json Unmarshal err: %v", err)
|
||
|
}
|
||
|
}
|
||
|
//applogger.Debug("data info:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// FundamentalsNew Obtain individual stock information data (add close)
|
||
|
func FundamentalsNew(c *gin.Context) {
|
||
|
// https://eodhistoricaldata.com/api/fundamentals/AAPL.US?api_token=demo
|
||
|
symbol := internal.ReplaceStr(c.Query("symbol"))
|
||
|
region := internal.ReplaceStr(c.Query("region"))
|
||
|
filter := internal.ReplaceStr(c.Query("filter"))
|
||
|
|
||
|
filterM := bson.M{"Code": symbol}
|
||
|
pagedData, err := data.MgoFind(data.StockList, filterM)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
var yesterdayClose, beforeClose string
|
||
|
for _, vue := range pagedData.([]primitive.M) {
|
||
|
yesterdayClose = vue["YesterdayClose"].(string)
|
||
|
beforeClose = vue["BeforeClose"].(string)
|
||
|
}
|
||
|
applogger.Debug("data info: %v", yesterdayClose, beforeClose)
|
||
|
|
||
|
var param string
|
||
|
param = fmt.Sprintf("api_token=%v", config.Config.ShareGather.FinancialKey)
|
||
|
if len(filter) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("filter=%v", filter)
|
||
|
}
|
||
|
|
||
|
qe := fmt.Sprintf("%v.%v", symbol, region)
|
||
|
url := fmt.Sprintf("%v%v/api/fundamentals/%v?%v", topIc, config.Config.ShareGather.FinancialHost, qe, param)
|
||
|
|
||
|
applogger.Debug("info url:%v", url)
|
||
|
|
||
|
bodyStr := make(map[string]interface{})
|
||
|
data, err := red.Get_Cache_Data(symbol)
|
||
|
if err != nil {
|
||
|
applogger.Error("Get_Cache_Data err: %v", err)
|
||
|
}
|
||
|
if len(data) == 0 {
|
||
|
bodyStr, err = internal.HttpGetDoNew(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
//applogger.Debug("bodyStr info:%v", bodyStr)
|
||
|
jsonStr, err := json.Marshal(bodyStr)
|
||
|
if err != nil {
|
||
|
//applogger.Debug("http data json Marshal err: %v", bodyStr)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
if err := red.Set_Cache_Data(symbol, jsonStr, 1440); err != nil {
|
||
|
applogger.Error("write Set_Cache_Data info err: %v", err)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
} else {
|
||
|
if err := json.Unmarshal([]byte(data), &bodyStr); err != nil {
|
||
|
applogger.Error("select redis data json Unmarshal err: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bodyStr["YesterdayClose"] = yesterdayClose
|
||
|
bodyStr["BeforeClose"] = beforeClose
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// Intraday Daily historical data
|
||
|
func Intraday(c *gin.Context) {
|
||
|
// https://eodhistoricaldata.com/api/intraday/AAPL.US?api_token=647dd6744b94f4.20894198&fmt=json&from=1564752900&to=1564753200&interval=1m
|
||
|
symbol := internal.ReplaceStr(c.Query("symbol"))
|
||
|
region := internal.ReplaceStr(c.Query("region"))
|
||
|
from := internal.ReplaceStr(c.Query("from"))
|
||
|
interval := internal.ReplaceStr(c.Query("interval"))
|
||
|
to := internal.ReplaceStr(c.Query("to"))
|
||
|
|
||
|
var param string
|
||
|
param = fmt.Sprintf("api_token=%v", config.Config.ShareGather.FinancialKey)
|
||
|
if len(from) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("from=%v", from)
|
||
|
}
|
||
|
if len(to) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("to=%v", to)
|
||
|
}
|
||
|
if len(interval) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("interval=%v", interval)
|
||
|
}
|
||
|
|
||
|
qe := fmt.Sprintf("%v.%v", symbol, region)
|
||
|
url := fmt.Sprintf("%v%v/api/intraday/%v?fmt=json&%v", topIc, config.Config.ShareGather.FinancialHost, qe, param)
|
||
|
|
||
|
applogger.Debug("url data info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// Eod End of Day Historical Data
|
||
|
func Eod(c *gin.Context) {
|
||
|
// https://eodhistoricaldata.com/api/eod/MCD.US?api_token=647dd6744b94f4.20894198&period=d&order=d&from=2017-01-05&to=2017-02-10&fmt=json
|
||
|
symbol := internal.ReplaceStr(c.Query("symbol"))
|
||
|
region := internal.ReplaceStr(c.Query("region"))
|
||
|
period := internal.ReplaceStr(c.Query("period"))
|
||
|
order := internal.ReplaceStr(c.Query("order"))
|
||
|
from := internal.ReplaceStr(c.Query("from"))
|
||
|
to := internal.ReplaceStr(c.Query("to"))
|
||
|
|
||
|
// 条件组装
|
||
|
var param string
|
||
|
param = fmt.Sprintf("api_token=%v", config.Config.ShareGather.FinancialKey)
|
||
|
if len(order) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("from=%v", from)
|
||
|
}
|
||
|
if len(period) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("period=%v", period)
|
||
|
}
|
||
|
if len(from) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("from=%v", from)
|
||
|
}
|
||
|
if len(to) > 0 {
|
||
|
param = param + "&" + fmt.Sprintf("to=%v", to)
|
||
|
}
|
||
|
|
||
|
qe := fmt.Sprintf("%v.%v", symbol, region)
|
||
|
url := fmt.Sprintf("%v%v/api/eod/%v?fmt=json&%v", topIc, config.Config.ShareGather.FinancialHost, qe, param)
|
||
|
|
||
|
applogger.Debug("url data info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
/****https://polygon.io/docs/stocks/get_v2_aggs_grouped_locale_us_market_stocks__date*****/
|
||
|
// Aggregates 股票聚合条形图
|
||
|
func Aggregates(c *gin.Context) {
|
||
|
stocksTicker := internal.ReplaceStr(c.Query("stocksTicker")) // AAPL
|
||
|
resolution := internal.ReplaceStr(c.Query("multiplier")) //multiplier
|
||
|
from := internal.ReplaceStr(c.Query("from")) // from
|
||
|
to := internal.ReplaceStr(c.Query("to"))
|
||
|
//fmt.Println(resolution, to)
|
||
|
if strings.Contains("5,15,30,60,1", resolution) && !common.IsOpeningUS() {
|
||
|
to = fmt.Sprintf("%d", common.GetToTime()/1000)
|
||
|
}
|
||
|
//fmt.Println(to)
|
||
|
//else if timespan == "minute" && multiplier == 15 && common.IsOpeningUS() {
|
||
|
// to = fmt.Sprintf("%d", common.GenerateSingaporeMinTimestamp(15).UnixMilli())
|
||
|
//} else if timespan == "minute" && multiplier == 5 && common.IsOpeningUS() {
|
||
|
// to = fmt.Sprintf("%d", common.GenerateSingaporeMinTimestamp(5).UnixMilli())
|
||
|
//}
|
||
|
url := fmt.Sprintf("%v%vstock/candle?symbol=%s&resolution=%s&from=%s&to=%s&token=%s",
|
||
|
topIc, config.Config.FinnhubUs.FinnhubHost, stocksTicker, resolution, from, to, config.Config.FinnhubUs.FinnhubKey)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// Grouped 获取整个股票/股票市场的每日开盘价、最高价、最低价和收盘价 (OHLC)
|
||
|
func Grouped(c *gin.Context) {
|
||
|
// /v2/aggs/grouped/locale/us/market/stocks/{date}
|
||
|
// https://api.polygon.io/v2/aggs/grouped/locale/us/market/stocks/2023-01-09?adjusted=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
date := internal.ReplaceStr(c.Query("date")) // date
|
||
|
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v2/aggs/grouped/locale/us/market/stocks/%v?adjusted=true&%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, date, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// OpenClose 股票每日开盘/收盘
|
||
|
func OpenClose(c *gin.Context) {
|
||
|
// /v1/open-close/{stocksTicker}/{date}
|
||
|
// https://api.polygon.io/v1/open-close/AAPL/2023-01-09?adjusted=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
stocksTicker := internal.ReplaceStr(c.Query("stocksTicker")) // AAPL
|
||
|
date := internal.ReplaceStr(c.Query("date")) // date
|
||
|
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v1/open-close/%v/%v?adjusted=true&%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, stocksTicker, date, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// PreviousClose 上一收盘价
|
||
|
func PreviousClose(c *gin.Context) {
|
||
|
// /v2/aggs/ticker/{stocksTicker}/prev
|
||
|
// https://api.polygon.io/v2/aggs/ticker/AAPL/prev?adjusted=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
stocksTicker := internal.ReplaceStr(c.Query("stocksTicker")) // AAPL
|
||
|
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
var tickerList []string
|
||
|
if len(stocksTicker) > 0 {
|
||
|
tickerList = strings.Split(stocksTicker, ",")
|
||
|
}
|
||
|
var codeCloseList []stock.Results
|
||
|
for _, ticker := range tickerList {
|
||
|
url := fmt.Sprintf("%v%v/v2/aggs/ticker/%v/prev?adjusted=true&%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, ticker, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//var code string
|
||
|
//var closePrice float64
|
||
|
//for key, value := range bodyStr {
|
||
|
// switch key {
|
||
|
// case "results":
|
||
|
// boDay := value.([]interface{})
|
||
|
// for _, vue := range boDay {
|
||
|
// switch vue.(type) {
|
||
|
// case map[string]interface{}:
|
||
|
// da := vue.(map[string]interface{})
|
||
|
// for e, v := range da {
|
||
|
// switch e {
|
||
|
// case "T":
|
||
|
// code = v.(string)
|
||
|
// case "c":
|
||
|
// closePrice = v.(float64)
|
||
|
// default:
|
||
|
// }
|
||
|
// }
|
||
|
// default:
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//}
|
||
|
item := stock.AggsTicke{}
|
||
|
json.Unmarshal([]byte(bodyStr), &item)
|
||
|
if len(item.Results) > 0 {
|
||
|
codeCloseList = append(codeCloseList, item.Results[0])
|
||
|
}
|
||
|
}
|
||
|
applogger.Debug("data info:%v", codeCloseList)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, codeCloseList, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// Trades 获取给定时间范围内股票代码的交易
|
||
|
func Trades(c *gin.Context) {
|
||
|
ticker := internal.ReplaceStr(c.Query("ticker")) // AAPL
|
||
|
date := internal.ReplaceStr(c.Query("date"))
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/trades/%s?timestamp=%s&order=desc&%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, ticker, date, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
|
||
|
}
|
||
|
|
||
|
// LastTrade 获取给定股票的最新交易
|
||
|
func LastTrade(c *gin.Context) {
|
||
|
// /v2/last/trade/{stocksTicker}
|
||
|
// https://api.polygon.io/v2/last/trade/AAPL?apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
stocksTicker := internal.ReplaceStr(c.Query("stocksTicker")) // AAPL
|
||
|
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v2/last/trade/%v?%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, stocksTicker, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// Quotes TODO: 获取给定时间范围内股票代码的交易
|
||
|
func Quotes(c *gin.Context) {
|
||
|
// https://api.polygon.io/v3/quotes/AAPL?apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
|
||
|
}
|
||
|
|
||
|
// LastQuote 股票的最新NBBO(报价)刻度
|
||
|
func LastQuote(c *gin.Context) {
|
||
|
// /v2/last/nbbo/{stocksTicker}
|
||
|
// https://api.polygon.io/v2/last/nbbo/AAPL?apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
stocksTicker := internal.ReplaceStr(c.Query("stocksTicker")) // AAPL
|
||
|
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v2/last/nbbo/%v?%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, stocksTicker, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// SnapshotAllTickers 所有交易股票代码的最新市场数据
|
||
|
func SnapshotAllTickers(c *gin.Context) {
|
||
|
// /v2/snapshot/locale/us/markets/stocks/tickers
|
||
|
// https://api.polygon.io/v2/snapshot/locale/us/markets/stocks/tickers?include_otc=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v2/snapshot/locale/us/markets/stocks/tickers?include_otc=true&%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// SnapshotGainersLosers 获取股票/股票市场当前前20名涨幅或跌幅的最新市场数据
|
||
|
func SnapshotGainersLosers(c *gin.Context) {
|
||
|
// /v2/snapshot/locale/us/markets/stocks/{direction}
|
||
|
// https://api.polygon.io/v2/snapshot/locale/us/markets/stocks/gainers?include_otc=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
// https://api.polygon.io/v2/snapshot/locale/us/markets/stocks/losers?include_otc=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
direction := internal.ReplaceStr(c.Query("direction")) // AAPL
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v2/snapshot/locale/us/markets/stocks/%v?include_otc=true&%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, direction, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// SnapshotOneTicker 获取单个交易股票行情的最新市场数据
|
||
|
func SnapshotOneTicker(c *gin.Context) {
|
||
|
// /v2/snapshot/locale/us/markets/stocks/tickers/{stocksTicker}
|
||
|
// https://api.polygon.io/v2/snapshot/locale/us/markets/stocks/tickers/AAPL?apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
|
||
|
stocksTicker := internal.ReplaceStr(c.Query("stocksTicker")) // AAPL
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v2/snapshot/locale/us/markets/stocks/tickers/%v?%v",
|
||
|
topIc, config.Config.ShareGather.PolygonHost, stocksTicker, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// ReferenceTicker TODO: 所有股票代码
|
||
|
func ReferenceTicker(c *gin.Context) {
|
||
|
// /v3/reference/tickers
|
||
|
// https://api.polygon.io/v3/reference/tickers?active=true&apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
|
||
|
url := fmt.Sprintf("%v%v/v3/reference/tickers?active=true&%v", topIc, config.Config.ShareGather.PolygonHost, param)
|
||
|
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// ReferenceTickerDetails 股票代码详细信息
|
||
|
func ReferenceTickerDetails(c *gin.Context) {
|
||
|
// /v3/reference/tickers/{ticker}
|
||
|
// https://api.polygon.io/v3/reference/tickers/AAPL?apiKey=CDGMfPJmyiEX5dbjagLSEipf5Y4XbXVb
|
||
|
ticker := internal.ReplaceStr(c.Query("ticker")) // AAPL
|
||
|
//param := fmt.Sprintf("apiKey=%v", config.Config.ShareGather.PolygonKey)
|
||
|
//
|
||
|
//url := fmt.Sprintf("%v%v/v3/reference/tickers/%v?%v",
|
||
|
// topIc, config.Config.ShareGather.PolygonHost, ticker, param)
|
||
|
//
|
||
|
//applogger.Debug("Url info:%v", url)
|
||
|
//
|
||
|
//bodyStr, err := internal.HttpGet(url)
|
||
|
//if err != nil {
|
||
|
// c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
// return
|
||
|
//}
|
||
|
var bodyStr string
|
||
|
//if strings.Contains(bodyStr, "Ticker not found") {
|
||
|
filter := bson.M{"Country": "US", "Code": ticker}
|
||
|
projection := bson.M{}
|
||
|
sort := bson.M{}
|
||
|
result, _ := data.MgoFindProjection(data.StockList, filter, projection, sort, 0)
|
||
|
if len(result) > 0 {
|
||
|
bodyStr = fmt.Sprintf(`{"results": {"ticker": "%s","name": "%s","market": "stocks","locale": "us","primary_exchange": "%s","description": "%s"},"status": "OK"}`, business.TypeCheck(result[0]["Code"]), business.TypeCheck(result[0]["Name"]), business.TypeCheck(result[0]["Exchange"]), business.TypeCheck(result[0]["Intro"]))
|
||
|
}
|
||
|
// }
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|
||
|
|
||
|
// 股票资讯
|
||
|
func ReferenceTickerNews(c *gin.Context) {
|
||
|
ticker := internal.ReplaceStr(c.Query("ticker")) // AAPL
|
||
|
url := fmt.Sprintf("%v%vcompany-news?symbol=%s&from=%s&to=%s&token=%s",
|
||
|
topIc, config.Config.FinnhubUs.FinnhubHost, ticker, common.NewsUsTime(-7), common.NewsUsTime(0), config.Config.FinnhubUs.FinnhubKey)
|
||
|
if ticker == "" {
|
||
|
url = fmt.Sprintf("%v%vnews?category=general&token=%s",
|
||
|
topIc, config.Config.FinnhubUs.FinnhubHost, config.Config.FinnhubUs.FinnhubKey)
|
||
|
}
|
||
|
applogger.Debug("Url info:%v", url)
|
||
|
|
||
|
bodyStr, err := internal.HttpGet(url)
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
||
|
return
|
||
|
}
|
||
|
//applogger.Debug("第三方数据接收:%v", bodyStr)
|
||
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, bodyStr, internal.QuerySuccess))
|
||
|
}
|