This commit is contained in:
2026-08-24 20:53:21 +08:00
commit 6e78bba16a
287 changed files with 32443 additions and 0 deletions

177
org/ft/BBMod2.go Normal file
View File

@@ -0,0 +1,177 @@
package ft
import (
"github.com/banbox/banbot/orm/ormo"
"math"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"gonum.org/v1/gonum/floats"
)
/*
https://strat.ninja/overview.php?strategy=BBMod_2
BBMod1 modified from BB_RPB_TSL ( https://github.com/jilv220/BB_RPB_TSL )
@author jilv220
210101-241101 48品种 5m 收益570%,回撤9.3%
*/
type BBModSta struct {
bigEmaUp bool
atrBase float64
tmpHolds map[int64]bool
}
func BBMod2(pol *config.RunPolicyConfig) *strat.TradeStrat {
//emaDfRate := pol.Def("emaDf", 4, core.PNorm(1.5, 6))
lenAtr := int(pol.Def("atr", 29, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
DrawDownExit: true,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 100},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = &BBModSta{
tmpHolds: make(map[int64]bool),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*BBModSta)
c, c1 := e.Close.Get(0), e.Close.Get(1)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
m.atrBase = atrBase
closeDelta := math.Abs(c - e.Close.Get(1))
hlc3 := ta.AvgPrice(e)
_, bbMidC, bbLowC := ta.BBANDS(hlc3, 20, 2, 2)
bbMid, bbLow := bbMidC.Get(0), bbLowC.Get(0)
sma9 := ta.SMA(e.Close, 9).Get(0)
//sma15 := ta.SMA(e.Close, 15).Get(0)
//
//cti := ta.CTI(e.Close, 20).Get(0)
ema8 := ta.EMA(e.Close, 8).Get(0)
ema12S := ta.EMA(e.Close, 12)
ema12 := ema12S.Get(0)
ema16 := ta.EMA(e.Close, 16).Get(0)
//ema20 := ta.EMA(e.Close, 20).Get(0)
ema24 := ta.EMA(e.Close, 24).Get(0)
ema26S := ta.EMA(e.Close, 26)
ema26 := ema26S.Get(0)
ema50 := ta.EMA(e.Close, 50).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
ewo := (ema50 - ema200) / atrBase
rsi := ta.RSI(e.Close, 14).Get(0)
rsiFast := ta.RSI(e.Close, 4).Get(0)
rsiSlowS := ta.RSI(e.Close, 20)
rsiSlow := rsiSlowS.Get(0)
//rsi84 := ta.RSI(e.Close, 84).Get(0)
//rsi112 := ta.RSI(e.Close, 112).Get(0)
//crsi := ta.CRSIBy(e.Close, 3, 2, 100, 1).Get(0)
//heiKA := ta.HeikinAshi(e).Cols
//heiHlc3 := ta.HLC3(heiKA[1], heiKA[2], heiKA[3])
//bb40Cols := ta.BBANDS(heiHlc3, 40, 2, 2).Cols
//bb40Mid, bb40Low := bb40Cols[1].Get(0), bb40Cols[2].Get(0)
//bb40Low1 := bb40Cols[2].Get(1)
//bb40Delta := bb40Mid - bb40Low
//tail := math.Abs(heiKA[3].Get(0) - heiKA[2].Get(0))
//_, vwapLow := vwapB(hlc3, e.Volume, 20, 1)
//tcpPct4 := ta.Highest(e.Open, 4).Get(0)/c - 1
tryTmpHold := c > max(sma9, ema24-atrBase*0.2, bbMid) && rsi > 50 && rsiFast > rsiSlow
holdTags := make(map[string]bool)
for _, od := range s.LongOrders {
holdTags[od.EnterTag] = true
if od.ProfitRate < atrBase*4 {
if tryTmpHold {
m.tmpHolds[od.ID] = true
}
} else if _, ok := m.tmpHolds[od.ID]; ok {
delete(m.tmpHolds, od.ID)
}
}
if len(m.tmpHolds) > 0 && c < floats.Min(e.Low.Range(1, 4)) {
for oid := range m.tmpHolds {
s.CloseOrders(&strat.ExitReq{Tag: "sellDrop", OrderID: oid})
}
m.tmpHolds = make(map[int64]bool)
}
_ = c1
tag := ""
ema26_12rate := (ema26 - ema12) / atrBase
ema26_12rateP := (ema26S.Get(1) - ema12S.Get(1)) / atrBase
closeDeltaRate := closeDelta / atrBase
if ema26_12rateP > 2 && c < bbLow-atrBase*0.2 {
if ema26_12rate > 5 && closeDeltaRate > 3.5 {
//use origin bb_rpb_tsl value
tag = "up2"
}
// 略不稳定
//else if ema26_12rate > emaDfRate && closeDeltaRate > 2.4 {
// // from NFI next gen, credit goes to @iterativ
// tag = "up1"
//}
}
if rsiFast < 44 && ewo > -10 && c < min(ema8-atrBase*13, ema16-atrBase*6.4) && rsi < 23 {
// from sma offset
//tag = "ewo"
tag = "smo"
}
// 下面的要么不稳定,要么几乎没有订单
//} else if ema26_12rate > 4.8 && ema26_12rateP > 2 && c < ema20+atrBase*2.6 && rsi < 21 && crsi > 10 && closeDeltaRate > 2.4 {
// tag = "localDip"
//} else if rsiSlow < rsiSlowS.Get(1) && rsiFast < 46 && rsi > 19 && c < sma15-atrBase*11 && cti < -0.86 {
// tag = "nfi32"
//} else if m.bigEmaUp && bb40Delta > atrBase*11 && closeDeltaRate > 2 && tail < bb40Delta*0.5 &&
// c < bb40Low1 && c <= c1 && c > ema12-atrBase*17 {
// tag = "nfix39"
//}
//else if c < vwapLow.Get(0) && tcpPct4 > atrBase*8 && cti < -0.8 && rsi < 35 && rsi84 < 60 && rsi112 < 60 {
// tag = "vwap"
//}
if _, hasOld := holdTags[tag]; tag != "" && !hasOld {
s.OpenOrder(&strat.EnterReq{Tag: tag})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*BBModSta)
ema200 := ta.EMA(e.Close, 200)
cur, p12, p24 := ema200.Get(0), ema200.Get(12), ema200.Get(24)
m.bigEmaUp = cur > p12 && p12 > p24
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
m, _ := s.More.(*BBModSta)
if maxChg > m.atrBase*10 {
return 0.15
} else if maxChg > m.atrBase*4 {
return 0.2
}
return 0
},
}
}
/*
vwapB 应传入hlc3和qtpylib.rolling_vwap中保持一致
return [vwap, low]
*/
func vwapB(p, v *ta.Series, period int, rate float64) (*ta.Series, *ta.Series) {
vwap := ta.VWMA(p, v, period)
dev := ta.StdDev(vwap, period)
return vwap, vwap.Add(dev.Mul(-rate))
}

224
org/ft/BBMod7.go Normal file
View File

