Files
banstagy/surge/alldown.go
2026-08-24 20:53:21 +08:00

158 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package surge
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
"sort"
)
/*
全市场瞬时暴跌做空策略。适用于十分钟跌去70%的情况。
可使用下面脚本回测:surge/down_test.go
E:\trade\go\bandata\backtest\bdb35c1d91\surge_alldown.log
*/
type AllDownSta struct {
volBase float64 // 平均成交量
dirtRate float64 // K线方向倍率,范围约:[-3,3]
barRate float64 // K线比率
volRate float64 // 成交量倍率
}
func AllDown(p *config.RunPolicyConfig) *strat.TradeStrat {
//var allowLog = false
lenAtr, lenAtrS := 20, 30
baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
baseAtrLenS := baseAtrLen * 3 / 2
env, _ := ta.NewBarEnv("", "", "", "1m")
lenS := env.NewSeries(nil)
volS := env.NewSeries(nil)
var prevLen float64
var volThres = 2.8
var openDirt float64
return &strat.TradeStrat{
WarmupNum: 150,
BatchInOut: true,
TimeFrames: "1m",
OnStartUp: func(s *strat.StratJob) {
s.More = &AllDownSta{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "15m", 100},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*AllDownSta)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtrS)
atrBase := ta.Lowest(ta.Highest(atr, lenAtrS), baseAtrLenS).Get(0)
o, c := e.Open.Get(0), e.Close.Get(0)
h, l := e.High.Get(0), e.Low.Get(0)
m.dirtRate = (c - o) / atrBase
m.barRate = (c - o) / (h - l)
m.volRate = ta.EMA(e.Volume, lenAtr).Get(0) / m.volBase
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*AllDownSta)
maVol := ta.EMA(e.Volume, lenAtr)
m.volBase = ta.Lowest(ta.Highest(maVol, lenAtr), baseAtrLen).Get(0) / 3
},
OnBatchJobs: func(jobs []*strat.StratJob) {
jobNum := len(jobs)
volRates := make([]float64, 0, jobNum)
lenRates := make([]float64, 0, jobNum)
solidRates := make([]float64, 0, jobNum)
volIds := make([]*core.Int64Flt, 0, jobNum)
var timeMS int64
for i, j := range jobs {
m, _ := j.More.(*AllDownSta)
volRates = append(volRates, m.volRate)
lenRates = append(lenRates, m.dirtRate)
solidRates = append(solidRates, m.barRate)
timeMS = max(timeMS, j.Env.TimeStop)
volIds = append(volIds, &core.Int64Flt{
Int: int64(i),
Val: m.volRate,
})
}
sort.Float64s(volRates)
sort.Float64s(lenRates)
sort.Float64s(solidRates)
vol := volRates[jobNum/2]
solid := solidRates[jobNum/2]
lenMid := lenRates[jobNum/2]
//len33 := lenRates[jobNum/3]
len66 := lenRates[jobNum*2/3]
val := lenMid + vol
env.TimeStop = max(timeMS, env.TimeStop)
if math.IsNaN(val) || math.IsInf(val, 0) || lenS.Cached() {
return
}
lenS.Append(lenMid)
volS.Append(vol)
dataLen := volS.Len()
if dataLen > env.MaxCache*2 {
volS.Cut(env.MaxCache)
lenS.Cut(env.MaxCache)
}
volMa1 := ta.SMA(volS, 3).Get(1)
low5len := ta.Lowest(lenS, 30).Get(1)
if openDirt >= -1 && vol > volThres && lenMid < low5len && len66 < 0 && solid < -0.5 && prevLen < 0 {
// 成交量突破阈值,全市场大阴线,前一个也是阴线
prevRate := lenMid / prevLen
if prevRate < 3 && prevRate > 1.5 && vol/volMa1 < 2 {
// 与前一个k线比率不超过3,成交量缓慢增长
openDirt -= 1
costRate := 2.0
if vol < 4 {
costRate *= vol / 4
}
sort.Slice(volIds, func(i, j int) bool {
return volIds[i].Val < volIds[j].Val
})
// 做空成交量最大的1/3部分,获利最丰(收益45%, 55%, 66%)
items := volIds[jobNum*2/3:]
for _, it := range items {
jobs[it.Int].OpenOrder(&strat.EnterReq{
Tag: "short",
CostRate: costRate,
Short: true,
})
}
}
}
if openDirt < 0 {
// 正在做空/多
if lenMid*openDirt < 0 {
openDirt = 0
for _, job := range jobs {
job.CloseOrders(&strat.ExitReq{
Tag: "exit",
Force: true,
})
}
}
}
prevLen = lenMid
//if !allowLog && vol > 2.5 {
// allowLog = true
//}
//if !math.IsNaN(vol) {
// jobs[0].Strat.WriteOutput(fmt.Sprintf("%.2f %.2f %.2f %.2f %.2f", vol, solid, lenMid, len33, len66), true)
// if vol < 1.4 {
// allowLog = false
// }
//}
},
}
}