调整
This commit is contained in:
parent
7a6893be16
commit
47bd02f138
84
candle.go
84
candle.go
@ -15,6 +15,7 @@ import (
|
||||
simple "github.com/bitly/go-simplejson"
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/phyer/texus/utils"
|
||||
logrus "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Candle struct {
|
||||
@ -32,32 +33,28 @@ type Candle struct {
|
||||
VolCcy float64
|
||||
Confirm bool
|
||||
}
|
||||
|
||||
type MaX struct {
|
||||
InstID string `json:"instID"`
|
||||
Period string `json:"period"`
|
||||
KeyName string `json:"keyName"`
|
||||
Data []interface{} `json:"data"`
|
||||
Count int `json:"count,number"`
|
||||
Ts int64 `json:"ts,number"`
|
||||
AvgVal float64 `json:"avgVal,number"`
|
||||
From string `json:"from,string"`
|
||||
type Sample interface {
|
||||
SetToKey(cr *Core) ([]interface{}, error)
|
||||
}
|
||||
|
||||
type SampleList interface {
|
||||
// 从左边插入一个元素,把超过长度的元素顶出去
|
||||
RPush(sp Sample) (Sample, error)
|
||||
// 得到一个切片,end一般是0,代表末尾元素,start是负值,-3代表倒数第三个
|
||||
// start:-10, end: -3 代表从倒数第10个到倒数第三个之间的元素组成的切片。
|
||||
GetSectionOf(start int, end int) ([]*Sample, error)
|
||||
}
|
||||
type CandleList struct {
|
||||
Count int `json:"count,number"`
|
||||
LastUpdateTime int64 `json:"lastUpdateTime"`
|
||||
UpdateNickName string `json:"updateNickName"`
|
||||
List []*Candle `json:"list"`
|
||||
}
|
||||
|
||||
type MaXList struct {
|
||||
Count int `json:"count"`
|
||||
LastUpdateTime int64 `json:"lastUpdateTime"`
|
||||
UpdateNickName string `json:"updateNickName"`
|
||||
List []*MaX `json:"list"`
|
||||
type CandleSegment struct {
|
||||
StartTime string `json:"startTime"`
|
||||
Enabled bool `json:"enabled,bool"`
|
||||
Seg string `json:"seg"`
|
||||
}
|
||||
|
||||
type MatchCheck struct {
|
||||
Minutes int64
|
||||
Matched bool
|
||||
@ -136,7 +133,7 @@ func (core *Core) GetCandlesWithRest(instId string, kidx int, dura time.Duration
|
||||
WithWs: true,
|
||||
}
|
||||
js, _ := json.Marshal(restQ)
|
||||
core.RedisCli.LPush("restQueue", js)
|
||||
core.RedisLocalCli.LPush("restQueue", js)
|
||||
}(i)
|
||||
i++
|
||||
}
|
||||
@ -291,32 +288,12 @@ func (cl *Candle) ToStruct(core *Core) (*Candle, error) {
|
||||
return &ncd, nil
|
||||
}
|
||||
|
||||
func (mx *MaX) SetToKey() ([]interface{}, error) {
|
||||
cstr := strconv.Itoa(mx.Count)
|
||||
tss := strconv.FormatInt(mx.Ts, 10)
|
||||
keyName := "ma" + cstr + "|candle" + mx.Period + "|" + mx.InstId + "|ts:" + tss
|
||||
//过期时间:根号(当前candle的周期/1分钟)*10000
|
||||
dt := []interface{}{}
|
||||
dt = append(dt, mx.Ts)
|
||||
dt = append(dt, mx.Value)
|
||||
dj, _ := json.Marshal(dt)
|
||||
exp := mx.Core.PeriodToMinutes(mx.Period)
|
||||
expf := utils.Sqrt(float64(exp)) * 100
|
||||
extt := time.Duration(expf) * time.Minute
|
||||
// loc, _ := time.LoadLocation("Asia/Shanghai")
|
||||
// tm := time.UnixMilli(mx.Ts).In(loc).Format("2006-01-02 15:04")
|
||||
// fmt.Println("setToKey:", keyName, "ts:", tm, string(dj), "from: ", mx.From)
|
||||
_, err := mx.Core.RedisCli.GetSet(keyName, dj).Result()
|
||||
mx.Core.RedisCli.Expire(keyName, extt)
|
||||
return dt, err
|
||||
}
|
||||
|
||||
// 保证同一个 period, keyName ,在一个周期里,SaveToSortSet只会被执行一次
|
||||
func (core *Core) SaveUniKey(period string, keyName string, extt time.Duration, tsi int64, cl *Candle) {
|
||||
func (core *Core) SaveUniKey(period string, keyName string, extt time.Duration, tsi int64) {
|
||||
|
||||
refName := keyName + "|refer"
|
||||
refRes, _ := core.RedisCli.GetSet(refName, 1).Result()
|
||||
core.RedisCli.Expire(refName, extt)
|
||||
refRes, _ := core.RedisLocalCli.GetSet(refName, 1).Result()
|
||||
core.RedisLocalCli.Expire(refName, extt)
|
||||
// 为保证唯一性机制,防止SaveToSortSet 被重复执行
|
||||
if len(refRes) != 0 {
|
||||
fmt.Println("refName exist: ", refName)
|
||||
@ -334,7 +311,7 @@ func (core *Core) SaveToSortSet(period string, keyName string, extt time.Duratio
|
||||
Score: float64(tsi),
|
||||
Member: keyName,
|
||||
}
|
||||
rs, err := core.RedisCli.ZAdd(setName, z).Result()
|
||||
rs, err := core.RedisLocalCli.ZAdd(setName, z).Result()
|
||||
if err != nil {
|
||||
fmt.Println("err of ma7|ma30 add to redis:", err)
|
||||
} else {
|
||||
@ -342,10 +319,15 @@ func (core *Core) SaveToSortSet(period string, keyName string, extt time.Duratio
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *Core) PeriodToMinutes(period string) int64 {
|
||||
// 根据周期的文本内容,返回这代表多少个分钟
|
||||
func (cr *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]
|
||||
@ -388,10 +370,11 @@ func (cr *Core) PeriodToMinutes(period string) int64 {
|
||||
}
|
||||
default:
|
||||
{
|
||||
fmt.Println("notmatch:", danwei)
|
||||
logrus.Warning("notmatch:", danwei, period)
|
||||
panic("notmatch:" + period)
|
||||
}
|
||||
}
|
||||
return int64(cheng)
|
||||
return int64(cheng), nil
|
||||
}
|
||||
|
||||
// type ScanCmd struct {
|
||||
@ -404,7 +387,7 @@ func (cr *Core) PeriodToMinutes(period string) int64 {
|
||||
// }
|
||||
func (core *Core) GetRangeKeyList(pattern string, from time.Time) ([]*simple.Json, error) {
|
||||
// 比如,用来计算ma30或ma7,倒推多少时间范围,
|
||||
redisCli := core.RedisCli
|
||||
redisCli := core.RedisLocalCli
|
||||
cursor := uint64(0)
|
||||
n := 0
|
||||
allTs := []int64{}
|
||||
@ -467,7 +450,10 @@ func (cl *Candle) SetToKey(core *Core) ([]interface{}, error) {
|
||||
//过期时间:根号(当前candle的周期/1分钟)*10000
|
||||
|
||||
dt, err := json.Marshal(cl.Data)
|
||||
exp := core.PeriodToMinutes(cl.Period)
|
||||
exp, err := core.PeriodToMinutes(cl.Period)
|
||||
if err != nil {
|
||||
fmt.Println("err of PeriodToMinutes:", err)
|
||||
}
|
||||
// expf := float64(exp) * 60
|
||||
expf := utils.Sqrt(float64(exp)) * 100
|
||||
extt := time.Duration(expf) * time.Minute
|
||||
@ -484,10 +470,10 @@ func (cl *Candle) SetToKey(core *Core) ([]interface{}, error) {
|
||||
err = errors.New("price有问题")
|
||||
return cl.Data, err
|
||||
}
|
||||
redisCli := core.RedisCli
|
||||
redisCli := core.RedisLocalCli
|
||||
// tm := time.UnixMilli(tsi).Format("2006-01-02 15:04")
|
||||
fmt.Println("setToKey:", keyName, "ts: ", "price: ", curPrice, "from:", cl.From)
|
||||
redisCli.Set(keyName, dt, extt).Result()
|
||||
core.SaveUniKey(cl.Period, keyName, extt, tsi, cl)
|
||||
core.SaveUniKey(cl.Period, keyName, extt, tsi)
|
||||
return cl.Data, err
|
||||
}
|
||||
|
38
config.go
38
config.go
@ -11,42 +11,42 @@ import (
|
||||
)
|
||||
|
||||
type MyConfig struct {
|
||||
Env string `json:"env", string`
|
||||
Env string `json:"env"`
|
||||
Config *simple.Json
|
||||
CandleDimentions []string `json:"candleDimentions"`
|
||||
RedisConf *RedisConfig `json:"redis"`
|
||||
CredentialReadOnlyConf *CredentialConfig `json:"credential"`
|
||||
CredentialMutableConf *CredentialConfig `json:"credential"`
|
||||
CredentialMutableConf *CredentialConfig `json:"credentialMutable"`
|
||||
ConnectConf *ConnectConfig `json:"connect"`
|
||||
// ThreadsConf *ThreadsConfig `json:"threads"`
|
||||
}
|
||||
|
||||
type RedisConfig struct {
|
||||
Url string `json:"url", string`
|
||||
Password string `json:"password", string`
|
||||
Index int `json:"index", string`
|
||||
Url string `json:"url"`
|
||||
Password string `json:"password"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
type CredentialConfig struct {
|
||||
SecretKey string `json:"secretKey", string`
|
||||
BaseUrl string `json:"baseUrl", string`
|
||||
OkAccessKey string `json:"okAccessKey", string`
|
||||
OkAccessPassphrase string `json:"okAccessPassphrase", string`
|
||||
SecretKey string `json:"secretKey"`
|
||||
BaseUrl string `json:"baseUrl"`
|
||||
OkAccessKey string `json:"okAccessKey"`
|
||||
OkAccessPassphrase string `json:"okAccessPassphrase"`
|
||||
}
|
||||
|
||||
type ConnectConfig struct {
|
||||
LoginSubUrl string `json:"loginSubUrl", string`
|
||||
WsPrivateBaseUrl string `json:"wsPrivateBaseUrl", string`
|
||||
WsPublicBaseUrl string `json:"wsPublicBaseUrl", string`
|
||||
RestBaseUrl string `json:"restBaseUrl", string`
|
||||
LoginSubUrl string `json:"loginSubUrl"`
|
||||
WsPrivateBaseUrl string `json:"wsPrivateBaseUrl"`
|
||||
WsPublicBaseUrl string `json:"wsPublicBaseUrl"`
|
||||
RestBaseUrl string `json:"restBaseUrl"`
|
||||
}
|
||||
type ThreadsConfig struct {
|
||||
MaxLenTickerStream int `json:"maxLenTickerStream", int`
|
||||
MaxCandles int `json:"maxCandles", string`
|
||||
AsyncChannels int `json:"asyncChannels", int`
|
||||
MaxTickers int `json:"maxTickers", int`
|
||||
RestPeriod int `json:"restPeriod", int`
|
||||
WaitWs int `json:"waitWs", int`
|
||||
MaxLenTickerStream int `json:"maxLenTickerStream"`
|
||||
MaxCandles int `json:"maxCandles"`
|
||||
AsyncChannels int `json:"asyncChannels"`
|
||||
MaxTickers int `json:"maxTickers"`
|
||||
RestPeriod int `json:"restPeriod"`
|
||||
WaitWs int `json:"waitWs"`
|
||||
}
|
||||
|
||||
func (cfg MyConfig) Init() (MyConfig, error) {
|
||||
|
773
core.go
773
core.go
@ -1,9 +1,9 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
// "context"
|
||||
"encoding/json"
|
||||
// "errors"
|
||||
"errors"
|
||||
"fmt"
|
||||
// "math/rand"
|
||||
"io/ioutil"
|
||||
@ -14,18 +14,18 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
simple "github.com/bitly/go-simplejson"
|
||||
// simple "github.com/bitly/go-simplejson"
|
||||
// "v5sdk_go/ws/wImpl"
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/phyer/texus/private"
|
||||
"github.com/phyer/texus/utils"
|
||||
// "github.com/phyer/texus/utils"
|
||||
logrus "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Core struct {
|
||||
Env string
|
||||
Cfg *MyConfig
|
||||
RedisLocalCli *redis.Client
|
||||
RedisLocal2Cli *redis.Client
|
||||
RedisRemoteCli *redis.Client
|
||||
FluentBitUrl string
|
||||
// PlateMap map[string]*Plate
|
||||
@ -43,6 +43,8 @@ type Core struct {
|
||||
MakeMaXsChan chan *Candle
|
||||
// ShearForceGrpChan chan *ShearForceGrp
|
||||
InvokeRestQueueChan chan *RestQueue
|
||||
RedisLocal2Cli *redis.Client
|
||||
RestQueueChan chan *RestQueue
|
||||
RestQueue
|
||||
WriteLogChan chan *WriteLog
|
||||
}
|
||||
@ -56,6 +58,7 @@ type RestQueue struct {
|
||||
Duration time.Duration
|
||||
WithWs bool
|
||||
}
|
||||
|
||||
type CandleData struct {
|
||||
Code string `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
@ -107,10 +110,10 @@ func WriteLogProcess(cr *Core) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *Core) ShowSysTime() {
|
||||
rsp, _ := cr.RestInvoke("/api/v5/public/time", rest.GET)
|
||||
fmt.Println("serverSystem time:", rsp)
|
||||
}
|
||||
// func (cr *Core) ShowSysTime() {
|
||||
// rsp, _ := cr.RestInvoke("/api/v5/public/time", rest.GET)
|
||||
// fmt.Println("serverSystem time:", rsp)
|
||||
// }
|
||||
|
||||
func (core *Core) Init() {
|
||||
core.Env = os.Getenv("GO_ENV")
|
||||
@ -123,16 +126,17 @@ func (core *Core) Init() {
|
||||
cfg := MyConfig{}
|
||||
cfg, _ = cfg.Init()
|
||||
core.Cfg = &cfg
|
||||
cli, err := core.GetRedisCli()
|
||||
core.RedisCli = cli
|
||||
cli, err := core.GetRedisLocalCli()
|
||||
core.RedisLocalCli = cli
|
||||
core.RestQueueChan = make(chan *RestQueue)
|
||||
core.WriteLogChan = make(chan *WriteLog)
|
||||
core.OrderChan = make(chan *private.Order)
|
||||
// 跟订单有关的都关掉
|
||||
// core.OrderChan = make(chan *private.Order)
|
||||
if err != nil {
|
||||
fmt.Println("init redis client err: ", err)
|
||||
}
|
||||
}
|
||||
func (core *Core) GetRemoteRedisCli() (*redis.Client, error) {
|
||||
func (core *Core) GetRemoteRedisLocalCli() (*redis.Client, error) {
|
||||
ru := core.Cfg.RedisConf.Url
|
||||
rp := core.Cfg.RedisConf.Password
|
||||
ri := core.Cfg.RedisConf.Index
|
||||
@ -154,7 +158,7 @@ func (core *Core) GetRemoteRedisCli() (*redis.Client, error) {
|
||||
|
||||
return client, nil
|
||||
}
|
||||
func (core *Core) GetRedisCli() (*redis.Client, error) {
|
||||
func (core *Core) GetRedisLocalCli() (*redis.Client, error) {
|
||||
ru := core.Cfg.RedisConf.Url
|
||||
rp := core.Cfg.RedisConf.Password
|
||||
ri := core.Cfg.RedisConf.Index
|
||||
@ -177,80 +181,85 @@ func (core *Core) GetRedisCli() (*redis.Client, error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
||||
// GET / 获取所有产品行情信息
|
||||
rsp, err := core.RestInvoke("/api/v5/market/tickers?instType=SPOT", rest.GET)
|
||||
return rsp, err
|
||||
}
|
||||
// 这些应该是放到 texus 里实现的
|
||||
// func (core *Core) GetAllTickerInfo() (*rest.RESTAPIResult, error) {
|
||||
// // GET / 获取所有产品行情信息
|
||||
// rsp, err := core.RestInvoke("/api/v5/market/tickers?instType=SPOT", rest.GET)
|
||||
// return rsp, err
|
||||
// }
|
||||
|
||||
func (core *Core) GetBalances() (*rest.RESTAPIResult, error) {
|
||||
// TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
||||
rsp, err := core.RestInvoke2("/api/v5/account/balance", rest.GET, nil)
|
||||
return rsp, err
|
||||
}
|
||||
func (core *Core) GetLivingOrderList() ([]*private.Order, error) {
|
||||
// TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
||||
params := make(map[string]interface{})
|
||||
data, err := core.RestInvoke2("/api/v5/trade/orders-pending", rest.GET, ¶ms)
|
||||
odrsp := private.OrderResp{}
|
||||
err = json.Unmarshal([]byte(data.Body), &odrsp)
|
||||
str, _ := json.Marshal(odrsp)
|
||||
fmt.Println("convert: err:", err, " body: ", data.Body, odrsp, " string:", string(str))
|
||||
list, err := odrsp.Convert()
|
||||
fmt.Println("loopLivingOrder response data:", str)
|
||||
fmt.Println(utils.GetFuncName(), " 当前数据是 ", data.V5Response.Code, " list len:", len(list))
|
||||
return list, err
|
||||
}
|
||||
func (core *Core) LoopInstrumentList() error {
|
||||
for {
|
||||
time.Sleep(3 * time.Second)
|
||||
ctype := ws.SPOT
|
||||
|
||||
redisCli := core.RedisCli
|
||||
counts, err := redisCli.HLen("instruments|" + ctype + "|hash").Result()
|
||||
if err != nil {
|
||||
fmt.Println("err of hset to redis:", err)
|
||||
}
|
||||
if counts == 0 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (core *Core) SubscribeTicker(op string) error {
|
||||
mp := make(map[string]string)
|
||||
|
||||
redisCli := core.RedisCli
|
||||
ctype := ws.SPOT
|
||||
mp, err := redisCli.HGetAll("instruments|" + ctype + "|hash").Result()
|
||||
b, err := json.Marshal(mp)
|
||||
js, err := simple.NewJson(b)
|
||||
if err != nil {
|
||||
fmt.Println("err of unMarshalJson3:", js)
|
||||
}
|
||||
// fmt.Println("ticker js: ", js)
|
||||
instAry := js.MustMap()
|
||||
for k, v := range instAry {
|
||||
b = []byte(v.(string))
|
||||
_, err := simple.NewJson(b)
|
||||
if err != nil {
|
||||
fmt.Println("err of unMarshalJson4:", js)
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
go func(instId string, op string) {
|
||||
|
||||
redisCli := core.RedisCli
|
||||
_, err = redisCli.SAdd("tickers|"+op+"|set", instId).Result()
|
||||
if err != nil {
|
||||
fmt.Println("err of unMarshalJson5:", js)
|
||||
}
|
||||
}(k, op)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// 这些跟 订单有关,都关掉
|
||||
//
|
||||
// func (core *Core) GetBalances() (*rest.RESTAPIResult, error) {
|
||||
// // TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
||||
// rsp, err := core.RestInvoke2("/api/v5/account/balance", rest.GET, nil)
|
||||
// return rsp, err
|
||||
// }
|
||||
//
|
||||
// func (core *Core) GetLivingOrderList() ([]*private.Order, error) {
|
||||
// // TODO 临时用了两个实现,restInvoke,复用原来的会有bug,不知道是谁的bug
|
||||
// params := make(map[string]interface{})
|
||||
// data, err := core.RestInvoke2("/api/v5/trade/orders-pending", rest.GET, ¶ms)
|
||||
// odrsp := private.OrderResp{}
|
||||
// err = json.Unmarshal([]byte(data.Body), &odrsp)
|
||||
// str, _ := json.Marshal(odrsp)
|
||||
// fmt.Println("convert: err:", err, " body: ", data.Body, odrsp, " string:", string(str))
|
||||
// list, err := odrsp.Convert()
|
||||
// fmt.Println("loopLivingOrder response data:", str)
|
||||
// fmt.Println(utils.GetFuncName(), " 当前数据是 ", data.V5Response.Code, " list len:", len(list))
|
||||
// return list, err
|
||||
// }
|
||||
// func (core *Core) LoopInstrumentList() error {
|
||||
// for {
|
||||
// time.Sleep(3 * time.Second)
|
||||
// ctype := ws.SPOT
|
||||
//
|
||||
// redisCli := core.RedisLocalCli
|
||||
// counts, err := redisCli.HLen("instruments|" + ctype + "|hash").Result()
|
||||
// if err != nil {
|
||||
// fmt.Println("err of hset to redis:", err)
|
||||
// }
|
||||
// if counts == 0 {
|
||||
// continue
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
// func (core *Core) SubscribeTicker(op string) error {
|
||||
// mp := make(map[string]string)
|
||||
//
|
||||
// redisCli := core.RedisLocalCli
|
||||
// ctype := ws.SPOT
|
||||
// mp, err := redisCli.HGetAll("instruments|" + ctype + "|hash").Result()
|
||||
// b, err := json.Marshal(mp)
|
||||
// js, err := simple.NewJson(b)
|
||||
// if err != nil {
|
||||
// fmt.Println("err of unMarshalJson3:", js)
|
||||
// }
|
||||
// // fmt.Println("ticker js: ", js)
|
||||
// instAry := js.MustMap()
|
||||
// for k, v := range instAry {
|
||||
// b = []byte(v.(string))
|
||||
// _, err := simple.NewJson(b)
|
||||
// if err != nil {
|
||||
// fmt.Println("err of unMarshalJson4:", js)
|
||||
// }
|
||||
// time.Sleep(5 * time.Second)
|
||||
// go func(instId string, op string) {
|
||||
//
|
||||
// redisCli := core.RedisLocalCli
|
||||
// _, err = redisCli.SAdd("tickers|"+op+"|set", instId).Result()
|
||||
// if err != nil {
|
||||
// fmt.Println("err of unMarshalJson5:", js)
|
||||
// }
|
||||
// }(k, op)
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// 通过接口获取一个币种名下的某个时间范围内的Candle对象集合
|
||||
// 按说这个应该放到 texus里实现
|
||||
func (core *Core) v5PublicInvoke(subUrl string) (*CandleData, error) {
|
||||
restUrl, _ := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
url := restUrl + subUrl
|
||||
@ -267,96 +276,98 @@ func (core *Core) v5PublicInvoke(subUrl string) (*CandleData, error) {
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult, error) {
|
||||
restUrl, _ := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
//ep, method, uri string, param *map[string]interface{}
|
||||
rest := rest.NewRESTAPI(restUrl, method, subUrl, nil)
|
||||
key, _ := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessKey").String()
|
||||
secure, _ := core.Cfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
||||
pass, _ := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
||||
isDemo := false
|
||||
if core.Env == "demoEnv" {
|
||||
isDemo = true
|
||||
}
|
||||
rest.SetSimulate(isDemo).SetAPIKey(key, secure, pass)
|
||||
response, err := rest.Run(context.Background())
|
||||
if err != nil {
|
||||
fmt.Println("restInvoke1 err:", subUrl, err)
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
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()
|
||||
secret, err2 := core.Cfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
||||
pass, err3 := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
||||
userId, err4 := core.Cfg.Config.Get("connect").Get("userId").String()
|
||||
restUrl, err5 := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
||||
fmt.Println(err1, err2, err3, err4, err5)
|
||||
} else {
|
||||
fmt.Println("key:", key, secret, pass, "userId:", userId, "restUrl: ", restUrl)
|
||||
}
|
||||
// reqParam := make(map[string]interface{})
|
||||
// if param != nil {
|
||||
// reqParam = *param
|
||||
// }
|
||||
// rs := rest.NewRESTAPI(restUrl, method, subUrl, &reqParam)
|
||||
isDemo := false
|
||||
if core.Env == "demoEnv" {
|
||||
isDemo = true
|
||||
}
|
||||
// rs.SetSimulate(isDemo).SetAPIKey(key, secret, pass).SetUserId(userId)
|
||||
// response, err := rs.Run(context.Background())
|
||||
// if err != nil {
|
||||
// fmt.Println("restInvoke2 err:", subUrl, err)
|
||||
// }
|
||||
apikey := rest.APIKeyInfo{
|
||||
ApiKey: key,
|
||||
SecKey: secret,
|
||||
PassPhrase: pass,
|
||||
}
|
||||
cli := rest.NewRESTClient(restUrl, &apikey, isDemo)
|
||||
rsp, err := cli.Get(context.Background(), subUrl, param)
|
||||
if err != nil {
|
||||
return rsp, err
|
||||
}
|
||||
fmt.Println("response:", rsp, err)
|
||||
return rsp, err
|
||||
}
|
||||
// func (core *Core) RestInvoke(subUrl string, method string) (*rest.RESTAPIResult, error) {
|
||||
// restUrl, _ := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
// //ep, method, uri string, param *map[string]interface{}
|
||||
// rest := rest.NewRESTAPI(restUrl, method, subUrl, nil)
|
||||
// key, _ := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessKey").String()
|
||||
// secure, _ := core.Cfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
||||
// pass, _ := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
||||
// isDemo := false
|
||||
// if core.Env == "demoEnv" {
|
||||
// isDemo = true
|
||||
// }
|
||||
// rest.SetSimulate(isDemo).SetAPIKey(key, secure, pass)
|
||||
// response, err := rest.Run(context.Background())
|
||||
// if err != nil {
|
||||
// fmt.Println("restInvoke1 err:", subUrl, err)
|
||||
// }
|
||||
// return response, err
|
||||
// }
|
||||
|
||||
func (core *Core) RestPost(subUrl string, param *map[string]interface{}) (*rest.RESTAPIResult, error) {
|
||||
key, err1 := core.Cfg.Config.Get("credentialMutable").Get("okAccessKey").String()
|
||||
secret, err2 := core.Cfg.Config.Get("credentialMutable").Get("secretKey").String()
|
||||
pass, err3 := core.Cfg.Config.Get("credentialMutable").Get("okAccessPassphrase").String()
|
||||
userId, err4 := core.Cfg.Config.Get("connect").Get("userId").String()
|
||||
restUrl, err5 := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
||||
fmt.Println(err1, err2, err3, err4, err5)
|
||||
} else {
|
||||
fmt.Println("key:", key, secret, pass, "userId:", userId, "restUrl: ", restUrl)
|
||||
}
|
||||
// 请求的另一种方式
|
||||
apikey := rest.APIKeyInfo{
|
||||
ApiKey: key,
|
||||
SecKey: secret,
|
||||
PassPhrase: pass,
|
||||
}
|
||||
isDemo := false
|
||||
if core.Env == "demoEnv" {
|
||||
isDemo = true
|
||||
}
|
||||
cli := rest.NewRESTClient(restUrl, &apikey, isDemo)
|
||||
rsp, err := cli.Post(context.Background(), subUrl, param)
|
||||
if err != nil {
|
||||
return rsp, err
|
||||
}
|
||||
return rsp, err
|
||||
}
|
||||
// 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()
|
||||
// secret, err2 := core.Cfg.Config.Get("credentialReadOnly").Get("secretKey").String()
|
||||
// pass, err3 := core.Cfg.Config.Get("credentialReadOnly").Get("okAccessPassphrase").String()
|
||||
// userId, err4 := core.Cfg.Config.Get("connect").Get("userId").String()
|
||||
// restUrl, err5 := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
// if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
||||
// fmt.Println(err1, err2, err3, err4, err5)
|
||||
// } else {
|
||||
// fmt.Println("key:", key, secret, pass, "userId:", userId, "restUrl: ", restUrl)
|
||||
// }
|
||||
// // reqParam := make(map[string]interface{})
|
||||
// // if param != nil {
|
||||
// // reqParam = *param
|
||||
// // }
|
||||
// // rs := rest.NewRESTAPI(restUrl, method, subUrl, &reqParam)
|
||||
// isDemo := false
|
||||
// if core.Env == "demoEnv" {
|
||||
// isDemo = true
|
||||
// }
|
||||
// // rs.SetSimulate(isDemo).SetAPIKey(key, secret, pass).SetUserId(userId)
|
||||
// // response, err := rs.Run(context.Background())
|
||||
// // if err != nil {
|
||||
// // fmt.Println("restInvoke2 err:", subUrl, err)
|
||||
// // }
|
||||
// apikey := rest.APIKeyInfo{
|
||||
// ApiKey: key,
|
||||
// SecKey: secret,
|
||||
// PassPhrase: pass,
|
||||
// }
|
||||
// cli := rest.NewRESTClient(restUrl, &apikey, isDemo)
|
||||
// rsp, err := cli.Get(context.Background(), subUrl, param)
|
||||
// if err != nil {
|
||||
// return rsp, err
|
||||
// }
|
||||
// fmt.Println("response:", rsp, err)
|
||||
// return rsp, err
|
||||
// }
|
||||
|
||||
// 跟下单有关的都关掉,以后再说
|
||||
// func (core *Core) RestPost(subUrl string, param *map[string]interface{}) (*rest.RESTAPIResult, error) {
|
||||
// key, err1 := core.Cfg.Config.Get("credentialMutable").Get("okAccessKey").String()
|
||||
// secret, err2 := core.Cfg.Config.Get("credentialMutable").Get("secretKey").String()
|
||||
// pass, err3 := core.Cfg.Config.Get("credentialMutable").Get("okAccessPassphrase").String()
|
||||
// userId, err4 := core.Cfg.Config.Get("connect").Get("userId").String()
|
||||
// restUrl, err5 := core.Cfg.Config.Get("connect").Get("restBaseUrl").String()
|
||||
// if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil {
|
||||
// fmt.Println(err1, err2, err3, err4, err5)
|
||||
// } else {
|
||||
// fmt.Println("key:", key, secret, pass, "userId:", userId, "restUrl: ", restUrl)
|
||||
// }
|
||||
// // 请求的另一种方式
|
||||
// apikey := rest.APIKeyInfo{
|
||||
// ApiKey: key,
|
||||
// SecKey: secret,
|
||||
// PassPhrase: pass,
|
||||
// }
|
||||
// isDemo := false
|
||||
// if core.Env == "demoEnv" {
|
||||
// isDemo = true
|
||||
// }
|
||||
// cli := rest.NewRESTClient(restUrl, &apikey, isDemo)
|
||||
// rsp, err := cli.Post(context.Background(), subUrl, param)
|
||||
// if err != nil {
|
||||
// return rsp, err
|
||||
// }
|
||||
// return rsp, err
|
||||
// }
|
||||
|
||||
// 我当前持有的币,每分钟刷新
|
||||
func (core *Core) GetMyFavorList() []string {
|
||||
redisCli := core.RedisCli
|
||||
redisCli := core.RedisLocalCli
|
||||
opt := redis.ZRangeBy{
|
||||
Min: "10",
|
||||
Max: "100000000000",
|
||||
@ -374,7 +385,7 @@ func (core *Core) GetMyFavorList() []string {
|
||||
// 改了,不需要交易排行榜,我手动指定一个排行即可, tickersVol|sortedSet 改成 tickersList|sortedSet
|
||||
func (core *Core) GetScoreList(count int) []string {
|
||||
|
||||
redisCli := core.RedisCli
|
||||
redisCli := core.RedisLocalCli
|
||||
|
||||
curList, err := redisCli.ZRange("tickersList|sortedSet", 0, int64(count-1)).Result()
|
||||
if err != nil {
|
||||
@ -384,113 +395,116 @@ func (core *Core) GetScoreList(count int) []string {
|
||||
return curList
|
||||
}
|
||||
|
||||
func LoopBalances(cr *Core, mdura time.Duration) {
|
||||
//协程:动态维护topScore
|
||||
ticker := time.NewTicker(mdura)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
//协程:循环执行rest请求candle
|
||||
fmt.Println("loopBalance: receive ccyChannel start")
|
||||
RestBalances(cr)
|
||||
}
|
||||
}
|
||||
}
|
||||
func LoopLivingOrders(cr *Core, mdura time.Duration) {
|
||||
//协程:动态维护topScore
|
||||
ticker := time.NewTicker(mdura)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
//协程:循环执行rest请求candle
|
||||
fmt.Println("loopLivingOrder: receive ccyChannel start")
|
||||
RestLivingOrder(cr)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 跟订单有关,关掉
|
||||
// func LoopBalances(cr *Core, mdura time.Duration) {
|
||||
// //协程:动态维护topScore
|
||||
// ticker := time.NewTicker(mdura)
|
||||
// for {
|
||||
// select {
|
||||
// case <-ticker.C:
|
||||
// //协程:循环执行rest请求candle
|
||||
// fmt.Println("loopBalance: receive ccyChannel start")
|
||||
// RestBalances(cr)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func RestBalances(cr *Core) ([]*private.Ccy, error) {
|
||||
// fmt.Println("restBalance loopBalance loop start")
|
||||
ccyList := []*private.Ccy{}
|
||||
rsp, err := cr.GetBalances()
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err00: ", err)
|
||||
}
|
||||
fmt.Println("loopBalance balance rsp: ", rsp)
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err01: ", err)
|
||||
return ccyList, err
|
||||
}
|
||||
if len(rsp.Body) == 0 {
|
||||
fmt.Println("loopBalance err03: rsp body is null")
|
||||
return ccyList, err
|
||||
}
|
||||
js1, err := simple.NewJson([]byte(rsp.Body))
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err1: ", err)
|
||||
}
|
||||
itemList := js1.Get("data").GetIndex(0).Get("details").MustArray()
|
||||
// maxTickers是重点关注的topScore的coins的数量
|
||||
cli := cr.RedisCli
|
||||
for _, v := range itemList {
|
||||
js, _ := json.Marshal(v)
|
||||
ccyResp := private.CcyResp{}
|
||||
err := json.Unmarshal(js, &ccyResp)
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err2: ", err)
|
||||
}
|
||||
ccy, err := ccyResp.Convert()
|
||||
ccyList = append(ccyList, ccy)
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err2: ", err)
|
||||
}
|
||||
z := redis.Z{
|
||||
Score: ccy.EqUsd,
|
||||
Member: ccy.Ccy + "|position|key",
|
||||
}
|
||||
res, err := cli.ZAdd("private|positions|sortedSet", z).Result()
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err3: ", res, err)
|
||||
}
|
||||
res1, err := cli.Set(ccy.Ccy+"|position|key", js, 0).Result()
|
||||
if err != nil {
|
||||
fmt.Println("loopBalance err4: ", res1, err)
|
||||
}
|
||||
bjs, _ := json.Marshal(ccy)
|
||||
tsi := time.Now().Unix()
|
||||
tsii := tsi - tsi%600
|
||||
tss := strconv.FormatInt(tsii, 10)
|
||||
cli.Set(CCYPOSISTIONS_PUBLISH+"|ts:"+tss, 1, 10*time.Minute).Result()
|
||||
fmt.Println("ccy published: ", string(bjs))
|
||||
//TODO FIXME 50毫秒,每分钟上限是1200个订单,超过就无法遍历完成
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
suffix := ""
|
||||
if cr.Env == "demoEnv" {
|
||||
suffix = "-demoEnv"
|
||||
}
|
||||
// TODO FIXME cli2
|
||||
cli.Publish(CCYPOSISTIONS_PUBLISH+suffix, string(bjs)).Result()
|
||||
}
|
||||
return ccyList, nil
|
||||
}
|
||||
// func LoopLivingOrders(cr *Core, mdura time.Duration) {
|
||||
// //协程:动态维护topScore
|
||||
// ticker := time.NewTicker(mdura)
|
||||
// for {
|
||||
// select {
|
||||
// case <-ticker.C:
|
||||
// //协程:循环执行rest请求candle
|
||||
// fmt.Println("loopLivingOrder: receive ccyChannel start")
|
||||
// RestLivingOrder(cr)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func RestLivingOrder(cr *Core) ([]*private.Order, error) {
|
||||
// fmt.Println("restOrder loopOrder loop start")
|
||||
orderList := []*private.Order{}
|
||||
list, err := cr.GetLivingOrderList()
|
||||
if err != nil {
|
||||
fmt.Println("loopLivingOrder err00: ", err)
|
||||
}
|
||||
fmt.Println("loopLivingOrder response:", list)
|
||||
go func() {
|
||||
for _, v := range list {
|
||||
fmt.Println("order orderV:", v)
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
cr.OrderChan <- v
|
||||
}
|
||||
}()
|
||||
return orderList, nil
|
||||
}
|
||||
// 跟订单有关,关掉
|
||||
// func RestBalances(cr *Core) ([]*private.Ccy, error) {
|
||||
// // fmt.Println("restBalance loopBalance loop start")
|
||||
// ccyList := []*private.Ccy{}
|
||||
// rsp, err := cr.GetBalances()
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err00: ", err)
|
||||
// }
|
||||
// fmt.Println("loopBalance balance rsp: ", rsp)
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err01: ", err)
|
||||
// return ccyList, err
|
||||
// }
|
||||
// if len(rsp.Body) == 0 {
|
||||
// fmt.Println("loopBalance err03: rsp body is null")
|
||||
// return ccyList, err
|
||||
// }
|
||||
// js1, err := simple.NewJson([]byte(rsp.Body))
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err1: ", err)
|
||||
// }
|
||||
// itemList := js1.Get("data").GetIndex(0).Get("details").MustArray()
|
||||
// // maxTickers是重点关注的topScore的coins的数量
|
||||
// cli := cr.RedisLocalCli
|
||||
// for _, v := range itemList {
|
||||
// js, _ := json.Marshal(v)
|
||||
// ccyResp := private.CcyResp{}
|
||||
// err := json.Unmarshal(js, &ccyResp)
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err2: ", err)
|
||||
// }
|
||||
// ccy, err := ccyResp.Convert()
|
||||
// ccyList = append(ccyList, ccy)
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err2: ", err)
|
||||
// }
|
||||
// z := redis.Z{
|
||||
// Score: ccy.EqUsd,
|
||||
// Member: ccy.Ccy + "|position|key",
|
||||
// }
|
||||
// res, err := cli.ZAdd("private|positions|sortedSet", z).Result()
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err3: ", res, err)
|
||||
// }
|
||||
// res1, err := cli.Set(ccy.Ccy+"|position|key", js, 0).Result()
|
||||
// if err != nil {
|
||||
// fmt.Println("loopBalance err4: ", res1, err)
|
||||
// }
|
||||
// bjs, _ := json.Marshal(ccy)
|
||||
// tsi := time.Now().Unix()
|
||||
// tsii := tsi - tsi%600
|
||||
// tss := strconv.FormatInt(tsii, 10)
|
||||
// cli.Set(CCYPOSISTIONS_PUBLISH+"|ts:"+tss, 1, 10*time.Minute).Result()
|
||||
// fmt.Println("ccy published: ", string(bjs))
|
||||
// //TODO FIXME 50毫秒,每分钟上限是1200个订单,超过就无法遍历完成
|
||||
// time.Sleep(50 * time.Millisecond)
|
||||
// suffix := ""
|
||||
// if cr.Env == "demoEnv" {
|
||||
// suffix = "-demoEnv"
|
||||
// }
|
||||
// // TODO FIXME cli2
|
||||
// cli.Publish(CCYPOSISTIONS_PUBLISH+suffix, string(bjs)).Result()
|
||||
// }
|
||||
// return ccyList, nil
|
||||
// }
|
||||
|
||||
// func RestLivingOrder(cr *Core) ([]*private.Order, error) {
|
||||
// // fmt.Println("restOrder loopOrder loop start")
|
||||
// orderList := []*private.Order{}
|
||||
// list, err := cr.GetLivingOrderList()
|
||||
// if err != nil {
|
||||
// fmt.Println("loopLivingOrder err00: ", err)
|
||||
// }
|
||||
// fmt.Println("loopLivingOrder response:", list)
|
||||
// go func() {
|
||||
// for _, v := range list {
|
||||
// fmt.Println("order orderV:", v)
|
||||
// time.Sleep(30 * time.Millisecond)
|
||||
// cr.OrderChan <- v
|
||||
// }
|
||||
// }()
|
||||
// return orderList, nil
|
||||
// }
|
||||
|
||||
func (cr *Core) ProcessOrder(od *private.Order) error {
|
||||
// publish
|
||||
@ -503,54 +517,55 @@ func (cr *Core) ProcessOrder(od *private.Order) error {
|
||||
bj, _ := json.Marshal(od)
|
||||
|
||||
// TODO FIXME cli2
|
||||
res, _ := cr.RedisCli.Publish(cn, string(bj)).Result()
|
||||
res, _ := cr.RedisLocalCli.Publish(cn, string(bj)).Result()
|
||||
fmt.Println("order publish res: ", res, " content: ", string(bj))
|
||||
rsch := ORDER_RESP_PUBLISH + suffix
|
||||
bj1, _ := json.Marshal(res)
|
||||
|
||||
// TODO FIXME cli2
|
||||
res, _ = cr.RedisCli.Publish(rsch, string(bj1)).Result()
|
||||
res, _ = cr.RedisLocalCli.Publish(rsch, string(bj1)).Result()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *Core) DispatchSubAction(action *SubAction) error {
|
||||
go func() {
|
||||
suffix := ""
|
||||
if cr.Env == "demoEnv" {
|
||||
suffix = "-demoEnv"
|
||||
}
|
||||
fmt.Println("action: ", action.ActionName, action.MetaInfo)
|
||||
res, err := cr.RestPostWrapper("/api/v5/trade/"+action.ActionName, action.MetaInfo)
|
||||
if err != nil {
|
||||
fmt.Println(utils.GetFuncName(), " actionRes 1:", err)
|
||||
}
|
||||
rsch := ORDER_RESP_PUBLISH + suffix
|
||||
bj1, _ := json.Marshal(res)
|
||||
// 跟订单有关,关掉
|
||||
// func (cr *Core) DispatchSubAction(action *SubAction) error {
|
||||
// go func() {
|
||||
// suffix := ""
|
||||
// if cr.Env == "demoEnv" {
|
||||
// suffix = "-demoEnv"
|
||||
// }
|
||||
// fmt.Println("action: ", action.ActionName, action.MetaInfo)
|
||||
// res, err := cr.RestPostWrapper("/api/v5/trade/"+action.ActionName, action.MetaInfo)
|
||||
// if err != nil {
|
||||
// fmt.Println(utils.GetFuncName(), " actionRes 1:", err)
|
||||
// }
|
||||
// rsch := ORDER_RESP_PUBLISH + suffix
|
||||
// bj1, _ := json.Marshal(res)
|
||||
//
|
||||
// // TODO FIXME cli2
|
||||
// rs, _ := cr.RedisLocalCli.Publish(rsch, string(bj1)).Result()
|
||||
// fmt.Println("action rs: ", rs)
|
||||
// }()
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// TODO FIXME cli2
|
||||
rs, _ := cr.RedisCli.Publish(rsch, string(bj1)).Result()
|
||||
fmt.Println("action rs: ", rs)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *Core) RestPostWrapper(url string, param map[string]interface{}) (rest.Okexv5APIResponse, error) {
|
||||
suffix := ""
|
||||
if cr.Env == "demoEnv" {
|
||||
suffix = "-demoEnv"
|
||||
}
|
||||
res, err := cr.RestPost(url, ¶m)
|
||||
fmt.Println("actionRes 2:", res.V5Response.Msg, res.V5Response.Data, err)
|
||||
bj, _ := json.Marshal(res)
|
||||
|
||||
// TODO FIXME cli2
|
||||
cr.RedisCli.Publish(ORDER_RESP_PUBLISH+suffix, string(bj))
|
||||
return res.V5Response, nil
|
||||
}
|
||||
// func (cr *Core) RestPostWrapper(url string, param map[string]interface{}) (rest.Okexv5APIResponse, error) {
|
||||
// suffix := ""
|
||||
// if cr.Env == "demoEnv" {
|
||||
// suffix = "-demoEnv"
|
||||
// }
|
||||
// res, err := cr.RestPost(url, ¶m)
|
||||
// fmt.Println("actionRes 2:", res.V5Response.Msg, res.V5Response.Data, err)
|
||||
// bj, _ := json.Marshal(res)
|
||||
//
|
||||
// // TODO FIXME cli2
|
||||
// cr.RedisLocalCli.Publish(ORDER_RESP_PUBLISH+suffix, string(bj))
|
||||
// return res.V5Response, nil
|
||||
// }
|
||||
|
||||
func (cr *Core) AddToGeneralCandleChnl(candle *Candle, channels []string) {
|
||||
redisCli := cr.RedisCli
|
||||
redisCli := cr.RedisLocalCli
|
||||
ab, _ := json.Marshal(candle)
|
||||
for _, v := range channels {
|
||||
suffix := ""
|
||||
@ -565,3 +580,137 @@ func (cr *Core) AddToGeneralCandleChnl(candle *Candle, channels []string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setName := "candle" + period + "|" + instId + "|sortedSet"
|
||||
// count: 倒推多少个周期开始拿数据
|
||||
// from: 倒推的起始时间点
|
||||
// ctype: candle或者maX
|
||||
func (core *Core) GetRangeMaXSortedSet(setName string, count int, from time.Time) (*MaXList, error) {
|
||||
mxl := MaXList{}
|
||||
ary1 := strings.Split(setName, "|")
|
||||
ary2 := []string{}
|
||||
period := ""
|
||||
ary2 = strings.Split(ary1[1], "candle")
|
||||
period = ary2[1]
|
||||
|
||||
dui, err := core.PeriodToMinutes(period)
|
||||
if err != nil {
|
||||
return &mxl, err
|
||||
}
|
||||
fromt := from.UnixMilli()
|
||||
froms := strconv.FormatInt(fromt, 10)
|
||||
sti := fromt - dui*int64(count)*60*1000
|
||||
sts := strconv.FormatInt(sti, 10)
|
||||
opt := redis.ZRangeBy{
|
||||
Min: sts,
|
||||
Max: froms,
|
||||
Count: int64(count),
|
||||
}
|
||||
ary := []string{}
|
||||
logrus.Debug("ZRevRangeByScore ", setName, froms, sts)
|
||||
dura, err := core.GetExpiration(period)
|
||||
if err != nil {
|
||||
return &mxl, err
|
||||
}
|
||||
// fmt.Println("GetExpiration dura: ", dura, " period: ", period)
|
||||
ot := time.Now().Add(dura * -1)
|
||||
oti := ot.UnixMilli()
|
||||
// fmt.Println(fmt.Sprint("GetExpiration zRemRangeByScore ", setName, " ", 0, " ", strconv.FormatInt(oti, 10)))
|
||||
cli := core.RedisLocalCli
|
||||
cli.LTrim(setName, 0, oti)
|
||||
cunt, _ := cli.ZRemRangeByScore(setName, "0", strconv.FormatInt(oti, 10)).Result()
|
||||
if cunt > 0 {
|
||||
logrus.Warning("移出过期的引用数量:", "setName:", setName, " count:", count)
|
||||
}
|
||||
ary, err = cli.ZRevRangeByScore(setName, opt).Result()
|
||||
if err != nil {
|
||||
logrus.Warning("GetRangeMaXSortedSet ZRevRangeByScore err: ", " setName: ", setName, ", opt:", opt, ", res:", ary, ", err:", err)
|
||||
return &mxl, err
|
||||
}
|
||||
keyAry, err := cli.MGet(ary...).Result()
|
||||
if err != nil {
|
||||
logrus.Warning("GetRangeMaXSortedSet mget err: ", "setName:", setName, ", max:", opt.Max, ", min:", opt.Min, ", res:", keyAry, ", err:", err)
|
||||
return &mxl, err
|
||||
}
|
||||
for _, str := range keyAry {
|
||||
if str == nil {
|
||||
continue
|
||||
}
|
||||
mx := MaX{}
|
||||
json.Unmarshal([]byte(str.(string)), &mx)
|
||||
curData := mx.Data
|
||||
if len(curData) == 0 {
|
||||
logrus.Warning("curData is null", str)
|
||||
continue
|
||||
}
|
||||
|
||||
ts := curData[0].(float64)
|
||||
tm := time.UnixMilli(int64(ts))
|
||||
if tm.Sub(from) > 0 {
|
||||
break
|
||||
}
|
||||
mxl.List = append(mxl.List, &mx)
|
||||
}
|
||||
mxl.Count = count
|
||||
return &mxl, nil
|
||||
}
|
||||
|
||||
// 根据周期的文本内容,返回这代表多少个分钟
|
||||
|
||||
func (cr *Core) GetExpiration(per string) (time.Duration, error) {
|
||||
if len(per) == 0 {
|
||||
erstr := fmt.Sprint("period没有设置")
|
||||
logrus.Warn(erstr)
|
||||
err := errors.New(erstr)
|
||||
return 0, err
|
||||
}
|
||||
exp, err := cr.PeriodToMinutes(per)
|
||||
dur := time.Duration(exp*49) * time.Minute
|
||||
return dur, err
|
||||
}
|
||||
|
||||
func (cr *Core) PeriodToLastTime(period string, from time.Time) (time.Time, error) {
|
||||
candles := cr.Cfg.Config.Get("softCandleSegmentList").MustArray()
|
||||
minutes := int64(0)
|
||||
tms := ""
|
||||
|
||||
for _, v := range candles {
|
||||
cs := CandleSegment{}
|
||||
sv, _ := json.Marshal(v)
|
||||
json.Unmarshal(sv, &cs)
|
||||
if cs.Seg == period {
|
||||
mns, err := cr.PeriodToMinutes(period)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
minutes = mns
|
||||
tms = cs.StartTime
|
||||
} else {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tm, err := time.ParseInLocation("2006-01-02 15:04.000", tms, time.Local)
|
||||
if err != nil {
|
||||
return from, err
|
||||
}
|
||||
// from.Unix() % minutes
|
||||
frmi := from.UnixMilli()
|
||||
frmi = frmi - (frmi)%(60*1000)
|
||||
tmi := tm.UnixMilli()
|
||||
tmi = tmi - (tmi)%(60*1000)
|
||||
oms := int64(0)
|
||||
for i := int64(0); true; i++ {
|
||||
if tmi+i*minutes*60*1000 > frmi {
|
||||
break
|
||||
} else {
|
||||
oms = tmi + i*minutes*60*1000
|
||||
continue
|
||||
}
|
||||
}
|
||||
// return from, nil
|
||||
// tm :=
|
||||
om := time.UnixMilli(oms)
|
||||
// fmt.Println("PeriodToLastTime: period: ", period, " lastTime:", om.Format("2006-01-02 15:04:05.000"))
|
||||
return om, nil
|
||||
}
|
||||
|
133
maX.go
Normal file
133
maX.go
Normal file
@ -0,0 +1,133 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
logrus "github.com/sirupsen/logrus"
|
||||
// "os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MaXList struct {
|
||||
Count int `json:"count"`
|
||||
LastUpdateTime int64 `json:"lastUpdateTime"`
|
||||
UpdateNickName string `json:"updateNickName"`
|
||||
List []*MaX `json:"list"`
|
||||
}
|
||||
|
||||
type MaX struct {
|
||||
InstID string `json:"instID"`
|
||||
Period string `json:"period"`
|
||||
KeyName string `json:"keyName"`
|
||||
Data []interface{} `json:"data"`
|
||||
Count int `json:"count,number"`
|
||||
Ts int64 `json:"ts,number"`
|
||||
AvgVal float64 `json:"avgVal,number"`
|
||||
From string `json:"from,string"`
|
||||
}
|
||||
|
||||
type WillMX struct {
|
||||
KeyName string
|
||||
Count int
|
||||
}
|
||||
|
||||
func (mx MaX) SetToKey(cr *Core) ([]interface{}, error) {
|
||||
// fmt.Println(utils.GetFuncName(), " step1 ", mx.InstID, " ", mx.Period)
|
||||
cstr := strconv.Itoa(mx.Count)
|
||||
tss := strconv.FormatInt(mx.Ts, 10)
|
||||
//校验时间戳是否合法
|
||||
ntm, err := cr.PeriodToLastTime(mx.Period, time.UnixMilli(mx.Ts))
|
||||
if ntm.UnixMilli() != mx.Ts {
|
||||
logrus.Warn(fmt.Sprint(GetFuncName(), " candles时间戳有问题 ", " 应该: ", ntm, "实际:", mx.Ts))
|
||||
mx.Ts = ntm.UnixMilli()
|
||||
}
|
||||
keyName := "ma" + cstr + "|candle" + mx.Period + "|" + mx.InstID + "|ts:" + tss
|
||||
//过期时间:根号(当前candle的周期/1分钟)*10000
|
||||
dj, _ := json.Marshal(mx)
|
||||
extt, err := cr.GetExpiration(mx.Period)
|
||||
if err != nil {
|
||||
fmt.Println("max SetToKey err: ", err)
|
||||
return mx.Data, err
|
||||
}
|
||||
// fmt.Println(utils.GetFuncName(), " step2 ", mx.InstID, " ", mx.Period)
|
||||
// tm := time.UnixMilli(mx.Ts).Format("01-02 15:04")
|
||||
cli := cr.RedisLocalCli
|
||||
if len(string(dj)) == 0 {
|
||||
fmt.Println("mx data is block data: ", mx, string(dj))
|
||||
err := errors.New("data is block")
|
||||
return mx.Data, err
|
||||
}
|
||||
// fmt.Println(utils.GetFuncName(), " step3 ", mx.InstID, " ", mx.Period)
|
||||
_, err = cli.Set(keyName, dj, extt).Result()
|
||||
if err != nil {
|
||||
fmt.Println(GetFuncName(), " maXSetToKey err:", err)
|
||||
return mx.Data, err
|
||||
}
|
||||
// fmt.Println(utils.GetFuncName(), " step4 ", mx.InstID, " ", mx.Period)
|
||||
// fmt.Println("max setToKey: ", keyName, "res:", res, "data:", string(dj), "from: ", mx.From)
|
||||
cr.SaveUniKey(mx.Period, keyName, extt, mx.Ts)
|
||||
return mx.Data, err
|
||||
}
|
||||
|
||||
// TODO
|
||||
// 返回:
|
||||
// Sample:被顶出队列的元素
|
||||
func (mxl *MaXList) RPush(sm *MaX) (Sample, error) {
|
||||
last := MaX{}
|
||||
bj, _ := json.Marshal(*sm)
|
||||
json.Unmarshal(bj, &sm)
|
||||
tsi := sm.Data[0]
|
||||
matched := false
|
||||
for k, v := range mxl.List {
|
||||
if v.Data[0] == tsi {
|
||||
matched = true
|
||||
mxl.List[k] = sm
|
||||
}
|
||||
}
|
||||
if matched {
|
||||
return nil, nil
|
||||
}
|
||||
if len(mxl.List) >= mxl.Count && len(mxl.List) > 1 {
|
||||
last = *mxl.List[0]
|
||||
mxl.List = mxl.List[1:]
|
||||
mxl.List = append(mxl.List, sm)
|
||||
return last, nil
|
||||
} else {
|
||||
mxl.List = append(mxl.List, sm)
|
||||
return nil, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 冒泡排序
|
||||
func (mxl *MaXList) RecursiveBubbleS(length int, ctype string) error {
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
realLength := len(mxl.List)
|
||||
//FIXME:在对这个List进行排序时,List中途长度变了,就会报错:
|
||||
// Jan 17 02:40:39 miracle ubuntu[25239]: panic: runtime error: index out of range [23] with length 23
|
||||
for idx, _ := range mxl.List {
|
||||
if idx >= length-1 || idx > realLength-1 {
|
||||
break
|
||||
}
|
||||
temp := MaX{}
|
||||
|
||||
pre, _ := mxl.List[idx].Data[0].(float64)
|
||||
nex, _ := mxl.List[idx+1].Data[0].(float64)
|
||||
daoxu := pre < nex
|
||||
if ctype == "asc" {
|
||||
daoxu = !daoxu
|
||||
}
|
||||
if daoxu { //改变成>,换成从小到大排序
|
||||
temp = *mxl.List[idx]
|
||||
mxl.List[idx] = mxl.List[idx+1]
|
||||
mxl.List[idx+1] = &temp
|
||||
}
|
||||
}
|
||||
length--
|
||||
mxl.RecursiveBubbleS(length, ctype)
|
||||
return nil
|
||||
}
|
208
util.go
Normal file
208
util.go
Normal file
@ -0,0 +1,208 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NextPeriod(curPeriod string, idx int) string {
|
||||
list := []string{
|
||||
"1m",
|
||||
"3m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1H",
|
||||
"2H",
|
||||
"4H",
|
||||
"6H",
|
||||
"12H",
|
||||
"1D",
|
||||
"2D",
|
||||
"5D",
|
||||
}
|
||||
nextPer := ""
|
||||
for i := 0; i < len(list)-1; i++ {
|
||||
if list[i] == curPeriod {
|
||||
nextPer = list[i+idx]
|
||||
}
|
||||
}
|
||||
return nextPer
|
||||
}
|
||||
func OtherPeriod(curPeriod string, cha int) string {
|
||||
list := []string{
|
||||
"1m",
|
||||
"3m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1H",
|
||||
"2H",
|
||||
"4H",
|
||||
"6H",
|
||||
"12H",
|
||||
"1D",
|
||||
"2D",
|
||||
"5D",
|
||||
}
|
||||
nextPer := ""
|
||||
for i := 0; i < len(list)-1; i++ {
|
||||
if list[i] == curPeriod {
|
||||
if i+cha > 0 && i+cha < len(list)-1 {
|
||||
nextPer = list[i+cha]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextPer
|
||||
}
|
||||
func ShaiziInt(n int) int {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
b := rand.Intn(n)
|
||||
return b
|
||||
}
|
||||
func Difference(slice1 []string, slice2 []string) []string {
|
||||
var diff []string
|
||||
|
||||
// Loop two times, first to find slice1 strings not in slice2,
|
||||
// second loop to find slice2 strings not in slice1
|
||||
for i := 0; i < 2; i++ {
|
||||
for _, s1 := range slice1 {
|
||||
found := false
|
||||
for _, s2 := range slice2 {
|
||||
if s1 == s2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// String not found. We add it to return slice
|
||||
if !found {
|
||||
diff = append(diff, s1)
|
||||
}
|
||||
}
|
||||
// Swap the slices, only if it was the first loop
|
||||
if i == 0 {
|
||||
slice1, slice2 = slice2, slice1
|
||||
}
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
func JsonToMap(str string) (map[string]interface{}, error) {
|
||||
|
||||
var tempMap map[string]interface{}
|
||||
|
||||
err := json.Unmarshal([]byte(str), &tempMap)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Unmarshal err: ", err, str)
|
||||
}
|
||||
|
||||
return tempMap, err
|
||||
}
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 1.0
|
||||
for math.Abs(z*z-x) > 0.000001 {
|
||||
z -= (z*z - x) / (2 * z)
|
||||
}
|
||||
return z
|
||||
}
|
||||
func RecursiveBubble(ary []int64, length int) []int64 {
|
||||
if length == 0 {
|
||||
return ary
|
||||
}
|
||||
for idx, _ := range ary {
|
||||
if idx >= length-1 {
|
||||
break
|
||||
}
|
||||
temp := int64(0)
|
||||
if ary[idx] < ary[idx+1] { //改变成>,换成从小到大排序
|
||||
temp = ary[idx]
|
||||
ary[idx] = ary[idx+1]
|
||||
ary[idx+1] = temp
|
||||
}
|
||||
}
|
||||
length--
|
||||
RecursiveBubble(ary, length)
|
||||
return ary
|
||||
}
|
||||
|
||||
func Decimal(value float64) string {
|
||||
va := fmt.Sprintf("%.5f", value)
|
||||
v1, _ := strconv.ParseFloat(va, 32)
|
||||
v1 = v1 * 100
|
||||
s1 := fmt.Sprintf("%.3f", v1)
|
||||
return s1 + "%"
|
||||
}
|
||||
func ShortNum(value float64) string {
|
||||
va := fmt.Sprintf("%.5f", value)
|
||||
v1, _ := strconv.ParseFloat(va, 32)
|
||||
v1 = v1 * 100
|
||||
s1 := fmt.Sprintf("%.3f", v1)
|
||||
return s1
|
||||
}
|
||||
|
||||
func GetRandomString(l int) string {
|
||||
str := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
bytes := []byte(str)
|
||||
result := []byte{}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[r.Intn(len(bytes))])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func Shaizi(n int) bool {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
b := rand.Intn(n)
|
||||
if b == 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func Sishewuru(x float64, digit int) (number float64, err error) {
|
||||
baseDigit := 10
|
||||
if digit < 0 {
|
||||
return x, errors.New("错误的精度,不能小于0")
|
||||
} else {
|
||||
baseDigit = pow(baseDigit, digit+1)
|
||||
}
|
||||
betweenNumber := float64(5)
|
||||
return (math.Floor((x*float64(baseDigit) + betweenNumber) / 10)) / float64(baseDigit/10), err
|
||||
}
|
||||
|
||||
func pow(x, n int) int {
|
||||
ret := 1 // 结果初始为0次方的值,整数0次方为1。如果是矩阵,则为单元矩阵。
|
||||
for n != 0 {
|
||||
if n%2 != 0 {
|
||||
ret = ret * x
|
||||
}
|
||||
n /= 2
|
||||
x = x * x
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// 获取当前函数名字
|
||||
func GetFuncName() string {
|
||||
pc := make([]uintptr, 1)
|
||||
runtime.Callers(2, pc)
|
||||
f := runtime.FuncForPC(pc[0])
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
func Md5V(str string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user