@@ -0,0 +1,224 @@
package ft
import (
"math"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://strat.ninja/overview.php?strategy=BBMod_7
48品种,210101-241101,盈利327%,回撤8.83%
*/
type BBMod7Sta struct {
bigEma200 *ta.Series
bigRoc float64
atrBase float64
bigBBWid2 float64
bigBBMid float64
bigT3 float64
}
func BBMod7(p *config.RunPolicyConfig) *strat.TradeStrat {
//lowRate := p.Def("lowRate", 6, core.PNorm(1, 3.5))
//highRate := p.Def("highRate", 15, core.PNorm(0.5, 2.5))
lenAtr := int(p.Def("atr", 13.35, core.PNorm(7, 25)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 300},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = &BBMod7Sta{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*BBMod7Sta)
o, c := e.Open.Get(0), e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
m.atrBase = atrBase
//sma15 := ta.SMA(e.Close, 15).Get(0)
//sma28 := ta.SMA(e.Close, 28).Get(0)
//tr := ta.TR(e.High, e.Low, e.Close)
//rangeMa28 := ta.SMA(tr, 28).Get(0)
//kcUpp28 := sma28 + rangeMa28
//kcLow28 := sma28 - rangeMa28
closeDelta := math.Abs(e.Close.Get(0) - e.Close.Get(1))
//rmi := ta.RMI(e.Close, 8, 4).Get(0)
//cci := ta.CCI(e.Close, 25).Get(0)
//srsiK := ta.StochRSI(e.Close, 15, 20, 2, 2).Cols[0].Get(0)
hlc3 := ta.HLC3(e.High, e.Low, e.Close)
bb2Up, _, bb2Dn := ta.BBANDS(hlc3, 20, 2, 2)
bb2Upp, bb2Low := bb2Up.Get(0), bb2Dn.Get(0)
//bb2Wid := (bb2Upp - bb2Low) / atrBase
//bb2Mid := bb2Cols[1].Get(0)
//bb3Cols := ta.BBANDS(hlc3, 20, 3, 3).Cols
//bb3Low := bb3Cols[2].Get(0)
//bbDelta := (bb2Cols[2].Get(0) - bb3Low) / atrBase
//ema13 := ta.EMA(e.Close, 13).Get(0)
ema8 := ta.EMA(e.Close, 8).Get(0)
//ema16 := ta.EMA(e.Close, 16).Get(0)
//ema20 := ta.EMA(e.Close, 20).Get(0)
ema50 := ta.EMA(e.Close, 50).Get(0)
//ema100 := ta.EMA(e.Close, 100).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
ewo := (ema50 - ema200) / atrBase
ema12S := ta.EMA(e.Close, 12)
ema26S := ta.EMA(e.Close, 26)
ema12, ema26 := ema12S.Get(0), ema26S.Get(0)
ema12P, ema26P := ema12S.Get(1), ema26S.Get(1)
//hh20 := ta.Highest(e.High, 20).Get(0)
//ll20 := ta.Lowest(e.Low, 20).Get(0)
//sma20 := ta.SMA(e.Close, 20).Get(0)
//linRegSrc := e.Close.To("_linRegSrc", 20)
//if !linRegSrc.Cached() {
// linRegSrc.Append(c - ((hh20+ll20)/2+sma20)/2)
//}
//linReg20 := ta.LinReg(linRegSrc, 20)
//rsi := ta.RSI(e.Close, 14).Get(0)
//rsiFast := ta.RSI(e.Close, 4).Get(0)
//rsiSlowS := ta.RSI(e.Close, 20)
//rsiSlow := rsiSlowS.Get(0)
//crsi := ta.CRSI(e.Close, 3, 2, 100).Get(0)
//lowWid := atrBase * lowRate
//highWid := atrBase * highRate
//emaEnt := c < ema8-lowWid && c < ema16+highWid
//
//volMa12 := ta.SMA(e.Volume, 12).Get(1)
//volMa24 := ta.SMA(e.Volume, 24).Get(1)
cti := ta.CTI(e.Close, 20).Get(0)
t3 := T3(e.Close, 5).Get(0)
fastD, _, fastK := ta.KDJBy(e.High, e.Low, e.Close, 5, 3, 3, "sma")
willR := ta.WillR(e, 14).Get(0)
//kdjRawX := fastK.Cross(fastD)
//
//adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0)
//
//vwapLow, _ := vwapB(hlc3, e.Volume, 20, 1)
//
//tcpPct := topPctChgDca(e.Open, e.Close, 4)
_, _, _ = o, bb2Upp, fastD
if fastK.Get(0) > 75 && s.OrderNum > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "fastk"})
return
}
for _, od := range s.LongOrders {
profit := (c - od.InitPrice) / atrBase
sl := od.GetStopLoss()
if profit > 15 {
sl.Price = od.InitPrice + atrBase*15
} else if profit > 6 {
sl.Price = od.InitPrice + atrBase*6
}
}
tag := ""
if ewo < -11 && m.bigBBMid >= m.bigT3 && t3 <= ema8-atrBase*6 && cti < -0.5 && willR < -60 {
//tag = "gumbo"
tag = "gb"
} else if ema26-ema12 > atrBase*5 && ema26P-ema12P > atrBase*2 &&
c < bb2Low-atrBase*0.6 && closeDelta > atrBase*3 {
//tag = "uptrend"
tag = "up"
}
//else if rmi < 35 && cci <= -133 && srsiK < 25 && bbDelta > 4.5 && bb2Wid > 18 && closeDelta > atrBase*3 &&
// c < bb3Low-atrBase*0.2 {
// // 略不稳定,可选
// tag = "BinH"
//}
// 下面的要么不稳定,要么几乎没有订单
// else if bb2Low < kcLow28 && bb2Upp > kcUpp28 && linReg20.Get(2) > linReg20.Get(1) &&
// linReg20.Get(1) < linReg20.Get(0) && linReg20.Get(0) < 0 && c < ema13-atrBase*6 &&
// ewo < 0 && willR < -50 {
// tag = "sqzmom"
//} else if m.bigEma200 != nil && m.bigEma200.Get(0) > m.bigEma200.Get(12) &&
// m.bigEma200.Get(12) > m.bigEma200.Get(24) &&
// rsiFast < 45 && emaEnt && ewo > 4.18 && rsi < 35 {
// tag = "ewo2"
//} else if ema100 < ema200+atrBase*16 && bb2Wid > 10 && c < bb2Mid && volMa12 < volMa24 && cti < -0.5 &&
// willR < -60 {
// // 亏损,效果差
// //tag = "deadfish"
//} else if m.bigRoc < 10 && m.bigBBWid2 < 60 && o < ema8-atrBase*6 && kdjRawX == 1 &&
// fastK.Get(0) < 20 && fastD.Get(0) < 20 && adx > 30 && ewo > 7 && cti < -0.5 && willR < -60 {
// tag = "cofi"
//} else if ema26-ema12 > atrBase*5 && ema26P-ema12P > atrBase*2 && c < ema20-atrBase*11 && rsi < 28 &&
// crsi > 10 && closeDelta > atrBase*3 {
// tag = "localDip"
//} else if rsiFast < 45 && c < ema8-atrBase*11 && ewo > -5.585 && c < ema16+atrBase*16 && rsi < 35 {
// tag = "ewo"
//} else if rsiSlow < rsiSlowS.Get(1) && rsiFast < 46 && rsi > 19 && c < sma15-atrBase*11 && cti < -0.86 {
// tag = "nfi32"
//} else if c < vwapLow.Get(0) && tcpPct > 4 && cti < -0.86 && rsi < 35 {
// tag = "vwap"
//}
if tag != "" && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: tag,
StopLossVal: atrBase * 20,
})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*BBMod7Sta)
m.bigEma200 = ta.EMA(e.Close, 200)
m.bigRoc = ta.ROC(e.Close, 9).Get(0)
hlc3 := ta.HLC3(e.High, e.Low, e.Close)
bb2Up, bb2Mid, bb2Dn := ta.BBANDS(hlc3, 20, 2, 2)
bb2Upp, bb2Low := bb2Up.Get(0), bb2Dn.Get(0)
m.bigBBWid2 = (bb2Upp - bb2Low) / m.atrBase
m.bigBBMid = bb2Mid.Get(0)
m.bigT3 = T3(e.Close, 5).Get(0)
},
}
}
/*
T3 Average by HPotter on Tradingview
https://www.tradingview.com/script/qzoC9H1I-T3-Average/
*/
func T3(p *ta.Series, period int) *ta.Series {
res := p.To("_t3", period)
if res.Cached() {
return res
}
xe1 := ta.EMA(p, period)
xe2 := ta.EMA(xe1, period)
xe3 := ta.EMA(xe2, period)
xe4 := ta.EMA(xe3, period)
xe5 := ta.EMA(xe4, period)
xe6 := ta.EMA(xe5, period)
b := 0.7
c1 := -b * b * b
c2 := 3*b*b + 3*b*b*b
c3 := -6*b*b - 3*b - 3*b*b*b
c4 := 1 + 3*b + b*b*b + 3*b*b
val := c1*xe6.Get(0) + c2*xe5.Get(0) + c3*xe4.Get(0) + c4*xe3.Get(0)
return res.Append(val)
}

View File

@@ -0,0 +1,80 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
https://strat.ninja/overview.php?strategy=BinHModWhiteHOV0
收益太低,210101-241101,48品种,15%收益,回撤3.4%
*/
func BinHModWhiteHOV0(pol *config.RunPolicyConfig) *strat.TradeStrat {
bbWidthVal := pol.Def("bb_width", 13.5, core.PNorm(1, 15))
bbDeltaDiff := pol.Def("bb_delta_diff", 4.4, core.PNorm(0.2, 12))
bbTailDiff := pol.Def("bb_tail_diff", 0.132, core.PNorm(0.05, 0.450))
bbBottomDeltaDiff := pol.Def("bb_bottom_delta_diff", 1.1, core.PNorm(0.8, 8))
bbTopDeltaDiff := pol.Def("bb_top_delta_diff", 2.5, core.PNorm(1, 18))
emaRise := int(pol.Def("ema_rise", 54, core.PNorm(6, 60)))
emaSlowPeriod := int(pol.Def("ema_slow", 160, core.PNorm(140, 300)))
emaTrendPeriod := int(pol.Def("ema_trend", 90, core.PNorm(50, 110)))
ewoBaseLen := int(pol.Def("ewo_base", 70, core.PNorm(50, 150)))
ewoStepLen := int(pol.Def("ewo_step", 90, core.PNorm(10, 150)))
ewoHigh := pol.Def("ewo_high", 6, core.PNorm(1.0, 12.0))
highOffset := pol.Def("high_offset", 0.0, core.PNorm(0.0, 4))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
bottom := e.Open.Min(e.Close)
up := e.Open.Max(e.Close)
bbUp, bbMd, bbDn := ta.BBANDS(e.Close, 40, 2.0, 2.0)
bbUpp, bbMid, bbLow := bbUp.Get(0), bbMd.Get(0), bbDn.Get(0)
bbWidthRaw := e.Close.To("_bbWid", 40)
if !bbWidthRaw.Cached() {
bbWidthRaw.Append((bbUpp - bbLow) / atrBase)
}
space := ta.SMA(bbWidthRaw, 60).Get(0)
bbDelta := bbMid - bbLow
bottomDelta := math.Abs(bottom.Get(0) - bottom.Get(1))
topDelta := math.Abs(up.Get(0) - up.Get(1))
tail := bottom.Get(0) - e.Low.Get(0)
emaTrend := ta.EMA(e.Close, emaTrendPeriod)
emaSlower := ta.EMA(e.Close, emaSlowPeriod)
ema1 := ta.EMA(e.Close, ewoBaseLen).Get(0)
ema2 := ta.EMA(e.Close, ewoBaseLen+ewoStepLen).Get(0)
ewo := (ema1 - ema2) / atrBase
buyProtection1 := emaTrend.Get(0) > emaSlower.Get(0)
buyProtection2 := emaSlower.Get(0) > emaSlower.Get(emaRise) &&
emaSlower.Get(emaRise) > emaSlower.Get(emaRise*2)
buyProtection3 := ewo > ewoHigh
if buyProtection1 && buyProtection2 && buyProtection3 &&
space > bbWidthVal && s.OrderNum == 0 &&
bottom.Get(0) < math.Min(bottom.Get(1), bbDn.Get(1)) &&
bbDelta > atrBase*bbDeltaDiff &&
tail < bbDelta*bbTailDiff &&
bottomDelta > atrBase*bbBottomDeltaDiff &&
topDelta < atrBase*bbTopDeltaDiff &&
bbDn.Get(1) > 0 {
s.OpenOrder(&strat.EnterReq{Tag: "buy"})
}
if e.Close.Get(0) > bbMid+atrBase*highOffset {
s.CloseOrders(&strat.ExitReq{Tag: "sell"})
}
},
}
}

101
org/ft/BinHV27.go Normal file
View File

