Files
banstagy/old/macd_v1.go
2026-08-24 20:53:21 +08:00

128 lines
3.2 KiB
Go
Raw Permalink 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 old
import (
"fmt"
"github.com/banbox/banbot/btime"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banexg/log"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"go.uber.org/zap"
)
func MACD(pol *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
Version: 1,
WarmupNum: 300,
MinTfScore: 0.75,
DrawDownExit: true,
OnStartUp: onStartUp,
OnBar: onBar,
}
}
type MoreMACD struct {
*com.ExmTrace
max1 *com.ExmItem
max2 *com.ExmItem
slope float64 // 斜率
delta float64 // 直线偏移值
}
/*
val: 当前指标值
pNum: 前一个索引
ptime:前一个时间戳
*/
func (m *MoreMACD) update(val float64, pNum int, ptime int64) bool {
if m.ExmTrace.Update(val, pNum, ptime) {
var exm *com.ExmItem
last := m.Hist[len(m.Hist)-1]
if last.Valid && m.ExmTrace.Expect < 0 {
exm = last
} else if len(m.Hist) > 1 && m.ExmTrace.Expect > 0 {
exm = m.Hist[len(m.Hist)-2]
} else {
return false
}
// 更新最高点和次高点
if m.max1 == nil || exm.Value >= m.max1.Value {
m.max1 = exm
m.max2 = nil
} else if m.max1 != nil && pNum-exm.BarNum > 500 {
// 最高点超过500个bar过期
if m.max2 != nil && m.max2.Value > exm.Value {
exm = m.max2
}
m.max1 = m.max2
m.max2 = nil
} else if m.max2 == nil || exm.Value > m.max2.Value {
m.max2 = exm
return true
}
}
return false
}
func onStartUp(s *strat.StratJob) {
s.More = &MoreMACD{
ExmTrace: &com.ExmTrace{},
}
}
func onBar(s *strat.StratJob) {
e := s.Env
macd, _ := ta.MACD(e.Close, 12, 26, 9)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
m, _ := s.More.(*MoreMACD)
c := e.Close.Get(0)
if m.slope > 0 && m.max1 != nil && m.max2 != nil {
point := m.slope*float64(e.BarNum) + m.delta
tag := ""
stopLoss := float64(0)
if c-atr*2 > point && len(s.LongOrders) == 0 {
// 突破压力线,做多
tag = "long"
stopLoss = point - atr
} else if c+atr*0.5 > point && c <= point+atr && len(s.ShortOrders) == 0 {
// 触发压力线,开空
tag = "short"
stopLoss = max(c, point) + atr*2
}
if tag != "" && !s.IsWarmUp {
price1 := e.Close.Get(e.BarNum - m.max1.BarNum)
price2 := e.Close.Get(e.BarNum - m.max2.BarNum)
date := btime.ToDateStr(e.TimeStop, "")
date1 := btime.ToDateStr(m.max1.TimeMS, "")
date2 := btime.ToDateStr(m.max2.TimeMS, "")
log.Info(fmt.Sprintf("%s open %s, %s %s %.5f - %s %.5f", date, tag, s.Symbol.Symbol,
date1, price1, date2, price2))
err := s.OpenOrder(&strat.EnterReq{
Tag: tag,
StopLoss: stopLoss,
Short: tag == "short",
})
if err != nil {
log.Error("open fail", zap.Error(err))
}
}
}
if m.update(macd.Get(0), e.BarNum-1, e.TimeStart-e.TFMSecs) {
price1 := e.Close.Get(e.BarNum - m.max1.BarNum)
price2 := e.Close.Get(e.BarNum - m.max2.BarNum)
// 更新斜率和偏移值
m.slope = (price2 - price1) / float64(m.max2.BarNum-m.max1.BarNum)
m.delta = price1 - m.slope*float64(m.max1.BarNum)
//date1 := btime.ToDateStr(m.max1.TimeMS, "")
//date2 := btime.ToDateStr(m.max2.TimeMS, "")
//log.Info(fmt.Sprintf("update pt2, %s %s %.5f - %s %.5f", s.Symbols.Symbols,
// date1, price1, date2, price2))
}
}