package marketwsscliert import ( "fmt" "github.com/shopspring/decimal" "math/rand" "strconv" "strings" "sync" "time" "wss-pool/cmd/common" "wss-pool/config" "wss-pool/internal/data" "wss-pool/internal/model" "wss-pool/logging/applogger" models "wss-pool/pkg/model" ) var ( conversion_forex = decimal.RequireFromString("1") proportion_forex = decimal.RequireFromString("1000000") ) var ( muForex = sync.Mutex{} ModifyForexMap = make(map[string]ModifyForex) ) type ModifyForex struct { ForexCode string `json:"ForexCode"` // 外汇 BeginTime string `json:"BeginTime"` // 开始时间-date EndTime string `json:"EndTime"` // 结束时间-date Price decimal.Decimal `json:"Prices"` // 设置价格 ChangePrice decimal.Decimal `json:"ChangePrice"` // 插针变化价格(开盘价,初始浮点变化区间起始价) - (初始浮点变化区间结束价-动态直至不在变化) - (浮点变化区间结束后的起始价格) EndPrice decimal.Decimal `json:"EndPrice"` // 浮点变化区间结束后的结束价格 Proportion decimal.Decimal `json:"Proportion"` // 浮动率 CheckBool bool `json:"CheckBool"` // 判断是负增长还是正增长 Digits int `json:"Digits"` // 保留几位小数 Step int `json:"Step"` // 浮点数 BeginUnix int64 `json:"BeginUnix"` // 开始时间-unix EndUnix int64 `json:"EndUnix"` // 结算时间-unix RestoreChangePrice decimal.Decimal `json:"RestorePrice"` // 插针恢复变化价格(开盘价,初始浮点变化区间起始价) - (初始浮点变化区间结束价-动态直至不在变化) - (浮点变化区间结束后的起始价格) RestoreBeginTime string `json:"RestoreBeginTime"` // 插针恢复开始时间-date RestoreEndTime string `json:"RestoreEndTime"` // 插针恢复结束时间-date RestoreBeginUnix int64 `json:"RestoreBeginUnix"` // 插针恢复开始时间-unix RestoreEndUnix int64 `json:"RestoreEndUnix"` // 插针恢复结束时间-unix RestoreBool bool `json:"RestoreBool"` // 插针恢复 RestoreSetChangePrice bool `json:"RestoreSetChangePrice"` // 插针恢复更新 DataHandling map[int]string `json:"DataHandling"` // 数据处理-需要初始化 NumIntervals int `json:"NumIntervals"` // 数据处理-间隔次数 } func SetValue_Forex(key string, value ModifyForex) { muForex.Lock() defer muForex.Unlock() ModifyForexMap[key] = value } func GetValue_Forex(key string) (ModifyForex, bool) { muForex.Lock() defer muForex.Unlock() value, ok := ModifyForexMap[key] return value, ok } func getData_Forex() []model.ForexMarket { forex := model.NewForexMarket() result := forex.ListModifyForex() return result } // 外汇加载交易对插针列表 func GetModifyForex() { data.InitGorm(config.Config.Bourse) for { t := time.NewTimer(10 * time.Second) <-t.C result := getData_Forex() applogger.Debug("加载需要插针的交易对设置:%v", result) for _, v := range result { end, _ := common.TimeStrToTimes(v.EndTime) if end.Unix() < time.Now().Unix() { applogger.Error("该调价已过期......") delete(ModifyForexMap, v.TradeName) forex := model.NewForexMarket() forex.ID = v.ID forex.UpdateIsGetOne() continue } price, err := decimal.NewFromString(v.MaxPrice) if price.IsZero() { applogger.Error("price err:%v", price) continue } // 插针设置 begin, err := common.TimeStrToTimestamp(v.BeginTime) if err != nil { applogger.Error("begin err:%v", err) continue } ends, err := common.TimeStrToTimestamp(v.EndTime) if err != nil { applogger.Info("end err:%v", err) continue } // 插针恢复 restoreBegin, err := common.TimeStrAddFiveTime(v.BeginTime) if err != nil { applogger.Error("restoreBegin err:%v", err) continue } restoreEnds, err := common.TimeStrAddFiveTime(v.EndTime) if err != nil { applogger.Info("restoreEnds err:%v", err) continue } restoreBeginUnix, err := common.TimeStrToTimestamp(restoreBegin) if err != nil { applogger.Error("restoreBeginUnix err:%v", err) continue } restoreEndsUnix, err := common.TimeStrToTimestamp(restoreEnds) if err != nil { applogger.Error("restoreEndsUnix err:%v", err) continue } //判断当前外汇,是否有任务还在执行 if mapVal, ok := GetValue_Forex(v.TradeName); ok { if mapVal.EndUnix >= time.Now().Unix() { applogger.Info(v.TradeName, " is run") continue } } // 第二次浮点随机数值的端点值(结束浮点) proportion_value := conversion_forex.Add(decimal.NewFromInt32(int32(v.Step)).Div(proportion_forex)) // 写入缓存中 SetValue_Forex(v.TradeName, ModifyForex{ ForexCode: v.TradeName, BeginTime: v.BeginTime, // 设置开始时间 EndTime: v.EndTime, // 设置结束时间 Price: price, // 设置价格 ChangePrice: decimal.Zero, // 插针变化价格(开盘价,初始浮点变化区间起始价) - (初始浮点变化区间结束价-动态直至不在变化) - (浮点变化区间结束后的起始价格) EndPrice: decimal.Zero, // 浮点变化区间结束后的结束价格 Proportion: proportion_value, // 区间浮动率 CheckBool: false, Digits: v.KeepDecimal, Step: v.Step, BeginUnix: begin, // 插针开始时间 EndUnix: ends, // 插针结束时间 RestoreBeginTime: restoreBegin, // 插针恢复开始时间-date RestoreEndTime: restoreEnds, // 插针恢复结束时间-date RestoreBeginUnix: restoreBeginUnix, // 插针恢复开始时间-unix RestoreEndUnix: restoreEndsUnix, // 插针恢复结束时间-unix RestoreBool: false, // 插针恢复标识 RestoreSetChangePrice: false, // 插针恢复更新 RestoreChangePrice: decimal.Zero, // 插针恢复变化价格(开盘价,初始浮点变化区间起始价) - (初始浮点变化区间结束价-动态直至不在变化) - (浮点变化区间结束后的起始价格) DataHandling: make(map[int]string), NumIntervals: 5, }) forex := model.NewForexMarket() forex.ID = v.ID forex.UpdateIsGetOne() } } } // 外汇插针 func RunModifyForex(param models.ForexJsonData) (models.ForexJsonData, bool) { // 缓存中插针的交易对信息 val, ok := GetValue_Forex(param.Pair) if !ok { return param, false } // 不在设置的时间区间范围过滤 if val.BeginUnix > param.Timestamp || val.EndUnix < param.Timestamp { return param, false } applogger.Debug("交易对%v,原始数据:%v", param.Pair, param) // 数据赋值 changePrice_New := val.ChangePrice price_new := val.Price endPrice_new := val.EndPrice checkBool := val.CheckBool // 第一次浮点区间的起始价 if val.ChangePrice.IsZero() { changePrice_New = decimal.NewFromFloat(param.Close) // k线闭盘价(即浮点起始价) endPrice_new = price_new.Mul(val.Proportion) // 第二次浮点结束价 if changePrice_New.Cmp(price_new) >= 1 { checkBool = true } } // 平滑价格生成(价格趋向结束价) var price decimal.Decimal if checkBool { // 负增长 if changePrice_New.Cmp(price_new) >= 0 { changePrice_New = changePrice_New.Div(val.Proportion) price = changePrice_New // 更新缓存变量字段 val.ChangePrice = changePrice_New val.Price = price_new val.EndPrice = endPrice_new val.CheckBool = checkBool SetValue_Forex(val.ForexCode, val) } else { randomPrice := RandomBetween(price_new.Div(val.Proportion).InexactFloat64(), endPrice_new.InexactFloat64()) price = decimal.NewFromFloat(randomPrice) } } else { // 正增长 if changePrice_New.Cmp(price_new) <= 0 { changePrice_New = changePrice_New.Mul(val.Proportion) price = changePrice_New // 更新缓存变量字段 val.ChangePrice = changePrice_New val.Price = price_new val.EndPrice = endPrice_new val.CheckBool = checkBool SetValue_Forex(val.ForexCode, val) } else { randomPrice := RandomBetween(changePrice_New.Div(val.Proportion).InexactFloat64(), endPrice_new.InexactFloat64()) price = decimal.NewFromFloat(randomPrice) } } param.Open = changePrice_New.InexactFloat64() param.Close = price.InexactFloat64() if price.GreaterThan(decimal.NewFromFloat(param.High)) { param.High = price.InexactFloat64() } if price.LessThan(decimal.NewFromFloat(param.Low)) { param.Low = price.InexactFloat64() } forexJson := models.ForexJsonData{ Event: "CAS", Pair: param.Pair, Open: param.Open, Close: param.Close, High: param.High, Low: param.Low, Volume: param.Volume, Timestamp: param.Timestamp, } applogger.Debug("交易对%v,插针数据:%v", param.Pair, forexJson) return forexJson, true } func RunModifyForexNew(param models.ForexJsonData) (models.ForexJsonData, bool) { // 缓存中插针的交易对信息 val, ok := GetValue_Forex(param.Pair) if !ok { return param, false } // 不在设置的时间区间范围过滤 if val.BeginUnix > param.Timestamp || val.EndUnix < param.Timestamp { if val.RestoreBeginUnix > param.Timestamp || val.RestoreEndUnix < param.Timestamp || val.RestoreBool { return param, false } else { applogger.Debug("恢复交易对%v,原始数据:%v", param.Pair, param) if val.RestoreChangePrice.IsZero() { var startT, endT time.Time var startF, endF float64 startT = common.TimeStringToTime(val.RestoreBeginTime) // 设置插针开始时间 endT = common.TimeStringToTime(val.RestoreEndTime) // 设置插针结束时间 msgTime := DivideTimeInterval(startT, endT, val.NumIntervals) // 时间区间划分 // 判定插针结束价格和当前即时价格 if param.Close == val.ChangePrice.InexactFloat64() { val.RestoreBool = true SetValue_Forex(val.ForexCode, val) return param, false } else { startF = val.ChangePrice.InexactFloat64() // 插针结束价格 endF = param.Close // 恢复即时价格 } applogger.Debug("开始价格:%v,结束价格:%v", startF, endF) msgFloat := DivideFloatInterval(startF, endF, val.NumIntervals) // 浮点区间划分 var msgTF = make(map[int]string) for i, mt := range msgTime { mf, okM := msgFloat[i] if okM { msgTF[i] = fmt.Sprintf("%v,%v", mt, mf) applogger.Debug("msgTF:%v,%v", i, msgTF[i]) } } val.DataHandling = msgTF val.RestoreSetChangePrice = true } } } else { applogger.Debug("插针交易对%v,原始数据:%v", param.Pair, param) // 第一次浮点区间的起始价 if val.ChangePrice.IsZero() { var startT, endT time.Time var startF, endF float64 val.ChangePrice = decimal.NewFromFloat(param.Close) // k线闭盘价(即浮点起始价) startT = common.TimeStringToTime(val.BeginTime) // 设置插针开始时间 endT = common.TimeStringToTime(val.EndTime) // 设置插针结束时间 msgTime := DivideTimeInterval(startT, endT, val.NumIntervals) // 时间区间划分 startF = param.Close // 设置插针开始价格 endF = val.Price.InexactFloat64() // 设置插针结束价格 applogger.Debug("开始价格:%v,结束价格:%v", startF, endF) msgFloat := DivideFloatInterval(startF, endF, val.NumIntervals) // 浮点区间划分 var msgTF = make(map[int]string) for i, mt := range msgTime { mf, okM := msgFloat[i] if okM { msgTF[i] = fmt.Sprintf("%v,%v", mt, mf) applogger.Debug("msgTF:%v,%v", i, msgTF[i]) } } val.DataHandling = msgTF } } /* 浮点区间价格随机生成浮点值 1、判定当前时间戳在区间内 2、在区间内则生成对应的浮点值 */ var price decimal.Decimal for _, msg := range val.DataHandling { // msgTF:0,1734426000-1734426108,2652.33-2653.5299999999997 splitMsg := strings.Split(msg, ",") if len(splitMsg) >= 2 { splitT := strings.Split(splitMsg[0], "-") // 开始时间~结束时间 1734426000-1734426108 if len(splitT) >= 2 { start, _ := strconv.Atoi(splitT[0]) // 开始时间 1734426000 end, _ := strconv.Atoi(splitT[1]) // 结束时间 1734426108 if param.Timestamp >= int64(start) && param.Timestamp <= int64(end) { splitF := strings.Split(splitMsg[1], "-") // 开始浮点~结束浮点 2652.33-2653.5299999999997 if len(splitF) >= 2 { sf := decimal.RequireFromString(splitF[0]) // 开始浮点 2652.33 ef := decimal.RequireFromString(splitF[1]) // 结束浮点 2653.5299999999997 randomPrice := RandomBetween(sf.InexactFloat64(), ef.InexactFloat64()) price = decimal.NewFromFloat(randomPrice) val.ChangePrice = price if val.RestoreSetChangePrice { val.RestoreChangePrice = price } SetValue_Forex(val.ForexCode, val) } break // 跳出循环 } } } } param.Close = price.InexactFloat64() param.Open = val.ChangePrice.InexactFloat64() if price.GreaterThan(decimal.NewFromFloat(param.High)) { param.High = price.InexactFloat64() } if price.LessThan(decimal.NewFromFloat(param.Low)) { param.Low = price.InexactFloat64() } forexJson := models.ForexJsonData{ Event: "CAS", Pair: param.Pair, Open: param.Open, Close: param.Close, High: param.High, Low: param.Low, Volume: param.Volume, Timestamp: param.Timestamp, } applogger.Debug("交易对%v,插针数据:%v", param.Pair, forexJson) return forexJson, true } // 在a和b之间生成平滑随机值 func RandomBetween(a, b float64) float64 { // 确保a小于b if a > b { a, b = b, a } // 计算范围 rangeVal := (b - a) // 在范围内生成随机数 return rand.Float64()*rangeVal + a } // 时间区间 func DivideTimeInterval(start, end time.Time, numIntervals int) map[int]string { // 计算两个时间点之间的间隔 duration := end.Sub(start) // 计算每个区间的持续时间 intervalDuration := duration / time.Duration(numIntervals) // 生成区间起始时间列表 var msg = make(map[int]string) for i := 0; i <= numIntervals; i++ { subStart := start.Add(time.Duration(i) * intervalDuration).Unix() subEnd := start.Add(time.Duration(i+1) * intervalDuration).Unix() msg[i] = fmt.Sprintf("%v-%v", subStart, subEnd) applogger.Debug("时间数据展示:%v,%v", i, msg[i]) } return msg } // 浮点区间 func DivideFloatInterval(start, end float64, numIntervals int) map[int]string { // 计算每个子区间的宽度 width := (end - start) / float64(numIntervals) // 生成区间起始时间列表 var msg = make(map[int]string) // 生成并打印子区间 for i := 0; i <= numIntervals; i++ { subStart := start + width*float64(i) subEnd := start + width*float64(i+1) msg[i] = fmt.Sprintf("%v-%v", decimal.NewFromFloat(subStart), decimal.NewFromFloat(subEnd)) applogger.Debug("浮点数据展示:%v,%v", i, msg[i]) } return msg }