Files
banstagy/llmjob/3464.go
2026-08-24 20:53:21 +08:00

174 lines
4.0 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 llmjob
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
type TrendlineData struct {
upper float64
lower float64
slopePh float64
slopePl float64
upos int
dnos int
prevUpos int
prevDnos int
}
func J3464(pol *config.RunPolicyConfig) *strat.TradeStrat {
length := pol.DefInt("length", 13, core.PNorm(5, 30))
mult := pol.Def("mult", 1.05, core.PNorm(0.5, 2.0))
calcMethod := pol.Def("calcMethod", 0, core.PUniform(0, 2)) // 0: Atr, 1: Stdev, 2: Linreg
_ = pol.Def("backpaint", 1.0, core.PUniform(0, 1)) == 1.0 // 使用下划线忽略未使用的变量
return &strat.TradeStrat{
WarmupNum: length * 2,
HedgeOff: true, // 单向持仓
RunTimeFrames: []string{"4h"},
OnStartUp: func(s *strat.StratJob) {
s.More = &TrendlineData{
upper: 0,
lower: 0,
slopePh: 0,
slopePl: 0,
upos: 0,
dnos: 0,
prevUpos: 0,
prevDnos: 0,
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
data, _ := s.More.(*TrendlineData)
// 获取当前价格
closePrice := e.Close.Get(0)
if math.IsNaN(closePrice) {
return
}
// 检测支点 - 实现与PineScript的pivothigh和pivotlow相似的功能
// 需要检查当前K线是否是过去length周期内的最高点,并且左右两侧都有length个K线
ph := false
pl := false
// 确保有足够的历史数据
if e.Close.Len() > length*2 {
// 检查当前K线是否是支点高
currentHigh := e.High.Get(length)
isPivotHigh := true
for i := 0; i < length; i++ {
if e.High.Get(i) >= currentHigh || e.High.Get(length*2-i) >= currentHigh {
isPivotHigh = false
break
}
}
// 检查当前K线是否是支点低
currentLow := e.Low.Get(length)
isPivotLow := true
for i := 0; i < length; i++ {
if e.Low.Get(i) <= currentLow || e.Low.Get(length*2-i) <= currentLow {
isPivotLow = false
break
}
}
ph = isPivotHigh && !math.IsNaN(currentHigh)
pl = isPivotLow && !math.IsNaN(currentLow)
}
// 计算斜率
var slope float64
method := int(calcMethod)
switch method {
case 0: // Atr
atr := ta.ATR(e.High, e.Low, e.Close, length)
slope = atr.Get(0) / float64(length) * mult
case 1: // Stdev
stdDev := ta.StdDev(e.Close, length)
slope = stdDev.Get(0) / float64(length) * mult
case 2: // Linreg
// 简化版的线性回归斜率计算
n := float64(length)
sumX := n * (n - 1) / 2
sumY := ta.SMA(e.Close, length).Get(0) * n
sumXY := 0.0
sumX2 := 0.0
for i := 0; i < length; i++ {
x := float64(i)
y := e.Close.Get(i)
if !math.IsNaN(y) {
sumXY += x * y
sumX2 += x * x
}
}
// 计算斜率
denominator := n*sumX2 - sumX*sumX
if denominator != 0 {
slope = (n*sumXY - sumX*sumY) / denominator * mult
} else {
slope = 0
}
}
// 更新趋势线斜率和值
if ph {
data.slopePh = slope
data.upper = e.High.Get(length)
} else {
data.upper = data.upper - data.slopePh
}
if pl {
data.slopePl = slope
data.lower = e.Low.Get(length)
} else {
data.lower = data.lower + data.slopePl
}
// 保存前一个状态
data.prevUpos = data.upos
data.prevDnos = data.dnos
// 检测突破状态
if ph {
data.upos = 0
} else if closePrice > data.upper-data.slopePh*float64(length) {
data.upos = 1
}
if pl {
data.dnos = 0
} else if closePrice < data.lower+data.slopePl*float64(length) {
data.dnos = 1
}
// 检测突破并生成交易信号
upBreakout := data.upos > data.prevUpos
dnBreakout := data.dnos > data.prevDnos
if upBreakout && len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "Up Breakout",
})
}
if dnBreakout && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "Down Breakout",
Short: true,
})
}
},
}
}