268 lines
7.9 KiB
Go
268 lines
7.9 KiB
Go
package analysis
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"os"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/go-redis/redis"
|
||
logrus "github.com/sirupsen/logrus"
|
||
)
|
||
|
||
type ShearItem struct {
|
||
ShearForce float64 // ma30-candle剪切力
|
||
VerticalElevation float64 // 仰角, Interval范围内线段的仰角
|
||
Ratio float64 // 剪切力除以仰角的比值
|
||
Score float64 // 当前LastCandleY点本值
|
||
PolarQuadrant string // shangxian,manyue,xiaxian,xinyue, 分别对应圆周的四个阶段。
|
||
LastUpdate int64
|
||
LastUpdateTime string
|
||
}
|
||
type ShearForceGrp struct {
|
||
InstID string
|
||
LastUpdate int64
|
||
LastUpdateTime string
|
||
Ma30PeriodGroup map[string]ShearItem
|
||
Ma7PeriodGroup map[string]ShearItem
|
||
From string
|
||
}
|
||
|
||
// TODO 弃用
|
||
// func (seg *SegmentItem) MakeShearForceGrp(cr *Core) (*ShearForceGrp, error) {
|
||
// shg := ShearForceGrp{
|
||
// InstID: seg.InstID,
|
||
// Ma30PeriodGroup: map[string]ShearItem{},
|
||
// Ma7PeriodGroup: map[string]ShearItem{},
|
||
// }
|
||
// err := shg.ForceUpdate(cr)
|
||
// sf1 := float64(0)
|
||
// sf1 = seg.LastCandle.Y - seg.LastMa7.Y
|
||
// she := ShearItem{
|
||
// LastUpdate: time.Now().UnixMilli(),
|
||
// VerticalElevation: seg.SubItemList[2].VerticalElevation,
|
||
// Ratio: seg.LastCandle.Y / seg.SubItemList[2].VerticalElevation,
|
||
// Score: seg.LastCandle.Score,
|
||
// PolarQuadrant: seg.PolarQuadrant,
|
||
// }
|
||
// if seg.Ctype == "ma7" {
|
||
// she.ShearForce = seg.LastCandle.Y
|
||
// shg.Ma7PeriodGroup[seg.Period] = she
|
||
// }
|
||
// if seg.Ctype == "ma30" {
|
||
// she.ShearForce = sf1
|
||
// shg.Ma30PeriodGroup[seg.Period] = she
|
||
// }
|
||
// return &shg, err
|
||
// }
|
||
|
||
// TODO 弃用
|
||
// func (shg *ShearForceGrp) ForceUpdate(cr *Core) error {
|
||
// ctype := "ma7"
|
||
// hmName := shg.InstID + "|" + ctype + "|shearForceGrp"
|
||
// res, err := cr.RedisLocalCli.HGetAll(hmName).Result()
|
||
//
|
||
// for k, v := range res {
|
||
// si := ShearItem{}
|
||
// json.Unmarshal([]byte(v), &si)
|
||
// shg.Ma7PeriodGroup[k] = si
|
||
// }
|
||
//
|
||
// ctype = "ma30"
|
||
// hmName = shg.InstID + "|" + ctype + "|shearForceGrp"
|
||
// res, err = cr.RedisLocalCli.HGetAll(hmName).Result()
|
||
//
|
||
// for k, v := range res {
|
||
// si := ShearItem{}
|
||
// json.Unmarshal([]byte(v), &si)
|
||
// shg.Ma30PeriodGroup[k] = si
|
||
// }
|
||
// shg.SetToKey(cr)
|
||
// return err
|
||
// }
|
||
func (she *ShearForceGrp) Show(cr *Core) error {
|
||
js, err := json.Marshal(she)
|
||
logrus.Info(GetFuncName(), ": ", string(js))
|
||
|
||
return err
|
||
}
|
||
|
||
// TODO 需要重构: 已经重构
|
||
// 对象数据库落盘
|
||
func (she *ShearForceGrp) SetToKey(cr *Core) error {
|
||
keyName := she.InstID + "|shearForce"
|
||
she.From = os.Getenv("HOSTNAME")
|
||
she.LastUpdateTime = time.Now().Format("2006-01-02 15:04:05.000")
|
||
js, err := json.Marshal(she)
|
||
if err != nil {
|
||
logrus.Panic(GetFuncName(), " err: ", err)
|
||
} else {
|
||
cr.RedisLocalCli.Set(keyName, string(js), 0).Result()
|
||
cr.RedisLocal2Cli.Set(keyName, string(js), 0).Result()
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (she *ShearForceGrp) maXPrd(cr *Core, ctype string) {
|
||
// 先把对象克隆,防止在处理的过程中对象发生变更
|
||
she2 := *she
|
||
she3 := &she2
|
||
// 查了一下,json marshal 有线程安全问题,需要用户自己加锁,先不用了
|
||
// bj, _ := json.Marshal(she3)
|
||
// bytes := []byte(bj)
|
||
// var she4 ShearForceGrp
|
||
// json.Unmarshal(bytes, she4)
|
||
// 先声明map
|
||
var grp map[string]ShearItem
|
||
// 再使用make函数创建一个非nil的map,nil map不能赋值
|
||
grp = make(map[string]ShearItem)
|
||
if ctype == "ma7" {
|
||
//fmt.Println("len of ma7 she.Ma7PeriodGroup: ", len(she3.Ma7PeriodGroup))
|
||
bj, err := json.Marshal(she3.Ma7PeriodGroup)
|
||
if err != nil {
|
||
logrus.Panic(GetFuncName(), " err:", err)
|
||
}
|
||
json.Unmarshal(bj, &grp)
|
||
//fmt.Println("len of ma30 she.Ma7PeriodGroup: ", len(she3.Ma7PeriodGroup))
|
||
} else if ctype == "ma30" {
|
||
bj, err := json.Marshal(she3.Ma30PeriodGroup)
|
||
if err != nil {
|
||
logrus.Panic(GetFuncName(), " err: ", err)
|
||
}
|
||
json.Unmarshal(bj, &grp)
|
||
}
|
||
for period, shearItem := range grp {
|
||
setName := "shearForce|ratio|" + ctype + "|" + period + "|sortedSet"
|
||
// TODO:这个key用于判定当前instID|maX|period|的ratio排名是否已经过期
|
||
timelinessKey := "shearForce|ratio|" + she.InstID + "|" + ctype + "|" + period + "|lastUpdate"
|
||
sei := SeriesInfo{
|
||
InstID: she3.InstID,
|
||
Period: period,
|
||
}
|
||
// 阈值先暂且设置为 -100
|
||
// SHEARFORCE_VERTICAL_RATE
|
||
threahold := float64(SHEARFORCE_VERTICAL_RATE)
|
||
bj, _ := json.Marshal(sei)
|
||
z := redis.Z{
|
||
Score: float64(shearItem.Ratio),
|
||
Member: string(bj),
|
||
}
|
||
//无论超过阈值,还是低于阈值的负数,都是达标
|
||
if shearItem.Ratio < -1*threahold {
|
||
cr.RedisLocalCli.ZAdd(setName, z).Result()
|
||
cr.RedisLocalCli.Set(timelinessKey, shearItem.LastUpdate, 3*time.Minute)
|
||
} else if shearItem.Ratio > threahold {
|
||
cr.RedisLocalCli.ZAdd(setName, z).Result()
|
||
cr.RedisLocalCli.Set(timelinessKey, shearItem.LastUpdate, 3*time.Minute)
|
||
} else {
|
||
cr.RedisLocalCli.ZRem(setName, string(bj)).Result()
|
||
}
|
||
}
|
||
}
|
||
|
||
// 把所有引用调用都改成传值调用,试试,看能不能解决那个陈年bug
|
||
func (she *ShearForceGrp) AddToRatioSorted(cr *Core) error {
|
||
she.maXPrd(cr, "ma7")
|
||
she.maXPrd(cr, "ma30")
|
||
return nil
|
||
}
|
||
|
||
// TODO 需要重构: 看了一下,不用重构
|
||
func (she *ShearForceGrp) MakeSnapShot(cr *Core) error {
|
||
nw := time.Now()
|
||
tm := nw.UnixMilli()
|
||
tm = tm - tm%60000
|
||
tms := strconv.FormatInt(tm, 10)
|
||
js, err := json.Marshal(she)
|
||
|
||
keyName1 := fmt.Sprint(she.InstID + "|shearForce|snapShot|ts:" + tms)
|
||
keyName2 := fmt.Sprint(she.InstID + "|shearForce|snapShot|last")
|
||
_, err = cr.RedisLocalCli.Set(keyName1, string(js), time.Duration(24)*time.Hour).Result()
|
||
_, err = cr.RedisLocalCli.Set(keyName2, string(js), time.Duration(24)*time.Hour).Result()
|
||
_, err = cr.RedisLocal2Cli.Set(keyName1, string(js), time.Duration(24)*time.Hour).Result()
|
||
_, err = cr.RedisLocal2Cli.Set(keyName2, string(js), time.Duration(24)*time.Hour).Result()
|
||
writeLog := os.Getenv("SARDINE_WRITELOG") == "true"
|
||
if !writeLog {
|
||
return err
|
||
}
|
||
wg := WriteLog{
|
||
Content: js,
|
||
Tag: she.InstID + ".shearForce",
|
||
}
|
||
go func() {
|
||
cr.WriteLogChan <- &wg
|
||
}()
|
||
return nil
|
||
}
|
||
|
||
func (sheGrp *ShearForceGrp) Refresh(cr *Core) error {
|
||
segments := cr.Cfg.Config.Get("softCandleSegmentList").MustArray()
|
||
ma7Grp := map[string]ShearItem{}
|
||
ma30Grp := map[string]ShearItem{}
|
||
//搜集各个维度未过期的shearItem数据,组合成shearForceGrp对象
|
||
for _, v := range segments {
|
||
cs := CandleSegment{}
|
||
sv, _ := json.Marshal(v)
|
||
json.Unmarshal(sv, &cs)
|
||
shi30, err := MakeShearItem(cr, sheGrp.InstID, cs.Seg, "ma30")
|
||
if err != nil {
|
||
logrus.Warn(GetFuncName(), err)
|
||
} else {
|
||
ma30Grp[cs.Seg] = *shi30
|
||
}
|
||
shi7, err := MakeShearItem(cr, sheGrp.InstID, cs.Seg, "ma7")
|
||
if err != nil {
|
||
logrus.Warn(GetFuncName(), err)
|
||
} else {
|
||
ma7Grp[cs.Seg] = *shi7
|
||
}
|
||
sheGrp.Ma7PeriodGroup = ma7Grp
|
||
sheGrp.Ma30PeriodGroup = ma30Grp
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func MakeShearItem(cr *Core, instId string, period string, ctype string) (*ShearItem, error) {
|
||
shi := ShearItem{}
|
||
keyn := instId + "|" + period + "|" + ctype + "|shearItem"
|
||
res, err := cr.RedisLocalCli.Get(keyn).Result()
|
||
if err != nil && len(res) == 0 {
|
||
return &shi, err
|
||
}
|
||
json.Unmarshal([]byte(res), &shi)
|
||
return &shi, err
|
||
}
|
||
|
||
func (sheGrp *ShearForceGrp) Process(cr *Core) error {
|
||
go func() {
|
||
sheGrp.Show(cr)
|
||
// 传递过来的shg对象是空的,需要从segmentItem对象创建的shearItem对象组合中来重建
|
||
sheGrp.Refresh(cr)
|
||
err := sheGrp.SetToKey(cr)
|
||
if err != nil {
|
||
logrus.Panic("srs SetToKey err: ", err)
|
||
}
|
||
// sheGrp.MakeSnapShot(cr)
|
||
// 下一个阶段计算
|
||
allow := os.Getenv("SARDINE_MAKEANALYTICS") == "true"
|
||
if !allow {
|
||
return
|
||
}
|
||
|
||
periodList := []string{}
|
||
for k := range sheGrp.Ma30PeriodGroup {
|
||
periodList = append(periodList, k)
|
||
}
|
||
}()
|
||
go func() {
|
||
sheGrp.AddToRatioSorted(cr)
|
||
}()
|
||
go func() {
|
||
// 另一个携程中,Analytics对象要读这里snapShot,我希望它读到的是老的而不是新的,所以等待2秒钟
|
||
time.Sleep(2 * time.Second)
|
||
sheGrp.MakeSnapShot(cr)
|
||
}()
|
||
return nil
|
||
}
|