restruct
This commit is contained in:
parent
7ce7deba92
commit
6cb2bcb49b
@ -7,6 +7,8 @@ import (
|
|||||||
logrus "github.com/sirupsen/logrus"
|
logrus "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/phyer/core/internal/core"
|
"github.com/phyer/core/internal/core"
|
||||||
|
"github.com/phyer/core/internal/models"
|
||||||
|
"github.com/phyer/core/internal/utils"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -38,14 +40,14 @@ type WillMX struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mx MaX) SetToKey(cr *core.Core) ([]interface{}, error) {
|
func (mx MaX) SetToKey(cr *core.Core) ([]interface{}, error) {
|
||||||
// fmt.Println(utils.GetFuncName(), " step1 ", mx.InstID, " ", mx.Period)
|
// fmt.Println(utils.utils.GetFuncName(), " step1 ", mx.InstID, " ", mx.Period)
|
||||||
// mx.Timestamp, _ = Int64ToTime(mx.Ts)
|
// mx.Timestamp, _ = Int64ToTime(mx.Ts)
|
||||||
cstr := strconv.Itoa(mx.Count)
|
cstr := strconv.Itoa(mx.Count)
|
||||||
tss := strconv.FormatInt(mx.Ts, 10)
|
tss := strconv.FormatInt(mx.Ts, 10)
|
||||||
//校验时间戳是否合法
|
//校验时间戳是否合法
|
||||||
ntm, err := cr.PeriodToLastTime(mx.Period, time.UnixMilli(mx.Ts))
|
ntm, err := cr.PeriodToLastTime(mx.Period, time.UnixMilli(mx.Ts))
|
||||||
if ntm.UnixMilli() != mx.Ts {
|
if ntm.UnixMilli() != mx.Ts {
|
||||||
logrus.Warn(fmt.Sprint(GetFuncName(), " candles时间戳有问题 ", " 应该: ", ntm, "实际:", mx.Ts))
|
logrus.Warn(fmt.Sprint(utils.GetFuncName(), " candles时间戳有问题 ", " 应该: ", ntm, "实际:", mx.Ts))
|
||||||
mx.Ts = ntm.UnixMilli()
|
mx.Ts = ntm.UnixMilli()
|
||||||
}
|
}
|
||||||
keyName := "ma" + cstr + "|candle" + mx.Period + "|" + mx.InstID + "|ts:" + tss
|
keyName := "ma" + cstr + "|candle" + mx.Period + "|" + mx.InstID + "|ts:" + tss
|
||||||
@ -60,7 +62,7 @@ func (mx MaX) SetToKey(cr *core.Core) ([]interface{}, error) {
|
|||||||
logrus.Error("max SetToKey err: ", err)
|
logrus.Error("max SetToKey err: ", err)
|
||||||
return mx.Data, err
|
return mx.Data, err
|
||||||
}
|
}
|
||||||
// fmt.Println(utils.GetFuncName(), " step2 ", mx.InstID, " ", mx.Period)
|
// fmt.Println(utils.utils.GetFuncName(), " step2 ", mx.InstID, " ", mx.Period)
|
||||||
// tm := time.UnixMilli(mx.Ts).Format("01-02 15:04")
|
// tm := time.UnixMilli(mx.Ts).Format("01-02 15:04")
|
||||||
cli := cr.RedisLocalCli
|
cli := cr.RedisLocalCli
|
||||||
if len(string(dj)) == 0 {
|
if len(string(dj)) == 0 {
|
||||||
@ -68,13 +70,13 @@ func (mx MaX) SetToKey(cr *core.Core) ([]interface{}, error) {
|
|||||||
err := errors.New("data is block")
|
err := errors.New("data is block")
|
||||||
return mx.Data, err
|
return mx.Data, err
|
||||||
}
|
}
|
||||||
// fmt.Println(utils.GetFuncName(), " step3 ", mx.InstID, " ", mx.Period)
|
// fmt.Println(utils.utils.GetFuncName(), " step3 ", mx.InstID, " ", mx.Period)
|
||||||
_, err = cli.Set(keyName, dj, extt).Result()
|
_, err = cli.Set(keyName, dj, extt).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(GetFuncName(), " maXSetToKey err:", err)
|
logrus.Error(utils.GetFuncName(), " maXSetToKey err:", err)
|
||||||
return mx.Data, err
|
return mx.Data, err
|
||||||
}
|
}
|
||||||
// fmt.Println(utils.GetFuncName(), " step4 ", mx.InstID, " ", mx.Period)
|
// fmt.Println(utils.utils.GetFuncName(), " step4 ", mx.InstID, " ", mx.Period)
|
||||||
// fmt.Println("max setToKey: ", keyName, "res:", res, "data:", string(dj), "from: ", mx.From)
|
// fmt.Println("max setToKey: ", keyName, "res:", res, "data:", string(dj), "from: ", mx.From)
|
||||||
cr.SaveUniKey(mx.Period, keyName, extt, mx.Ts)
|
cr.SaveUniKey(mx.Period, keyName, extt, mx.Ts)
|
||||||
return mx.Data, err
|
return mx.Data, err
|
||||||
@ -94,7 +96,7 @@ func Int64ToTime(ts int64) (time.Time, error) {
|
|||||||
t = t.In(loc)
|
t = t.In(loc)
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
func (mx *MaX) PushToWriteLogChan(cr *Core) error {
|
func (mx *MaX) PushToWriteLogChan(cr *core.Core) error {
|
||||||
s := strconv.FormatFloat(float64(mx.Ts), 'f', 0, 64)
|
s := strconv.FormatFloat(float64(mx.Ts), 'f', 0, 64)
|
||||||
did := "ma" + ToString(mx.Count) + "|" + mx.InstID + "|" + mx.Period + "|" + s
|
did := "ma" + ToString(mx.Count) + "|" + mx.InstID + "|" + mx.Period + "|" + s
|
||||||
logrus.Debug("did of max:", did)
|
logrus.Debug("did of max:", did)
|
||||||
@ -113,7 +115,7 @@ func (mx *MaX) PushToWriteLogChan(cr *Core) error {
|
|||||||
// TODO
|
// TODO
|
||||||
// 返回:
|
// 返回:
|
||||||
// Sample:被顶出队列的元素
|
// Sample:被顶出队列的元素
|
||||||
func (mxl *MaXList) RPush(sm *MaX) (Sample, error) {
|
func (mxl *MaXList) RPush(sm *MaX) (models.Sample, error) {
|
||||||
last := MaX{}
|
last := MaX{}
|
||||||
bj, _ := json.Marshal(*sm)
|
bj, _ := json.Marshal(*sm)
|
||||||
json.Unmarshal(bj, &sm)
|
json.Unmarshal(bj, &sm)
|
||||||
@ -171,7 +173,7 @@ func (mxl *MaXList) RecursiveBubbleS(length int, ctype string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO pixel
|
// TODO pixel
|
||||||
func (mxl *MaXList) MakePixelList(cr *Core, mx *MaX, score float64) (*PixelList, error) {
|
func (mxl *MaXList) MakePixelList(cr *core.Core, mx *MaX, score float64) (*core.PixelList, error) {
|
||||||
if len(mx.Data) == 2 {
|
if len(mx.Data) == 2 {
|
||||||
err := errors.New("ma30 原始数据不足30条")
|
err := errors.New("ma30 原始数据不足30条")
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -180,14 +182,14 @@ func (mxl *MaXList) MakePixelList(cr *Core, mx *MaX, score float64) (*PixelList,
|
|||||||
err := errors.New("ma30 原始数据不足30条")
|
err := errors.New("ma30 原始数据不足30条")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pxl := PixelList{
|
pxl := core.PixelList{
|
||||||
Count: mxl.Count,
|
Count: mxl.Count,
|
||||||
UpdateNickName: mxl.UpdateNickName,
|
UpdateNickName: mxl.UpdateNickName,
|
||||||
LastUpdateTime: mxl.LastUpdateTime,
|
LastUpdateTime: mxl.LastUpdateTime,
|
||||||
List: []*Pixel{},
|
List: []*core.Pixel{},
|
||||||
}
|
}
|
||||||
for i := 0; i < mxl.Count; i++ {
|
for i := 0; i < mxl.Count; i++ {
|
||||||
pix := Pixel{}
|
pix := core.Pixel{}
|
||||||
pxl.List = append(pxl.List, &pix)
|
pxl.List = append(pxl.List, &pix)
|
||||||
}
|
}
|
||||||
ma30Val := (mx.Data[1]).(float64)
|
ma30Val := (mx.Data[1]).(float64)
|
||||||
|
@ -14,30 +14,33 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis"
|
"github.com/go-redis/redis"
|
||||||
"github.com/phyer/texus/private"
|
// "github.com/phyer/texus/private"
|
||||||
|
"github.com/phyer/core/analysis"
|
||||||
|
"github.com/phyer/core/config"
|
||||||
|
"github.com/phyer/core/models"
|
||||||
"github.com/phyer/v5sdkgo/rest"
|
"github.com/phyer/v5sdkgo/rest"
|
||||||
logrus "github.com/sirupsen/logrus"
|
logrus "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Core struct {
|
type Core struct {
|
||||||
Env string
|
Env string
|
||||||
Cfg *MyConfig
|
Cfg *config.MyConfig
|
||||||
RedisLocalCli *redis.Client
|
RedisLocalCli *redis.Client
|
||||||
RedisRemoteCli *redis.Client
|
RedisRemoteCli *redis.Client
|
||||||
FluentBitUrl string
|
FluentBitUrl string
|
||||||
PlateMap map[string]*Plate
|
PlateMap map[string]*models.Plate
|
||||||
TrayMap map[string]*Tray
|
TrayMap map[string]*models.Tray
|
||||||
CoasterMd5SyncMap sync.Map
|
CoasterMd5SyncMap sync.Map
|
||||||
Mu *sync.Mutex
|
Mu *sync.Mutex
|
||||||
Mu1 *sync.Mutex
|
Mu1 *sync.Mutex
|
||||||
Waity *sync.WaitGroup
|
Waity *sync.WaitGroup
|
||||||
CandlesProcessChan chan *Candle
|
CandlesProcessChan chan *models.Candle
|
||||||
MaXProcessChan chan *MaX
|
MaXProcessChan chan *MaX
|
||||||
RsiProcessChan chan *Rsi
|
RsiProcessChan chan *Rsi
|
||||||
StockRsiProcessChan chan *StockRsi
|
StockRsiProcessChan chan *StockRsi
|
||||||
TickerInforocessChan chan *TickerInfo
|
TickerInforocessChan chan *TickerInfo
|
||||||
CoasterChan chan *CoasterInfo
|
CoasterChan chan *CoasterInfo
|
||||||
SeriesChan chan *SeriesInfo // to be init
|
analysis.SeriesChan chan *analysis.SeriesInfo // to be init
|
||||||
SegmentItemChan chan *SegmentItem // to be init
|
SegmentItemChan chan *SegmentItem // to be init
|
||||||
MakeMaXsChan chan *Candle
|
MakeMaXsChan chan *Candle
|
||||||
ShearForceGrpChan chan *ShearForceGrp // to be init
|
ShearForceGrpChan chan *ShearForceGrp // to be init
|
||||||
@ -48,6 +51,77 @@ type Core struct {
|
|||||||
WriteLogChan chan *WriteLog
|
WriteLogChan chan *WriteLog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cre *coreCore) GetCandlesWithRest(instId string, kidx int, dura time.Duration, maxCandles int) error {
|
||||||
|
ary := []string{}
|
||||||
|
|
||||||
|
wsary := cre.Cfg.CandleDimentions
|
||||||
|
for k, v := range wsary {
|
||||||
|
matched := false
|
||||||
|
// 这个算法的目的是:越靠后的candles维度,被命中的概率越低,第一个百分之百命中,后面开始越来越低, 每分钟都会发生这样的计算,
|
||||||
|
// 因为维度多了的话,照顾不过来
|
||||||
|
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
n := (k*2 + 2) * 3
|
||||||
|
if n < 1 {
|
||||||
|
n = 1
|
||||||
|
}
|
||||||
|
b := rand.Intn(n)
|
||||||
|
if b < 8 {
|
||||||
|
matched = true
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
|
ary = append(ary, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mdura := dura/(time.Duration(len(ary)+1)) - 50*time.Millisecond
|
||||||
|
// fmt.Println("loop4 Ticker Start instId, dura: ", instId, dura, dura/10, mdura, len(ary), " idx: ", kidx)
|
||||||
|
// time.Duration(len(ary)+1)
|
||||||
|
ticker := time.NewTicker(mdura)
|
||||||
|
done := make(chan bool)
|
||||||
|
idx := 0
|
||||||
|
go func(i int) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if i >= (len(ary)) {
|
||||||
|
done <- true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
b := rand.Intn(2)
|
||||||
|
maxCandles = maxCandles * (i + b) * 2
|
||||||
|
|
||||||
|
if maxCandles < 3 {
|
||||||
|
maxCandles = 3
|
||||||
|
}
|
||||||
|
if maxCandles > 30 {
|
||||||
|
maxCandles = 30
|
||||||
|
}
|
||||||
|
mx := strconv.Itoa(maxCandles)
|
||||||
|
// fmt.Println("loop4 getCandlesWithRest, instId, period,limit,dura, t: ", instId, ary[i], mx, mdura)
|
||||||
|
go func(ii int) {
|
||||||
|
restQ := RestQueue{
|
||||||
|
InstId: instId,
|
||||||
|
Bar: ary[ii],
|
||||||
|
Limit: mx,
|
||||||
|
Duration: mdura,
|
||||||
|
WithWs: true,
|
||||||
|
}
|
||||||
|
js, _ := json.Marshal(restQ)
|
||||||
|
coreRedisLocalCli.LPush("restQueue", js)
|
||||||
|
}(i)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(idx)
|
||||||
|
time.Sleep(dura - 10*time.Millisecond)
|
||||||
|
ticker.Stop()
|
||||||
|
// fmt.Println("loop4 Ticker stopped instId, dura: ", instId, dura, mdura)
|
||||||
|
done <- true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type RestQueue struct {
|
type RestQueue struct {
|
||||||
InstId string
|
InstId string
|
||||||
Bar string
|
Bar string
|
||||||
@ -124,22 +198,22 @@ func WriteLogProcess(cr *Core) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
func (core *Core) Init() {
|
func (core *Core) Init() {
|
||||||
core.Env = os.Getenv("GO_ENV")
|
coreEnv = os.Getenv("GO_ENV")
|
||||||
gitBranch := os.Getenv("gitBranchName")
|
gitBranch := os.Getenv("gitBranchName")
|
||||||
commitID := os.Getenv("gitCommitID")
|
commitID := os.Getenv("gitCommitID")
|
||||||
|
|
||||||
logrus.Info("当前环境: ", core.Env)
|
logrus.Info("当前环境: ", coreEnv)
|
||||||
logrus.Info("gitBranch: ", gitBranch)
|
logrus.Info("gitBranch: ", gitBranch)
|
||||||
logrus.Info("gitCommitID: ", commitID)
|
logrus.Info("gitCommitID: ", commitID)
|
||||||
cfg := MyConfig{}
|
cfg := MyConfig{}
|
||||||
cfg, _ = cfg.Init()
|
cfg, _ = cfg.Init()
|
||||||
core.Cfg = &cfg
|
coreCfg = &cfg
|
||||||
cli, err := core.GetRedisLocalCli()
|
cli, err := coreGetRedisLocalCli()
|
||||||
core.RedisLocalCli = cli
|
coreRedisLocalCli = cli
|
||||||
core.RestQueueChan = make(chan *RestQueue)
|
coreRestQueueChan = make(chan *RestQueue)
|
||||||
core.WriteLogChan = make(chan *WriteLog)
|
coreWriteLogChan = make(chan *WriteLog)
|
||||||
// 跟订单有关的都关掉
|
// 跟订单有关的都关掉
|
||||||
// core.OrderChan = make(chan *private.Order)
|
// coreOrderChan = make(chan *private.Order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error("init redis client err: ", err)
|
logrus.Error("init redis client err: ", err)
|
||||||
}
|
}
|
||||||
@ -162,9 +236,9 @@ func (core *Core) GetRedisCliFromConf(conf RedisConfig) (*redis.Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (core *Core) GetRemoteRedisLocalCli() (*redis.Client, error) {
|
func (core *Core) GetRemoteRedisLocalCli() (*redis.Client, error) {
|
||||||
ru := core.Cfg.RedisConf.Url
|
ru := coreCfg.RedisConf.Url
|
||||||
rp := core.Cfg.RedisConf.Password
|
rp := coreCfg.RedisConf.Password
|
||||||
ri := core.Cfg.RedisConf.Index
|
ri := coreCfg.RedisConf.Index
|
||||||
re := os.Getenv("REDIS_URL")
|
re := os.Getenv("REDIS_URL")
|
||||||
if len(re) > 0 {
|
if len(re) > 0 {
|
||||||
ru = re
|
ru = re
|
||||||
@ -184,9 +258,9 @@ func (core *Core) GetRemoteRedisLocalCli() (*redis.Client, error) {
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
func (core *Core) GetRedisLocalCli() (*redis.Client, error) {
|
func (core *Core) GetRedisLocalCli() (*redis.Client, error) {
|
||||||
ru := core.Cfg.RedisConf.Url
|
ru := coreCfg.RedisConf.Url
|
||||||
rp := core.Cfg.RedisConf.Password
|
rp := coreCfg.RedisConf.Password
|
||||||
ri := core.Cfg.RedisConf.Index
|
ri := coreCfg.RedisConf.Index
|
||||||
re := os.Getenv("REDIS_URL")
|
re := os.Getenv("REDIS_URL")
|
||||||
if len(re) > 0 {
|
if len(re) > 0 {
|
||||||
ru = re
|
ru = re
|
||||||
@ -209,7 +283,7 @@ func (core *Core) GetRedisLocalCli() (*redis.Client, error) {
|
|||||||
// 这些应该是放到 texus 里实现的
|
// 这些应该是放到 texus 里实现的
|
||||||
func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
||||||
// GET / 获取所有产品行情信息
|
// GET / 获取所有产品行情信息
|
||||||
rsp, err := core.RestInvoke("/api/v5/market/tickers?instType=SPOT", rest.GET)
|
rsp, err := coreRestInvoke("/api/v5/market/tickers?instType=SPOT", rest.GET)
|
||||||
return rsp, err
|
return rsp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,14 +291,14 @@ func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
|||||||
//
|
//
|
||||||
// func (core *Core) GetBalances() (*rest.RESTAPIResult, error) {
|
// func (core *Core) GetBalances() (*rest.RESTAPIResult, error) {
|
||||||
// // TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
// // TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
||||||
// rsp, err := core.RestInvoke2("/api/v5/account/balance", rest.GET, nil)
|
// rsp, err := coreRestInvoke2("/api/v5/account/balance", rest.GET, nil)
|
||||||
// return rsp, err
|
// return rsp, err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// func (core *Core) GetLivingOrderList() ([]*private.Order, error) {
|
// func (core *Core) GetLivingOrderList() ([]*private.Order, error) {
|
||||||
// // TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
// // TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
||||||
// params := make(map[string]interface{})
|
// params := make(map[string]interface{})
|
||||||
// data, err := core.RestInvoke2("/api/v5/trade/orders-pending", rest.GET, ¶ms)
|
// data, err := coreRestInvoke2("/api/v5/trade/orders-pending", rest.GET, ¶ms)
|
||||||
// odrsp := private.OrderResp{}
|
// odrsp := private.OrderResp{}
|
||||||
// err = json.Unmarshal([]byte(data.Body), &odrsp)
|
// err = json.Unmarshal([]byte(data.Body), &odrsp)
|
||||||
// str, _ := json.Marshal(odrsp)
|
// str, _ := json.Marshal(odrsp)
|
||||||
@ -239,7 +313,7 @@ func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
|||||||
// time.Sleep(3 * time.Second)
|
// time.Sleep(3 * time.Second)
|
||||||
// ctype := ws.SPOT
|
// ctype := ws.SPOT
|
||||||
//
|
//
|
||||||
// redisCli := core.RedisLocalCli
|
// redisCli := coreRedisLocalCli
|
||||||
// counts, err := redisCli.HLen("instruments|" + ctype + "|hash").Result()
|
// counts, err := redisCli.HLen("instruments|" + ctype + "|hash").Result()
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println("err of hset to redis:", err)
|
// fmt.Println("err of hset to redis:", err)
|
||||||
@ -254,7 +328,7 @@ func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
|||||||
// func (core *Core) SubscribeTicker(op string) error {
|
// func (core *Core) SubscribeTicker(op string) error {
|
||||||
// mp := make(map[string]string)
|
// mp := make(map[string]string)
|
||||||
//
|
//
|
||||||
// redisCli := core.RedisLocalCli
|
// redisCli := coreRedisLocalCli
|
||||||
// ctype := ws.SPOT
|
// ctype := ws.SPOT
|
||||||
// mp, err := redisCli.HGetAll("instruments|" + ctype + "|hash").Result()
|
// mp, err := redisCli.HGetAll("instruments|" + ctype + "|hash").Result()
|
||||||
// b, err := json.Marshal(mp)
|
// b, err := json.Marshal(mp)
|
||||||
@ -273,7 +347,7 @@ func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
|||||||
// time.Sleep(5 * time.Second)
|
// time.Sleep(5 * time.Second)
|
||||||
// go func(instId string, op string) {
|
// go func(instId string, op string) {
|
||||||
//
|
//
|
||||||
// redisCli := core.RedisLocalCli
|
// redisCli := coreRedisLocalCli
|
||||||
// _, err = redisCli.SAdd("tickers|"+op+"|set", instId).Result()
|
// _, err = redisCli.SAdd("tickers|"+op+"|set", instId).Result()
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println("err of unMarshalJson5:", js)
|
// fmt.Println("err of unMarshalJson5:", js)
|
||||||
@ -286,7 +360,7 @@ func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
|||||||
// 通过接口获取一个币种名下的某个时间范围内的Candle对象集合
|
// 通过接口获取一个币种名下的某个时间范围内的Candle对象集合
|
||||||
// 按说这个应该放到 texus里实现
|
// 按说这个应该放到 texus里实现
|
||||||
func (core *Core) v5PublicInvoke(subUrl string) (*CandleData, error) {
|
func (core *Core) v5PublicInvoke(subUrl string) (*CandleData, error) {
|
||||||
restUrl, _ := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
restUrl, _ := coreCfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||||
url := restUrl + subUrl
|
url := restUrl + subUrl
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -303,14 +377,14 @@ func (core *Core) v5PublicInvoke(subUrl string) (*CandleData, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult, error) {
|
func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult, error) {
|
||||||
restUrl, _ := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
restUrl, _ := coreCfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||||
//ep, method, uri string, param *map[string]interface{}
|
//ep, method, uri string, param *map[string]interface{}
|
||||||
rest := rest.NewRESTAPI(restUrl, method, subUrl, nil)
|
rest := rest.NewRESTAPI(restUrl, method, subUrl, nil)
|
||||||
key, _ := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessKey").String()
|
key, _ := coreCfg.Config.Get("credentialReadOnly").Get("okAccessKey").String()
|
||||||
secure, _ := core.Cfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
secure, _ := coreCfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
||||||
pass, _ := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
pass, _ := coreCfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
||||||
isDemo := false
|
isDemo := false
|
||||||
if core.Env == "demoEnv" {
|
if coreEnv == "demoEnv" {
|
||||||
isDemo = true
|
isDemo = true
|
||||||
}
|
}
|
||||||
rest.SetSimulate(isDemo).SetAPIKey(key, secure, pass)
|
rest.SetSimulate(isDemo).SetAPIKey(key, secure, pass)
|
||||||
@ -320,13 +394,187 @@ func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult,
|
|||||||
}
|
}
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
// 保证同一个 period, keyName ,在一个周期里,SaveToSortSet只会被执行一次
|
||||||
|
func (core *core.Core) SaveUniKey(period string, keyName string, extt time.Duration, tsi int64) {
|
||||||
|
|
||||||
|
refName := keyName + "|refer"
|
||||||
|
// refRes, _ := core.RedisLocalCli.GetSet(refName, 1).Result()
|
||||||
|
core.RedisLocalCli.Expire(refName, extt)
|
||||||
|
// 为保证唯一性机制,防止SaveToSortSet 被重复执行, ps: 不需要唯一,此操作幂等在redis里
|
||||||
|
// founded, _ := core.findInSortSet(period, keyName, extt, tsi)
|
||||||
|
// if len(refRes) != 0 {
|
||||||
|
// logrus.Error("refName exist: ", refName)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
core.SaveToSortSet(period, keyName, extt, tsi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (core *core.Core) findInSortSet(period string, keyName string, extt time.Duration, tsi int64) (bool, error) {
|
||||||
|
founded := false
|
||||||
|
ary := strings.Split(keyName, "ts:")
|
||||||
|
setName := ary[0] + "sortedSet"
|
||||||
|
opt := redis.ZRangeBy{
|
||||||
|
Min: ToString(tsi),
|
||||||
|
Max: ToString(tsi),
|
||||||
|
}
|
||||||
|
rs, err := core.RedisLocalCli.ZRangeByScore(setName, opt).Result()
|
||||||
|
if len(rs) > 0 {
|
||||||
|
founded = true
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("err of ma7|ma30 add to redis:", err)
|
||||||
|
} else {
|
||||||
|
logrus.Info("sortedSet added to redis:", rs, keyName)
|
||||||
|
}
|
||||||
|
return founded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tsi: 上报时间timeStamp millinSecond
|
||||||
|
func (core *core.Core) SaveToSortSet(period string, keyName string, extt time.Duration, tsi int64) {
|
||||||
|
ary := strings.Split(keyName, "ts:")
|
||||||
|
setName := ary[0] + "sortedSet"
|
||||||
|
z := redis.Z{
|
||||||
|
Score: float64(tsi),
|
||||||
|
Member: keyName,
|
||||||
|
}
|
||||||
|
rs, err := core.RedisLocalCli.ZAdd(setName, z).Result()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warn("err of ma7|ma30 add to redis:", err)
|
||||||
|
} else {
|
||||||
|
logrus.Warn("sortedSet added to redis:", rs, keyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据周期的文本内容,返回这代表多少个分钟
|
||||||
|
func (cr *core.Core) PeriodToMinutes(period string) (int64, error) {
|
||||||
|
ary := strings.Split(period, "")
|
||||||
|
beiStr := "1"
|
||||||
|
danwei := ""
|
||||||
|
if len(ary) == 0 {
|
||||||
|
err := errors.New(utils.GetFuncName() + " period is block")
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if len(ary) == 3 {
|
||||||
|
beiStr = ary[0] + ary[1]
|
||||||
|
danwei = ary[2]
|
||||||
|
} else {
|
||||||
|
beiStr = ary[0]
|
||||||
|
danwei = ary[1]
|
||||||
|
}
|
||||||
|
cheng := 1
|
||||||
|
bei, _ := strconv.Atoi(beiStr)
|
||||||
|
switch danwei {
|
||||||
|
case "m":
|
||||||
|
{
|
||||||
|
cheng = bei
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "H":
|
||||||
|
{
|
||||||
|
cheng = bei * 60
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "D":
|
||||||
|
{
|
||||||
|
cheng = bei * 60 * 24
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "W":
|
||||||
|
{
|
||||||
|
cheng = bei * 60 * 24 * 7
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "M":
|
||||||
|
{
|
||||||
|
cheng = bei * 60 * 24 * 30
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "Y":
|
||||||
|
{
|
||||||
|
cheng = bei * 60 * 24 * 365
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
logrus.Warning("notmatch:", danwei, period)
|
||||||
|
panic("notmatch:" + period)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int64(cheng), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// type ScanCmd struct {
|
||||||
|
// baseCmd
|
||||||
|
//
|
||||||
|
// page []string
|
||||||
|
// cursor uint64
|
||||||
|
//
|
||||||
|
// process func(cmd Cmder) error
|
||||||
|
// }
|
||||||
|
func (core *core.Core) GetRangeKeyList(pattern string, from time.Time) ([]*simple.Json, error) {
|
||||||
|
// 比如,用来计算ma30或ma7,倒推多少时间范围,
|
||||||
|
redisCli := core.RedisLocalCli
|
||||||
|
cursor := uint64(0)
|
||||||
|
n := 0
|
||||||
|
allTs := []int64{}
|
||||||
|
var keys []string
|
||||||
|
for {
|
||||||
|
var err error
|
||||||
|
keys, cursor, _ = redisCli.Scan(cursor, pattern+"*", 2000).Result()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
n += len(keys)
|
||||||
|
if n == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keys, _ := redisCli.Keys(pattern + "*").Result()
|
||||||
|
for _, key := range keys {
|
||||||
|
keyAry := strings.Split(key, ":")
|
||||||
|
key = keyAry[1]
|
||||||
|
keyi64, _ := strconv.ParseInt(key, 10, 64)
|
||||||
|
allTs = append(allTs, keyi64)
|
||||||
|
}
|
||||||
|
nary := utils.RecursiveBubble(allTs, len(allTs))
|
||||||
|
tt := from.UnixMilli()
|
||||||
|
ff := tt - tt%60000
|
||||||
|
fi := int64(ff)
|
||||||
|
mary := []int64{}
|
||||||
|
for _, v := range nary {
|
||||||
|
if v < fi {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mary = append(mary, v)
|
||||||
|
}
|
||||||
|
res := []*simple.Json{}
|
||||||
|
for _, v := range mary {
|
||||||
|
// if k > 1 {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
nv := pattern + strconv.FormatInt(v, 10)
|
||||||
|
str, err := redisCli.Get(nv).Result()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("err of redis get key:", nv, err)
|
||||||
|
}
|
||||||
|
cur, err := simple.NewJson([]byte(str))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("err of create newJson:", str, err)
|
||||||
|
}
|
||||||
|
res = append(res, cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// func (core *Core) RestInvoke2(subUrl string, method string, param *map[string]interface{}) (*rest.RESTAPIResult, error) {
|
// func (core *Core) RestInvoke2(subUrl string, method string, param *map[string]interface{}) (*rest.RESTAPIResult, error) {
|
||||||
// key, err1 := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessKey").String()
|
// key, err1 := coreCfg.Config.Get("credentialReadOnly").Get("okAccessKey").String()
|
||||||
// secret, err2 := core.Cfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
// secret, err2 := coreCfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
||||||
// pass, err3 := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
// pass, err3 := coreCfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
||||||
// userId, err4 := core.Cfg.Config.Get("connect").Get("userId").String()
|
// userId, err4 := coreCfg.Config.Get("connect").Get("userId").String()
|
||||||
// restUrl, err5 := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
// restUrl, err5 := coreCfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||||
// if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
// if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
||||||
// fmt.Println(err1, err2, err3, err4, err5)
|
// fmt.Println(err1, err2, err3, err4, err5)
|
||||||
// } else {
|
// } else {
|
||||||
@ -338,7 +586,7 @@ func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult,
|
|||||||
// // }
|
// // }
|
||||||
// // rs := rest.NewRESTAPI(restUrl, method, subUrl, &reqParam)
|
// // rs := rest.NewRESTAPI(restUrl, method, subUrl, &reqParam)
|
||||||
// isDemo := false
|
// isDemo := false
|
||||||
// if core.Env == "demoEnv" {
|
// if coreEnv == "demoEnv" {
|
||||||
// isDemo = true
|
// isDemo = true
|
||||||
// }
|
// }
|
||||||
// // rs.SetSimulate(isDemo).SetAPIKey(key, secret, pass).SetUserId(userId)
|
// // rs.SetSimulate(isDemo).SetAPIKey(key, secret, pass).SetUserId(userId)
|
||||||
@ -362,11 +610,11 @@ func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult,
|
|||||||
|
|
||||||
// 跟下单有关的都关掉,以后再说
|
// 跟下单有关的都关掉,以后再说
|
||||||
// func (core *Core) RestPost(subUrl string, param *map[string]interface{}) (*rest.RESTAPIResult, error) {
|
// func (core *Core) RestPost(subUrl string, param *map[string]interface{}) (*rest.RESTAPIResult, error) {
|
||||||
// key, err1 := core.Cfg.Config.Get("credentialMutable").Get("okAccessKey").String()
|
// key, err1 := coreCfg.Config.Get("credentialMutable").Get("okAccessKey").String()
|
||||||
// secret, err2 := core.Cfg.Config.Get("credentialMutable").Get("secretKey").String()
|
// secret, err2 := coreCfg.Config.Get("credentialMutable").Get("secretKey").String()
|
||||||
// pass, err3 := core.Cfg.Config.Get("credentialMutable").Get("okAccessPassphrase").String()
|
// pass, err3 := coreCfg.Config.Get("credentialMutable").Get("okAccessPassphrase").String()
|
||||||
// userId, err4 := core.Cfg.Config.Get("connect").Get("userId").String()
|
// userId, err4 := coreCfg.Config.Get("connect").Get("userId").String()
|
||||||
// restUrl, err5 := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
// restUrl, err5 := coreCfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||||
// if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
// if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
||||||
// fmt.Println(err1, err2, err3, err4, err5)
|
// fmt.Println(err1, err2, err3, err4, err5)
|
||||||
// } else {
|
// } else {
|
||||||
@ -379,7 +627,7 @@ func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult,
|
|||||||
// PassPhrase: pass,
|
// PassPhrase: pass,
|
||||||
// }
|
// }
|
||||||
// isDemo := false
|
// isDemo := false
|
||||||
// if core.Env == "demoEnv" {
|
// if coreEnv == "demoEnv" {
|
||||||
// isDemo = true
|
// isDemo = true
|
||||||
// }
|
// }
|
||||||
// cli := rest.NewRESTClient(restUrl, &apikey, isDemo)
|
// cli := rest.NewRESTClient(restUrl, &apikey, isDemo)
|
||||||
@ -392,7 +640,7 @@ func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult,
|
|||||||
|
|
||||||
// 我当前持有的币,每分钟刷新
|
// 我当前持有的币,每分钟刷新
|
||||||
func (core *Core) GetMyFavorList() []string {
|
func (core *Core) GetMyFavorList() []string {
|
||||||
redisCli := core.RedisLocalCli
|
redisCli := coreRedisLocalCli
|
||||||
opt := redis.ZRangeBy{
|
opt := redis.ZRangeBy{
|
||||||
Min: "10",
|
Min: "10",
|
||||||
Max: "100000000000",
|
Max: "100000000000",
|
||||||
@ -410,8 +658,8 @@ func (core *Core) GetMyFavorList() []string {
|
|||||||
// 改了,不需要交易排行榜,我手动指定一个排行即可, tickersVol|sortedSet 改成 tickersList|sortedSet
|
// 改了,不需要交易排行榜,我手动指定一个排行即可, tickersVol|sortedSet 改成 tickersList|sortedSet
|
||||||
func (core *Core) GetScoreList(count int) []string {
|
func (core *Core) GetScoreList(count int) []string {
|
||||||
|
|
||||||
// redisCli := core.RedisLocalCli
|
// redisCli := coreRedisLocalCli
|
||||||
myFocusList := core.Cfg.Config.Get("focusList").MustArray()
|
myFocusList := coreCfg.Config.Get("focusList").MustArray()
|
||||||
logrus.Debug("curList: ", myFocusList)
|
logrus.Debug("curList: ", myFocusList)
|
||||||
lst := []string{}
|
lst := []string{}
|
||||||
for _, v := range myFocusList {
|
for _, v := range myFocusList {
|
||||||
@ -622,7 +870,7 @@ func (core *Core) GetRangeMaXSortedSet(setName string, count int, from time.Time
|
|||||||
ary2 = strings.Split(ary1[1], "candle")
|
ary2 = strings.Split(ary1[1], "candle")
|
||||||
period = ary2[1]
|
period = ary2[1]
|
||||||
|
|
||||||
dui, err := core.PeriodToMinutes(period)
|
dui, err := corePeriodToMinutes(period)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mxl, err
|
return mxl, err
|
||||||
}
|
}
|
||||||
@ -637,7 +885,7 @@ func (core *Core) GetRangeMaXSortedSet(setName string, count int, from time.Time
|
|||||||
}
|
}
|
||||||
ary := []string{}
|
ary := []string{}
|
||||||
logrus.Debug("ZRevRangeByScore ", " setName:", setName, " froms:", froms, " sts:", sts)
|
logrus.Debug("ZRevRangeByScore ", " setName:", setName, " froms:", froms, " sts:", sts)
|
||||||
dura, err := core.GetExpiration(period)
|
dura, err := coreGetExpiration(period)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mxl, err
|
return mxl, err
|
||||||
}
|
}
|
||||||
@ -645,7 +893,7 @@ func (core *Core) GetRangeMaXSortedSet(setName string, count int, from time.Time
|
|||||||
ot := time.Now().Add(dura * -1)
|
ot := time.Now().Add(dura * -1)
|
||||||
oti := ot.UnixMilli()
|
oti := ot.UnixMilli()
|
||||||
// fmt.Println(fmt.Sprint("GetExpiration zRemRangeByScore ", setName, " ", 0, " ", strconv.FormatInt(oti, 10)))
|
// fmt.Println(fmt.Sprint("GetExpiration zRemRangeByScore ", setName, " ", 0, " ", strconv.FormatInt(oti, 10)))
|
||||||
cli := core.RedisLocalCli
|
cli := coreRedisLocalCli
|
||||||
cli.LTrim(setName, 0, oti)
|
cli.LTrim(setName, 0, oti)
|
||||||
cunt, _ := cli.ZRemRangeByScore(setName, "0", strconv.FormatInt(oti, 10)).Result()
|
cunt, _ := cli.ZRemRangeByScore(setName, "0", strconv.FormatInt(oti, 10)).Result()
|
||||||
if cunt > 0 {
|
if cunt > 0 {
|
||||||
@ -763,7 +1011,7 @@ func (core *Core) GetRangeCandleSortedSet(setName string, count int, from time.T
|
|||||||
period := strings.TrimPrefix(ary[0], "candle")
|
period := strings.TrimPrefix(ary[0], "candle")
|
||||||
|
|
||||||
// 获取period对应的分钟数
|
// 获取period对应的分钟数
|
||||||
durationMinutes, err := core.PeriodToMinutes(period)
|
durationMinutes, err := corePeriodToMinutes(period)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get period minutes: %w", err)
|
return nil, fmt.Errorf("failed to get period minutes: %w", err)
|
||||||
}
|
}
|
||||||
@ -779,12 +1027,12 @@ func (core *Core) GetRangeCandleSortedSet(setName string, count int, from time.T
|
|||||||
startTs := fromTs - durationMinutes*int64(count)*60*1000
|
startTs := fromTs - durationMinutes*int64(count)*60*1000
|
||||||
|
|
||||||
// 清理过期数据
|
// 清理过期数据
|
||||||
if err := core.cleanExpiredData(setName, period); err != nil {
|
if err := corecleanExpiredData(setName, period); err != nil {
|
||||||
logrus.Warnf("Failed to clean expired data: %v", err)
|
logrus.Warnf("Failed to clean expired data: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从Redis获取数据
|
// 从Redis获取数据
|
||||||
cli := core.RedisLocalCli
|
cli := coreRedisLocalCli
|
||||||
opt := redis.ZRangeBy{
|
opt := redis.ZRangeBy{
|
||||||
Min: strconv.FormatInt(startTs, 10),
|
Min: strconv.FormatInt(startTs, 10),
|
||||||
Max: strconv.FormatInt(fromTs, 10),
|
Max: strconv.FormatInt(fromTs, 10),
|
||||||
@ -836,12 +1084,12 @@ func (core *Core) GetRangeCandleSortedSet(setName string, count int, from time.T
|
|||||||
|
|
||||||
// cleanExpiredData 清理过期的数据
|
// cleanExpiredData 清理过期的数据
|
||||||
func (core *Core) cleanExpiredData(setName, period string) error {
|
func (core *Core) cleanExpiredData(setName, period string) error {
|
||||||
expiration, err := core.GetExpiration(period)
|
expiration, err := coreGetExpiration(period)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cli := core.RedisLocalCli
|
cli := coreRedisLocalCli
|
||||||
expirationTime := time.Now().Add(-expiration)
|
expirationTime := time.Now().Add(-expiration)
|
||||||
expirationTs := strconv.FormatInt(expirationTime.UnixMilli(), 10)
|
expirationTs := strconv.FormatInt(expirationTime.UnixMilli(), 10)
|
||||||
|
|
||||||
@ -868,40 +1116,40 @@ func (cr *Core) GetCoasterFromPlate(instID string, period string) (Coaster, erro
|
|||||||
return co, nil
|
return co, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (core *Core) GetPixelSeries(instId string, period string) (Series, error) {
|
func (core *Core) GetPixelanalysis.Series(instId string, period string) (analysis.Series, error) {
|
||||||
srs := Series{}
|
srs := analysis.Series{}
|
||||||
srName := instId + "|" + period + "|series"
|
srName := instId + "|" + period + "|series"
|
||||||
cli := core.RedisLocalCli
|
cli := coreRedisLocalCli
|
||||||
srsStr, err := cli.Get(srName).Result()
|
srsStr, err := cli.Get(srName).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *new(Series), err
|
return *new(analysis.Series), err
|
||||||
}
|
}
|
||||||
err = json.Unmarshal([]byte(srsStr), &srs)
|
err = json.Unmarshal([]byte(srsStr), &srs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *new(Series), err
|
return *new(analysis.Series), err
|
||||||
}
|
}
|
||||||
logrus.Info("sei:", srsStr)
|
logrus.Info("sei:", srsStr)
|
||||||
err = srs.CandleSeries.RecursiveBubbleS(srs.CandleSeries.Count, "asc")
|
err = srs.Candleanalysis.Series.RecursiveBubbleS(srs.Candleanalysis.Series.Count, "asc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *new(Series), err
|
return *new(analysis.Series), err
|
||||||
}
|
}
|
||||||
// err = srs.CandleSeries.RecursiveBubbleX(srs.CandleSeries.Count, "asc")
|
// err = srs.Candleanalysis.Series.RecursiveBubbleX(srs.Candleanalysis.Series.Count, "asc")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return nil, err
|
// return nil, err
|
||||||
// }
|
// }
|
||||||
err = srs.Ma7Series.RecursiveBubbleS(srs.CandleSeries.Count, "asc")
|
err = srs.Ma7analysis.Series.RecursiveBubbleS(srs.Candleanalysis.Series.Count, "asc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *new(Series), err
|
return *new(analysis.Series), err
|
||||||
}
|
}
|
||||||
// err = srs.Ma7Series.RecursiveBubbleX(srs.CandleSeries.Count, "asc")
|
// err = srs.Ma7analysis.Series.RecursiveBubbleX(srs.Candleanalysis.Series.Count, "asc")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return nil, err
|
// return nil, err
|
||||||
// }
|
// }
|
||||||
err = srs.Ma30Series.RecursiveBubbleS(srs.CandleSeries.Count, "asc")
|
err = srs.Ma30analysis.Series.RecursiveBubbleS(srs.Candleanalysis.Series.Count, "asc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *new(Series), err
|
return *new(analysis.Series), err
|
||||||
}
|
}
|
||||||
// err = srs.Ma30Series.RecursiveBubbleX(srs.CandleSeries.Count, "asc")
|
// err = srs.Ma30analysis.Series.RecursiveBubbleX(srs.Candleanalysis.Series.Count, "asc")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return nil, err
|
// return nil, err
|
||||||
// }
|
// }
|
||||||
|
@ -2,11 +2,9 @@ package market
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/phyer/core/internal/core" // 新增
|
||||||
"github.com/phyer/core/internal/utils" // 新增
|
"github.com/phyer/core/internal/utils" // 新增
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,52 +31,16 @@ func (tir *TickerInfoResp) Convert() TickerInfo {
|
|||||||
Id: utils.HashString(tir.InstID + tir.Ts),
|
Id: utils.HashString(tir.InstID + tir.Ts),
|
||||||
InstID: tir.InstID,
|
InstID: tir.InstID,
|
||||||
InstType: tir.InstType,
|
InstType: tir.InstType,
|
||||||
Last: ToFloat64(tir.Last),
|
Last: utils.ToFloat64(tir.Last),
|
||||||
VolCcy24h: ToFloat64(tir.VolCcy24h),
|
VolCcy24h: utils.ToFloat64(tir.VolCcy24h),
|
||||||
Ts: ToInt64(tir.Ts),
|
Ts: utils.ToInt64(tir.Ts),
|
||||||
LastUpdate: time.Now(),
|
LastUpdate: time.Now(),
|
||||||
}
|
}
|
||||||
return ti
|
return ti
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToString(val interface{}) string {
|
|
||||||
valstr := ""
|
|
||||||
if reflect.TypeOf(val).Name() == "string" {
|
|
||||||
valstr = val.(string)
|
|
||||||
} else if reflect.TypeOf(val).Name() == "float64" {
|
|
||||||
valstr = fmt.Sprintf("%f", val)
|
|
||||||
} else if reflect.TypeOf(val).Name() == "int64" {
|
|
||||||
valstr = strconv.FormatInt(val.(int64), 16)
|
|
||||||
} else if reflect.TypeOf(val).Name() == "int" {
|
|
||||||
valstr = fmt.Sprintf("%d", val)
|
|
||||||
}
|
|
||||||
return valstr
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToInt64(val interface{}) int64 {
|
|
||||||
vali := int64(0)
|
|
||||||
if reflect.TypeOf(val).Name() == "string" {
|
|
||||||
vali, _ = strconv.ParseInt(val.(string), 10, 64)
|
|
||||||
} else if reflect.TypeOf(val).Name() == "float64" {
|
|
||||||
vali = int64(val.(float64))
|
|
||||||
}
|
|
||||||
return vali
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToFloat64(val interface{}) float64 {
|
|
||||||
valf := float64(0)
|
|
||||||
if reflect.TypeOf(val).Name() == "string" {
|
|
||||||
valf, _ = strconv.ParseFloat(val.(string), 64)
|
|
||||||
} else if reflect.TypeOf(val).Name() == "float64" {
|
|
||||||
valf = val.(float64)
|
|
||||||
} else if reflect.TypeOf(val).Name() == "int64" {
|
|
||||||
valf = float64(val.(int64))
|
|
||||||
}
|
|
||||||
return valf
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 有待实现
|
// TODO 有待实现
|
||||||
func (ti *TickerInfo) SetToKey(cr *Core) error {
|
func (ti *TickerInfo) SetToKey(cr *core.Core) error {
|
||||||
js, _ := json.Marshal(*ti)
|
js, _ := json.Marshal(*ti)
|
||||||
plateName := ti.InstID + "|tickerInfo"
|
plateName := ti.InstID + "|tickerInfo"
|
||||||
_, err := cr.RedisLocalCli.Set(plateName, string(js), 0).Result()
|
_, err := cr.RedisLocalCli.Set(plateName, string(js), 0).Result()
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
// "reflect"
|
// "reflect"
|
||||||
@ -78,77 +76,6 @@ func (mc *MatchCheck) SetMatched(value bool) {
|
|||||||
mc.Matched = value
|
mc.Matched = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (core *core.Core) GetCandlesWithRest(instId string, kidx int, dura time.Duration, maxCandles int) error {
|
|
||||||
ary := []string{}
|
|
||||||
|
|
||||||
wsary := core.Cfg.CandleDimentions
|
|
||||||
for k, v := range wsary {
|
|
||||||
matched := false
|
|
||||||
// 这个算法的目的是:越靠后的candles维度,被命中的概率越低,第一个百分之百命中,后面开始越来越低, 每分钟都会发生这样的计算,
|
|
||||||
// 因为维度多了的话,照顾不过来
|
|
||||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
n := (k*2 + 2) * 3
|
|
||||||
if n < 1 {
|
|
||||||
n = 1
|
|
||||||
}
|
|
||||||
b := rand.Intn(n)
|
|
||||||
if b < 8 {
|
|
||||||
matched = true
|
|
||||||
}
|
|
||||||
if matched {
|
|
||||||
ary = append(ary, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mdura := dura/(time.Duration(len(ary)+1)) - 50*time.Millisecond
|
|
||||||
// fmt.Println("loop4 Ticker Start instId, dura: ", instId, dura, dura/10, mdura, len(ary), " idx: ", kidx)
|
|
||||||
// time.Duration(len(ary)+1)
|
|
||||||
ticker := time.NewTicker(mdura)
|
|
||||||
done := make(chan bool)
|
|
||||||
idx := 0
|
|
||||||
go func(i int) {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
if i >= (len(ary)) {
|
|
||||||
done <- true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
b := rand.Intn(2)
|
|
||||||
maxCandles = maxCandles * (i + b) * 2
|
|
||||||
|
|
||||||
if maxCandles < 3 {
|
|
||||||
maxCandles = 3
|
|
||||||
}
|
|
||||||
if maxCandles > 30 {
|
|
||||||
maxCandles = 30
|
|
||||||
}
|
|
||||||
mx := strconv.Itoa(maxCandles)
|
|
||||||
// fmt.Println("loop4 getCandlesWithRest, instId, period,limit,dura, t: ", instId, ary[i], mx, mdura)
|
|
||||||
go func(ii int) {
|
|
||||||
restQ := RestQueue{
|
|
||||||
InstId: instId,
|
|
||||||
Bar: ary[ii],
|
|
||||||
Limit: mx,
|
|
||||||
Duration: mdura,
|
|
||||||
WithWs: true,
|
|
||||||
}
|
|
||||||
js, _ := json.Marshal(restQ)
|
|
||||||
core.RedisLocalCli.LPush("restQueue", js)
|
|
||||||
}(i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(idx)
|
|
||||||
time.Sleep(dura - 10*time.Millisecond)
|
|
||||||
ticker.Stop()
|
|
||||||
// fmt.Println("loop4 Ticker stopped instId, dura: ", instId, dura, mdura)
|
|
||||||
done <- true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前的时间毫秒数 对于某个时间段,比如3分钟,10分钟,是否可以被整除,
|
// 当前的时间毫秒数 对于某个时间段,比如3分钟,10分钟,是否可以被整除,
|
||||||
func IsModOf(curInt int64, duration time.Duration) bool {
|
func IsModOf(curInt int64, duration time.Duration) bool {
|
||||||
vol := int64(0)
|
vol := int64(0)
|
||||||
@ -284,15 +211,6 @@ func Daoxu(arr []interface{}) {
|
|||||||
arr[length-1-i] = temp
|
arr[length-1-i] = temp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func HashString(input string) string {
|
|
||||||
// 计算SHA-256哈希值
|
|
||||||
hash := sha256.Sum256([]byte(input))
|
|
||||||
// 转换为十六进制字符串
|
|
||||||
hashHex := hex.EncodeToString(hash[:])
|
|
||||||
// 返回前20位
|
|
||||||
return hashHex[:23]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cl *Candle) ToStruct(core *core.Core) (*Candle, error) {
|
func (cl *Candle) ToStruct(core *core.Core) (*Candle, error) {
|
||||||
// cl.Timestamp
|
// cl.Timestamp
|
||||||
// 将字符串转换为 int64 类型的时间戳
|
// 将字符串转换为 int64 类型的时间戳
|
||||||
@ -340,180 +258,6 @@ func (cl *Candle) ToStruct(core *core.Core) (*Candle, error) {
|
|||||||
return cl, nil
|
return cl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保证同一个 period, keyName ,在一个周期里,SaveToSortSet只会被执行一次
|
|
||||||
func (core *core.Core) SaveUniKey(period string, keyName string, extt time.Duration, tsi int64) {
|
|
||||||
|
|
||||||
refName := keyName + "|refer"
|
|
||||||
// refRes, _ := core.RedisLocalCli.GetSet(refName, 1).Result()
|
|
||||||
core.RedisLocalCli.Expire(refName, extt)
|
|
||||||
// 为保证唯一性机制,防止SaveToSortSet 被重复执行, ps: 不需要唯一,此操作幂等在redis里
|
|
||||||
// founded, _ := core.findInSortSet(period, keyName, extt, tsi)
|
|
||||||
// if len(refRes) != 0 {
|
|
||||||
// logrus.Error("refName exist: ", refName)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
core.SaveToSortSet(period, keyName, extt, tsi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (core *core.Core) findInSortSet(period string, keyName string, extt time.Duration, tsi int64) (bool, error) {
|
|
||||||
founded := false
|
|
||||||
ary := strings.Split(keyName, "ts:")
|
|
||||||
setName := ary[0] + "sortedSet"
|
|
||||||
opt := redis.ZRangeBy{
|
|
||||||
Min: ToString(tsi),
|
|
||||||
Max: ToString(tsi),
|
|
||||||
}
|
|
||||||
rs, err := core.RedisLocalCli.ZRangeByScore(setName, opt).Result()
|
|
||||||
if len(rs) > 0 {
|
|
||||||
founded = true
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("err of ma7|ma30 add to redis:", err)
|
|
||||||
} else {
|
|
||||||
logrus.Info("sortedSet added to redis:", rs, keyName)
|
|
||||||
}
|
|
||||||
return founded, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// tsi: 上报时间timeStamp millinSecond
|
|
||||||
func (core *core.Core) SaveToSortSet(period string, keyName string, extt time.Duration, tsi int64) {
|
|
||||||
ary := strings.Split(keyName, "ts:")
|
|
||||||
setName := ary[0] + "sortedSet"
|
|
||||||
z := redis.Z{
|
|
||||||
Score: float64(tsi),
|
|
||||||
Member: keyName,
|
|
||||||
}
|
|
||||||
rs, err := core.RedisLocalCli.ZAdd(setName, z).Result()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warn("err of ma7|ma30 add to redis:", err)
|
|
||||||
} else {
|
|
||||||
logrus.Warn("sortedSet added to redis:", rs, keyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据周期的文本内容,返回这代表多少个分钟
|
|
||||||
func (cr *core.Core) PeriodToMinutes(period string) (int64, error) {
|
|
||||||
ary := strings.Split(period, "")
|
|
||||||
beiStr := "1"
|
|
||||||
danwei := ""
|
|
||||||
if len(ary) == 0 {
|
|
||||||
err := errors.New(utils.GetFuncName() + " period is block")
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if len(ary) == 3 {
|
|
||||||
beiStr = ary[0] + ary[1]
|
|
||||||
danwei = ary[2]
|
|
||||||
} else {
|
|
||||||
beiStr = ary[0]
|
|
||||||
danwei = ary[1]
|
|
||||||
}
|
|
||||||
cheng := 1
|
|
||||||
bei, _ := strconv.Atoi(beiStr)
|
|
||||||
switch danwei {
|
|
||||||
case "m":
|
|
||||||
{
|
|
||||||
cheng = bei
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "H":
|
|
||||||
{
|
|
||||||
cheng = bei * 60
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "D":
|
|
||||||
{
|
|
||||||
cheng = bei * 60 * 24
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "W":
|
|
||||||
{
|
|
||||||
cheng = bei * 60 * 24 * 7
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "M":
|
|
||||||
{
|
|
||||||
cheng = bei * 60 * 24 * 30
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "Y":
|
|
||||||
{
|
|
||||||
cheng = bei * 60 * 24 * 365
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
logrus.Warning("notmatch:", danwei, period)
|
|
||||||
panic("notmatch:" + period)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return int64(cheng), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// type ScanCmd struct {
|
|
||||||
// baseCmd
|
|
||||||
//
|
|
||||||
// page []string
|
|
||||||
// cursor uint64
|
|
||||||
//
|
|
||||||
// process func(cmd Cmder) error
|
|
||||||
// }
|
|
||||||
func (core *core.Core) GetRangeKeyList(pattern string, from time.Time) ([]*simple.Json, error) {
|
|
||||||
// 比如,用来计算ma30或ma7,倒推多少时间范围,
|
|
||||||
redisCli := core.RedisLocalCli
|
|
||||||
cursor := uint64(0)
|
|
||||||
n := 0
|
|
||||||
allTs := []int64{}
|
|
||||||
var keys []string
|
|
||||||
for {
|
|
||||||
var err error
|
|
||||||
keys, cursor, _ = redisCli.Scan(cursor, pattern+"*", 2000).Result()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
n += len(keys)
|
|
||||||
if n == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// keys, _ := redisCli.Keys(pattern + "*").Result()
|
|
||||||
for _, key := range keys {
|
|
||||||
keyAry := strings.Split(key, ":")
|
|
||||||
key = keyAry[1]
|
|
||||||
keyi64, _ := strconv.ParseInt(key, 10, 64)
|
|
||||||
allTs = append(allTs, keyi64)
|
|
||||||
}
|
|
||||||
nary := utils.RecursiveBubble(allTs, len(allTs))
|
|
||||||
tt := from.UnixMilli()
|
|
||||||
ff := tt - tt%60000
|
|
||||||
fi := int64(ff)
|
|
||||||
mary := []int64{}
|
|
||||||
for _, v := range nary {
|
|
||||||
if v < fi {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
mary = append(mary, v)
|
|
||||||
}
|
|
||||||
res := []*simple.Json{}
|
|
||||||
for _, v := range mary {
|
|
||||||
// if k > 1 {
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
nv := pattern + strconv.FormatInt(v, 10)
|
|
||||||
str, err := redisCli.Get(nv).Result()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("err of redis get key:", nv, err)
|
|
||||||
}
|
|
||||||
cur, err := simple.NewJson([]byte(str))
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("err of create newJson:", str, err)
|
|
||||||
}
|
|
||||||
res = append(res, cur)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cl *Candle) SetToKey(core *core.Core) ([]interface{}, error) {
|
func (cl *Candle) SetToKey(core *core.Core) ([]interface{}, error) {
|
||||||
data := cl.Data
|
data := cl.Data
|
||||||
tsi, err := strconv.ParseInt(data[0].(string), 10, 64)
|
tsi, err := strconv.ParseInt(data[0].(string), 10, 64)
|
||||||
|
@ -2,6 +2,7 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
logrus "github.com/sirupsen/logrus"
|
logrus "github.com/sirupsen/logrus"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -207,3 +209,47 @@ func Md5V(str string) string {
|
|||||||
h.Write([]byte(str))
|
h.Write([]byte(str))
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
func ToString(val interface{}) string {
|
||||||
|
valstr := ""
|
||||||
|
if reflect.TypeOf(val).Name() == "string" {
|
||||||
|
valstr = val.(string)
|
||||||
|
} else if reflect.TypeOf(val).Name() == "float64" {
|
||||||
|
valstr = fmt.Sprintf("%f", val)
|
||||||
|
} else if reflect.TypeOf(val).Name() == "int64" {
|
||||||
|
valstr = strconv.FormatInt(val.(int64), 16)
|
||||||
|
} else if reflect.TypeOf(val).Name() == "int" {
|
||||||
|
valstr = fmt.Sprintf("%d", val)
|
||||||
|
}
|
||||||
|
return valstr
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToInt64(val interface{}) int64 {
|
||||||
|
vali := int64(0)
|
||||||
|
if reflect.TypeOf(val).Name() == "string" {
|
||||||
|
vali, _ = strconv.ParseInt(val.(string), 10, 64)
|
||||||
|
} else if reflect.TypeOf(val).Name() == "float64" {
|
||||||
|
vali = int64(val.(float64))
|
||||||
|
}
|
||||||
|
return vali
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToFloat64(val interface{}) float64 {
|
||||||
|
valf := float64(0)
|
||||||
|
if reflect.TypeOf(val).Name() == "string" {
|
||||||
|
valf, _ = strconv.ParseFloat(val.(string), 64)
|
||||||
|
} else if reflect.TypeOf(val).Name() == "float64" {
|
||||||
|
valf = val.(float64)
|
||||||
|
} else if reflect.TypeOf(val).Name() == "int64" {
|
||||||
|
valf = float64(val.(int64))
|
||||||
|
}
|
||||||
|
return valf
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashString(input string) string {
|
||||||
|
// 计算SHA-256哈希值
|
||||||
|
hash := sha256.Sum256([]byte(input))
|
||||||
|
// 转换为十六进制字符串
|
||||||
|
hashHex := hex.EncodeToString(hash[:])
|
||||||
|
// 返回前20位
|
||||||
|
return hashHex[:23]
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user