init
This commit is contained in:
154
llmjob/3087.go
Normal file
154
llmjob/3087.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package llmjob
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/core"
|
||||
"github.com/banbox/banbot/strat"
|
||||
ta "github.com/banbox/banta"
|
||||
"gonum.org/v1/gonum/floats"
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
/*
|
||||
基于初始的3087进行了简化,只保留盈利较好的14-26
|
||||
*/
|
||||
|
||||
// DCAStrategyState 存储每个品种的策略状态
|
||||
type DCAStrategyState struct {
|
||||
currentSO int // 当前安全订单计数器
|
||||
firstPrice float64 // 初始订单价格
|
||||
totalQtys float64 // 总交易数量
|
||||
totalCost float64 // 累计花费
|
||||
realTotQtys float64 // 总交易数量
|
||||
realTotCost float64 // 累计花费
|
||||
}
|
||||
|
||||
// calculateSafetyOrderThreshold 计算安全订单触发价格阈值
|
||||
func calculateSafetyOrderThreshold(initPrice, priceDeviation, stepScale float64, currentSO int) float64 {
|
||||
curSO := float64(currentSO)
|
||||
if stepScale == 1.0 {
|
||||
return initPrice - initPrice*priceDeviation*stepScale*curSO
|
||||
}
|
||||
rate := priceDeviation*math.Pow(stepScale, curSO) - priceDeviation
|
||||
return initPrice - initPrice*(rate/(stepScale-1))
|
||||
}
|
||||
|
||||
// DynamicDCA 动态DCA策略
|
||||
func J3087(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
// 定义可调参数
|
||||
priceDeviation := pol.Def("priceDeviation", 0.82, core.PNorm(0.5, 3.0))
|
||||
volumeScale := pol.Def("volumeScale", 1.16, core.PNorm(1.05, 1.5))
|
||||
stepScale := pol.Def("stepScale", 1.06, core.PNorm(1.05, 1.3))
|
||||
takeProfit := pol.Def("takeProfit", 1.15, core.PNorm(0.5, 2.5))
|
||||
baseOrder := pol.Def("baseOrder", 10.0, core.PNorm(5, 20))
|
||||
startLvl := pol.DefInt("startLvl", 14.0, core.PNorm(1, 20))
|
||||
endLvl := pol.DefInt("endLvl", 26.0, core.PNorm(3, 30))
|
||||
maxSafeOrders := pol.DefInt("maxSafeOrders", 30, core.PNorm(5, 50))
|
||||
|
||||
lenAtr := 20
|
||||
baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
|
||||
var rates []float64
|
||||
// 14/15/16/17/18/19/20/21/22/23/24/25/26
|
||||
return &strat.TradeStrat{
|
||||
WarmupNum: 1,
|
||||
HedgeOff: true, // 单向持仓
|
||||
RunTimeFrames: []string{"15m"},
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
// 初始化策略状态
|
||||
s.More = &DCAStrategyState{}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
state, _ := s.More.(*DCAStrategyState)
|
||||
|
||||
// 计算OHLC4加权均价
|
||||
price := (e.High.Get(0) + e.Low.Get(0) + e.Close.Get(0) + e.Open.Get(0)) / 4
|
||||
closeP := e.Close.Get(0)
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
|
||||
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
|
||||
openRate := 0.004 * closeP / atrBase
|
||||
if openRate < 1 {
|
||||
openRate = math.Sqrt(openRate)
|
||||
}
|
||||
openRate = max(0.7, min(1.5, openRate))
|
||||
|
||||
// 计算止盈水平
|
||||
hasOrders := state.currentSO > 0
|
||||
var avgPrice, realAvgPrice float64
|
||||
if hasOrders && state.totalQtys > 0 {
|
||||
avgPrice = state.totalCost / state.totalQtys
|
||||
realAvgPrice = state.realTotCost / state.realTotQtys
|
||||
}
|
||||
takeProfitLevel := avgPrice * (1 + takeProfit/100)
|
||||
|
||||
// 初始建仓逻辑
|
||||
if state.currentSO == 0 && price > 0 {
|
||||
// 计算买入数量
|
||||
qty := baseOrder / price
|
||||
// 首次买入表现不佳,禁止实际买入
|
||||
state.totalQtys += qty
|
||||
state.totalCost += qty * closeP
|
||||
state.firstPrice = price
|
||||
state.currentSO = 1
|
||||
}
|
||||
|
||||
// 计算安全订单触发价格阈值
|
||||
priceRate := priceDeviation / 100
|
||||
threshold := calculateSafetyOrderThreshold(state.firstPrice, priceRate, stepScale, state.currentSO)
|
||||
|
||||
// 动态补仓逻辑
|
||||
if hasOrders && price <= threshold && state.currentSO <= maxSafeOrders {
|
||||
// 计算补仓数量
|
||||
orderQty := baseOrder * openRate * math.Pow(volumeScale, float64(state.currentSO-1)) / price
|
||||
|
||||
// endLvl用于实际下单。maxSafeOrders用于止盈价格
|
||||
if state.currentSO >= startLvl && state.currentSO <= endLvl {
|
||||
s.OpenOrder(&strat.EnterReq{
|
||||
Tag: fmt.Sprintf("%v", state.currentSO),
|
||||
Amount: orderQty,
|
||||
Log: true,
|
||||
})
|
||||
state.realTotQtys += orderQty
|
||||
state.realTotCost += orderQty * closeP
|
||||
}
|
||||
|
||||
state.totalQtys += orderQty
|
||||
state.totalCost += orderQty * closeP
|
||||
state.currentSO += 1
|
||||
}
|
||||
|
||||
// 止盈平仓逻辑
|
||||
if price >= takeProfitLevel && hasOrders {
|
||||
s.CloseOrders(&strat.ExitReq{
|
||||
Tag: "TakeProfit",
|
||||
})
|
||||
if realAvgPrice > 0 {
|
||||
rates = append(rates, takeProfitLevel/realAvgPrice)
|
||||
}
|
||||
|
||||
// 重置状态变量
|
||||
state.currentSO = 0
|
||||
state.totalQtys = 0.0
|
||||
state.totalCost = 0
|
||||
state.realTotQtys = 0
|
||||
state.realTotCost = 0
|
||||
state.firstPrice = 0
|
||||
}
|
||||
},
|
||||
OnShutDown: func(s *strat.StratJob) {
|
||||
if len(rates) == 0 {
|
||||
return
|
||||
}
|
||||
sort.Float64s(rates)
|
||||
step := len(rates) / 7
|
||||
for i := 0; i < len(rates); i += step {
|
||||
block := rates[i:min(len(rates), i+step)]
|
||||
avg := floats.Sum(block) / float64(len(block))
|
||||
fmt.Printf("rate: %v: %v\n", i, avg)
|
||||
}
|
||||
rates = nil
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user