@@ -0,0 +1,101 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://strat.ninja/overview.php?strategy=BinHV27_long
亏损,无效策略
*/
func BinHV27(p *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr := int(p.Def("atr", 29, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
ema60 := ta.EMA(e.Close, 60).Get(0)
ema120 := ta.EMA(e.Close, 120).Get(0)
sma120 := ta.SMA(e.Close, 120)
sma240 := ta.SMA(e.Close, 240)
plusDi, minusDi := ta.PluMinDI(e.High, e.Low, e.Close, 14)
minDiMa := ta.EMA(minusDi, 25).Get(0)
adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0)
rsi := ta.RSI(e.Close, 5)
rsiMa := ta.EMA(rsi, 5).Get(0)
minDiOk := minusDi.Get(0) > minDiMa
rsiOk := rsi.Get(0) >= rsi.Get(1)
bigTrendChg := sma120.Get(0)-sma240.Get(0) > sma120.Get(1)-sma240.Get(1)
bigContiUp := sma240.Get(0) > sma240.Get(1) && sma240.Get(1) > sma240.Get(2)
bigUp := (sma120.Get(0) - sma240.Get(0)) > atrBase*0.7
bigDown := !bigUp
bigTrendChgCfm := bigTrendChg && sma120.Get(1)-sma240.Get(1) > sma120.Get(2)-sma240.Get(2)
slowDown := sma120.Get(0)-sma120.Get(1) < sma120.Get(1)-sma120.Get(2)
if s.OrderNum > 0 {
exitTag := ""
if !bigTrendChgCfm && !bigContiUp && c > min(ema60, ema120) && bigDown {
exitTag = "exit1"
} else if !bigTrendChgCfm && !bigContiUp && c > ema120 && (rsiMa > 75 || c > sma240.Get(0)) && bigDown {
exitTag = "exit2"
} else if !bigTrendChgCfm && c > ema120 && adx > 30 && rsiMa >= 80 && bigUp {
exitTag = "exit3"
} else if bigTrendChgCfm && !bigContiUp && slowDown && rsiMa >= 75 {
exitTag = "exit4"
} else if bigTrendChgCfm && minusDi.Get(0) < plusDi.Get(0) && c > ema60 {
exitTag = "exit5"
}
for _, od := range s.LongOrders {
profit := (c - od.InitPrice) / atrBase
if profit <= 3 && exitTag != "" {
s.CloseOrders(&strat.ExitReq{Tag: exitTag, OrderID: od.ID})
continue
}
sl := od.GetStopLoss()
var newSl float64
if profit > 16 {
newSl = c - atrBase*8
} else if profit > 3 {
newSl = od.InitPrice + atrBase*profit*0.5
}
if newSl > sl.Price {
sl.Price = newSl
}
}
}
tag := ""
if c < min(ema120, ema60) && minDiOk && rsiOk {
if !bigTrendChg && !bigContiUp && adx > 25 && bigDown && rsiMa <= 20 {
tag = "buy1"
} else if !bigTrendChg && bigContiUp && adx > 30 && bigDown && rsiMa <= 20 {
tag = "buy2"
} else if !bigContiUp && adx > 35 && bigUp && rsiMa <= 20 {
tag = "buy3"
} else if bigContiUp && adx > 30 && bigUp && rsiMa <= 25 {
tag = "buy4"
}
}
if tag != "" && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: tag,
StopLossVal: atrBase * 16,
})
}
},
}
}

81
org/ft/Cenderawasih.go Normal file
View File

@@ -0,0 +1,81 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
func CenderaWasih3(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 超参数解析
hmaLen := int(pol.Def("hmaLen", 42, core.PNorm(5, 100)))
hmaOffRate := pol.Def("hmaOffRate", 20, core.PNorm(2, 80))
zemaLen := int(pol.Def("zemaLen", 93, core.PNorm(5, 100)))
zemaHighRate := pol.Def("zemaHighRate", 18, core.PNorm(1, 30))
zemaLowRate := pol.Def("zemaLowRate", 24, core.PNorm(2, 50))
emaShortLen1 := int(pol.Def("emaShort1", 31, core.PNorm(5, 100)))
emaHighRate1 := pol.Def("emaHigh1", 0.0, core.PNorm(0, 30))
emaShortLen2 := int(pol.Def("emaShort2", 91, core.PNorm(5, 100)))
emaHighRate2 := pol.Def("emaHigh2", 22.5, core.PNorm(0, 40))
emaShortLenL1 := int(pol.Def("emaShortL1", 87, core.PNorm(5, 100)))
emaLowRate1 := pol.Def("emaLow1", 32, core.PNorm(2, 60))
emaShortLenL2 := int(pol.Def("emaShortL2", 98, core.PNorm(5, 100)))
emaLowRate2 := pol.Def("emaLow2", 6, core.PNorm(2, 60))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 200,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
hmaLow := ta.HMA(e.Close, hmaLen).Get(0) - atrBase*hmaOffRate
// 计算ZEMA指标
ema1 := ta.EMA(e.Close, zemaLen)
ema2 := ta.EMA(ema1, zemaLen)
zema := ema1.Add(ema1.Sub(ema2)).Get(0)
// 计算ZEMA偏移量
zemaHigh, zemaLow := zema+atrBase*zemaHighRate, zema-atrBase*zemaLowRate
emaHigh1 := ta.EMA(e.Close, emaShortLen1).Get(0) + atrBase*emaHighRate1
emaHigh2 := ta.EMA(e.Close, emaShortLen2).Get(0) + atrBase*emaHighRate2
emaLow1 := ta.EMA(e.Close, emaShortLenL1).Get(0) - atrBase*emaLowRate1
emaLow2 := ta.EMA(e.Close, emaShortLenL2).Get(0) - atrBase*emaLowRate2
// 买入条件
if c < hmaLow && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "buy",
})
}
exitTag := ""
if c > zemaHigh {
exitTag = "zemaHigh"
} else if c < zemaLow {
exitTag = "zemaLow"
} else if c > emaHigh1 {
exitTag = "emaH1"
} else if c > emaHigh2 {
exitTag = "emaH2"
} else if c < emaLow1 {
exitTag = "emaL1"
} else if c < emaLow2 {
exitTag = "emaL2"
}
if exitTag != "" {
s.CloseOrders(&strat.ExitReq{
Tag: exitTag,
})
}
},
}
}

108
org/ft/Clucha.go Normal file
View File

@@ -0,0 +1,108 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
https://strat.ninja/overview.php?strategy=ch
48个品种 210101-241101 289% 回撤14%
整体盈利,中间部分不稳定回撤
*/
type CSSta struct {
ROC1h float64
}
func Clucha(pol *config.RunPolicyConfig) *strat.TradeStrat {
BbdeltaClose := pol.Def("BbdeltaClose", 3.5, core.PNorm(2, 10))
BbdeltaTail := pol.Def("BbdeltaTail", 0.72235, core.PNorm(0.7, 1.2))
CloseBblower := pol.Def("CloseBblower", 2.3, core.PNorm(0.2, 10))
ClosedeltaClose := pol.Def("ClosedeltaClose", 1.8, core.PNorm(0.2, 10))
Rocr1h := pol.Def("Rocr1h", 0.79492, core.PNorm(0.1, 1.0))
sellFastx := pol.Def("sellFastx", 75, core.PUniform(50, 100))
sellDeadfishBbWidth := pol.Def("sellDeadfishBbWidth", 10, core.PUniform(6, 100))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 50,
EachMaxLong: 1, // 每个品种最多开1单
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 200},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = &CSSta{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*CSSta)
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
// 计算指标
_, haHigh, haLow, haClose := ta.HeikinAshi(e)
hahlc3 := ta.HLC3(haHigh, haLow, haClose)
_, mid, lower := ta.BBANDS(hahlc3, 40, 2, 2)
bbdelta := mid.Get(0) - lower.Get(0)
closedelta := math.Abs(haClose.Get(0) - haClose.Get(1))
tail := math.Abs(haClose.Get(0) - haLow.Get(0))
emaSlow := ta.EMA(haClose, 50).Get(0)
hlc3 := ta.HLC3(e.High, e.Low, e.Close)
bb20Up, bb20Md, bb20Dn := ta.BBANDS(hlc3, 20, 2, 2)
bb20Wid := (bb20Up.Get(0) - bb20Dn.Get(0)) / atrBase
bb20Mid := bb20Md.Get(0)
fastK := ta.Stoch(e.High, e.Low, e.Close, 5).Get(0)
volMa12 := ta.SMA(e.Volume, 12).Get(1)
volMa24 := ta.SMA(e.Volume, 24).Get(1)
// 买入条件
isEwo := m.ROC1h > Rocr1h &&
((lower.Get(1) > 0 &&
bbdelta > atrBase*BbdeltaClose &&
closedelta > atrBase*ClosedeltaClose &&
tail < bbdelta*BbdeltaTail &&
haClose.Get(0) < lower.Get(1) &&
haClose.Get(0) <= haClose.Get(1)) ||
(haClose.Get(0) < emaSlow && haClose.Get(0) < lower.Get(0)-CloseBblower*atrBase))
if isEwo && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{Tag: "buy_ewo"})
}
// 自定义卖出逻辑
for _, od := range s.LongOrders {
holdNum := e.BarCount(od.EnterAt)
profit := (c - od.InitPrice) / atrBase
exitTag := ""
if profit > 0 && fastK > sellFastx {
exitTag = "fastx"
} else if holdNum > 11.5 && profit > -2 && fastK > sellFastx {
exitTag = "kalah"
} else if holdNum > 288 && profit > -10 && fastK > sellFastx {
exitTag = "lama"
} else if profit < -10 && bb20Wid < sellDeadfishBbWidth && c > bb20Mid && volMa12 < volMa24 {
exitTag = "deadfish"
}
if exitTag != "" {
s.CloseOrders(&strat.ExitReq{OrderID: od.ID, Tag: exitTag})
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*CSSta)
_, _, _, haClose := ta.HeikinAshi(e)
m.ROC1h = ta.ROC(haClose, 168).Get(0)
},
}
}

79
org/ft/HPSV7.go Normal file
View File

