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

268
llmjob/4513.go Normal file
View File

@@ -0,0 +1,268 @@
// 修复后的banbot完整策略代码
package llmjob
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
// State4513 存储每个品种的策略状态
type State4513 struct {
dir int // 当前趋势方向,1=上升趋势,-1=下降趋势
longStop float64 // 多头止损价格
shortStop float64 // 空头止损价格
longStopPrev float64 // 前一个多头止损价格
shortStopPrev float64 // 前一个空头止损价格
trailingStop float64 // 当前跟踪止损价格
}
// Demo 创建并返回策略实例
func J4513(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义可调超参数
bbLength := pol.DefInt("BBLength", 100, core.PNorm(20, 200))
stdDev := pol.Def("StdDev", 10, core.PNorm(1, 20))
useMovingAverage := pol.Def("useMovingAverage", 1, core.PUniform(0, 1)) // 1=true, 0=false
maType := pol.DefInt("maType", 3, core.PUniform(0, 5)) // 0=ema, 1=sma, 2=hma, 3=rma, 4=vwma, 5=wma
lookbackPeriod := pol.DefInt("lookbackPeriod", 22, core.PNorm(5, 50))
atrMaType := pol.DefInt("atrMaType", 2, core.PUniform(0, 5)) // 0=ema, 1=sma, 2=hma, 3=rma, 4=vwma, 5=wma
atrLength := pol.DefInt("atrLength", 10, core.PNorm(5, 30))
atrMult := pol.Def("atrMult", 4.2, core.PNorm(1, 10))
wicks := pol.Def("wicks", 0, core.PUniform(0, 1)) // 1=true, 0=false
considerYearlyHighLow := pol.Def("considerYearlyHighLow", 0, core.PUniform(0, 1)) // 1=true, 0=false
considerNewLongTermHighLows := pol.Def("considerNewLongTermHighLows", 0, core.PUniform(0, 1)) // 1=true, 0=false
tradeDirection := pol.DefInt("tradeDirection", 0, core.PUniform(0, 2)) // 0=all, 1=long, 2=short
// 固定参数
shortHighLowPeriod := 100
longHighLowPeriod := 200
return &strat.TradeStrat{
Name: "Bollinger Percentage Bands",
WarmupNum: int(math.Max(float64(bbLength), float64(longHighLowPeriod))) + 10,
HedgeOff: true, // 单向持仓
EachMaxLong: 1,
EachMaxShort: 1,
RunTimeFrames: []string{"8h"},
OnStartUp: func(s *strat.StratJob) {
// 初始化策略状态
state := &State4513{
dir: 1,
longStop: 0,
shortStop: 0,
}
s.More = state
},
OnBar: func(s *strat.StratJob) {
e := s.Env
state, _ := s.More.(*State4513)
// 1. 计算布林带指标
// 修复错误1:布林带计算参数错误
// 原始策略使用bb(close, BBLength, StdDev),其中StdDev是标准差倍数
// 修改为使用正确的参数格式,提供上下轨的标准差倍数
upperClose, _, lowerClose := ta.BBANDS(e.Close, bbLength, stdDev, stdDev)
upperHigh, _, lowerHigh := ta.BBANDS(e.High, bbLength, stdDev, stdDev)
upperLow, _, lowerLow := ta.BBANDS(e.Low, bbLength, stdDev, stdDev)
// 2. 计算布林带百分比
percentBClose := e.Close.Sub(lowerClose).Div(upperClose.Sub(lowerClose)).Mul(100)
percentBHigh := e.High.Sub(lowerHigh).Div(upperHigh.Sub(lowerHigh)).Mul(100)
percentBLow := e.Low.Sub(lowerLow).Div(upperLow.Sub(lowerLow)).Mul(100)
// 3. 应用移动平均线平滑
var newClose, newHigh, newLow *ta.Series
if useMovingAverage > 0.5 {
percentBMAClose := getMovingAverage(percentBClose, maType, lookbackPeriod)
percentBMAHigh := getMovingAverage(percentBHigh, maType, lookbackPeriod)
percentBMALow := getMovingAverage(percentBLow, maType, lookbackPeriod)
newClose = percentBMAClose
newHigh = percentBMAHigh
newLow = percentBMALow
} else {
newClose = percentBClose
newHigh = percentBHigh
newLow = percentBLow
}
// 4. 计算ATR和止损
closePrev := newClose.Back(1)
highPrev := newHigh.Back(1)
lowPrev := newLow.Back(1)
trueRange := newHigh.Max(closePrev).Sub(newLow.Min(closePrev))
averageTrueRange := getMovingAverage(trueRange, atrMaType, atrLength)
atr := averageTrueRange.Mul(atrMult)
longStopVal := newClose.Sub(atr)
shortStopVal := newClose.Add(atr)
// 修复错误2:止损更新逻辑不完整
// 原始策略使用nz(longStop[1], longStop)处理前一个止损值不存在的情况
// 修改为正确处理初始状态,并确保止损只能向有利方向移动
if state.longStopPrev == 0 {
state.longStopPrev = longStopVal.Get(0)
}
if state.shortStopPrev == 0 {
state.shortStopPrev = shortStopVal.Get(0)
}
// 修复错误3:使用Series运算创建常量而不是ta.Const
if wicks > 0.5 {
if lowPrev.Get(0) > state.longStopPrev {
// 使用Max确保止损只能向有利方向移动
longStopVal = longStopVal.Max(newClose.Sub(newClose).Add(state.longStopPrev))
}
} else {
if closePrev.Get(0) > state.longStopPrev {
longStopVal = longStopVal.Max(newClose.Sub(newClose).Add(state.longStopPrev))
}
}
if wicks > 0.5 {
if highPrev.Get(0) < state.shortStopPrev {
shortStopVal = shortStopVal.Min(newClose.Sub(newClose).Add(state.shortStopPrev))
}
} else {
if closePrev.Get(0) < state.shortStopPrev {
shortStopVal = shortStopVal.Min(newClose.Sub(newClose).Add(state.shortStopPrev))
}
}
// 5. 判断趋势方向
// 修复错误4:趋势方向判断可能存在边界条件处理错误
// 原始策略使用三元运算符,逻辑清晰且紧凑
// 修改为更接近原始策略的实现
if state.dir == -1 {
if wicks > 0.5 {
if newHigh.Get(0) > state.shortStopPrev {
state.dir = 1
}
} else {
if newClose.Get(0) > state.shortStopPrev {
state.dir = 1
}
}
} else if state.dir == 1 {
if wicks > 0.5 {
if newLow.Get(0) < state.longStopPrev {
state.dir = -1
}
} else {
if newClose.Get(0) < state.longStopPrev {
state.dir = -1
}
}
}
if state.dir == 1 {
state.trailingStop = longStopVal.Get(0)
} else {
state.trailingStop = shortStopVal.Get(0)
}
// 6. 判断辅助条件
yearlyHighCondition, yearlyLowCondition := getYearlyHighLowCondition(e, considerYearlyHighLow > 0.5)
newHighS, newLowS := calculateNewHighLows(e, shortHighLowPeriod, longHighLowPeriod, considerNewLongTermHighLows > 0.5)
// 7. 生成交易信号
buyCondition := state.dir == 1 && yearlyHighCondition && newHighS
exitBuyCondition := state.dir == -1
sellCondition := state.dir == -1 && yearlyLowCondition && newLowS
exitSellCondition := state.dir == 1
// 8. 执行交易
if buyCondition && (tradeDirection == 0 || tradeDirection == 1) {
s.OpenOrder(&strat.EnterReq{
Tag: "Buy",
Short: false,
})
}
if exitBuyCondition && len(s.LongOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "ExitBuy",
Dirt: core.OdDirtLong,
})
}
if sellCondition && (tradeDirection == 0 || tradeDirection == 2) {
s.OpenOrder(&strat.EnterReq{
Tag: "Sell",
Short: true,
})
}
if exitSellCondition && len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "ExitSell",
Dirt: core.OdDirtShort,
})
}
// 更新状态
state.longStop = longStopVal.Get(0)
state.shortStop = shortStopVal.Get(0)
state.longStopPrev = state.longStop
state.shortStopPrev = state.shortStop
},
}
}
// getMovingAverage 根据类型获取移动平均线
func getMovingAverage(source *ta.Series, maType int, length int) *ta.Series {
switch maType {
case 0: // ema
return ta.EMA(source, length)
case 1: // sma
return ta.SMA(source, length)
case 2: // hma
return ta.HMA(source, length)
case 3: // rma
return ta.RMA(source, length)
case 4: // vwma - 在Banbot中可能没有直接对应,使用SMA代替
return ta.SMA(source, length)
case 5: // wma
return ta.WMA(source, length)
default:
return ta.SMA(source, length)
}
}
// calculateNewHighLows 计算新的高低点条件
func calculateNewHighLows(e *ta.BarEnv, shortPeriod, longPeriod int, consider bool) (bool, bool) {
shortHigh := ta.Highest(e.High, shortPeriod)
longHigh := ta.Highest(e.High, longPeriod)
shortLow := ta.Lowest(e.Low, shortPeriod)
longLow := ta.Lowest(e.Low, longPeriod)
newHigh := true
newLow := true
if consider {
newHigh = math.Abs(shortHigh.Get(0)-longHigh.Get(0)) < 1e-10
newLow = math.Abs(shortLow.Get(0)-longLow.Get(0)) < 1e-10
}
return newHigh, newLow
}
// getYearlyHighLowCondition 获取年度高低点条件
func getYearlyHighLowCondition(e *ta.BarEnv, consider bool) (bool, bool) {
if !consider {
return true, true
}
// 在Banbot中,我们无法直接获取年度数据,所以简化处理
// 使用较长期的高低点来近似年度高低点
yearlyHigh := ta.Highest(e.High, 365)
yearlyLow := ta.Lowest(e.Low, 365)
yearlyHighCondition := e.Close.Get(0) > yearlyHigh.Get(0)
yearlyLowCondition := e.Close.Get(0) < yearlyLow.Get(0)
return yearlyHighCondition, yearlyLowCondition
}