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.
217 lines
6.0 KiB
217 lines
6.0 KiB
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)))
|
|
}
|
|
|