This commit is contained in:
2026-08-24 20:53:21 +08:00
commit 6e78bba16a
287 changed files with 32443 additions and 0 deletions

135
com/exm.go Normal file
View File

@@ -0,0 +1,135 @@
package com
import (
"math"
"slices"
)
type ExmItem struct {
BarNum int
TimeMS int64
Value float64
Valid bool
}
type ExmTrace struct {
Hist []*ExmItem
Expect int // 1寻找极大值,-1寻找极小值
PrevVals []float64 // 前一个值
PrevDist float64 // 前两个极值的距离
distList []float64 // 前面极值距离,保留最近3个
}
/*
Update
val: 当前指标值
pNum: 前一个索引
ptime:前一个时间戳
*/
func (m *ExmTrace) Update(val float64, pNum int, ptime int64) bool {
if math.IsNaN(val) {
return false
}
if len(m.PrevVals) < 2 {
// 至少积累2个
if len(m.PrevVals) > 0 && m.PrevVals[len(m.PrevVals)-1] == val {
// 和前一个值相同,跳过
return false
}
m.PrevVals = append(m.PrevVals, val)
return false
}
// 前1个,前2个
p1, p2 := m.PrevVals[1], m.PrevVals[0]
if p1 == val {
// 当前值无效
return false
}
// 更新
m.PrevVals = append(m.PrevVals, val)
m.PrevVals = m.PrevVals[len(m.PrevVals)-2:]
pSub := p1 - p2
sub := p1 - val
var last *ExmItem
if len(m.Hist) > 0 {
last = m.Hist[len(m.Hist)-1]
}
getMinDist := func() float64 {
if last == nil {
return math.Abs(p1) * 0.3
}
if m.PrevDist != 0 {
return m.PrevDist * 0.3
}
return max(math.Abs(last.Value), math.Abs(p1)) * 0.3
}
if pSub*sub <= 0 {
// 非极大值或极小值
if last != nil && !last.Valid && (val-last.Value)*float64(m.Expect) > getMinDist() {
// 检查最后一个是否有效
last.Valid = true
if len(m.Hist) > 1 {
dist := math.Abs(m.Hist[len(m.Hist)-2].Value - m.Hist[len(m.Hist)-1].Value)
m.distList = append(m.distList, dist)
if len(m.distList) > 3 {
m.distList = m.distList[len(m.distList)-3:]
}
m.PrevDist = slices.Max(m.distList)
}
return true
}
return false
}
valid := 0
if sub > 0 {
if m.Expect == 0 || m.Expect == 1 {
// 新增极大值
if last == nil || p1-last.Value >= getMinDist() {
valid = -1
}
} else if p1 > last.Value {
// 更新极大值
valid = -1
}
} else if sub < 0 {
if m.Expect == 0 || m.Expect == -1 {
// 新增极小值
if last == nil || last.Value-p1 >= getMinDist() {
valid = 1
}
} else if p1 < last.Value {
// 更新极小值
valid = 1
}
}
if valid != 0 {
exm := &ExmItem{
TimeMS: ptime,
BarNum: pNum,
Value: p1,
}
if m.Expect != valid {
m.Hist = append(m.Hist, exm)
//log.Info("add exm", zap.String("date", btime.ToDateStr(ptime, "")),
// zap.Float64("val", p1))
} else {
m.Hist[len(m.Hist)-1] = exm
//log.Info("update exm", zap.String("date", btime.ToDateStr(ptime, "")),
// zap.Float64("val", p1))
}
if len(m.Hist) > 2 {
dist := math.Abs(m.Hist[len(m.Hist)-3].Value - m.Hist[len(m.Hist)-2].Value)
if len(m.distList) == 0 || dist != m.distList[len(m.distList)-1] {
m.distList = append(m.distList, dist)
if len(m.distList) > 3 {
m.distList = m.distList[len(m.distList)-3:]
}
m.PrevDist = slices.Max(m.distList)
}
}
m.Expect = valid
m.PrevVals = nil
return true
}
return false
}