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.

518 lines
16 KiB

2 months ago
package selfContract
import (
"encoding/json"
"fmt"
"github.com/shopspring/decimal"
"math/rand"
"time"
"wss-pool/cmd/common"
"wss-pool/cmd/websocketservice"
"wss-pool/internal/gzip"
red "wss-pool/internal/redis"
"wss-pool/logging/applogger"
"wss-pool/pkg/model/market"
"wss-pool/pkg/model/stock"
)
const (
volRand int = 1 //成交张数 随机最大值
maxRand float64 = 1000 //成交笔数 随机最大值
minRand float64 = 0.1
minLeastRand float64 = 1
quantity int = 60 //成交币
tradeNum int = 50
DepthNum int = 80 //深度数据只要
DepthMaxNum int = 300 //深度数据只要
defaultMaxStep float64 = 0.003
defaultMinStep float64 = 0.000001
)
var (
TotalAmount decimal.Decimal // 当前总成交量
TotalTradeTurnover decimal.Decimal //总成交额
TotalVol decimal.Decimal //总成交两张数
TotalCount decimal.Decimal //总成交笔数
oldAsks int64
oldBids int64
)
func ClearTotal() {
TotalAmount = decimal.NewFromFloat(0)
TotalTradeTurnover = decimal.NewFromFloat(0)
TotalVol = decimal.NewFromFloat(0)
TotalCount = decimal.NewFromFloat(0)
}
func CreateDepth(old, closePrice decimal.Decimal) {
chStep6 := fmt.Sprintf("market-%s-depth-step6", SelfContractCode)
//redisStep6, _ := red.Get_Cache_Data(chStep6)
//随机生成单量
rand.New(rand.NewSource(time.Now().UnixNano()))
tick := market.CtDepthTick{
Mrid: rand.Int63n(99999999999) + int64(99999),
Id: common.TimeToNow(),
Ts: common.TimeToNow(),
}
//卖单,买单
tick.Asks, tick.Bids = DepthStep(closePrice, old)
//applogger.Info("asks ", tick.Asks, tick.Bids)
CreateTradeDetail(tick)
//升序
tick.Asks = insertionSort(tick.Asks)
//降序
tick.Bids = quickSort(tick.Bids)
res := market.SubscribeCtDepthResponse{
Channel: chStep6,
Timestamp: common.TimeToNow(),
Tick: &tick,
}
resByte, _ := json.Marshal(res)
resStep6, _ := gzip.DecompressData(resByte)
OneDayContractDepth(res)
red.RedisClient.Publish(res.Channel, resStep6)
}
// 卖单 买单
func DepthStep(closePrice, old decimal.Decimal) ([][]decimal.Decimal, [][]decimal.Decimal) {
data := make([][]decimal.Decimal, 0)
datas := make([][]decimal.Decimal, 0)
if old.Equal(closePrice) {
return data, datas
}
amaxRand := float64(0)
bmaxRand := float64(0)
//跌
if old.GreaterThan(closePrice) {
diff := old.Sub(closePrice)
amaxRand, _ = diff.Div(old).Mul(decimal.NewFromFloat(maxRand)).Round(2).Float64()
bmaxRand = amaxRand / float64(3)
} else {
diff := closePrice.Sub(old)
bmaxRand, _ = diff.Div(old).Mul(decimal.NewFromFloat(maxRand)).Round(2).Float64()
amaxRand = bmaxRand / float64(3)
}
asksMap := make(map[string]int)
bidsMap := make(map[string]int)
minRands := minRand
if closePrice.LessThan(decimal.NewFromInt(int64(1))) {
minRands = minLeastRand
}
for i := 0; i < DepthNum; i++ {
item := make([]decimal.Decimal, 0)
price := calculateMaxMinContractPrice(closePrice, false)
if _, ok := asksMap[price.String()]; ok {
continue
}
item = append(item, price)
item = append(item, decimal.NewFromFloat(common.RandFloats(minRands, amaxRand)))
data = append(data, item)
asksMap[price.String()] = 1
if len(data) >= 20 {
break
}
}
for i := 0; i < DepthNum; i++ {
item := make([]decimal.Decimal, 0)
price := calculateMaxMinContractPrice(closePrice, true)
if _, ok := bidsMap[price.String()]; ok {
continue
}
item = append(item, price)
item = append(item, decimal.NewFromFloat(common.RandFloats(minRands, bmaxRand)))
datas = append(datas, item)
bidsMap[price.String()] = 1
if len(datas) >= 20 {
break
}
}
return data, datas
}
// 生成一天聚合深度
func OneDayContractDepth(item market.SubscribeCtDepthResponse) {
result := market.SubscribeCtDepthTempResponse{}
result.Tick = &market.CtDepthTick{}
title := fmt.Sprintf("market-%s-depth-step6", SelfContractCode)
rand.New(rand.NewSource(time.Now().UnixNano()))
result.Tick.Mrid = rand.Int63n(99999999999) + int64(99999)
result.Tick.Id = common.TimeToNow() * 1000
result.Tick.Ts = common.TimeToNow() * 1000
result.Tick.Asks = insertionSort(item.Tick.Asks)
result.Tick.Bids = quickSort(item.Tick.Bids)
result.Channel = fmt.Sprintf("market.%s.depth.step6", SelfContractCode)
resultJsons, _ := json.Marshal(result)
red.Set_Cache_Value(title, string(resultJsons))
return
//titleInfo := fmt.Sprintf("market-%s-depth-step6-info", SelfContractCode)
//redisRes, _ := red.Get_Cache_Data(title)
//if common.GetWeeHours() || redisRes == "" {
// itemJson, _ := json.Marshal(item)
// if err := red.Set_Cache_Value(title, string(itemJson)); err != nil {
// applogger.Error(title, err)
// }
// //if err := red.Set_Cache_Value(titleInfo, string(itemJson)); err != nil {
// // applogger.Error(title, err)
// //}
// return
//}
//result := market.SubscribeCtDepthTempResponse{}
//if err := json.Unmarshal([]byte(redisRes), &result); err != nil {
// applogger.Error("json err", err)
// return
//}
//bids := make(map[decimal.Decimal]decimal.Decimal, 0)
//asks := make(map[decimal.Decimal]decimal.Decimal, 0)
//for _, v := range result.Tick.Bids {
// bids[v[0]] = v[1]
//}
//for _, v := range result.Tick.Asks {
// asks[v[0]] = v[1]
//}
//bidsTemp := make([][]decimal.Decimal, 0)
//bidsAbandonMap := make(map[decimal.Decimal]int)
//// fmt.Println("bids map" ,bids)
//// fmt.Println("bids",result.Tick.Bids)
//for _, v := range item.Tick.Bids {
// value := make([]decimal.Decimal, 0)
// if len(v) <= 0 {
// continue
// }
// if num, ok := bids[v[0]]; !ok {
// value = append(value, v[0])
// value = append(value, v[1].Add(num))
// bidsTemp = append(bidsTemp, value)
// bidsAbandonMap[v[0]] = 1
// } else {
// value = append(value, v[0])
// value = append(value, v[1])
// bidsTemp = append(bidsTemp, value)
// }
//}
////fmt.Println("bidsAb",bidsAbandonMap)
//for key, val := range bids {
// if _, ok := bidsAbandonMap[key]; !ok {
// value := make([]decimal.Decimal, 0)
// value = append(value, key)
// value = append(value, val)
// bidsTemp = append(bidsTemp, value)
// }
//}
//asksTemp := make([][]decimal.Decimal, 0)
//asksAbandonMap := make(map[decimal.Decimal]int)
//for _, v := range item.Tick.Asks {
// if len(v) <= 0 {
// continue
// }
// value := make([]decimal.Decimal, 0)
// if num, ok := asks[v[0]]; ok {
// value = append(value, v[0])
// value = append(value, v[1].Add(num))
// asksAbandonMap[v[0]] = 1 //收集起来
// asksTemp = append(asksTemp, value)
// } else {
// value = append(value, v[0])
// value = append(value, v[1])
// asksTemp = append(asksTemp, value)
// }
//}
//for key, val := range asks {
// if _, ok := asksAbandonMap[key]; !ok {
// value := make([]decimal.Decimal, 0)
// value = append(value, key)
// value = append(value, val)
// asksTemp = append(asksTemp, value)
// }
//}
//result.Channel = fmt.Sprintf("market.%s.depth.step6-info", SelfContractCode)
//result.Tick.Asks = asksTemp
//result.Tick.Bids = bidsTemp
//result.Tick.Mrid = rand.Int63n(99999999999) + int64(99999)
//result.Tick.Id = common.TimeToNow() * 1000
//result.Tick.Ts = common.TimeToNow() * 1000
////resultJson, _ := json.Marshal(result)
//////所有的买卖保存
////if err := red.Set_Cache_Value(titleInfo, string(resultJson)); err != nil {
//// applogger.Error(title, err)
////}
////推给前端数据
//if len(asksTemp) >= DepthNum {
// asksTemp = asksTemp[:DepthNum]
// //fmt.Println(len(asksTemp))
// //os.Exit(11)
//}
//if len(bidsTemp) >= DepthNum {
// bidsTemp = bidsTemp[:DepthNum]
//}
////result := market.SubscribeCtDepthTempResponse{}
//result.Tick.Asks = insertionSort(asksTemp)
//result.Tick.Bids = quickSort(bidsTemp)
//result.Channel = fmt.Sprintf("market.%s.depth.step6", SelfContractCode)
//resultJsons, _ := json.Marshal(result)
//red.Set_Cache_Value(title, string(resultJsons))
//applogger.Info("OneDayContractDepth ", string(resultJsons))
}
// 生成一天聚合行情
func OneDayDetailMerged(param market.SubscribeCtKlineResponse) {
title := fmt.Sprintf("market-%s-detail-merged", SelfContractCode)
chStep6 := fmt.Sprintf("market-%s-depth-step6", SelfContractCode)
redisStep6, _ := red.Get_Cache_Data(chStep6)
resultStep6 := market.SubscribeCtDepthResponse{}
if err := json.Unmarshal([]byte(redisStep6), &resultStep6); err != nil {
applogger.Error("OneDayContractDepth json err", err)
return
}
result := market.SubscribeCtDetailResponse{}
tick := &market.CtDetailTick{}
result.Channel = title
rand.Seed(time.Now().UnixNano())
var totalPriceAsks decimal.Decimal
var totalNumAsks decimal.Decimal
for _, v := range resultStep6.Tick.Asks {
if len(v) <= 0 {
continue
}
totalPriceAsks = totalPriceAsks.Add(v[0])
totalNumAsks = totalNumAsks.Add(v[1])
}
if len(resultStep6.Tick.Asks) > 0 {
value := make([]decimal.Decimal, 0)
value = append(value, totalPriceAsks.Div(decimal.NewFromInt(int64(len(resultStep6.Tick.Asks)))).Round(digits))
value = append(value, totalNumAsks)
tick.Asks = value
}
bidsTemp := make([][]decimal.Decimal, 0)
var totalPriceBids decimal.Decimal
var totalNumBids decimal.Decimal
for _, v := range resultStep6.Tick.Bids {
if len(v) <= 0 {
continue
}
totalPriceBids = totalPriceBids.Add(v[0])
totalNumBids = totalNumBids.Add(v[1])
}
if len(resultStep6.Tick.Bids) > 0 {
value := make([]decimal.Decimal, 0)
value = append(value, totalPriceBids.Div(decimal.NewFromInt(int64(len(resultStep6.Tick.Bids)))).Round(digits))
value = append(value, totalNumBids)
bidsTemp = append(bidsTemp, value)
tick.Bids = value
}
tick.Mrid = rand.Int63n(99999999999) + int64(99999)
tick.Id = common.TimeToNow()
tick.TradeTurnover = param.Tick.Rrade_Turnover
tick.Count = param.Tick.Count.IntPart()
tick.High = param.Tick.High
tick.Open = param.Tick.Open
tick.Vol = param.Tick.Vol
tick.Close = param.Tick.Close
tick.Low = param.Tick.Low
tick.Amount = param.Tick.Amount
result.Tick = tick
result.Timestamp = common.TimeToNow()
result.Channel = fmt.Sprintf("market.%s.detail.merged", SelfContractCode)
resultJson, _ := json.Marshal(result)
if err := red.Set_Cache_Value(title, string(resultJson)); err != nil {
applogger.Error(title, err)
}
//applogger.Info("OneDayContractDepth ", string(resultJson))
}
// 生成详情
func CreateTradeDetail(tick market.CtDepthTick) {
res := market.SubscribeCtTradeDetailResponse{}
res.Tick = &market.CtTradeDetailTick{}
res.Tick.Data = make([]market.TradeDetail, 0)
TotalCount = decimal.NewFromInt(0)
//最近交易接口
tradeDetailAPI := make([]stock.MarketTrade, 0)
for key, v := range tick.Asks {
if key >= 1 {
break
}
trade := v[1].Mul(FaceValue).Mul(v[0]) //每一笔成交张数 * 合约面值 * 成交价格
item := market.TradeDetail{
Amount: v[1],
Ts: common.TimeToNow() * 1000,
Id: common.TimeToNow() * 1000,
Price: v[0],
Direction: "sell",
Quantity: trade.Div(v[0]).Round(digits), //成交币
TradeTurnover: trade,
}
//总成交额
//TotalTradeTurnover = TotalTradeTurnover.Add(trade)
//总成交量
//TotalAmount = TotalAmount.Add(item.Quantity)
//成交张数
//TotalVol = TotalVol.Add(v[1])
res.Tick.Data = append(res.Tick.Data, item)
apiItem := stock.MarketTrade{
ID: common.TimeToNow() * 1000,
OrderNumber: item.Amount.String(),
DealPrice: item.Price.String(),
OrderTime: common.TimeToNow() * 1000,
TradeType: 2,
TradeTurnover: trade,
}
tradeDetailAPI = append(tradeDetailAPI, apiItem)
}
res.Channel = fmt.Sprintf("market.%s.trade.detail", SelfContractCode)
res.Timestamp = common.TimeToNow() * 1000
if len(res.Tick.Data) > 0 {
// fmt.Println(res.Tick.Data)
jsonMessage, _ := json.Marshal(websocketservice.Message{
ServersId: res.Channel,
Content: res,
Symbol: res.Channel})
//applogger.Info("CreateTradeDetail sell:", string(jsonMessage))
red.RedisClient.Publish(res.Channel, string(jsonMessage))
}
//总成交笔数
//TotalCount = TotalCount.Add(decimal.NewFromInt(int64(len(tick.Asks))))
res = market.SubscribeCtTradeDetailResponse{}
res.Tick = &market.CtTradeDetailTick{}
res.Tick.Data = make([]market.TradeDetail, 0)
res.Channel = fmt.Sprintf("market.%s.trade.detail", SelfContractCode)
for key, v := range tick.Bids {
if key >= 1 {
break
}
trade := v[1].Mul(FaceValue).Mul(v[0]) //每一笔成交张数 * 合约面值 * 成交价格
item := market.TradeDetail{
Amount: v[1], //张数
Ts: common.TimeToNow() * 1000,
Id: common.TimeToNow() * 1000,
Price: v[0],
Direction: "buy",
Quantity: trade.Div(v[0]).Round(digits), //成交币
TradeTurnover: trade,
}
//总成交额
TotalTradeTurnover = TotalTradeTurnover.Add(trade)
//总成交量
TotalAmount = TotalAmount.Add(item.Quantity)
//成交张数
TotalVol = TotalVol.Add(v[1])
res.Tick.Data = append(res.Tick.Data, item)
apiItem := stock.MarketTrade{
ID: common.TimeToNow() * 1000,
OrderNumber: item.Amount.String(),
DealPrice: item.Price.String(),
OrderTime: common.TimeToNow() * 1000,
TradeType: 1,
TradeTurnover: trade,
}
tradeDetailAPI = append(tradeDetailAPI, apiItem)
}
res.Timestamp = common.TimeToNow() * 1000
//总成交笔数
TotalCount = TotalCount.Add(decimal.NewFromInt(int64(len(tick.Bids))))
if len(res.Tick.Data) > 0 {
//fmt.Println(res.Tick.Data)
jsonMessage, _ := json.Marshal(websocketservice.Message{
ServersId: res.Channel,
Content: res,
Symbol: res.Channel})
//applogger.Info("CreateTradeDetail buy:", string(jsonMessage))
go func(channel string, jsonMessage []byte) {
time.Sleep(1 * time.Second)
red.RedisClient.Publish(channel, string(jsonMessage))
}(res.Channel, jsonMessage)
}
//缓存
title := fmt.Sprintf("market-%s-trade-detail", SelfContractCode)
var resultJson []byte
//if len(tradeDetailAPI) < tradeNum {
// item, _ := red.Get_Cache_Data(title)
// //itemJson, _ := json.Marshal(item)
// res := make([]stock.MarketTrade, 0)
// json.Unmarshal([]byte(item), &res)
// l := len(res)
// res = append(res, tradeDetailAPI...)
// if l > 0 {
// res = res[l:]
// }
// resultJson, _ = json.Marshal(res)
//} else {
resultJson, _ = json.Marshal(tradeDetailAPI)
// }
if err := red.Set_Cache_Value(title, string(resultJson)); err != nil {
applogger.Error(title, err)
}
// os.Exit(11111)
//
// applogger.Info(string(resultJson))
}
func calculateMaxMinContractPrice(basePrice decimal.Decimal, isNegative bool) decimal.Decimal {
rand.New(rand.NewSource(time.Now().UnixNano()))
max := basePrice.Mul(decimal.NewFromFloat(rand.Float64()*defaultMinStep + rand.Float64()*(defaultMaxStep-defaultMinStep))).Round(digits)
// fmt.Println(max)
if isNegative {
return basePrice.Sub(max).Round(digits)
}
return basePrice.Add(max).Round(digits)
}
// 买单不能高于当前价,卖但不能低于当前价
func randDepth(max, min int, closePrice, old decimal.Decimal) ([][]decimal.Decimal, [][]decimal.Decimal) {
data := make([][]decimal.Decimal, 0)
datas := make([][]decimal.Decimal, 0)
//item := make([]decimal.Decimal, 0)
//item = append(item, calculateMaxMinContractPrice(closePrice, false))
//item = append(item, decimal.NewFromInt(int64(max)))
//data = append(data, item)
//item = make([]decimal.Decimal, 0)
//item = append(item, calculateMaxMinContractPrice(closePrice, true))
//item = append(item, decimal.NewFromInt(int64(min)))
//datas = append(datas, item)
//}
//if old.GreaterThan(closePrice) {
// //跌
// return data, datas
//}
//dataTemp := make([][]decimal.Decimal, 0)
//datasTemp := make([][]decimal.Decimal, 0)
//item = make([]decimal.Decimal, 0)
//item = append(item, data[0][0])
//item = append(item, datas[0][1])
//dataTemp = append(dataTemp, item)
//item = make([]decimal.Decimal, 0)
//item = append(item, datas[0][0])
//item = append(item, data[0][1])
//datasTemp = append(datasTemp, item)
return data, datas
}
// 升序
func insertionSort(nums [][]decimal.Decimal) [][]decimal.Decimal {
n := len(nums)
for i := 0; i < n-1; i++ {
for j := 0; j < n-i-1; j++ {
if nums[j][0].GreaterThan(nums[j+1][0]) {
nums[j], nums[j+1] = nums[j+1], nums[j]
}
}
}
return nums
}
// 降序
func quickSort(nums [][]decimal.Decimal) [][]decimal.Decimal {
n := len(nums)
for i := 0; i < n-1; i++ {
minIdx := i
for j := i + 1; j < n; j++ {
if nums[j][0].GreaterThan(nums[minIdx][0]) {
minIdx = j
}
}
nums[i], nums[minIdx] = nums[minIdx], nums[i]
}
return nums
}