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

178 lines
5.7 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 (
"math"
"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"
)
// Sta4009 存储每个品种的策略状态
type Sta4009 struct {
atrTrailingStop float64 // ATR跟踪止损值
position int // 当前持仓方向(1=多头,-1=空头,0=无持仓)
entryPrice float64 // 入场价格
buyTarget float64 // 多头目标价格
sellTarget float64 // 空头目标价格
}
func J4009(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义可调参数
keyValue := pol.Def("keyValue", 1, core.PNorm(0.1, 5))
atrPeriod := pol.DefInt("atrPeriod", 14, core.PNorm(5, 30))
useHeikinAshi := pol.DefInt("useHeikinAshi", 0, core.PNorm(0, 1)) // 0=false, 1=true
exitPercentage := pol.Def("exitPercentage", 0.002, core.PNorm(0.001, 0.01))
rsiPeriod := pol.DefInt("rsiPeriod", 14, core.PNorm(7, 30))
donchianLength := pol.DefInt("donchianLength", 20, core.PNorm(10, 50))
return &strat.TradeStrat{
WarmupNum: donchianLength + 20, // 确保有足够数据计算所有指标
HedgeOff: true, // 单向持仓模式
TimeFrames: "1d",
OnStartUp: func(s *strat.StratJob) {
// 初始化策略状态
s.More = &Sta4009{
atrTrailingStop: math.NaN(),
position: 0,
entryPrice: math.NaN(),
buyTarget: math.NaN(),
sellTarget: math.NaN(),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
state, _ := s.More.(*Sta4009)
// 计算基础指标
atr := ta.ATR(e.High, e.Low, e.Close, atrPeriod)
lossDistance := keyValue * atr.Get(0)
rsiValue := ta.RSI(e.Close, rsiPeriod).Get(0)
// 计算价格源(普通收盘价或惠金-阿希收盘价)
var priceSource *ta.Series
if useHeikinAshi > 0 {
haOpen, haHigh, haLow, haClose := ta.HeikinAshi(e)
haCloseSeries := haOpen.Add(haHigh).Add(haLow).Add(haClose).Div(4)
priceSource = haCloseSeries
} else {
priceSource = e.Close
}
currentPrice := priceSource.Get(0)
prevPrice := priceSource.Get(1)
// 计算ATR跟踪止损
if !math.IsNaN(lossDistance) && !math.IsNaN(currentPrice) && !math.IsNaN(prevPrice) {
prevStop := state.atrTrailingStop
if math.IsNaN(prevStop) {
prevStop = 0
}
if currentPrice > prevStop && prevPrice > prevStop {
// 价格在止损线上方且前一价格也在止损线上方,止损线上移
state.atrTrailingStop = math.Max(prevStop, currentPrice-lossDistance)
} else if currentPrice < prevStop && prevPrice < prevStop {
// 价格在止损线下方且前一价格也在止损线下方,止损线下移
state.atrTrailingStop = math.Min(prevStop, currentPrice+lossDistance)
} else if currentPrice > prevStop {
// 价格上穿止损线,设置新的止损线
state.atrTrailingStop = currentPrice - lossDistance
} else {
// 价格下穿止损线,设置新的止损线
state.atrTrailingStop = currentPrice + lossDistance
}
}
// 计算持仓方向
if !math.IsNaN(prevPrice) && !math.IsNaN(state.atrTrailingStop) {
if prevPrice < state.atrTrailingStop && currentPrice > state.atrTrailingStop {
state.position = 1 // 多头信号
} else if prevPrice > state.atrTrailingStop && currentPrice < state.atrTrailingStop {
state.position = -1 // 空头信号
}
// 否则保持原有方向
}
// 计算唐奇安通道
donchianUpper := ta.Highest(e.High, donchianLength)
donchianLower := ta.Lowest(e.Low, donchianLength)
donchianBasis := donchianUpper.Add(donchianLower).Div(2).Get(0)
// 计算交叉信号
above := currentPrice > state.atrTrailingStop && prevPrice <= state.atrTrailingStop
below := currentPrice < state.atrTrailingStop && prevPrice >= state.atrTrailingStop
// 生成交易信号
buySignal := currentPrice > state.atrTrailingStop && above && rsiValue > 50 && currentPrice > donchianBasis
sellSignal := currentPrice < state.atrTrailingStop && below && rsiValue < 50 && currentPrice < donchianBasis
// 执行交易
if buySignal && s.OrderNum == 0 {
state.entryPrice = currentPrice
state.buyTarget = state.entryPrice * (1 + exitPercentage)
state.sellTarget = state.entryPrice * (1 - exitPercentage)
s.OpenOrder(&strat.EnterReq{
Tag: "Buy",
OrderType: core.OrderTypeMarket,
})
} else if sellSignal && s.OrderNum == 0 {
state.entryPrice = currentPrice
state.buyTarget = state.entryPrice * (1 + exitPercentage)
state.sellTarget = state.entryPrice * (1 - exitPercentage)
s.OpenOrder(&strat.EnterReq{
Tag: "Sell",
Short: true,
OrderType: core.OrderTypeMarket,
})
}
// 退出条件检查
if len(s.LongOrders) > 0 {
od := s.LongOrders[0]
if od.Status >= ormo.InOutStatusFullEnter {
if currentPrice >= state.buyTarget {
// 达到止盈目标
s.CloseOrders(&strat.ExitReq{
Tag: "Take Profit",
Dirt: core.OdDirtLong,
Limit: state.buyTarget,
})
} else if currentPrice <= state.sellTarget {
// 触发止损
s.CloseOrders(&strat.ExitReq{
Tag: "Stop Loss",
Dirt: core.OdDirtLong,
Limit: state.sellTarget,
})
}
}
}
if len(s.ShortOrders) > 0 {
od := s.ShortOrders[0]
if od.Status >= ormo.InOutStatusFullEnter {
if currentPrice <= state.sellTarget {
// 达到止盈目标
s.CloseOrders(&strat.ExitReq{
Tag: "Take Profit",
Dirt: core.OdDirtShort,
Limit: state.sellTarget,
})
} else if currentPrice >= state.buyTarget {
// 触发止损
s.CloseOrders(&strat.ExitReq{
Tag: "Stop Loss",
Dirt: core.OdDirtShort,
Limit: state.buyTarget,
})
}
}
}
},
}
}