package selfMarketSpot import ( "encoding/json" "fmt" "github.com/shopspring/decimal" "math/rand" "time" "wss-pool/cmd/common" "wss-pool/cmd/websocketservice" red "wss-pool/internal/redis" "wss-pool/logging/applogger" "wss-pool/pkg/model/market" "wss-pool/pkg/model/stock" ) const ( maxRand float64 = 2000 //成交笔数 随机最大值 minRand float64 = 0.1 minLeastRand float64 = 1 DepthNum int = 80 //深度数据只要 DepthMaxNum int = 300 //深度数据只要 defaultMaxStep float64 = 0.003 defaultMinStep float64 = 0.000001 ) var ( TotalAmount decimal.Decimal // 当前总成交量 TotalCount decimal.Decimal //总成交笔数 oldAsks int64 oldBids int64 ) func ClearTotal() { TotalAmount = decimal.NewFromFloat(0) TotalCount = decimal.NewFromFloat(0) } func CreateDepth(old, closePrice decimal.Decimal) { chStep0 := fmt.Sprintf("market-%s-depth-step0", SelfSymbol) 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: chStep0, Timestamp: common.TimeToNow(), Tick: &tick, } jsonMessage, _ := json.Marshal(websocketservice.Message{ ServersId: res.Channel, Content: res, Symbol: res.Channel}) OneDayContractDepth(res) red.RedisClient.Publish(res.Channel, string(jsonMessage)) } // 卖单 买单 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-step0", SelfSymbol) 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.step0", SelfSymbol) resultJsons, _ := json.Marshal(result) red.Set_Cache_Value(title, string(resultJsons)) } // TODO: 生成 聚合行情/市场概要 func OneDayDetailMerged(param market.SubscribeCandlestickResponse) { result := market.TickerWebsocketResponse{} tick := &market.TickR{} tick.Count = int(param.Tick.Count) 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.ticker", SelfSymbol) jsonMessage, _ := json.Marshal(websocketservice.Message{ ServersId: result.Channel, Content: result, Symbol: result.Channel}) red.RedisClient.Publish(result.Channel, string(jsonMessage)) res := market.TickerWebsocketResponses{} title := fmt.Sprintf("market-%s-detail-merged", SelfSymbol) res.Tick = tick res.Channel = title jsonMessages, _ := json.Marshal(res) if err := red.Set_Cache_Value(title, string(jsonMessages)); err != nil { applogger.Error(title, err) } //applogger.Info("subscribeTicker data,ServersId:%v,Sender:%v,Content:%v-%v", result.Channel, result.Tick, result.Data) //applogger.Info("OneDayContractDepth ", string(resultJson)) } // 生成详情 func CreateTradeDetail(tick market.CtDepthTick) { res := market.SubscribeTradeResponse{} res.Tick = &market.TickTrade{} res.Tick.Data = make([]market.Trade, 0) TotalCount = decimal.NewFromInt(0) //最近交易接口 tradeDetailAPI := make([]stock.MarketTrade, 0) for key, v := range tick.Asks { if key >= 1 { break } item := market.Trade{ Amount: v[1], Timestamp: common.TimeToNow() * 1000, TradeId: common.TimeToNow() * 1000, Price: v[0], Direction: "sell", } 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, } tradeDetailAPI = append(tradeDetailAPI, apiItem) } res.Channel = fmt.Sprintf("market.%s.trade.detail", SelfSymbol) res.Timestamp = common.TimeToNow() * 1000 if len(res.Tick.Data) > 0 { 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)) } res = market.SubscribeTradeResponse{} res.Tick = &market.TickTrade{} res.Tick.Data = make([]market.Trade, 0) res.Channel = fmt.Sprintf("market.%s.trade.detail", SelfSymbol) for key, v := range tick.Bids { if key >= 1 { break } item := market.Trade{ Amount: v[1], //CHEN Timestamp: common.TimeToNow() * 1000, TradeId: common.TimeToNow() * 1000, Price: v[0], Direction: "buy", } //总成交量 TotalAmount = TotalAmount.Add(item.Amount) 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, } 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", SelfSymbol) var resultJson []byte resultJson, _ = json.Marshal(tradeDetailAPI) if err := red.Set_Cache_Value(title, string(resultJson)); err != nil { applogger.Error(title, err) } } 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 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 }