100 lines
2.4 KiB
Go
100 lines
2.4 KiB
Go
package llmjob
|
||
|
||
import (
|
||
"math"
|
||
|
||
"github.com/banbox/banbot/config"
|
||
"github.com/banbox/banbot/core"
|
||
"github.com/banbox/banbot/strat"
|
||
ta "github.com/banbox/banta"
|
||
)
|
||
|
||
// fErf 实现Horner方法的误差函数
|
||
func fErf(x float64) float64 {
|
||
nT := 1.0 / (1.0 + 0.5*math.Abs(x))
|
||
nAns := 1.0 - nT*math.Exp(-x*x-1.26551223+
|
||
nT*(1.00002368+nT*(0.37409196+nT*(0.09678418+
|
||
nT*(-0.18628806+nT*(0.27886807+nT*(-1.13520398+
|
||
nT*(1.48851587+nT*(-0.82215223+nT*(0.17087277))))))))))
|
||
if x >= 0 {
|
||
return nAns
|
||
}
|
||
return -nAns
|
||
}
|
||
|
||
// fPSignal 计算P-Signal指标
|
||
func fPSignal(series *ta.Series, period int) *ta.Series {
|
||
res := series.To("_psignal", period)
|
||
if res.Cached() {
|
||
return res
|
||
}
|
||
|
||
if series.Len() < period {
|
||
return res.Append(math.NaN())
|
||
}
|
||
|
||
nStDev := ta.StdDev(series, period)
|
||
nSma := ta.SMA(series, period)
|
||
|
||
stdevVal := nStDev.Get(0)
|
||
smaVal := nSma.Get(0)
|
||
|
||
var rawPSignal float64
|
||
if stdevVal > 0 {
|
||
rawPSignal = fErf(smaVal / (stdevVal * math.Sqrt(2)))
|
||
} else {
|
||
rawPSignal = math.Copysign(1.0, smaVal)
|
||
}
|
||
|
||
return res.Append(rawPSignal)
|
||
}
|
||
|
||
func J7096(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||
nPoints := pol.DefInt("nPoints", 13, core.PUniform(4, 50))
|
||
|
||
return &strat.TradeStrat{
|
||
Name: "P-Signal Strategy",
|
||
WarmupNum: nPoints + 10, // 额外预留空间确保计算准确
|
||
HedgeOff: true, // 单向持仓模式
|
||
EachMaxLong: 1, // 最多一个多头仓位
|
||
TimeFrames: "8h",
|
||
OnBar: func(s *strat.StratJob) {
|
||
e := s.Env
|
||
nIntr := nPoints - 1
|
||
|
||
// 1. 计算价格变化 (ohlc4的变化量)
|
||
avgPrice := ta.AvgPrice(e)
|
||
priceChange := avgPrice.Sub(avgPrice.Back(1))
|
||
|
||
// 2. 计算P-Signal原始值
|
||
rawPSignal := fPSignal(priceChange, nIntr)
|
||
|
||
// 3. 计算平滑P-Signal
|
||
nPSignal := ta.SMA(rawPSignal, nIntr)
|
||
|
||
// 检查数据有效性
|
||
if nPSignal.Len() < 2 {
|
||
return
|
||
}
|
||
|
||
// 4. 计算P-Signal变化方向
|
||
currentPSignal := nPSignal.Get(0)
|
||
prevPSignal := nPSignal.Get(1)
|
||
ndPSignal := math.Copysign(1.0, currentPSignal-prevPSignal)
|
||
|
||
// 5. 生成交易信号
|
||
if currentPSignal < 0 && ndPSignal > 0 && len(s.LongOrders) == 0 {
|
||
// 开多条件:nPSignal < 0 and ndPSignal > 0
|
||
s.OpenOrder(&strat.EnterReq{
|
||
Tag: "long",
|
||
})
|
||
} else if currentPSignal > 0 && ndPSignal < 0 && len(s.LongOrders) > 0 {
|
||
// 平多条件:nPSignal > 0 and ndPSignal < 0
|
||
s.CloseOrders(&strat.ExitReq{
|
||
Tag: "close_long",
|
||
})
|
||
}
|
||
},
|
||
}
|
||
}
|