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.
350 lines
12 KiB
350 lines
12 KiB
package processor
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/gin-gonic/gin"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"net/http"
|
|
"strings"
|
|
"wss-pool/cmd/common"
|
|
"wss-pool/internal"
|
|
"wss-pool/internal/data"
|
|
"wss-pool/internal/data/business"
|
|
red "wss-pool/internal/redis"
|
|
"wss-pool/logging/applogger"
|
|
"wss-pool/pkg/model"
|
|
"wss-pool/pkg/model/stock"
|
|
)
|
|
|
|
func OptionInfoAdd(c *gin.Context) {
|
|
param := make([]model.OptionInfoParam, 0)
|
|
err := c.BindJSON(¶m)
|
|
total := len(param)
|
|
if err != nil {
|
|
applogger.Error("BindJSON", err.Error())
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "param error", internal.QueryError))
|
|
return
|
|
} else if total <= 0 {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "param null", internal.QueryError))
|
|
return
|
|
} else if param[0].Token != Token {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "token error", internal.QueryError))
|
|
return
|
|
} else if param[0].Country == "" {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "country error", internal.QueryError))
|
|
return
|
|
} else if param[0].CloseDate != common.TimeToNows().Format("2006-01-02") {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "option date not today ", internal.QueryError))
|
|
return
|
|
}
|
|
country := common.CapitalizeFirstLetter(param[0].Country)
|
|
if country == "Us" {
|
|
country = "US"
|
|
}
|
|
var dataList []mongo.WriteModel
|
|
applogger.Debug("stock info add param total: %d", total)
|
|
for _, v := range param {
|
|
red.HsetMap(business.StockClosingPrice[fmt.Sprintf("Option%sNew", country)], v.Stock, v.FutPrice)
|
|
//爬虫抓取列表数据 延迟较大 统一用info 数据
|
|
business.StockPyWsOptionList(model.OptionPolygon{
|
|
Stock: v.Stock,
|
|
Percent: v.Percent,
|
|
FutPrice: v.FutPrice,
|
|
Country: country,
|
|
}, fmt.Sprintf("%s%s%s", common.StockOption, country, common.StockOptionList))
|
|
filter := bson.M{"code": bson.M{"$eq": v.Stock}}
|
|
update := bson.D{{"$set", bson.D{
|
|
{"code", v.Stock},
|
|
{"fut_price", v.FutPrice},
|
|
{"percent", v.Percent},
|
|
{"atmiv", v.ATMIV},
|
|
{"ivp", v.IVP},
|
|
{"option_date", v.CloseDate},
|
|
{"country", v.Country},
|
|
}}}
|
|
code := fmt.Sprintf("%s:%s", business.StockClosingPrice[fmt.Sprintf("Option%sPrice", country)], v.Stock)
|
|
strike := make(map[string]string)
|
|
for key, val := range v.Results {
|
|
//标的名+到期时间+行权价+类型
|
|
for key2, val2 := range val {
|
|
title := fmt.Sprintf("%s%s%s", v.Stock, strings.Replace(key, "-", "", -1), val2.Strike)
|
|
val[key2].Calls.Name = title + "CE"
|
|
business.OptionResPrice(model.StrikePrice{
|
|
Ask: val2.Calls.OfferOff,
|
|
Bid: val2.Calls.BidOff,
|
|
Price: val2.Calls.LTPOff,
|
|
Code: v.Stock,
|
|
}, val[key2].Calls.Name, code, v.IsClose, v.CloseDate, key)
|
|
val[key2].Puts.Name = title + "PE"
|
|
business.OptionResPrice(model.StrikePrice{
|
|
Ask: val2.Puts.OfferOff,
|
|
Bid: val2.Puts.BidOff,
|
|
Price: val2.Puts.LTPOff,
|
|
Code: v.Stock,
|
|
}, val[key2].Puts.Name, code, v.IsClose, v.CloseDate, key)
|
|
if val2.IsDefault {
|
|
strike[key] = val2.Strike
|
|
// break
|
|
}
|
|
}
|
|
val = common.QuickSort(val)
|
|
//fmt.Printf("%v",val)
|
|
//分开写入mogodb
|
|
filterExpiry := bson.M{"code": v.Stock, "expiry": key}
|
|
info, _ := json.Marshal(val)
|
|
expiryDate, _ := common.TimeStrToTimestamp(fmt.Sprintf("%s 23:59:59", key))
|
|
updateExpiry := bson.D{{"$set", bson.D{
|
|
{"code", v.Stock},
|
|
{"expiry", key},
|
|
{"expiry_date", expiryDate},
|
|
{"info", string(info)},
|
|
}}}
|
|
if err := data.MgoUpdateOneTrue(data.GetOptionExpiryTableName(country), filterExpiry, updateExpiry); err != nil {
|
|
applogger.Error("%s MgoInsertMany err:%v", v.Stock, err)
|
|
}
|
|
}
|
|
business.StockPyWsOptionInfo(v, fmt.Sprintf("%s%s%s", common.StockOption, country, common.StockOptionInfo))
|
|
business.StockPyWsOptionInfoExchange(model.OptionInfoExchange{
|
|
Country: v.Country,
|
|
Stock: v.Stock,
|
|
FutPrice: v.FutPrice,
|
|
Percent: v.Percent,
|
|
Strike: strike,
|
|
}, fmt.Sprintf("%s%s%s.%s", common.StockOption, country, common.StockOptionInfo, "Exchange"))
|
|
models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true)
|
|
dataList = append(dataList, models)
|
|
}
|
|
if len(dataList) > 0 {
|
|
if err := data.MgoBulkWrite(data.GetOptionTableName(country), dataList); err != nil {
|
|
applogger.Error("stock MgoInsertMany err:%v", err)
|
|
}
|
|
|
|
}
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", "ok"))
|
|
}
|
|
|
|
func OptionListAdd(c *gin.Context) {
|
|
param := model.OptionIndexList{}
|
|
err := c.BindJSON(¶m)
|
|
fmt.Println(param)
|
|
if err != nil {
|
|
applogger.Error("BindJSON", err.Error())
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "param error", internal.QueryError))
|
|
return
|
|
} else if len(param.Results) <= 0 {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "param null", internal.QueryError))
|
|
return
|
|
} else if param.Token != Token {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "token error", internal.QueryError))
|
|
return
|
|
} else if param.Results[0].Stock == "" {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "ticker error", internal.QueryError))
|
|
return
|
|
} else if param.Results[0].Country == "" {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "locale error", internal.QueryError))
|
|
return
|
|
}
|
|
locale := common.CapitalizeFirstLetter(param.Results[0].Country)
|
|
closeDate := common.TimeToNows().Format("2006-01-02")
|
|
if locale == "Us" {
|
|
locale = "US"
|
|
}
|
|
var dataList []mongo.WriteModel
|
|
for _, value := range param.Results {
|
|
if closeDate != strings.TrimSpace(value.CloseDate) {
|
|
continue
|
|
}
|
|
filter := bson.D{{"Code", bson.M{
|
|
"$eq": value.Stock,
|
|
}}, {"Country", bson.M{
|
|
"$eq": locale,
|
|
}}}
|
|
update := bson.D{{"$set", bson.D{
|
|
{"Code", value.Stock},
|
|
{"Country", locale},
|
|
{"FutPrice", value.FutPrice},
|
|
{"Percent", value.Percent},
|
|
{"IVChg", value.IVChg},
|
|
{"IVP", value.IVP},
|
|
{"Exchange", value.PrimaryExchange},
|
|
{"DateTime", closeDate},
|
|
{"ATMIV", value.ATMIV}}}}
|
|
if value.IsClose {
|
|
red.HsetMap(business.StockClosingPrice[fmt.Sprintf("Option%sNew", locale)], value.Stock, "0")
|
|
red.HsetMap(business.StockClosingPrice[locale], value.Stock, value.FutPrice)
|
|
list, _ := data.MgoFind(data.OptionList, bson.M{"Country": locale, "Code": value.Stock, "CloseDate": bson.M{"$ne": closeDate}})
|
|
lists := list.([]primitive.M)
|
|
if len(lists) > 0 {
|
|
beforeClose, ok := lists[0]["YesterdayClose"].(string)
|
|
if ok {
|
|
red.HsetMap(business.StockClosingPrice[fmt.Sprintf("Option%sBeforeClose", locale)], value.Stock, beforeClose)
|
|
}
|
|
update = bson.D{{"$set", bson.D{
|
|
{"Code", value.Stock},
|
|
{"Country", locale},
|
|
{"FutPrice", value.FutPrice},
|
|
{"Percent", value.Percent},
|
|
{"IVChg", value.IVChg},
|
|
{"IVP", value.IVP},
|
|
{"Exchange", value.PrimaryExchange},
|
|
{"DateTime", closeDate},
|
|
{"YesterdayClose", value.FutPrice}, //上一次 闭盘价
|
|
{"BeforeClose", beforeClose}, //前一天
|
|
{"CloseDate", closeDate},
|
|
{"ATMIV", value.ATMIV}}}}
|
|
} else {
|
|
update = bson.D{{"$set", bson.D{
|
|
{"Code", value.Stock},
|
|
{"Country", locale},
|
|
{"FutPrice", value.FutPrice},
|
|
{"Percent", value.Percent},
|
|
{"IVChg", value.IVChg},
|
|
{"IVP", value.IVP},
|
|
{"Exchange", value.PrimaryExchange},
|
|
{"DateTime", closeDate},
|
|
{"YesterdayClose", value.FutPrice}, //上一次 闭盘价
|
|
{"CloseDate", closeDate},
|
|
{"ATMIV", value.ATMIV}}}}
|
|
}
|
|
}
|
|
models := mongo.NewUpdateOneModel().SetFilter(filter).SetUpdate(update).SetUpsert(true)
|
|
dataList = append(dataList, models)
|
|
}
|
|
//标记 批量少于 3 不做修改
|
|
if len(dataList) >= 3 {
|
|
data.MgoUpdateMany(data.OptionList, bson.D{{"Country", bson.M{
|
|
"$eq": locale,
|
|
}}, {"DateTime", bson.M{
|
|
"$ne": "0",
|
|
}}}, bson.D{{"$set", bson.D{
|
|
{"DateTime", "0"}}}})
|
|
}
|
|
if len(dataList) > 0 {
|
|
data.MgoBulkWrite(data.OptionList, dataList)
|
|
if err := data.MgoBulkWrite(data.OptionList, dataList); err != nil {
|
|
applogger.Error("MgoInsertMany err:%v", err)
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "operation failure", internal.QueryError))
|
|
return
|
|
}
|
|
} else {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "error operation repetition", internal.QueryError))
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, "", "ok"))
|
|
}
|
|
|
|
func ExchangeOptionList(c *gin.Context) {
|
|
country := internal.ReplaceStr(c.Query("country"))
|
|
pageSize := internal.IntegerInit(internal.ReplaceStr(c.Query("pageSize")))
|
|
pageNumber := internal.IntegerInit(internal.ReplaceStr(c.Query("pageNumber")))
|
|
sort := internal.IntegerInit(internal.ReplaceStr(c.Query("sort")))
|
|
search := internal.ReplaceStr(c.Query("search"))
|
|
code := internal.ReplaceStr(c.Query("code"))
|
|
if pageSize <= 0 || pageNumber <= 0 {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "分页参数不能为零", internal.QueryError))
|
|
return
|
|
}
|
|
var condition = country
|
|
var filter bson.M
|
|
if len(search) > 0 {
|
|
if len(condition) > 0 {
|
|
filter = bson.M{"Country": condition, "DateTime": bson.M{"$ne": "0"}, "$or": []bson.M{{"Code": bson.M{"$regex": search}}}}
|
|
} else {
|
|
filter = bson.M{"$or": []bson.M{{"Code": bson.M{"$regex": search}}}, "DateTime": bson.M{"$ne": "0"}}
|
|
}
|
|
} else {
|
|
filter = bson.M{"Country": condition, "DateTime": bson.M{"$ne": "0"}}
|
|
}
|
|
|
|
strs := strings.Split(code, "-")
|
|
if len(code) > 0 {
|
|
filter = bson.M{"Country": condition, "DateTime": bson.M{"$ne": "0"}, "Code": bson.M{"$in": strs}}
|
|
}
|
|
//fmt.Println(filter)
|
|
total, err := data.MgoFindTotal(data.OptionList, filter)
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, err, internal.QueryError))
|
|
return
|
|
}
|
|
|
|
//applogger.Debug("查询数据总数: %v", total)
|
|
pageData := make([]model.OptionPolygon, 0)
|
|
if sort == 0 {
|
|
sort = -1
|
|
}
|
|
data.MgoPagingFindStructList(data.OptionList, filter, int64(pageSize), int64(pageNumber), "Percent", sort, &pageData)
|
|
var md stock.MgoPageSize
|
|
md.PageSize = pageSize
|
|
md.PageNumber = pageNumber
|
|
md.Total = total
|
|
if len(pageData) <= 0 {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
|
return
|
|
}
|
|
data := make([]model.OptionPolygon, 0)
|
|
for k, v := range pageData {
|
|
if ok, rate := common.IsExistOption(v.Country, v.Stock); ok {
|
|
pageData[k].Rate = rate
|
|
data = append(data, pageData[k])
|
|
}
|
|
}
|
|
md.Data = data
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, md, internal.QuerySuccess))
|
|
}
|
|
|
|
func OptionPHPList(c *gin.Context) {
|
|
country := internal.ReplaceStr(c.Query("country"))
|
|
var condition = country
|
|
filter := bson.M{"Country": condition, "DateTime": bson.M{"$ne": "0"}}
|
|
result, _ := data.MgoFind(data.OptionList, filter)
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, result, internal.QuerySuccess))
|
|
}
|
|
|
|
func OptionInfo(c *gin.Context) {
|
|
code := internal.ReplaceStr(c.Query("option"))
|
|
country := internal.ReplaceStr(c.Query("country"))
|
|
if code == "" {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "option error", internal.QueryError))
|
|
return
|
|
} else if country == "" {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusBadRequest, "country error", internal.QueryError))
|
|
return
|
|
}
|
|
country = common.CapitalizeFirstLetter(country)
|
|
fmt.Println(common.TimeToNow())
|
|
var res = make([]model.OptionInfoMogo, 1)
|
|
filter := bson.M{"code": code}
|
|
data.MgoFindToStr(data.GetOptionTableName(country), filter, int64(1), &res)
|
|
strikeMap := make(map[string][]model.StrikeInfo)
|
|
if len(res) <= 0 {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, model.OptionInfoParam{}, internal.QuerySuccess))
|
|
return
|
|
}
|
|
filter = bson.M{"code": code, "expiry_date": bson.M{
|
|
"$gte": common.TimeToNow(),
|
|
}}
|
|
info := make([]model.OptionInfoExpiryMogo, 0)
|
|
data.MgoFindToStr(data.GetOptionExpiryTableName(country), filter, int64(0), &info)
|
|
if len(info) <= 0 {
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, model.OptionInfoParam{}, internal.QuerySuccess))
|
|
return
|
|
}
|
|
for _, v := range info {
|
|
item := make([]model.StrikeInfo, 0)
|
|
json.Unmarshal([]byte(v.Info), &item)
|
|
strikeMap[v.Expiry] = item
|
|
}
|
|
var pageData = model.OptionInfoParam{
|
|
Country: res[0].Country,
|
|
Stock: res[0].Stock,
|
|
FutPrice: res[0].FutPrice,
|
|
Percent: res[0].Percent,
|
|
IVP: res[0].IVP,
|
|
ATMIV: res[0].ATMIV,
|
|
Results: strikeMap,
|
|
}
|
|
c.JSON(http.StatusOK, internal.GinResult(http.StatusOK, pageData, internal.QuerySuccess))
|
|
}
|
|
|