@@ -0,0 +1,79 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
https://github.com/mkajnar/DailyBuyStrategy
历史提交中的策略
*/
type hpsState struct {
downBar int // 连续下跌的bar数量
chg3MA float64 // 间隔3个bar的价格变化率均值
}
func HPSV7Ultra(pol *config.RunPolicyConfig) *strat.TradeStrat {
// donchLen := int(pol.Def("donchLen", 23, core.PNorm(5, 50)))
rsiThs := pol.Def("rsiThs", 35, core.PNorm(10, 50))
cciThs := pol.Def("cciThs", -100, core.PNorm(-200, -10))
kickOffThs := -pol.Def("kickOffThs", 10, core.PNorm(1, 30))
minRedNum := int(math.Round(pol.Def("minRedNum", 1, core.PNorm(0.7, 5.3))))
chgRate1 := pol.Def("chgRate1", 0.3, core.PNorm(0.05, 2))
chgRate2 := pol.Def("chgRate2", 2, core.PNorm(0.5, 5))
lenAtr := int(pol.Def("atr", 29, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
chgAlpha := 0.35
return &strat.TradeStrat{
WarmupNum: 100,
OnStartUp: func(s *strat.StratJob) {
s.More = &hpsState{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*hpsState)
cc := e.Close
o, c := e.Open.Get(0), e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
if c < o {
m.downBar += 1
} else {
m.downBar = 0
}
chg3 := c/cc.Get(3) - 1
if !math.IsNaN(chg3) {
m.chg3MA = m.chg3MA*(1-chgAlpha) + chg3*chgAlpha
}
rsi := ta.RSI(e.Close, 14).Get(0)
cci := ta.CCI(e.Close, 20).Get(0)
// swingLow := cc.Get(1) < min(c, cc.Get(2))
swingHigh := cc.Get(1) > max(c, cc.Get(2))
//donUpp := ta.Highest(e.High, donchLen).Get(0)
//donLow := ta.Lowest(e.Low, donchLen).Get(0)
//donMid := (donUpp + donLow) / 2
// 原始策略入场要求close>donMid并记录到字段,但没有close<donMid时改回去的逻辑,实际上未生效
chg3Rate := m.chg3MA / (atrBase / c)
chg3RateAbs := math.Abs(chg3Rate)
if swingHigh {
s.CloseOrders(&strat.ExitReq{Tag: "swingHigh"})
} else if chg3Rate <= kickOffThs {
s.CloseOrders(&strat.ExitReq{Tag: "kickOff"})
} else if m.downBar >= minRedNum && rsi < rsiThs && cci < cciThs &&
chg3RateAbs > chgRate1 && chg3RateAbs < chgRate2 && s.OrderNum == 0 {
//(swingLow || c < donLow || c > donMid) &&
s.OpenOrder(&strat.EnterReq{Tag: "long"})
}
},
}
}

144
org/ft/MadV9HO.go Normal file
View File

@@ -0,0 +1,144 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
https://strat.ninja/overview.php?strategy=MadV9HO
48个品种,210101-241101 收益360% 回撤5.9% 夏普11
*/
type MadV9HOSta struct {
bigEma50 float64
bigEma200 float64
bigRsi float64
bigSSLUp float64
bigSSLDn float64
}
func MadV9HO(p *config.RunPolicyConfig) *strat.TradeStrat {
//bbLowRate1 := p.Def("bbLowRate1", 2, core.PNorm(0.5, 10))
//bbLowRate2 := p.Def("bbLowRate2", 3.6, core.PNorm(0.0, 10))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 200},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = &MadV9HOSta{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*MadV9HOSta)
o, c := e.Open.Get(0), e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
hlc3 := ta.HLC3(e.High, e.Low, e.Close)
bbUpp, bbMid, bbLow := ta.BBANDS(hlc3, 20, 2, 2)
//volMa := ta.SMA(e.Volume, 30)
ema12S := ta.EMA(e.Close, 12)
ema26S := ta.EMA(e.Close, 26)
ema12, ema26 := ema12S.Get(0), ema26S.Get(0)
ema12P, ema26P := ema12S.Get(1), ema26S.Get(1)
//ema200 := ta.EMA(e.Close, 200).Get(0)
//
//rsi := ta.RSI(e.Close, 14).Get(0)
//sma5 := ta.SMA(e.Close, 5).Get(0)
tag := ""
volOk := e.Volume.Get(0) < e.Volume.Get(1)*8
//vol30ok := volMa.Get(0) > volMa.Get(30)*0.5
_, _, _ = m, o, bbUpp
if ema26-ema12 > atrBase*6 && ema26P-ema12P > atrBase*2 && c < bbLow.Get(0) && volOk {
tag = "buy6"
}
// 下面的要么不稳定,要么几乎没有订单
//if c > max(ema200, m.bigEma200) && c < bbLow.Get(0)-atrBase*bbLowRate1 && vol30ok &&
// volOk && o-c < bbUpp.Get(2)-bbLow.Get(2) {
// tag = "buy1"
//} else if c > ema200 && c < bbLow.Get(0)-atrBase*bbLowRate2 && vol30ok &&
// volOk && o-c < bbUpp.Get(2)-bbLow.Get(2) {
// // 订单很少,盈利很少
// //tag = "buy2"
//} else if c > m.bigEma200 && c < bbLow.Get(0) && rsi < 8.5 && volOk {
// // 订单很少,盈利很少
// //tag = "buy3"
//} else if m.bigRsi < 10.3 && c < bbLow.Get(0) && volOk {
// // 小额亏损
// //tag = "buy4"
//} else if c > max(ema200, m.bigEma200) && ema26-ema12 > atrBase*18 && ema26P-ema12P > atrBase*2 &&
// c < bbLow.Get(0) && volOk && vol30ok {
// tag = "buy5"
//} else if m.bigRsi < 13 && ema26-ema12 > atrBase*18 && ema26P-ema12P > atrBase*2 && volOk && vol30ok {
// // 订单很少,盈利很少
// //tag = "buy7"
//} else if m.bigRsi < 12.2 && rsi < 39.6 && volOk && vol30ok {
// tag = "buy8"
//} else if m.bigRsi < 18 && rsi < 24.2 && volOk && vol30ok {
// tag = "buy9"
//} else if c < sma5 && m.bigSSLUp > m.bigSSLDn && m.bigEma50 > m.bigEma200 && rsi < m.bigRsi-43.69 {
// tag = "buy10"
//}
if tag != "" && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{Tag: tag})
}
for _, od := range s.LongOrders {
holdNum := int(math.Round(e.BarCount(od.EnterAt)))
if holdNum >= 10 && od.ProfitRate < 0 && c+atrBase*3 < e.Open.Get(holdNum) {
od.SetStopLoss(&ormo.ExitTrigger{Price: c - atrBase*2})
}
}
if s.OrderNum > 0 && c > bbMid.Get(0)+atrBase*2 {
s.CloseOrders(&strat.ExitReq{Tag: "sell"})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*MadV9HOSta)
m.bigEma50 = ta.EMA(e.Close, 50).Get(0)
m.bigEma200 = ta.EMA(e.Close, 200).Get(0)
m.bigRsi = ta.RSI(e.Close, 14).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
smaHigh := ta.SMA(e.High, 20).Get(0) + atr
smaLow := ta.SMA(e.Low, 20).Get(0) - atr
hlv := e.Close.To("_hlv", 20)
sslUp := e.Close.To("_sslUp", 20)
sslDn := e.Close.To("_sslDn", 20)
c := e.Close.Get(0)
if !hlv.Cached() {
if c > smaHigh {
hlv.Append(1)
} else if c < smaLow {
hlv.Append(-1)
} else {
hlv.Append(hlv.Get(0))
}
if hlv.Get(0) < 0 {
sslUp.Append(smaLow)
sslDn.Append(smaHigh)
} else {
sslUp.Append(smaHigh)
sslDn.Append(smaLow)
}
}
m.bigSSLUp = sslUp.Get(0)
m.bigSSLDn = sslDn.Get(0)
},
}
}

69
org/ft/SMAOG.go Normal file
View File

@@ -0,0 +1,69 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
type maogState struct {
atrBase float64
}
func SMAOG(pol *config.RunPolicyConfig) *strat.TradeStrat {
longRate := pol.Def("longRate", 3.03, core.PNorm(1.5, 6))
shortRate := pol.Def("shortRate", 1.03, core.PNorm(0.5, 4))
lls2 := pol.Def("lls2", 4, core.PNorm(0, 10))
lls12 := pol.Def("lls12", 6, core.PNorm(2, 15))
lls144 := pol.Def("lls144", 16, core.PNorm(4, 30))
lenAtr := int(pol.Def("atr", 20, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 200,
DrawDownExit: true,
OnStartUp: func(s *strat.StratJob) {
s.More = &maogState{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*maogState)
c := e.Close.Get(0)
oo := e.Open
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
m.atrBase = atrBase
maBuy := ta.SMA(e.Close, 26).Get(0)
maSell := ta.EMA(e.Close, 28).Get(0)
badLL2 := ta.Lowest(e.Open, 2).Get(0)-c > atrBase*lls2
badLL12 := ta.Lowest(e.Open, 12).Get(0)-c > atrBase*lls12
badLL144 := ta.Lowest(e.Open, 144).Get(0)-c > atrBase*lls144
pairBad := badLL2 || badLL12 || badLL144
ema50 := ta.EMA(e.Close, 50).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
rsiExit := ta.RSI(e.Close, 2)
if maSell-c < atrBase*shortRate {
if oo.Get(0) < oo.Get(1) || rsiExit.Get(0) < 50 || rsiExit.Get(0) < rsiExit.Get(1) {
s.CloseOrders(&strat.ExitReq{Tag: "short"})
return
}
}
if ema50 > ema200 && c > ema200 && !pairBad && maBuy-c > atrBase*longRate && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: atrBase * 15})
}
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
m, _ := s.More.(*maogState)
if maxChg/(m.atrBase/od.InitPrice) > 2 {
return 0.35
}
return 0
},
}
}

47
org/ft/Synthesis.go Normal file
View File

@@ -0,0 +1,47 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://strat.ninja/overview.php?strategy=Money
过于简单,无法盈利,针对1h周期
*/
func Synthesis(pol *config.RunPolicyConfig) *strat.TradeStrat {
buyRSI := pol.Def("buy_rsi", 30, core.PNorm(20, 40))
sellRSI := pol.Def("sell_rsi", 70, core.PNorm(60, 80))
buyEmaShort := int(pol.Def("buy_ema_short", 10, core.PNorm(5, 15)))
buyEmaLong := int(pol.Def("buy_ema_long", 50, core.PNorm(20, 60)))
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
EachMaxShort: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
// 计算指标
rsi := ta.RSI(e.Close, 14)
emaShort := ta.EMA(e.Close, buyEmaShort)
emaLong := ta.EMA(e.Close, buyEmaLong)
// 买入条件:RSI低于买入阈值且短期EMA高于长期EMA
if rsi.Get(0) < buyRSI && emaShort.Get(0) > emaLong.Get(0) && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
// 卖出条件:RSI高于卖出阈值且短期EMA低于长期EMA
if rsi.Get(0) > sellRSI && emaShort.Get(0) < emaLong.Get(0) {
s.CloseOrders(&strat.ExitReq{
Tag: "short",
})
}
},
}
}

64
org/ft/bbrsitv.go Normal file
View File

@@ -0,0 +1,64 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://github.com/jilv220/freqtrade-stuff/BBRSITV.py
滚动优化:bt_opt -review-period 18M -run-period 2M -opt-rounds 20
bt_opt_2d11bb5607 最近两年半40%收益,回撤37%;不稳定。
5m,80品种,3年531%,中间不够稳定,待优化
15m, 80品种,3年553%,中间略不稳定,两次半年回撤,待优化
1h,80品种,3年278%,回撤49%,熊市时回撤较大
*/
func BBRSITV(pol *config.RunPolicyConfig) *strat.TradeStrat {
ewoRate := pol.Def("ewoRate", 1.0, core.PNorm(0.1, 3))
ewoHigh := 5 * ewoRate
maLen := int(pol.Def("maLen", 22, core.PNorm(5, 80)))
maLenS := int(pol.Def("maLenS", 65, core.PNorm(5, 80)))
rsiSigma := pol.Def("rsiSigma", 1.74, core.PNorm(0, 6))
rsiSigmaS := pol.Def("rsiSigmaS", 1.9, core.PNorm(0, 6))
rsiHigh := pol.Def("rsiHigh", 72, core.PNorm(60, 100))
lenAtr := int(pol.Def("atr", 20, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
//c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
rsi := ta.RSI(e.Close, 14)
rsiV := rsi.Get(0)
//rsi4 := ta.RSI(e.Close, 4).Get(0)
basisBuy := ta.EMA(rsi, maLen).Get(0)
basisSell := ta.EMA(rsi, maLenS).Get(0)
devBuy := ta.StdDev(rsi, maLen)
devSell := ta.StdDev(rsi, maLenS)
ema1 := ta.EMA(e.Close, 50).Get(0)
ema2 := ta.EMA(e.Close, 200).Get(0)
ewo := (ema1 - ema2) / atrBase
if rsiV > rsiHigh || rsiV > basisSell+devSell.Get(0)*rsiSigmaS {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
return
}
if rsiV < basisBuy-devBuy.Get(0)*rsiSigma && ewo > ewoHigh && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: atrBase * 20})
}
},
}
}

