178 lines
5.7 KiB
Go
178 lines
5.7 KiB
Go
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,
|
||
})
|
||
}
|
||
}
|
||
}
|
||
},
|
||
}
|
||
}
|