174 lines
4.0 KiB
Go
174 lines
4.0 KiB
Go
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,
|
||
})
|
||
}
|
||
},
|
||
}
|
||
}
|