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

132 lines
3.8 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 (
"math"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
func J7046(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义可调超参数
smaPeriod := pol.DefInt("smaPeriod", 22, core.PNorm(10, 50))
mult := pol.Def("mult", 1.0, core.PNorm(0.8, 3.0))
trailingLossPct := pol.Def("trailingLossPct", 0.075, core.PNorm(0.03, 0.15))
trailingPointsPct := pol.Def("trailingPointsPct", 0.05, core.PNorm(0.01, 0.10))
trailingOffsetPct := pol.Def("trailingOffsetPct", 0.005, core.PNorm(0.001, 0.02))
return &strat.TradeStrat{
Name: "Bollinger Band Breakout",
WarmupNum: smaPeriod + 10, // 预热K线数量
HedgeOff: true, // 单向持仓模式
EachMaxLong: 1, // 最多1个多单
EachMaxShort: 1, // 最多1个空单
TimeFrames: "8h",
OnBar: func(s *strat.StratJob) {
e := s.Env
closePrice := e.Close.Get(0)
// 检查数据有效性
if math.IsNaN(closePrice) {
return
}
// 计算布林带指标
upper, _, lower := ta.BBANDS(e.Close, smaPeriod, mult, mult)
// 检测突破信号
longSignal := e.Close.Cross(upper) // 上穿上轨,返回1表示上穿
shortSignal := e.Close.Cross(lower) // 下穿下轨,返回-1表示下穿
// 多头入场逻辑
if longSignal == 1 && len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
Short: false,
OrderType: core.OrderTypeMarket,
})
}
// 空头入场逻辑
if shortSignal == -1 && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
OrderType: core.OrderTypeMarket,
})
}
// 更新追踪止损
updateTrailingStop(s, closePrice, trailingLossPct, trailingPointsPct, trailingOffsetPct)
},
}
}
// 更新追踪止损的辅助函数
func updateTrailingStop(s *strat.StratJob, closePrice, lossPct, pointsPct, offsetPct float64) {
// 处理多头仓位的追踪止损
for _, order := range s.LongOrders {
if order.Status >= 2 { // 已入场
entryPrice := order.Enter.Average
maxLossPrice := entryPrice * (1 - lossPct) // 最大损失价格
activationPrice := entryPrice * (1 + pointsPct) // 激活追踪的价格
// 获取当前止损信息
currentStop := order.GetStopLoss()
var newStopPrice float64
// 判断是否已激活追踪止损
if closePrice >= activationPrice {
// 已激活,使用偏移量计算止损
newStopPrice = closePrice * (1 - offsetPct)
} else {
// 未激活,使用最大损失作为止损
newStopPrice = maxLossPrice
}
// 只有当新止损价格更优(更高)时才更新
if currentStop == nil || newStopPrice > currentStop.Price {
order.SetStopLoss(&ormo.ExitTrigger{
Price: newStopPrice,
Tag: "trailing_stop",
})
}
}
}
// 处理空头仓位的追踪止损
for _, order := range s.ShortOrders {
if order.Status >= 2 { // 已入场
entryPrice := order.Enter.Average
maxLossPrice := entryPrice * (1 + lossPct) // 最大损失价格
activationPrice := entryPrice * (1 - pointsPct) // 激活追踪的价格
// 获取当前止损信息
currentStop := order.GetStopLoss()
var newStopPrice float64
// 判断是否已激活追踪止损
if closePrice <= activationPrice {
// 已激活,使用偏移量计算止损
newStopPrice = closePrice * (1 + offsetPct)
} else {
// 未激活,使用最大损失作为止损
newStopPrice = maxLossPrice
}
// 只有当新止损价格更优(更低)时才更新
if currentStop == nil || newStopPrice < currentStop.Price {
order.SetStopLoss(&ormo.ExitTrigger{
Price: newStopPrice,
Tag: "trailing_stop",
})
}
}
}
}