245
org/ft/bin_ha_cluc_v8.go Normal file
View File

@@ -0,0 +1,245 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
https://github.com/zmomz/freq_strategies/blob/f25f8493ebab589e327cd011b829d1c64cafae84/strategies/CombinedBinHAndClucV8Hyper.py#L53
滚动回测 bt_opt -review-period 18M -run-period 2M -opt-rounds 20
bt_opt_d0c194932b 2年半收益61%,回撤14%;最近三四个月亏损
*/
type haClucState struct {
sma200Dec bool
rsi float64
atrBase float64
bigMa50 float64
bigMa100 float64
bigEMA200 float64
bigSMA200 float64
bigSma200Dec bool //bigSMA200是否低于20小时前的值
bigRsi float64
bigHlv float64 // 大周期市场趋势
sslDown float64
sslUp float64
}
func CombinedBinHAndClucV8Hyper(pol *config.RunPolicyConfig) *strat.TradeStrat {
BuyThs1 := pol.Def("BuyThs1", 0.15, core.PNorm(0.05, 0.3))
BuyThs2 := pol.Def("BuyThs2", 0.49, core.PNorm(0.1, 0.6))
BuyThs3 := pol.Def("BuyThs3", 0.24, core.PNorm(0.15, 0.7))
bb40BBDeltaClose := pol.Def("bb40BBDeltaClose", 7.4, core.PNorm(5, 30))
bb40CloseDeltaClose := pol.Def("bb40CloseDeltaClose", 9, core.PNorm(3, 20))
bb40TailBBDelta := pol.Def("bb40TailBBDelta", 0.27, core.PNorm(0.1, 0.5))
bb20CloseBBLower := pol.Def("bb20CloseBBLower", 0.94, core.PNorm(0.5, 3))
bb20Vol := pol.Def("bb20Vol", 20.2, core.PNorm(5, 50))
rsiDiff := pol.Def("rsiDiff", 53.23, core.PNorm(20, 80))
minInc := pol.Def("minInc", 1.2, core.PNorm(0.5, 5))
rsi1H := 67.0
rsiSml := 38.5
mfiThs := 36.0
vol1 := 2.0
emaOpenMult := pol.Def("emaOpenMult", 2.3, core.PNorm(1.5, 5))
earlyExitRate := pol.Def("earlyExitRate", 1, core.PNorm(-1, 2))
earlyExitNum := int(pol.Def("earlyExitNum", 65, core.PNorm(10, 70)))
shortRsiMain := pol.Def("shortRsiMain", 80.75, core.PNorm(70, 95))
sellRoiProfit1 := pol.Def("sellRoiProfit1", 2, core.PNorm(0.3, 5))
sellRoiRsi1 := pol.Def("sellRoiRsi1", 63.4, core.PNorm(40, 64))
sellRoiProfit2 := pol.Def("sellRoiProfit2", 3, core.PNorm(1, 7))
sellRoiRsi2 := pol.Def("sellRoiRsi2", 63.4, core.PNorm(40, 64))
sellRoiProfit3 := pol.Def("sellRoiProfit3", 8, core.PNorm(4, 12))
sellRoiRsi3 := pol.Def("sellRoiRsi3", 50.1, core.PNorm(45, 67))
sellRoiProfit4 := pol.Def("sellRoiProfit4", 12.4, core.PNorm(7, 18))
sellRoiRsi4 := pol.Def("sellRoiRsi4", 55.4, core.PNorm(50, 70))
sellRoiProfit5 := pol.Def("sellRoiProfit5", 1, core.PNorm(1, 7))
trailProfitMin1 := pol.Def("trailProfitMin1", 0.06, core.PNorm(0.03, 0.3))
trailProfitMin2 := pol.Def("trailProfitMin2", 0.04, core.PNorm(0.01, 0.1))
customSL1 := -pol.Def("customSL1", 2.17, core.PNorm(0.5, 3))
lenAtr := int(pol.Def("atr", 40, core.PNorm(10, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
pol.KeepHyperOnly("earlyExitRate", "earlyExitNum", "sellRoiProfit1", "sellRoiProfit2", "sellRoiProfit3",
"sellRoiProfit4", "sellRoiProfit5", "customSL1")
return &strat.TradeStrat{
WarmupNum: 300,
DrawDownExit: true,
EachMaxLong: 1,
OnStartUp: func(s *strat.StratJob) {
s.More = &haClucState{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 300},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
more, _ := s.More.(*haClucState)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
more.atrBase = atrBase
o, l, c, v := e.Open.Get(0), e.Low.Get(0), e.Close.Get(0), e.Volume.Get(0)
c1, c2 := e.Close.Get(1), e.Close.Get(2)
_, bbMidC, bbLowCol := ta.BBANDS(e.Close, 40, 2, 2)
bbLow, bbMid := bbLowCol.Get(0), bbMidC.Get(0)
bbDelta := math.Abs(bbMid - bbLow)
closeDelta := math.Abs(c - e.Close.Get(1))
tail := math.Abs(c - l)
avgPrice := ta.AvgPrice(e)
bb20UppC, _, bb20Dn := ta.BBANDS(avgPrice, 20, 2, 2)
bb20Upp, bb20Low := bb20UppC.Get(0), bb20Dn.Get(0)
volSlow1 := ta.SMA(e.Volume, 30).Get(1)
volMa4 := ta.SMA(e.Volume, 4).Get(0)
ema12C, ema26C := ta.EMA(e.Close, 12), ta.EMA(e.Close, 26)
ema12 := ema12C.Get(0)
ema26 := ema26C.Get(0)
ema50 := ta.EMA(e.Close, 50).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
sma5 := ta.SMA(e.Close, 5).Get(0)
sma200 := ta.SMA(e.Close, 200)
sma200V := sma200.Get(0)
sma200Dec := sma200V < sma200.Get(20)
more.sma200Dec = sma200Dec
mfi := ta.MFI(e, 14).Get(0)
rsi := ta.RSI(e.Close, 14).Get(0)
more.rsi = rsi
openHH2 := ta.Highest(e.Open, 2).Get(0)
openHH12 := ta.Highest(e.Open, 12).Get(0)
openHH144 := ta.Highest(e.Open, 144).Get(0)
openLL24 := ta.Lowest(e.Open, 24).Get(0)
if c > bb20Upp && c1 > bb20UppC.Get(1) && c2 > bb20UppC.Get(2) {
s.CloseOrders(&strat.ExitReq{Tag: "exit1", Dirt: core.OdDirtLong})
return
}
if rsi > shortRsiMain {
s.CloseOrders(&strat.ExitReq{Tag: "exit2", Dirt: core.OdDirtLong})
return
}
if (openHH2-c)/c < BuyThs1 && (openHH12-c)/c < BuyThs2 {
if c > more.bigEMA200 && ema50 > ema200 && more.bigMa50 > more.bigEMA200 {
if bbDelta > atrBase*bb40BBDeltaClose && closeDelta > atrBase*bb40CloseDeltaClose &&
tail < bbDelta*bb40TailBBDelta && c < bbLowCol.Get(1) && c <= e.Close.Get(1) {
s.OpenOrder(&strat.EnterReq{Tag: "long1"})
return
}
}
if c > more.bigEMA200 && c > ema200 && more.bigMa50 > max(more.bigMa100, more.bigEMA200) {
if c < ema50 && (bb20Low-c) > atrBase*bb20CloseBBLower && v < volSlow1*bb20Vol {
s.OpenOrder(&strat.EnterReq{Tag: "long2"})
return
}
}
if c < sma5 && more.sslUp > more.sslDown && ema50 > ema200 && more.bigMa50 > more.bigEMA200 {
if (openHH144-c)/c < BuyThs3 && rsi < more.bigRsi-rsiDiff {
s.OpenOrder(&strat.EnterReq{Tag: "long3"})
return
}
}
if !sma200Dec && !more.bigSma200Dec && (openHH144-c)/c < BuyThs3 && (openLL24-c)/c > atrBase*minInc {
if more.bigRsi > rsi1H && rsi < rsiSml && mfi < mfiThs {
s.OpenOrder(&strat.EnterReq{Tag: "long4"})
return
}
}
if c > more.bigMa100 && more.bigMa50 > more.bigMa100 && (openHH144-c)/c < BuyThs3 && volMa4*vol1 > v {
if ema26 > ema12 && ema26-ema12 > atrBase*emaOpenMult {
if ema26C.Get(1)-ema12C.Get(1) > o/100 && c < bb20Low {
s.OpenOrder(&strat.EnterReq{Tag: "long5"})
return
}
}
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
more, _ := s.More.(*haClucState)
more.bigMa50 = ta.EMA(e.Close, 50).Get(0)
more.bigMa100 = ta.EMA(e.Close, 100).Get(0)
more.bigEMA200 = ta.EMA(e.Close, 200).Get(0)
sma200 := ta.SMA(e.Close, 200)
more.bigSMA200 = sma200.Get(0)
more.bigSma200Dec = more.bigSMA200 < sma200.Get(20)
more.bigRsi = ta.RSI(e.Close, 14).Get(0)
length := 20
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
maHigh := ta.SMA(e.High, length).Get(0) + atr
maLow := ta.SMA(e.Low, length).Get(0) - atr
c := e.Close.Get(0)
if c > maHigh {
more.bigHlv = 1
} else if c < maLow {
more.bigHlv = -1
}
if more.bigHlv < 0 {
more.sslDown = maHigh
more.sslUp = maLow
} else {
more.sslDown = maLow
more.sslUp = maHigh
}
},
OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq {
more, _ := s.More.(*haClucState)
holdNum := int((s.Env.TimeStop - od.RealEnterMS()) / s.Env.TFMSecs)
// 计算相对利润率,1%利润对应均值大概为1
profitRate := od.ProfitRate / od.Leverage / (more.atrBase / od.InitPrice)
if holdNum >= earlyExitNum && profitRate < earlyExitRate {
od.SetStopLoss(&ormo.ExitTrigger{Price: s.Env.Close.Get(0) - more.atrBase*0.65})
} else if profitRate < customSL1 && more.sma200Dec && more.bigSma200Dec {
return &strat.ExitReq{Tag: "sl2"}
}
if profitRate > sellRoiProfit4 && more.rsi < sellRoiRsi4 {
return &strat.ExitReq{Tag: "roi4"}
}
if profitRate > sellRoiProfit3 && more.rsi < sellRoiRsi3 {
return &strat.ExitReq{Tag: "roi3"}
}
if profitRate > sellRoiProfit2 && more.rsi < sellRoiRsi2 {
return &strat.ExitReq{Tag: "roi2"}
}
if profitRate > sellRoiProfit1 && more.rsi < sellRoiRsi1 {
return &strat.ExitReq{Tag: "roi1"}
}
if profitRate > 0 && profitRate < sellRoiProfit5 && more.sma200Dec {
return &strat.ExitReq{Tag: "roi5"}
}
return nil
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
if maxChg > trailProfitMin1 {
return 0.3
} else if maxChg > trailProfitMin2 {
return 0.7
}
return 0
},
}
}

97
org/ft/binance.go Normal file
View File

@@ -0,0 +1,97 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://strat.ninja/overview.php?strategy=binance
210101-241101 48品种,收益159% 回撤5% 夏普10.25
*/
func binance(pol *config.RunPolicyConfig) *strat.TradeStrat {
//ewoRate := pol.Def("ewoRate", 1.0, core.PNorm(0.1, 3))
//ewoHigh := -2.7 * ewoRate
//lowRate := pol.Def("lowRate", 8.6, core.PNorm(1, 3.5))
//highRate := pol.Def("highRate", 2.7, core.PNorm(0.5, 2.5))
//rsiLong := pol.Def("rsiLong", 30, core.PNorm(20, 65))
//maLongF := pol.Def("maLong", 8, core.PNorm(8, 16))
//maLong := int(math.Round(maLongF))
//maRate := pol.Def("maRate", 2, core.PNorm(1.5, 3))
//maShort := int(math.Round(maLongF * maRate))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
//emaLong := ta.EMA(e.Close, maLong).Get(0)
//emaShort := ta.EMA(e.Close, maShort).Get(0)
sma15 := ta.SMA(e.Close, 15).Get(0)
cti := ta.CTI(e.Close, 20).Get(0)
//ema1 := ta.EMA(e.Close, 50).Get(0)
//ema2 := ta.EMA(e.Close, 200).Get(0)
//ewo := (ema1 - ema2) / atrBase
rsi := ta.RSI(e.Close, 14).Get(0)
rsiFast := ta.RSI(e.Close, 4).Get(0)
rsiSlowS := ta.RSI(e.Close, 20)
rsiSlow, rsiSlowP := rsiSlowS.Get(0), rsiSlowS.Get(1)
fastK := ta.Stoch(e.High, e.Low, e.Close, 5).Get(0)
bb20Up, bb20Md, bb20Dn := ta.BBANDS(ta.HLC3(e.High, e.Low, e.Close), 20, 2, 2)
bb20Upp, bb20Mid, bb20Low := bb20Up.Get(0), bb20Md.Get(0), bb20Dn.Get(0)
bb20Wid := (bb20Upp - bb20Low) / atrBase
volMa12 := ta.SMA(e.Volume, 12).Get(1)
volMa24 := ta.SMA(e.Volume, 24).Get(1)
//lowWid := atrBase * lowRate
//highWid := atrBase * highRate
for _, od := range s.LongOrders {
holdNum := e.BarCount(od.EnterAt)
profit := (c - od.Enter.Average) / atrBase
if od.Short {
profit *= -1
}
if profit < -10 && bb20Wid < 10 && c > bb20Mid && volMa12 < volMa24 {
s.CloseOrders(&strat.ExitReq{Tag: "deadfish"})
continue
}
if fastK > 75 && (holdNum > 11.5 && profit > -2 || holdNum > 287 && profit > -10) {
od.SetStopLoss(&ormo.ExitTrigger{Price: c - atrBase*0.2})
} else if od.EnterTag == "ewo" && profit > 10 {
od.SetStopLoss(&ormo.ExitTrigger{Price: c - atrBase})
} else if profit > 0 && fastK > 75 {
od.SetStopLoss(&ormo.ExitTrigger{Price: c - atrBase*0.2})
}
}
if rsiSlow < rsiSlowP && rsiFast < 63 && rsi > 16 && c < sma15-atrBase*13 && cti < -0.8 {
s.OpenOrder(&strat.EnterReq{
Tag: "buy1",
})
}
// 略不稳定
//emaEnt := c < emaLong-lowWid && c < emaShort-highWid
//if rsiFast < 50 && emaEnt && ewo > ewoHigh && rsi < rsiLong {
// s.OpenOrder(&strat.EnterReq{
// Tag: "ewo",
// })
//}
},
}
}

35
org/ft/common.go Normal file
View File

@@ -0,0 +1,35 @@
package ft
import "github.com/banbox/banbot/strat"
func init() {
strat.AddStratGroup("ft", map[string]strat.FuncMakeStrat{
"smaoff": SMAOffset,
"smaoff2": SMAOffsetV2,
"bin_ha": CombinedBinHAndClucV8Hyper,
"hpsv7": HPSV7Ultra,
"namaoff": NotAnotherSMAOffset,
"e0v1e": E0V1E,
"smaog": SMAOG,
"BBRSITV": BBRSITV,
"ichiv3": ichiv3,
"ichiV1": ichiV1,
"BBMod2": BBMod2,
"Synthesis": Synthesis,
"CenderaWasih3": CenderaWasih3,
"x_zvwap06": x_zvwap06,
"binance": binance,
"BinHModWhiteHOV0": BinHModWhiteHOV0,
"Clucha": Clucha,
"MadV9HO": MadV9HO,
"BBMod7": BBMod7,
"BinHV27": BinHV27,
"01": SMAOffset,
"02": BBMod2,
"03": BBMod7,
"04": MadV9HO,
"05": binance,
"06": CenderaWasih3,
})
}

165
org/ft/e0v1e.go Normal file
View File

@@ -0,0 +1,165 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://github.com/28dec/E0V1E-HO/blob/main/user_data/strategies/E0V1E_20231014_0847.py
https://github.com/ssssi/freqtrade_strs/blob/main/binance/E0V1E.py
https://strat.ninja/overview.php?strategy=E0V1E
params: {ctiThs: -0.86, maOffRate: 11.5, buyRsi: 19, buyRsiFast: 46}
比上面多了个入场逻辑,反而更差了
1h3年只有40订单,收益为正
15m和5m收益均不稳定
*/
type E0State struct {
c float64
h float64
atrBase float64
kdjK float64
cci float64
ma120 float64
ma240 float64
hold map[int64]bool
hold1 map[int64]bool
}
func E0V1E(pol *config.RunPolicyConfig) *strat.TradeStrat {
buyRsiFast := pol.Def("buyRsiFast", 41, core.PNorm(20, 70))
buyRsi := pol.Def("buyRsi", 46.7, core.PNorm(15, 50))
maOffRate := pol.Def("maOffRate", 2.05, core.PNorm(0.2, 5))
ctiThs := pol.Def("ctiThs", -0.73, core.PNorm(-1, 0))
sellKdX := pol.Def("sellKdX", 85.2, core.PNorm(50, 100))
sellCCI := pol.Def("sellCCI", 80, core.PNorm(0, 400))
lenAtr := int(pol.Def("atr", 13.35, core.PNorm(7, 25)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 300,
DrawDownExit: true,
OnStartUp: func(s *strat.StratJob) {
s.More = &E0State{
hold: make(map[int64]bool),
hold1: make(map[int64]bool),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
m, _ := s.More.(*E0State)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
m.atrBase = atrBase
m.h = e.High.Get(0)
sma15 := ta.SMA(e.Close, 15).Get(0)
cti := ta.CTI(e.Close, 20).Get(0)
rsi := ta.RSI(e.Close, 14).Get(0)
rsi4 := ta.RSI(e.Close, 4).Get(0)
rsi20S := ta.RSI(e.Close, 20)
rsi20 := rsi20S.Get(0)
kdjK, _, _ := ta.KDJBy(e.High, e.Low, e.Close, 5, 3, 3, "sma")
cci := ta.CCI(e.Close, 20).Get(0)
ma120 := ta.SMA(e.Close, 120).Get(0)
ma240 := ta.SMA(e.Close, 240).Get(0)
m.kdjK = kdjK.Get(0)
m.cci = cci
m.ma120 = ma120
m.ma240 = ma240
fastK := ta.Stoch(e.High, e.Low, e.Close, 5).Get(0)
ema100 := ta.EMA(e.Close, 100).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
hlc3 := ta.HLC3(e.High, e.Low, e.Close)
bb20Up, bb20Md, bb20Dn := ta.BBANDS(hlc3, 20, 2, 2)
bb20Wid := (bb20Up.Get(0) - bb20Dn.Get(0)) / atrBase
bb20Mid := bb20Md.Get(0)
volMa12 := ta.SMA(e.Volume, 12).Get(1)
volMa24 := ta.SMA(e.Volume, 24).Get(1)
willR := ta.WillR(e, 14).Get(0)
if s.OrderNum > 0 && fastK > 75 {
// 这是strat.ninja的出场逻辑,差
// s.CloseOrders(&strat.ExitReq{Tag: "exit"})
// return
}
if s.OrderNum > 0 && e.Open.Get(0) < ma120 {
s.CloseOrders(&strat.ExitReq{Tag: "ma120"})
return
}
tag := ""
if rsi20 < rsi20S.Get(1) && rsi4 < buyRsiFast && rsi > buyRsi && c < sma15-atrBase*maOffRate && cti < ctiThs {
tag = "buy1"
} else if ema100 < ema200+atrBase*17 && bb20Wid > 10 && c < bb20Mid && volMa12 > volMa24 && cti < -0.5 &&
willR < -60 {
// 这是strat.ninja的入场逻辑,差
//tag = "buy2"
}
if s.OrderNum == 0 && tag != "" {
s.OpenOrder(&strat.EnterReq{Tag: tag, StopLossVal: atrBase * 20})
}
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
m, _ := s.More.(*E0State)
bestRate := maxChg / (m.atrBase / od.InitPrice)
if bestRate > 2.3 {
return 0.3
}
return 0
},
OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq {
m, _ := s.More.(*E0State)
if m.c > min(m.ma120, m.ma240) {
m.hold[od.ID] = true
} else {
m.hold1[od.ID] = true
}
profitRate := od.ProfitRate / od.Leverage / (m.atrBase / od.InitPrice)
if profitRate > 0 && m.kdjK > sellKdX {
return &strat.ExitReq{Tag: "fastK"}
}
if m.cci > sellCCI {
if profitRate > -0.5 {
return &strat.ExitReq{Tag: "cci_.5"}
}
if profitRate > -2 {
return &strat.ExitReq{Tag: "cci_2"}
}
if profitRate > -8 {
return &strat.ExitReq{Tag: "cci_8"}
}
}
holdNum := int((s.Env.TimeStop - od.RealEnterMS()) / s.Env.TFMSecs)
if holdNum > 3 {
_, inHold := m.hold[od.ID]
if inHold && m.c < min(m.ma120, m.ma240) {
delete(m.hold, od.ID)
return &strat.ExitReq{Tag: "ma120"}
}
_, inHold1 := m.hold1[od.ID]
if inHold1 && m.h > min(m.ma120, m.ma240) {
delete(m.hold1, od.ID)
return &strat.ExitReq{Tag: "x120_240"}
}
}
return nil
},
}
}

80
org/ft/ichiV1.go Normal file
View File

@@ -0,0 +1,80 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"gonum.org/v1/gonum/floats"
)
func ichiV1(p *config.RunPolicyConfig) *strat.TradeStrat {
senkouLevel := 1
bullLevel := 6
h1Rate := 2.0
fanMagLen := 3
lenAtr := 14
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
hkasOpen, _, _, _ := ta.HeikinAshi(e)
c := e.Close.Get(0)
close15m := ta.EMA(e.Close, 3).Get(0)
close30m := ta.EMA(e.Close, 6).Get(0)
close1hS := ta.EMA(e.Close, 12)
close1h := close1hS.Get(0)
close2h := ta.EMA(e.Close, 24).Get(0)
close4h := ta.EMA(e.Close, 48).Get(0)
close6h := ta.EMA(e.Close, 72).Get(0)
close8hS := ta.EMA(e.Close, 96)
close8h := close8hS.Get(0)
open15m := ta.EMA(hkasOpen, 3).Get(0)
open30m := ta.EMA(hkasOpen, 6).Get(0)
open1h := ta.EMA(hkasOpen, 12).Get(0)
open2h := ta.EMA(hkasOpen, 24).Get(0)
open4h := ta.EMA(hkasOpen, 48).Get(0)
open6h := ta.EMA(hkasOpen, 72).Get(0)
open8h := ta.EMA(hkasOpen, 96).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
fanMagnitude := close1h / close8h
fanMagnitudeGain := (close1h - close1hS.Get(1)) / atrBase
ihci := com.IchimokuCloud(e, 20, 60, 120, 30).Cols
senkouA, senkouB := ihci[2].Get(0), ihci[3].Get(0)
closeArr := []float64{c, close15m, close30m, close1h, close2h, close4h, close6h, close8h}
openArr := []float64{c, open15m, open30m, open1h, open2h, open4h, open6h, open8h}
senkouOK := floats.Min(closeArr[senkouLevel-1:]) > max(senkouA, senkouB)
bullOk := true
for i := bullLevel - 1; i < 8; i++ {
if closeArr[i] <= openArr[i] {
bullOk = false
break
}
}
fanMag := true
for i := fanMagLen; i > 0; i-- {
if close1hS.Get(i)/close8hS.Get(i) >= fanMagnitude {
fanMag = false
break
}
}
if s.OrderNum > 0 {
if c < close2h {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
}
} else if senkouOK && bullOk && fanMagnitude > 1 && fanMagnitudeGain >= h1Rate && fanMag {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
},
}
}

78
org/ft/ichiv3.go Normal file
View File

@@ -0,0 +1,78 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
SMAOffset 的升级版本,也称为 ElliotV8 NASOS
https://github.com/jilv220/freqtrade-stuff/blob/main/ElliotV8_original_ichiv3.py
滚动回测远不如默认参数稳定
滚动回测:bt_opt_0529d353d7
bt_opt -review-period 18M -run-period 2M -opt-rounds 20
*/
func ichiv3(pol *config.RunPolicyConfig) *strat.TradeStrat {
ewoRate := pol.Def("ewoRate", 1.0, core.PNorm(0.1, 3))
ewoHigh := 3.15 * ewoRate
ewoLow := -17.15 * ewoRate
lowRate := pol.Def("lowRate", 1.7, core.PNorm(1, 3.5))
highRate := pol.Def("highRate", 0.85, core.PNorm(0.5, 2.5))
highRate2 := highRate * 2
rsiLong := pol.Def("rsiLong", 57, core.PNorm(50, 65))
maLongF := pol.Def("maLong", 12, core.PNorm(8, 16))
maLong := int(math.Round(maLongF))
maRate := pol.Def("maRate", 1.833, core.PNorm(1.5, 3))
maShort := int(math.Round(maLongF * maRate))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
emaLong := ta.EMA(e.Close, maLong).Get(0)
emaShort := ta.EMA(e.Close, maShort).Get(0)
hma50 := ta.HMA(e.Close, 50).Get(0)
ema1 := ta.EMA(e.Close, 50).Get(0)
ema2 := ta.EMA(e.Close, 200).Get(0)
ewo := (ema1 - ema2) / atrBase
rsi := ta.RSI(e.Close, 14).Get(0)
rsiFast := ta.RSI(e.Close, 4).Get(0)
rsiSlow := ta.RSI(e.Close, 20).Get(0)
lowWid := atrBase * lowRate
highWid := atrBase * highRate
highWid2 := atrBase * highRate2
emaEnt := c < emaLong-lowWid && c < emaShort+highWid
if rsiFast < 35 && emaEnt && (ewo > ewoHigh && rsi < rsiLong || ewo < ewoLow) {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
} else if rsiFast > rsiSlow && c < hma50 && c > emaShort+highWid {
s.CloseOrders(&strat.ExitReq{
Dirt: core.OdDirtLong,
Tag: "exit",
})
} else if rsiFast > rsiSlow && c > hma50 && rsi > 50 && c > emaShort+highWid2 {
s.CloseOrders(&strat.ExitReq{
Dirt: core.OdDirtLong,
Tag: "exit2",
})
}
},
}
}

74
org/ft/noAnSmaOff.go Normal file
View File

@@ -0,0 +1,74 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
滚动优化:bt_opt -review-period 18M -run-period 2M -opt-rounds 20
bt_opt_9954bcb1d0 最近两年半1.6%收益,回撤7.6%;不稳定。
1h > 15m > 5m
*/
func NotAnotherSMAOffset(pol *config.RunPolicyConfig) *strat.TradeStrat {
maBuyLen := int(pol.Def("maBuyLen", 14, core.PNorm(5, 80)))
maSellLen := int(pol.Def("maSellLen", 24, core.PNorm(5, 80)))
lowOff := pol.Def("lowOff", 2, core.PNorm(0.5, 4))
lowOff2 := pol.Def("lowOff2", 4, core.PNorm(1.5, 7))
highOff := pol.Def("highOff", 1, core.PNorm(0.3, 2.5))
highOff2 := pol.Def("highOff2", 0.5, core.PNorm(-0.5, 1.5))
ewoLow := pol.Def("ewoLow", -21, core.PNorm(-25, -8))
ewoHigh := pol.Def("ewoHigh", 2.33, core.PNorm(1, 12))
ewoHigh2 := pol.Def("ewoHigh2", -2.33, core.PNorm(-6, 12))
rsiBuy := pol.Def("rsiBuy", 69, core.PNorm(30, 85))
hmaExRate := pol.Def("hmaExRate", 12, core.PNorm(3, 20))
emaExRate := pol.Def("emaExRate", 4, core.PNorm(1.5, 7))
lenAtr := int(pol.Def("atr", 29, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
maBuy := ta.EMA(e.Close, maBuyLen).Get(0)
maSell := ta.EMA(e.Close, maSellLen).Get(0)
hma50 := ta.HMA(e.Close, 50).Get(0)
ema100 := ta.EMA(e.Close, 100).Get(0)
sma9 := ta.SMA(e.Close, 9).Get(0)
ema50 := ta.EMA(e.Close, 50).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
ewo := (ema50 - ema200) * 100 / e.Low.Get(0)
rsi14 := ta.RSI(e.Close, 14).Get(0)
rsi4 := ta.RSI(e.Close, 4).Get(0)
rsi20 := ta.RSI(e.Close, 20).Get(0)
if c > sma9 && c-maSell > atrBase*highOff2 && rsi14 > 50 && rsi4 > rsi20 {
s.CloseOrders(&strat.ExitReq{Tag: "exit1"})
} else if c < hma50 && c-maSell > atrBase*highOff && rsi4 > rsi20 {
s.CloseOrders(&strat.ExitReq{Tag: "exit2"})
} else if ema100-hma50 >= atrBase*hmaExRate {
s.CloseOrders(&strat.ExitReq{Tag: "exit3"})
} else if c-ema100 <= atrBase*emaExRate {
s.CloseOrders(&strat.ExitReq{Tag: "exit4"})
} else if rsi4 < 35 && maSell-c > atrBase*highOff && s.OrderNum == 0 {
if maBuy-c > atrBase*lowOff && ewo > ewoHigh && rsi14 < rsiBuy {
s.OpenOrder(&strat.EnterReq{Tag: "ewo1"})
} else if maBuy-c > atrBase*lowOff2 && ewo > ewoHigh2 && rsi14 < min(25, rsiBuy) {
s.OpenOrder(&strat.EnterReq{Tag: "ewo2"})
} else if maBuy-c > atrBase*lowOff && ewo < ewoLow {
s.OpenOrder(&strat.EnterReq{Tag: "ewoLow"})
}
}
},
}
}

73
org/ft/sma_offset.go Normal file
View File

@@ -0,0 +1,73 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
来自
https://github.com/hippocritical/strategies/blob/main/SMAOffset_Hippocritical_dca/SMAOffset_Hippocritical_dca.py
也称ElliotV3 ElliotV5_SMA
https://github.com/minulislam/freqtrade-strategies/user_data/strategies/ElliotV3.py
滚动测试:
bt_opt_745b13cd06 bt_opt -review-period 18M -run-period 2M -opt-rounds 20
添加止损或长期未盈利退出,都会导致整体收益下降
*/
func SMAOffset(pol *config.RunPolicyConfig) *strat.TradeStrat {
ewoRate := pol.Def("ewoRate", 1.0, core.PNorm(0.1, 3))
ewoHigh := 4.0 * ewoRate
ewoLow := -12 * ewoRate
lowRate := pol.Def("lowRate", 3.03, core.PNorm(1.5, 5))
highRate := pol.Def("highRate", 1.03, core.PNorm(0.5, 5))
lenAtr := int(pol.Def("atr", 29, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 300,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
emaLong := ta.EMA(e.Close, 16).Get(0)
emaShort := ta.EMA(e.Close, 20).Get(0)
ema1 := ta.EMA(e.Close, 50).Get(0)
ema2 := ta.EMA(e.Close, 200).Get(0)
ewo := (ema1 - ema2) / atrBase
rsi := ta.RSI(e.Close, 14).Get(0)
if s.OrderNum > 0 {
if c-emaShort > atrBase*highRate {
s.CloseOrders(&strat.ExitReq{
Dirt: core.OdDirtLong,
Tag: "exit",
})
}
return
}
if emaLong-c > atrBase*lowRate {
tag := ""
if ewo > ewoHigh && rsi < 59 {
tag = "buy1"
} else if ewo < ewoLow {
//tag = "buy2"
}
if tag != "" {
s.OpenOrder(&strat.EnterReq{
Tag: tag,
})
}
}
},
}
}

74
org/ft/sma_offv2.go Normal file
View File

@@ -0,0 +1,74 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://github.com/GeorgeMurAlkh/freqtrade-stuff/tree/main/user_data/strategies
考虑加入大趋势过滤
滚动回测:bt_opt_59cb7a0075
bt_opt -review-period 18M -run-period 2M -opt-rounds 20
波动性较大,2年累计收益300%但回撤48%
*/
type SmaOf2 struct {
goLong bool
atrBase float64
}
func SMAOffsetV2(pol *config.RunPolicyConfig) *strat.TradeStrat {
longRate := pol.Def("longRate", 3.03, core.PNorm(1.5, 6))
shortRate := pol.Def("shortRate", 1.03, core.PNorm(0.5, 4))
lenAtr := int(pol.Def("atr", 20, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
OnStartUp: func(s *strat.StratJob) {
s.More = &SmaOf2{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 50},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*SmaOf2)
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
m.atrBase = atrBase
sma := ta.SMA(e.Close, 20).Get(0)
if m.goLong && sma-c > atrBase*longRate && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{Tag: "long"})
} else if !m.goLong && c-sma > atrBase*shortRate {
s.CloseOrders(&strat.ExitReq{Tag: "short"})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*SmaOf2)
emaFast := ta.EMA(e.Close, 20).Get(0)
emaSlow := ta.EMA(e.Close, 25).Get(0)
m.goLong = emaFast > emaSlow
},
OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq {
m, _ := s.More.(*SmaOf2)
holdNum := int((s.Env.TimeStop - od.RealEnterMS()) / s.Env.TFMSecs)
profitRate := od.ProfitRate / od.Leverage / (m.atrBase / od.InitPrice)
if holdNum > 8 && profitRate < -8 {
return &strat.ExitReq{Tag: "sl"}
}
return nil
},
}
}

