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)) } }