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.

218 lines
6.0 KiB

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