197
org/ft/x_zvwap06.go Normal file
View File

@@ -0,0 +1,197 @@
package ft
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"gonum.org/v1/gonum/floats"
"math"
)
/*
https://strat.ninja/overview.php?strategy=x_zvwap06
整体盈利,48品种,盈利190%,回撤30%,中间不够稳定。
*/
type zvwapSta struct {
atrBase float64
fastK float64
rsi float64
cmf15m float64
cmf1h float64
tpctChange1h float64
}
func x_zvwap06(p *config.RunPolicyConfig) *strat.TradeStrat {
tpctChange4Val := p.Def("tpctChange4", 8, core.PNorm(1, 16))
ctiVal := p.Def("cti", -0.087, core.PNorm(-0.9, 0))
rsiLongVal := p.Def("rsiLong", 35, core.PNorm(15, 50))
bbWidVol := p.Def("bbWid", 6, core.PNorm(3, 15))
bbMidRateVol := p.Def("bbMidRate", 0.4, core.PNorm(-20, 30))
emaHighRate := p.Def("emaHighRate", 2, core.PNorm(1, 10))
emaHighRate2 := p.Def("emaHighRate2", 3, core.PNorm(1, 10))
lenAtr := 29
baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
OnStartUp: func(s *strat.StratJob) {
s.More = &zvwapSta{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "15m", 100},
{"_cur_", "1h", 100},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*zvwapSta)
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
hlc3 := ta.HLC3(e.High, e.Low, e.Close)
zvwpCol := zvwap(e.Close, e.Volume, 14)
zvwp := zvwpCol.Get(0)
rsi := ta.RSI(e.Close, 14).Get(0)
rsiFast := ta.RSI(e.Close, 4).Get(0)
rsiSlow := ta.RSI(e.Close, 20).Get(0)
rsi84 := ta.RSI(e.Close, 84).Get(0)
rsi112 := ta.RSI(e.Close, 112).Get(0)
m.rsi = rsi
//tpctChange0 := topPctChgDca(e.Open, e.Close, 0) / atrBase
//tpctChange1 := topPctChgDca(e.Open, e.Close, 1) / atrBase
//tpctChange2 := topPctChgDca(e.Open, e.Close, 2) / atrBase
tpctChange4 := topPctChgDca(e.Open, e.Close, 4) / atrBase
//tpctChange12 := topPctChgDca(e.Open, e.Close, 12) / atrBase
//tpctChange72 := topPctChgDca(e.Open, e.Close, 72) / atrBase
//tpctChange144 := topPctChgDca(e.Open, e.Close, 144) / atrBase
cti := ta.CTI(e.Close, 20).Get(0)
cmf := ta.CMF(e, 20).Get(0)
haOpen, _, _, haClose := ta.HeikinAshi(e)
ema22 := ta.EMA(e.Close, 22).Get(0)
ema200 := ta.EMA(e.Close, 200).Get(0)
hma50 := ta.HMA(e.Close, 50).Get(0)
//hma30 := ta.HMA(e.Close, 30).Get(0)
//hma15 := ta.HMA(e.Close, 15).Get(0)
bb20Up, bb20Md, bb20Dn := ta.BBANDS(hlc3, 20, 2, 2)
bb20Upp, bb20Mid, bb20Low := bb20Up.Get(0), bb20Md.Get(0), bb20Dn.Get(0)
bb20Wid := (bb20Upp - bb20Low) / atrBase
deadfish := e.Close.To("_deadfish", 0)
if !deadfish.Cached() {
dfVal := 0.0
if c < ema200 && bb20Wid < bbWidVol && c > bb20Mid+atrBase*bbMidRateVol && cmf < 0 &&
haOpen.Get(0) > haClose.Get(0) {
dfVal = 1
}
deadfish.Append(dfVal)
}
fastK := ta.Stoch(e.High, e.Low, e.Close, 5).Get(0)
m.fastK = fastK
for _, od := range s.LongOrders {
profitRate := (c - od.InitPrice) / atrBase
exitTag := ""
if profitRate > 10 && c > hma50+atrBase && c > ema22+atrBase*emaHighRate && rsi > 50 && rsiFast > rsiSlow {
exitTag = "sell1"
} else if profitRate > 10 && c > hma50+atrBase && c > ema22+atrBase*emaHighRate2 {
exitTag = "sell2"
} else if profitRate > 10 && rsi < 42 && cmf < -0.4 {
exitTag = "pft1"
} else if profitRate > 10 && rsi < 43 && cmf < 0 && m.cmf15m < 0 && m.cmf1h < 0 {
exitTag = "pft2"
} else if profitRate > 10 && rsi < 41 && cmf < -0.2 && m.cmf1h < 0 {
exitTag = "pft3"
} else if profitRate > 10 && rsi < 44 && cmf < -0.1 && m.cmf15m < -0.1 && m.cmf1h < -0.1 {
exitTag = "pft4"
} else if profitRate > 10 && rsi < 40 && cmf < -0.2 && m.cmf15m < -0.2 {
exitTag = "pft5"
} else if profitRate > 10 && rsi < 43 && cmf < -0.4 && m.cmf15m < 0 && m.cmf1h < 0 {
exitTag = "pft6"
} else if profitRate > 4 && rsi < 30 && cmf < -0.4 {
exitTag = "bear1"
} else if profitRate > 6 && rsi < 35 && cmf < -0.4 {
exitTag = "bear2"
} else if profitRate > 2 && rsi < 25 && cmf < -0.6 {
exitTag = "bear3"
} else if profitRate < -10 && c < ema200 && bb20Wid < bbWidVol && c > bb20Mid+atrBase*bbMidRateVol && cmf < 0 {
exitTag = "deadfish"
}
if exitTag != "" {
s.CloseOrders(&strat.ExitReq{Tag: exitTag, OrderID: od.ID})
}
}
tag := ""
if c < zvwp && tpctChange4 > tpctChange4Val && cti < ctiVal && rsi < rsiLongVal && max(rsi84, rsi112) < 60 &&
floats.Max(deadfish.Range(0, 4)) == 0 {
tag = "zvwap"
} else if c < zvwp && tpctChange4 > 13 && cti < -0.8 && rsi < 35 && max(rsi84, rsi112) < 60 && m.tpctChange1h < 0.45 {
tag = "pcdown"
}
if tag != "" && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{Tag: tag})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*zvwapSta)
if tf == "15m" {
m.cmf15m = ta.CMF(e, 20).Get(0)
} else {
m.cmf1h = ta.CMF(e, 20).Get(0)
m.tpctChange1h = topPctChgDca(e.Open, e.Close, 72) / m.atrBase
}
},
OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq {
m, _ := s.More.(*zvwapSta)
c := s.Env.Close.Get(0)
profitRate := (c - od.InitPrice) / m.atrBase
if od.Short {
profitRate *= -1
}
if profitRate > 20 && profitRate < 80 && od.MaxDrawDown > 0.3 {
return &strat.ExitReq{Tag: "trail1"}
} else if profitRate > 8 && profitRate < 22 && od.MaxDrawDown > 0.35 {
return &strat.ExitReq{Tag: "trail2"}
} else if profitRate > 200 && m.rsi > 85 {
return &strat.ExitReq{Tag: "rsi85"}
}
return nil
},
}
}
func zvwap(p, v *ta.Series, period int) *ta.Series {
res := p.To("_zvwap", period)
if res.Cached() {
return res
}
maP := ta.SMA(p, period)
maV := ta.SMA(v, period)
mean := ta.VWMA(p, maV, period)
pow2 := mean.To("_pow2", period)
pow2.Append(math.Pow(p.Get(0)-mean.Get(0), 2))
pow2Ma := ta.SMA(pow2, period)
vwapsd := math.Sqrt(pow2Ma.Get(0))
return res.Append((maP.Get(0) - mean.Get(0)) / vwapsd)
}
func topPctChgDca(o, c *ta.Series, period int) float64 {
if period == 0 {
return o.Get(0)/c.Get(0) - 1
} else {
return ta.Highest(o, period).Get(0)/c.Get(0) - 1
}
}