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

175 lines
5.1 KiB
Go
Raw Permalink 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 (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
// Sta2391 用于保存每个品种的策略状态
type Sta2391 struct {
posReversal123 float64 // 123反转策略的信号值
posmStochCross float64 // 随机指标交叉策略的信号值
}
func J2391(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 123反转策略参数
length := pol.DefInt("length", 40, core.PNorm(5, 30))
kSmoothing := pol.DefInt("kSmoothing", 1, core.PNorm(1, 5))
dLength := pol.DefInt("dLength", 3, core.PNorm(1, 5))
level := pol.Def("level", 30, core.PNorm(30, 70))
// 随机指标交叉策略参数
lengthSC := pol.DefInt("lengthSC", 20, core.PNorm(3, 21))
dLengthSC := pol.DefInt("dLengthSC", 3, core.PNorm(1, 5))
oversold := pol.Def("oversold", 10, core.PNorm(10, 30))
overbought := pol.Def("overbought", 90, core.PNorm(70, 90))
reverse := pol.Def("reverse", 0, core.PUniform(0, 1)) // 0表示不反转,1表示反转
// 计算预热数量,取两个策略中需要的历史数据最大值
warmupNum := length
if lengthSC > warmupNum {
warmupNum = lengthSC
}
if kSmoothing+dLength > warmupNum {
warmupNum = kSmoothing + dLength
}
if dLengthSC > warmupNum {
warmupNum = dLengthSC
}
// 额外需要2个历史K线判断价格反转
warmupNum += 2
return &strat.TradeStrat{
WarmupNum: warmupNum,
HedgeOff: true, // 单向持仓模式
TimeFrames: "8h",
OnStartUp: func(s *strat.StratJob) {
// 初始化策略状态
s.More = &Sta2391{
posReversal123: 0,
posmStochCross: 0,
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
state, _ := s.More.(*Sta2391)
// 获取价格数据
close0 := e.Close.Get(0) // 当前收盘价
close1 := e.Close.Get(1) // 前一个收盘价
close2 := e.Close.Get(2) // 前两个收盘价
// 1. 计算123反转策略信号
// 计算随机指标
kFast := ta.Stoch(e.High, e.Low, e.Close, length)
// 对K值进行平滑
vFast := ta.SMA(kFast, kSmoothing)
// 计算D值
vSlow := ta.SMA(vFast, dLength)
// 获取当前值
vFastVal := vFast.Get(0)
vSlowVal := vSlow.Get(0)
// 判断123反转策略信号
if close2 < close1 && close1 < close0 && vFastVal < vSlowVal && vFastVal > level {
// 买入信号:两天内收盘价从低点转为高点,且随机指标快速线在慢速线下方但高于阈值
state.posReversal123 = 1
} else if close2 > close1 && close1 > close0 && vFastVal > vSlowVal && vFastVal < level {
// 卖出信号:两天内收盘价从高点转为低点,且随机指标快速线在慢速线上方但低于阈值
state.posReversal123 = -1
}
// 否则保持之前的信号(不需要else,因为不改变state.posReversal123的值)
// 2. 计算随机指标交叉策略信号
// 计算随机指标
kFastSC := ta.Stoch(e.High, e.Low, e.Close, lengthSC)
// 计算D值
vSlowSC := ta.SMA(kFastSC, dLengthSC)
// 获取当前值
vFastSCVal := kFastSC.Get(0)
vSlowSCVal := vSlowSC.Get(0)
// 判断随机指标交叉策略信号
if vFastSCVal >= vSlowSCVal && vFastSCVal < oversold && vSlowSCVal < oversold {
// 买入信号:快速线在慢速线上方,且两者都处于超卖区域
state.posmStochCross = 1
} else if vFastSCVal < vSlowSCVal && vFastSCVal > overbought && vSlowSCVal > overbought {
// 卖出信号:快速线在慢速线下方,且两者都处于超买区域
state.posmStochCross = -1
}
// 否则保持之前的信号(不需要else,因为不改变state.posmStochCross的值)
// 3. 组合信号
var pos float64
if state.posReversal123 == 1 && state.posmStochCross == 1 {
// 两个策略都给出买入信号
pos = 1
} else if state.posReversal123 == -1 && state.posmStochCross == -1 {
// 两个策略都给出卖出信号
pos = -1
} else {
// 信号不一致,无交易信号
pos = 0
}
// 4. 处理信号反转
var possig float64
if reverse == 1 { // 明确检查reverse是否为1
if pos == 1 {
possig = -1 // 反转买入信号为卖出信号
} else if pos == -1 {
possig = 1 // 反转卖出信号为买入信号
} else {
possig = 0
}
} else {
possig = pos // 不反转信号
}
// 5. 执行交易
if possig == 1 {
// 买入信号
if len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
// 如果有做空持仓,平仓
if len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "close_short",
Dirt: core.OdDirtShort,
})
}
} else if possig == -1 {
// 卖出信号
if len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
})
}
// 如果有做多持仓,平仓
if len(s.LongOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "close_long",
Dirt: core.OdDirtLong,
})
}
} else if possig == 0 {
// 无信号,平仓所有持仓
if len(s.LongOrders) > 0 || len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "close_all",
Dirt: core.OdDirtBoth,
})
}
}
},
}
}