198 lines
5.1 KiB
Go
198 lines
5.1 KiB
Go
// 修复后的完整策略代码
|
||
// 请勿修改package包名和任意函数名
|
||
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导致虚假净值曲线
|
||
*/
|
||
|
||
// SuperTrendData 存储每个品种的Supertrend相关数据
|
||
type SuperTrendData struct {
|
||
trend int // 当前趋势方向,1表示上升趋势,-1表示下降趋势
|
||
longTrailStop float64 // 多头仓位的移动止损价格
|
||
shortTrailStop float64 // 空头仓位的移动止损价格
|
||
up float64 // 上轨值
|
||
dn float64 // 下轨值
|
||
}
|
||
|
||
func J1662(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||
// 定义可调参数
|
||
atrPeriod := pol.DefInt("atrPeriod", 8, core.PNorm(5, 30))
|
||
atrMultiplier := pol.Def("atrMultiplier", 2.5, core.PNorm(1.5, 5.0))
|
||
|
||
lenAtr := 20
|
||
baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
|
||
return &strat.TradeStrat{
|
||
WarmupNum: baseAtrLen, // 预热K线数量,确保有足够数据计算指标
|
||
RunTimeFrames: []string{"8h"},
|
||
OnStartUp: func(s *strat.StratJob) {
|
||
// 初始化每个品种的Supertrend数据
|
||
s.More = &SuperTrendData{
|
||
trend: 1, // 初始趋势设为上升
|
||
longTrailStop: math.NaN(),
|
||
shortTrailStop: math.NaN(),
|
||
up: math.NaN(),
|
||
dn: math.NaN(),
|
||
}
|
||
},
|
||
OnBar: func(s *strat.StratJob) {
|
||
e := s.Env
|
||
data, _ := s.More.(*SuperTrendData)
|
||
|
||
// 计算数据源 (hl2 = (high + low) / 2)
|
||
src := ta.HL2(e.High, e.Low)
|
||
|
||
// 计算ATR值
|
||
atr := ta.ATR(e.High, e.Low, e.Close, atrPeriod)
|
||
|
||
// 计算Supertrend指标
|
||
upVal := src.Get(0) - atr.Get(0)*atrMultiplier
|
||
dnVal := src.Get(0) + atr.Get(0)*atrMultiplier
|
||
|
||
atr2 := ta.ATR(e.High, e.Low, e.Close, lenAtr)
|
||
atrBase := ta.Lowest(ta.Highest(atr2, lenAtr), baseAtrLen).Get(0)
|
||
|
||
// 获取历史值
|
||
up1 := data.up
|
||
if math.IsNaN(up1) {
|
||
up1 = upVal
|
||
}
|
||
dn1 := data.dn
|
||
if math.IsNaN(dn1) {
|
||
dn1 = dnVal
|
||
}
|
||
|
||
// 更新上轨和下轨
|
||
close1 := e.Close.Get(1)
|
||
if !math.IsNaN(close1) {
|
||
if close1 > up1 {
|
||
upVal = math.Max(upVal, up1)
|
||
}
|
||
if close1 < dn1 {
|
||
dnVal = math.Min(dnVal, dn1)
|
||
}
|
||
}
|
||
|
||
// 保存当前上下轨值
|
||
data.up = upVal
|
||
data.dn = dnVal
|
||
|
||
// 判断趋势方向
|
||
prevTrend := data.trend
|
||
closePrice := e.Close.Get(0)
|
||
if !math.IsNaN(closePrice) && !math.IsNaN(dn1) && !math.IsNaN(up1) && !math.IsNaN(atrBase) {
|
||
if data.trend == -1 && closePrice > dn1 {
|
||
data.trend = 1 // 趋势由下降转为上升
|
||
} else if data.trend == 1 && closePrice < up1 {
|
||
data.trend = -1 // 趋势由上升转为下降
|
||
}
|
||
}
|
||
|
||
// 生成交易信号
|
||
buySignal := data.trend == 1 && prevTrend == -1
|
||
sellSignal := data.trend == -1 && prevTrend == 1
|
||
|
||
// 执行交易策略
|
||
if buySignal {
|
||
// 开仓多头,使用下轨作为触发价格
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "Long",
|
||
Stop: dnVal,
|
||
Log: true,
|
||
})
|
||
s.CloseOrders(&strat.ExitReq{
|
||
Tag: "XShort",
|
||
Dirt: core.OdDirtShort,
|
||
Log: true,
|
||
})
|
||
}
|
||
|
||
if sellSignal {
|
||
// 开仓空头,使用上轨作为触发价格
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "Short",
|
||
Short: true,
|
||
Stop: upVal,
|
||
Log: true,
|
||
})
|
||
s.CloseOrders(&strat.ExitReq{
|
||
Tag: "XLong",
|
||
Dirt: core.OdDirtLong,
|
||
Log: true,
|
||
})
|
||
}
|
||
|
||
pipValue := atrBase * 0
|
||
trailingValue := atrBase * 0
|
||
|
||
// 移动止损逻辑
|
||
if s.OrderNum > 0 {
|
||
// 多头移动止损
|
||
if len(s.LongOrders) > 0 {
|
||
// 获取持仓均价
|
||
avgPrice := s.PositionAvgPrice(core.OdDirtLong, "")
|
||
|
||
if avgPrice > 0 {
|
||
if math.IsNaN(data.longTrailStop) || closePrice > avgPrice+trailingValue {
|
||
data.longTrailStop = e.High.Get(0) - trailingValue
|
||
}
|
||
|
||
// 计算初始止损
|
||
longStopLevel := upVal - pipValue
|
||
// 使用更严格的止损(更接近当前价格的止损)
|
||
finalStop := math.Max(data.longTrailStop, longStopLevel)
|
||
if finalStop >= closePrice {
|
||
s.CloseOrders(&strat.ExitReq{
|
||
Tag: "SLLong",
|
||
Dirt: core.OdDirtLong,
|
||
})
|
||
} else {
|
||
s.SetAllStopLoss(core.OdDirtLong, &ormo.ExitTrigger{
|
||
Price: finalStop,
|
||
Tag: "sl",
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
// 空头移动止损
|
||
if len(s.ShortOrders) > 0 {
|
||
// 获取持仓均价
|
||
avgPrice := s.PositionAvgPrice(core.OdDirtShort, "")
|
||
|
||
if avgPrice > 0 {
|
||
if math.IsNaN(data.shortTrailStop) || closePrice < avgPrice-trailingValue {
|
||
data.shortTrailStop = e.Low.Get(0) + trailingValue
|
||
}
|
||
|
||
// 计算初始止损
|
||
shortStopLevel := dnVal + pipValue
|
||
// 使用更严格的止损(更接近当前价格的止损)
|
||
finalStop := math.Min(data.shortTrailStop, shortStopLevel)
|
||
if finalStop < closePrice {
|
||
s.CloseOrders(&strat.ExitReq{
|
||
Tag: "SLShort",
|
||
Dirt: core.OdDirtShort,
|
||
})
|
||
} else {
|
||
s.SetAllStopLoss(core.OdDirtShort, &ormo.ExitTrigger{
|
||
Price: finalStop,
|
||
Tag: "sl",
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
}
|
||
}
|