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

215
llmjob/5609.go Normal file
View File

@@ -0,0 +1,215 @@
package llmjob
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
// State5609 存储每个品种的策略状态
type State5609 struct {
longEntryPrice float64
shortEntryPrice float64
longEntryBar int64
shortEntryBar int64
}
func J5609(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义可调超参数
atrPeriod := pol.DefInt("atrPeriod", 14, core.PNorm(7, 30))
bbLength := pol.DefInt("bbLength", 18, core.PNorm(10, 50))
bbStdDev := pol.Def("bbStdDev", 1.9, core.PNorm(1, 3))
rsiPeriod := pol.DefInt("rsiPeriod", 12, core.PNorm(7, 21))
atrMultiplier := pol.Def("atrMultiplier", 1.6, core.PNorm(0.5, 3))
vwapLength := pol.DefInt("vwapLength", 20, core.PNorm(10, 40))
targetMultiplier := pol.Def("targetMultiplier", 2.4, core.PNorm(1, 4))
maxHoldingBars := pol.DefInt("maxHoldingBars", 3, core.PNorm(2, 10))
// 计算预热期,确保所有指标都有足够的数据计算
warmupNum := bbLength
if atrPeriod > warmupNum {
warmupNum = atrPeriod
}
if rsiPeriod > warmupNum {
warmupNum = rsiPeriod
}
if vwapLength > warmupNum {
warmupNum = vwapLength
}
// 额外增加20个K线确保稳定性
warmupNum += 20
return &strat.TradeStrat{
Name: "OptionsStrategy",
WarmupNum: warmupNum,
HedgeOff: true, // 单向持仓模式
EachMaxLong: 1, // 最多一个多头订单
EachMaxShort: 1, // 最多一个空头订单
RunTimeFrames: []string{"4h"},
OnStartUp: func(s *strat.StratJob) {
// 初始化每个品种的策略状态
s.More = &State5609{
longEntryPrice: 0,
shortEntryPrice: 0,
longEntryBar: 0,
shortEntryBar: 0,
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
state := s.More.(*State5609)
// 计算技术指标
atrValue := ta.ATR(e.High, e.Low, e.Close, atrPeriod)
smaValue := ta.SMA(e.Close, bbLength)
stdDev := ta.StdDev(e.Close, bbLength)
upperBB := smaValue.Add(stdDev.Mul(bbStdDev))
lowerBB := smaValue.Sub(stdDev.Mul(bbStdDev))
rsiValue := ta.RSI(e.Close, rsiPeriod)
// 修复错误1:使用正确的VWAP计算方法
vwap := ta.Sum(e.Close.Mul(e.Volume), vwapLength).Div(ta.Sum(e.Volume, vwapLength))
volSMA := ta.SMA(e.Volume, 10)
atrSMA := ta.SMA(atrValue, 20)
// 获取当前值
closePrice := e.Close.Get(0)
atrVal := atrValue.Get(0)
upperBBVal := upperBB.Get(0)
lowerBBVal := lowerBB.Get(0)
rsiVal := rsiValue.Get(0)
vwapVal := vwap.Get(0)
volumeVal := e.Volume.Get(0)
volSMAVal := volSMA.Get(0)
atrSMAVal := atrSMA.Get(0)
// 检查数据有效性
if math.IsNaN(closePrice) || math.IsNaN(atrVal) || math.IsNaN(upperBBVal) ||
math.IsNaN(lowerBBVal) || math.IsNaN(rsiVal) || math.IsNaN(vwapVal) ||
math.IsNaN(volumeVal) || math.IsNaN(volSMAVal) || math.IsNaN(atrSMAVal) {
return
}
// 计算条件
volSpike := volumeVal > volSMAVal*1.5
atrFilter := atrVal > atrSMAVal*0.5
// 生成交易信号
longCE := e.Close.Cross(upperBB) == 1 && rsiVal > 60 && volSpike && closePrice > vwapVal && atrFilter
longPE := e.Close.Cross(lowerBB) == -1 && rsiVal < 40 && volSpike && closePrice < vwapVal && atrFilter
// 计算止损止盈
longStopLoss := 0.0
longTarget := 0.0
shortStopLoss := 0.0
shortTarget := 0.0
// 修复错误5:使用实际成交的平均价格作为止损止盈的计算基准
if len(s.LongOrders) > 0 {
// 获取多头持仓的平均价格
longAvgPrice := state.longEntryPrice
if longAvgPrice > 0 {
longStopLoss = longAvgPrice - atrMultiplier*atrVal
longTarget = longAvgPrice + targetMultiplier*atrVal
}
}
if len(s.ShortOrders) > 0 {
// 获取空头持仓的平均价格
shortAvgPrice := state.shortEntryPrice
if shortAvgPrice > 0 {
shortStopLoss = shortAvgPrice + atrMultiplier*atrVal
shortTarget = shortAvgPrice - targetMultiplier*atrVal
}
}
// 执行交易
if longCE && len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "CE Entry",
OrderType: core.OrderTypeMarket,
StopLossVal: atrMultiplier * atrVal,
TakeProfitVal: targetMultiplier * atrVal,
})
// 记录入场价格和K线时间
state.longEntryPrice = closePrice
state.longEntryBar = e.TimeStop
}
if longPE && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "PE Entry",
Short: true,
OrderType: core.OrderTypeMarket,
StopLossVal: atrMultiplier * atrVal,
TakeProfitVal: targetMultiplier * atrVal,
})
// 记录入场价格和K线时间
state.shortEntryPrice = closePrice
state.shortEntryBar = e.TimeStop
}
// 出场管理
if len(s.LongOrders) > 0 {
// 计算持仓时间(K线数)
holdBars := e.BarCount(state.longEntryBar)
// 止盈出场
if closePrice >= longTarget {
s.CloseOrders(&strat.ExitReq{
Tag: "CE Target Hit",
Dirt: core.OdDirtLong,
Force: true,
})
}
// 止损出场
if closePrice <= longStopLoss {
s.CloseOrders(&strat.ExitReq{
Tag: "CE Stop Loss Hit",
Dirt: core.OdDirtLong,
Force: true,
})
}
// 时间出场
if int64(holdBars) >= int64(maxHoldingBars) {
s.CloseOrders(&strat.ExitReq{
Tag: "CE Timed Exit",
Dirt: core.OdDirtLong,
Force: true,
})
}
}
if len(s.ShortOrders) > 0 {
// 计算持仓时间(K线数)
holdBars := e.BarCount(state.shortEntryBar)
// 止盈出场
if closePrice <= shortTarget {
s.CloseOrders(&strat.ExitReq{
Tag: "PE Target Hit",
Dirt: core.OdDirtShort,
Force: true,
})
}
// 止损出场
if closePrice >= shortStopLoss {
s.CloseOrders(&strat.ExitReq{
Tag: "PE Stop Loss Hit",
Dirt: core.OdDirtShort,
Force: true,
})
}
// 时间出场
if int64(holdBars) >= int64(maxHoldingBars) {
s.CloseOrders(&strat.ExitReq{
Tag: "PE Timed Exit",
Dirt: core.OdDirtShort,
Force: true,
})
}
}
},
}
}