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.

301 lines
8.8 KiB

2 months ago
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
}