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

164 lines
4.4 KiB
Go
Raw 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/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
type KijunData struct {
initialCapital float64
netProfit float64
}
func J3746(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义可调超参数
ksPeriod := pol.DefInt("ksPeriod", 30, core.PNorm(9, 50))
atrPeriod := pol.DefInt("atrPeriod", 14, core.PNorm(7, 30))
atrMultiplier := pol.Def("atrMultiplier", 1.5, core.PNorm(0.8, 4))
targetPoints := pol.Def("targetPoints", 100, core.PNorm(50, 200))
riskPercent := pol.Def("riskPercent", 4, core.PNorm(1, 10))
equityProtection := pol.Def("equityProtection", 30, core.PNorm(10, 50))
return &strat.TradeStrat{
WarmupNum: ksPeriod, // 预热K线数量,确保基均线计算有足够数据
HedgeOff: true, // 单向持仓模式
RunTimeFrames: []string{"3d"},
OnStartUp: func(s *strat.StratJob) {
// 初始化每个品种的特定数据
s.More = &KijunData{
initialCapital: 50000.0, // 初始资金
netProfit: 0.0, // 初始净利润
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*KijunData)
// 计算技术指标
atr := ta.ATR(e.High, e.Low, e.Close, atrPeriod)
atrValue := atr.Get(0)
// 计算基均线 (Kijun Sen)
highest := ta.Highest(e.High, ksPeriod)
lowest := ta.Lowest(e.Low, ksPeriod)
kijunSen := highest.Add(lowest).Div(2)
kijunSenValue := kijunSen.Get(0)
// 检查数据有效性
if math.IsNaN(atrValue) || math.IsNaN(kijunSenValue) {
return
}
// 生成交易信号
openPrice := e.Open.Get(0)
closePrice := e.Close.Get(0)
baseLong := openPrice < kijunSenValue && closePrice > kijunSenValue
baseShort := openPrice > kijunSenValue && closePrice < kijunSenValue
// 计算止损距离
stopLossVal := atrValue * atrMultiplier
// 更新净利润
// 计算总浮动盈亏
totalFloating := 0.0
for _, od := range s.LongOrders {
totalFloating += od.Profit
}
for _, od := range s.ShortOrders {
totalFloating += od.Profit
}
m.netProfit = totalFloating
// 权益保护检查
equityStopout := false
if s.OrderNum > 0 {
// 计算当前余额(初始资金 + 净利润)
totalBalance := m.initialCapital + m.netProfit
// 检查是否触发权益保护
if totalFloating < 0 && math.Abs(totalFloating/totalBalance) > equityProtection/100 {
equityStopout = true
}
}
// 权益保护触发时平仓所有头寸
if equityStopout {
s.CloseOrders(&strat.ExitReq{
Tag: "equity_protection",
Dirt: core.OdDirtBoth,
Force: true,
})
return
}
// 检查是否有持仓
hasLongPosition := len(s.LongOrders) > 0
hasShortPosition := len(s.ShortOrders) > 0
// 计算头寸大小
balance := m.initialCapital + m.netProfit
riskAmount := balance * (riskPercent / 100) // 风险金额
size := riskAmount / stopLossVal // 合约数量
if size < 0.001 { // 最小合约数量检查
size = 0.001
}
// 多头交易
if baseLong && !hasLongPosition && !hasShortPosition {
s.OpenOrder(&strat.EnterReq{
Tag: "l_en",
Amount: size,
StopLossVal: stopLossVal,
TakeProfitVal: targetPoints,
StopLossTag: "stop_loss",
TakeProfitTag: "take_profit",
})
}
// 空头交易
if baseShort && !hasShortPosition && !hasLongPosition {
s.OpenOrder(&strat.EnterReq{
Tag: "s_en",
Short: true,
Amount: size,
StopLossVal: stopLossVal,
TakeProfitVal: targetPoints,
StopLossTag: "stop_loss",
TakeProfitTag: "take_profit",
})
}
},
OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq {
// 计算基均线
highest := ta.Highest(s.Env.High, ksPeriod)
lowest := ta.Lowest(s.Env.Low, ksPeriod)
kijunSen := highest.Add(lowest).Div(2)
kijunSenValue := kijunSen.Get(0)
closePrice := s.Env.Close.Get(0)
// 多头平仓条件:收盘价低于基均线
if !od.Short && closePrice < kijunSenValue {
return &strat.ExitReq{
Tag: "long_exit",
}
}
// 空头平仓条件:收盘价高于基均线
if od.Short && closePrice > kijunSenValue {
return &strat.ExitReq{
Tag: "short_exit",
}
}
return nil
},
}
}