core/internal/analysis/shearGorceGrp.go
zhangkun9038@dingtalk.com 7ce7deba92 restruct
2025-02-20 14:27:18 +08:00

269 lines
7.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package analysis
import (
"encoding/json"
"fmt"
"os"
"strconv"
"time"
"github.com/go-redis/redis"
"github.com/phyer/core/internal/core"
logrus "github.com/sirupsen/logrus"
)
type ShearItem struct {
ShearForce float64 // ma30-candle剪切力
VerticalElevation float64 // 仰角, Interval范围内线段的仰角
Ratio float64 // 剪切力除以仰角的比值
Score float64 // 当前LastCandleY点本值
PolarQuadrant string // shangxianmanyuexiaxian,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的mapnil 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
}