205 lines
5.9 KiB
Go
205 lines
5.9 KiB
Go
package llmjob
|
||
|
||
import (
|
||
"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"
|
||
"math"
|
||
)
|
||
|
||
/*
|
||
因止损未检查bug导致表现看起来很好,不可用
|
||
*/
|
||
|
||
type State5689 struct {
|
||
entryPrice float64
|
||
hlv3 int // 保存三重均线状态
|
||
}
|
||
|
||
func J5689(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||
// 定义可调超参数
|
||
tpPercent := pol.Def("tpPercent", 0.33, core.PNorm(0.15, 0.5)) // 止盈百分比
|
||
length := pol.DefInt("length", 18, core.PNorm(10, 50)) // 通道计算周期
|
||
lengthChop := pol.DefInt("lengthChop", 14, core.PNorm(5, 30)) // CHOP指标周期
|
||
emaPeriod := pol.DefInt("emaPeriod", 10, core.PNorm(5, 30)) // EMA平滑周期
|
||
maPeriod := pol.DefInt("maPeriod", 50, core.PNorm(30, 100)) // 主均线周期
|
||
channelRate := pol.Def("channelRate", 0.15, core.PNorm(0.1, 0.5)) // 通道倍率
|
||
exitPeriod := pol.DefInt("exitPeriod", 12, core.PNorm(5, 30)) // 退出均线周期
|
||
|
||
return &strat.TradeStrat{
|
||
WarmupNum: maPeriod, // 预热K线数量,至少需要主均线周期
|
||
RunTimeFrames: []string{"1h"},
|
||
OnStartUp: func(s *strat.StratJob) {
|
||
// 初始化每个品种的状态变量
|
||
s.More = &State5689{
|
||
entryPrice: math.NaN(),
|
||
hlv3: 0, // 初始状态为0
|
||
}
|
||
},
|
||
OnBar: func(s *strat.StratJob) {
|
||
e := s.Env
|
||
state, _ := s.More.(*State5689)
|
||
|
||
// 计算技术指标
|
||
upper := ta.Highest(e.High, length)
|
||
lower := ta.Lowest(e.Low, length)
|
||
|
||
// 计算output值:价格在通道中的百分比位置
|
||
output := e.Close.Sub(upper).Div(upper.Sub(lower)).Mul(100)
|
||
emaOutput := ta.EMA(output, emaPeriod)
|
||
|
||
// 自定义MA函数:双重WMA平滑
|
||
maFunc := func(src *ta.Series, len int) *ta.Series {
|
||
wma1 := ta.WMA(src, len/2)
|
||
wma2 := ta.WMA(src, len)
|
||
return ta.WMA(wma1.Mul(2).Sub(wma2), int(math.Round(math.Sqrt(float64(len)))))
|
||
}
|
||
|
||
// 计算主均线和通道
|
||
BBMC := maFunc(e.Close, maPeriod)
|
||
rangema := ta.EMA(ta.TR(e.High, e.Low, e.Close), maPeriod)
|
||
upperk := BBMC.Add(rangema.Mul(channelRate))
|
||
lowerk := BBMC.Sub(rangema.Mul(channelRate))
|
||
|
||
// 计算退出均线
|
||
exitHigh := ta.WMA(e.High, exitPeriod)
|
||
exitLow := ta.WMA(e.Low, exitPeriod)
|
||
|
||
// 计算RSI指标(原始代码中计算但未使用)
|
||
_ = ta.RSI(e.Close, 14)
|
||
|
||
// 计算CHOP指标(虽然不影响交易逻辑,但为了完整性实现)
|
||
atr1 := ta.ATR(e.High, e.Low, e.Close, 1)
|
||
sumAtr := ta.Sum(atr1, lengthChop)
|
||
highestChop := ta.Highest(e.High, lengthChop)
|
||
lowestChop := ta.Lowest(e.Low, lengthChop)
|
||
chopRange := highestChop.Sub(lowestChop)
|
||
// 避免除以零
|
||
chopRangeValid := chopRange.Get(0) > 0
|
||
if chopRangeValid {
|
||
_ = sumAtr.Div(chopRange).Mul(100)
|
||
} else {
|
||
_ = ta.EMA(e.Close, 1).Mul(0) // 创建全0序列
|
||
}
|
||
|
||
// 获取当前值
|
||
closePrice := e.Close.Get(0)
|
||
upperkVal := upperk.Get(0)
|
||
lowerkVal := lowerk.Get(0)
|
||
BBMCVal := BBMC.Get(0)
|
||
outputVal := output.Get(0)
|
||
emaOutputVal := emaOutput.Get(0)
|
||
exitHighVal := exitHigh.Get(0)
|
||
exitLowVal := exitLow.Get(0)
|
||
|
||
// 检查数据有效性
|
||
if math.IsNaN(closePrice) || math.IsNaN(BBMCVal) || math.IsNaN(outputVal) || math.IsNaN(emaOutputVal) {
|
||
return
|
||
}
|
||
|
||
// 判断价格位置和颜色
|
||
colorBlue := closePrice > upperkVal
|
||
colorBarFuchsia := closePrice < lowerkVal
|
||
|
||
// 更新三重均线状态
|
||
if closePrice > exitHighVal {
|
||
state.hlv3 = 1
|
||
} else if closePrice < exitLowVal {
|
||
state.hlv3 = -1
|
||
}
|
||
// 否则保持上一个状态
|
||
|
||
// 计算退出线
|
||
_ = exitHigh
|
||
if state.hlv3 < 0 {
|
||
_ = exitLow
|
||
}
|
||
|
||
// 生成交易信号
|
||
closeXBBMC := e.Close.Cross(BBMC)
|
||
longCondition := closeXBBMC == 1 && outputVal > emaOutputVal
|
||
shortCondition := closeXBBMC == -1 && outputVal < emaOutputVal
|
||
|
||
// 执行交易逻辑
|
||
if longCondition && len(s.LongOrders) == 0 {
|
||
// 记录入场价格
|
||
state.entryPrice = closePrice
|
||
// 开多单
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "ENTER-LONG",
|
||
OrderType: core.OrderTypeMarket,
|
||
TakeProfit: closePrice * (1 + tpPercent),
|
||
})
|
||
}
|
||
|
||
// 为已有订单设置动态止损
|
||
if len(s.LongOrders) > 0 && !math.IsNaN(state.entryPrice) {
|
||
od := s.LongOrders[0]
|
||
if od.Status == ormo.InOutStatusFullEnter {
|
||
// 只有当color_bar为FUCHSIA时才设置止损
|
||
if colorBarFuchsia && !math.IsNaN(BBMCVal) {
|
||
// 设置BBMC作为止损价格
|
||
od.SetStopLoss(&ormo.ExitTrigger{
|
||
Price: BBMCVal,
|
||
Rate: 1.0, // 全部退出
|
||
Tag: "dynamic_stop_loss",
|
||
})
|
||
} else {
|
||
// 不设置止损
|
||
od.SetStopLoss(nil)
|
||
}
|
||
|
||
// 更新止盈
|
||
takeProfitPrice := state.entryPrice * (1 + tpPercent)
|
||
od.SetTakeProfit(&ormo.ExitTrigger{
|
||
Price: takeProfitPrice,
|
||
Rate: 1.0, // 全部退出
|
||
Tag: "take_profit",
|
||
})
|
||
}
|
||
}
|
||
|
||
// 做空部分(原始代码中被注释,这里也注释掉)
|
||
|
||
if shortCondition && len(s.ShortOrders) == 0 {
|
||
state.entryPrice = closePrice
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "ENTER-SHORT",
|
||
OrderType: core.OrderTypeMarket,
|
||
Short: true,
|
||
TakeProfit: closePrice * (1 - tpPercent),
|
||
})
|
||
}
|
||
|
||
if len(s.ShortOrders) > 0 && !math.IsNaN(state.entryPrice) {
|
||
od := s.ShortOrders[0]
|
||
if od.Status == ormo.InOutStatusFullEnter {
|
||
// 只有当color_bar为BLUE时才设置止损
|
||
if colorBlue && !math.IsNaN(BBMCVal) {
|
||
// 设置BBMC作为止损价格
|
||
od.SetStopLoss(&ormo.ExitTrigger{
|
||
Price: BBMCVal,
|
||
Rate: 1.0, // 全部退出
|
||
Tag: "dynamic_stop_loss_short",
|
||
})
|
||
} else {
|
||
// 不设置止损
|
||
od.SetStopLoss(nil)
|
||
}
|
||
|
||
// 更新止盈
|
||
takeProfitPrice := state.entryPrice * (1 - tpPercent)
|
||
od.SetTakeProfit(&ormo.ExitTrigger{
|
||
Price: takeProfitPrice,
|
||
Rate: 1.0, // 全部退出
|
||
Tag: "take_profit_short",
|
||
})
|
||
}
|
||
}
|
||
|
||
},
|
||
}
|
||
}
|