package marketwsscliert import ( "fmt" "github.com/shopspring/decimal" "math/rand" "strings" "sync" "time" "wss-pool/cmd/common" "wss-pool/cmd/selfContract" "wss-pool/config" "wss-pool/internal/data" "wss-pool/internal/model" "wss-pool/logging/applogger" "wss-pool/pkg/model/market" ) const ( proportion int32 = 10000 //调价原价比例 numPrices int = 60 * 5 //生成随机价格数量 ) var ( ModifyContractMap = make(map[string]ModifyContract) mu = sync.Mutex{} UpdatePrice = make(map[string]decimal.Decimal) ) type ModifyContract struct { ContractCode string `json:"ContractCode"` //合约 BeginTime string `json:"BeginTime"` //开始时间 EndTime string `json:"EndTime"` //结束时间 Price decimal.Decimal `json:"Prices"` //价格 Prices string `json:"Price"` //价格 Digits int `json:"Digits"` //保留几位小数 Step int `json:"Step"` // 浮点数 BeginUnix int64 EndUnix int64 } func SetValue(key string, value ModifyContract) { mu.Lock() defer mu.Unlock() ModifyContractMap[key] = value } func GetValue(key string) (ModifyContract, bool) { mu.Lock() defer mu.Unlock() value, ok := ModifyContractMap[key] return value, ok } func getData() []model.ContractMarket { contract := model.NewContractMarket() result := contract.ListModifyContract() return result } // 加载配置数据 func GetModifyContract() { data.InitGorm(config.Config.Bourse) for { t := time.NewTimer(10 * time.Second) <-t.C result := getData() for _, v := range result { end, _ := common.TimeStrToTimes(v.EndTime) if end.Unix() < time.Now().Unix() { applogger.Error("该调价已过期") continue } price, err := decimal.NewFromString(v.MaxPrice) if price.IsZero() { applogger.Error("价格有误", price) continue } begin, err := common.TimeStrToTimestamp(v.BeginTime) if err != nil { applogger.Error("begin err", err) continue } ends, err := common.TimeStrToTimestamp(v.EndTime) if err != nil { applogger.Info("end err", err) continue } //判断当前合约 是否有任务还在执行 if mapVal, ok := GetValue(v.TradeName); ok { if mapVal.EndUnix >= time.Now().Unix() { applogger.Info(v.TradeName, " is run") continue } } SetValue(v.TradeName, ModifyContract{ ContractCode: v.TradeName, BeginTime: v.BeginTime, EndTime: v.EndTime, Price: price, Digits: v.KeepDecimal, Step: v.Step, BeginUnix: begin, EndUnix: ends, }) contract := model.NewContractMarket() contract.ID = v.ID contract.UpdateIsGetOne() } } } // 合约插针 func RunModify(param market.SubscribeCtKlineResponse) market.SubscribeCtKlineResponse { countSplit := strings.Split(param.Channel, ".") if len(countSplit) < 2 { return param } val, ok := GetValue(countSplit[1]) if !ok { return param } //不在设置的时间区间范围 过滤 ,因k线间隔 不同 id误差大,使用ts if (val.BeginUnix)*1000 > param.Timestamp || (val.EndUnix*1000) < param.Timestamp { return param } key := fmt.Sprintf("%s-%s", param.Tick.Close.String(), countSplit[1]) var price decimal.Decimal applogger.Info("old", param.Tick.Close) tick := param.Tick //保持各种K线 落盘价一致 问题 price, ok = UpdatePrice[key] if !ok { fmt.Println("new data") price = calculateContractPrice(val.Price, int32(val.Step), int32(val.Digits)) UpdatePrice[key] = price } go clearPrice(key) tick.Close = price if price.GreaterThan(tick.High) { tick.High = price } if price.LessThan(tick.Low) { tick.Low = price } applogger.Info("new", tick.Close, "channel", param.Channel) var timestamp int64 var open decimal.Decimal expot := countSplit[len(countSplit)-1] switch expot { case "1min": timestamp = common.GenerateSingaporeMinuteTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) case "5min": timestamp = common.GenerateSingaporeFiveMinTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) case "15min": timestamp = common.GenerateSingaporeFifteenMinTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) case "30min": timestamp = common.GenerateSingaporeThirtyMinTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) case "60min": timestamp = common.GenerateSingaporeHourTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) case "4hour": timestamp = common.GenerateSingaporeFourHourTimestamp() - (4 * 60 * 60) open = GetContractOpen(timestamp, expot, countSplit[1]) case "1day": timestamp = common.GenerateSingaporeDayTimestamp("") open = GetContractOpen(timestamp, expot, countSplit[1]) case "1week": timestamp = common.GetWeekTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) case "1mon": timestamp = common.GenerateSingaporeMonTimestamp() open = GetContractOpen(timestamp, expot, countSplit[1]) } tick.Open = open param.Tick = tick return param } func GetContractOpen(timestamp int64, period, contract string) decimal.Decimal { var open decimal.Decimal tick := selfContract.GetNewPriceAll(contract, period) if len(tick) > 0 { switch tick[0].Code { case timestamp: open, _ = decimal.NewFromString(tick[0].Open) default: open, _ = decimal.NewFromString(tick[0].Close) } } return open } func clearPrice(close string) { if len(UpdatePrice) >= 10 { for key := range UpdatePrice { if key != close { delete(UpdatePrice, key) break } } } } // 计算虚拟合约价格 func calculateContractPrice(basePrice decimal.Decimal, step int32, digits int32) decimal.Decimal { rand.New(rand.NewSource(time.Now().UnixNano())) max := basePrice.Mul(decimal.NewFromFloat(float64(step) / float64(proportion))).Round(digits) min := max.Neg() return basePrice.Add(generateRandomStep(max, min)).Round(digits) } func generateRandomStep(min, max decimal.Decimal) decimal.Decimal { return min.Add(decimal.NewFromFloat(rand.Float64()).Mul(max.Sub(min))) }