114 lines
3.5 KiB
Go
114 lines
3.5 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"
|
||
)
|
||
|
||
// StrategyMore 存储每个品种的策略状态
|
||
type StrategyMore struct {
|
||
LastBarNum float64 // 上次交易的K线编号
|
||
}
|
||
|
||
// MultiEMACross 多重均线交叉与时间间隔整合策略
|
||
func J4225(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||
// 定义可调参数
|
||
emaBasePeriod := pol.DefInt("emaBasePeriod", 4, core.PNorm(3, 15))
|
||
emaMidRatio := pol.Def("emaMidRatio", 2.1, core.PNorm(1.5, 4))
|
||
emaSlowRatio := pol.Def("emaSlowRatio", 10, core.PNorm(5, 20))
|
||
timeInterval := pol.DefInt("timeInterval", 35, core.PNorm(10, 100))
|
||
atrMultiplier := pol.Def("atrMultiplier", 1.9, core.PNorm(0.5, 5))
|
||
|
||
// 计算EMA周期
|
||
emaMidPeriod := int(float64(emaBasePeriod) * emaMidRatio)
|
||
emaSlowPeriod := int(float64(emaBasePeriod) * emaSlowRatio)
|
||
|
||
// 确定预热K线数量,取最慢EMA周期的2倍
|
||
warmupNum := emaSlowPeriod * 2
|
||
|
||
return &strat.TradeStrat{
|
||
WarmupNum: warmupNum,
|
||
HedgeOff: true, // 单向持仓模式
|
||
RunTimeFrames: []string{"8h"},
|
||
OnStartUp: func(s *strat.StratJob) {
|
||
// 初始化每个品种的策略状态
|
||
s.More = &StrategyMore{
|
||
LastBarNum: -1, // 初始化为-1,表示尚未交易
|
||
}
|
||
},
|
||
OnBar: func(s *strat.StratJob) {
|
||
e := s.Env
|
||
m, _ := s.More.(*StrategyMore)
|
||
|
||
// 计算EMA指标
|
||
emaFast := ta.EMA(e.Close, emaBasePeriod)
|
||
emaMid := ta.EMA(e.Close, emaMidPeriod)
|
||
emaSlow := ta.EMA(e.Close, emaSlowPeriod)
|
||
|
||
// 计算ATR用于动态止盈止损
|
||
atr := ta.ATR(e.High, e.Low, e.Close, 14)
|
||
atrVal := atr.Get(0)
|
||
|
||
// 检查EMA交叉条件 - 修复重复计算问题
|
||
fastCrossSlow := emaFast.Cross(emaSlow)
|
||
midCrossSlow := emaMid.Cross(emaSlow)
|
||
fastCrossSlowUp := fastCrossSlow == 1 // 快线上穿慢线
|
||
midCrossSlowUp := midCrossSlow == 1 // 中线上穿慢线
|
||
fastCrossSlowDown := fastCrossSlow == -1 // 快线下穿慢线
|
||
midCrossSlowDown := midCrossSlow == -1 // 中线下穿慢线
|
||
|
||
// 生成交易信号
|
||
buyCondition := fastCrossSlowUp && midCrossSlowUp
|
||
sellCondition := fastCrossSlowDown && midCrossSlowDown
|
||
|
||
// 检查时间间隔是否满足要求
|
||
currentBarNum := e.BarCount(0)
|
||
barsSinceLastTrade := currentBarNum - m.LastBarNum
|
||
timeElapsedOk := m.LastBarNum == -1 || barsSinceLastTrade >= float64(timeInterval)
|
||
|
||
// 如果有交易信号且时间间隔满足要求
|
||
if (buyCondition || sellCondition) && timeElapsedOk {
|
||
// 先平掉所有现有仓位
|
||
if len(s.LongOrders) > 0 || len(s.ShortOrders) > 0 {
|
||
s.CloseOrders(&strat.ExitReq{
|
||
Tag: "close_all",
|
||
Dirt: core.OdDirtBoth,
|
||
Force: true,
|
||
})
|
||
}
|
||
|
||
// 计算止盈止损价格
|
||
stopLossDist := atrVal * atrMultiplier
|
||
takeProfitDist := stopLossDist * 1.67 // 保持5:3的盈亏比
|
||
|
||
// 根据信号方向开仓
|
||
if buyCondition {
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "Buy",
|
||
Short: false,
|
||
OrderType: core.OrderTypeMarket,
|
||
StopLossVal: stopLossDist,
|
||
TakeProfitVal: takeProfitDist,
|
||
StopLossTag: "stop_loss",
|
||
TakeProfitTag: "take_profit",
|
||
})
|
||
m.LastBarNum = currentBarNum
|
||
} else if sellCondition {
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "Sell",
|
||
Short: true,
|
||
OrderType: core.OrderTypeMarket,
|
||
StopLossVal: stopLossDist,
|
||
TakeProfitVal: takeProfitDist,
|
||
StopLossTag: "stop_loss",
|
||
TakeProfitTag: "take_profit",
|
||
})
|
||
m.LastBarNum = currentBarNum
|
||
}
|
||
}
|
||
},
|
||
}
|
||
}
|