init
This commit is contained in:
268
llmjob/4513.go
Normal file
268
llmjob/4513.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user