111 lines
2.5 KiB
Go
111 lines
2.5 KiB
Go
package ptn
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/banbox/banbot/config"
|
|
"github.com/banbox/banbot/strat"
|
|
ta "github.com/banbox/banta"
|
|
"math"
|
|
)
|
|
|
|
type tunmoMore struct {
|
|
topVal float64
|
|
btmVal float64
|
|
barNum int
|
|
}
|
|
|
|
/*
|
|
检查是否是吞没形态
|
|
*/
|
|
func isTunMo(e *ta.BarEnv) (int, float64, float64) {
|
|
o, h, l, c := GetMains(e, 0)
|
|
o1, h1, l1, c1 := GetMains(e, 1)
|
|
solid := math.Abs(o - c)
|
|
if solid/(h-l) < 0.6 {
|
|
// 第二个蜡烛实体至少60%
|
|
return 0, 0, 0
|
|
}
|
|
solid1 := math.Abs(o1 - c1)
|
|
if solid1/(h1-l1) <= 0.13 && solid > solid1*3 {
|
|
// 第一个是十字星,直接符合
|
|
if o > c {
|
|
return -1, min(l, l1), max(h, h1)
|
|
} else {
|
|
return 1, min(l, l1), max(h, h1)
|
|
}
|
|
}
|
|
if o < c {
|
|
// 后一个是阳线,要求前一个是阴线
|
|
if o1 > c1 && o1 <= c && c1 >= o {
|
|
// 前开<收盘 & 前收 > 开盘
|
|
return 1, min(l, l1), max(h, h1)
|
|
}
|
|
} else if o1 < c1 && c1 <= o && o1 >= c {
|
|
// 后一个阴线,要求前一个阳线
|
|
// 前收<开盘 & 前开 > 收盘
|
|
return -1, min(l, l1), max(h, h1)
|
|
}
|
|
return 0, 0, 0
|
|
}
|
|
|
|
func TunMo(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
|
const v1AtrLen = 14
|
|
return &strat.TradeStrat{
|
|
Version: 1,
|
|
WarmupNum: 30,
|
|
MinTfScore: 0.75,
|
|
DrawDownExit: true,
|
|
OnStartUp: func(s *strat.StratJob) {
|
|
s.More = &tunmoMore{}
|
|
},
|
|
OnBar: func(s *strat.StratJob) {
|
|
e := s.Env
|
|
// ma5 := ta.SMA(e.Close, 5).Get(1)
|
|
atr := ta.ATR(e.High, e.Low, e.Close, v1AtrLen)
|
|
baseAtrLen := int(math.Round(float64(v1AtrLen) * 4.3))
|
|
atrBase := ta.Lowest(ta.Highest(atr, v1AtrLen), baseAtrLen).Get(0)
|
|
|
|
//rsiCol := ta.RSI(e.Close, 14)
|
|
//rsi := rsiCol.Range(0, 2)
|
|
|
|
if math.IsNaN(atrBase) || s.OrderNum > 0 {
|
|
return
|
|
}
|
|
m, _ := s.More.(*tunmoMore)
|
|
mode, btmVal, topVal := isTunMo(e)
|
|
if mode != 0 && atr.Get(0) > atrBase*2 {
|
|
m.btmVal = btmVal - atrBase
|
|
m.topVal = topVal + atrBase
|
|
m.barNum = e.BarNum
|
|
}
|
|
if e.BarNum-m.barNum > 10 {
|
|
// 忽略吞没形态10个之后的蜡烛
|
|
return
|
|
}
|
|
c := e.Close.Get(0)
|
|
// slices.Max(rsi) > 70
|
|
// && c > ma5
|
|
if c > m.topVal {
|
|
stopLoss := max(m.topVal, c) + atr.Get(0)
|
|
err := s.OpenOrder(&strat.EnterReq{
|
|
Tag: "short",
|
|
StopLoss: stopLoss,
|
|
Short: true,
|
|
})
|
|
if err != nil {
|
|
fmt.Printf("open fail %v", err)
|
|
}
|
|
} else if c < m.btmVal {
|
|
stopLoss := min(m.btmVal, c) - atr.Get(0)
|
|
err := s.OpenOrder(&strat.EnterReq{
|
|
Tag: "long",
|
|
StopLoss: stopLoss,
|
|
})
|
|
if err != nil {
|
|
fmt.Printf("open fail %v", err)
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|