175 lines
5.1 KiB
Go
175 lines
5.1 KiB
Go
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,
|
||
})
|
||
}
|
||
}
|
||
},
|
||
}
|
||
}
|