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

74
org/sf/01.go Normal file
View File

@@ -0,0 +1,74 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
此策略核心是同时突破均线和n周期最高/低价时入场。然后跟踪止损出场。
适合品种:['AG888', 'RB888', 'I888', 'J888', 'A888', 'Y888', 'JM888', 'PP888', 'C888', 'V888', 'JD888', 'SS888',
'EB888', 'BC888', 'SC888', 'PG888', 'EG888', 'LH888', 'SI888', 'BR888', 'EC888', 'LC888']
*/
func SF01V2(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa2 = int(pol.Def("ma2", 130, core.PNorm(50, 200)))
lenExtrm = int(pol.Def("extrm", 240, core.PNorm(100, 400)))
lenAtr = int(pol.Def("atr", 14, core.PNorm(7, 40)))
initSl := pol.Def("initSl", 100, core.PNorm(50, 150))
baseAtrLen := int(float64(lenAtr) * 4.3)
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenMa2, lenExtrm, baseAtrLen),
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(initSl, slMinRate, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
//date := btime.ToDateStrLoc(e.TimeStop, "")
maVal := ta.SMA(e.Close, lenMa2).Get(1)
openUp := e.High.Back(1).Sub(e.Close.Back(1)).Add(e.Open)
openDn := e.Low.Back(1).Sub(e.Close.Back(1)).Add(e.Open)
hh1 := ta.Highest(openUp, lenExtrm).Get(1)
ll1 := ta.Lowest(openDn, lenExtrm).Get(1)
c := e.Close.Get(1)
midPrice := (e.High.Get(1) + e.Low.Get(1)) * 0.5
width := e.High.Sub(e.Low)
m, _ := s.More.(*MTRSDirt)
var openDirt = 0.0
if width.Get(1) > width.Get(2) {
// 价差是否增大
if len(s.LongOrders) == 0 && c > max(maVal, hh1) && midPrice > e.High.Get(2) {
// 价格突破均线、周期内最高价;中间价>前bar最高
openDirt = 1
m.TrialLong(e.Close.Get(0))
} else if len(s.ShortOrders) == 0 && c < min(maVal, ll1) && midPrice < e.Low.Get(2) {
// 价格跌破均线、周期内最低价;中间价<前bar最低
openDirt = -1
m.TrialShort(e.Close.Get(0))
}
}
stopLong, stopShort := m.CalcSL2(s, lenAtr, baseAtrLen, slPow, slRate)
if s.IsWarmUp {
return
}
if openDirt != 0 {
//log.Info(fmt.Sprintf("%s, open, slVal: %.1f%% slUnit: %.2f%%",
// s.Symbols.Symbols, slUnit*m.InitSLTR*100/c, slUnit*100/c))
com.FastOpen(s, openDirt, stopLong, stopShort, 0)
}
setAllStopLoss(s, stopLong, stopShort)
},
}
}

87
org/sf/02.go Normal file
View File

@@ -0,0 +1,87 @@
package sf
import (
"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"
)
/*
AROON_UP和AROON_DN,反映了一段时间内出现最高价和最低价距离当前时间的远近。
数值越大,说明发生的时间越近;反之,数值越小,说明发生的时间越远。
AROON为二者的差值,大于0,说明最高价出现在最低价之后,离现在更近;
反之,则说明最高价出现在最低价之前,离现在更远。
使用方法
(1) 当 AROON_UP 上穿 70,并且 AROON>0,说明上涨趋势形成,产生买入信号;
(2) 当 AROON_DOWN 上穿 70,并且 AROON<0,说明下跌趋势形成,产生卖出信号;
(3) 当 AROON_UP 下穿 30,并且 AROON<0,说明上涨趋势减弱,可能反转下跌,产生卖出信号;
(4) 当 AROON_DOWN 下穿 30,并且 AROON>0,说明下跌趋势减弱,可能反转上涨,产生买入信号。
在币圈市场15m/1h/4h上均不稳定,且交易次数太少
*/
func SF02V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 250
return &strat.TradeStrat{
Version: 1,
WarmupNum: lenMa1 + 1,
MinTfScore: 0.75,
OnBar: func(s *strat.StratJob) {
e := s.Env
cXMa := e.Close.Get(0) - ta.EMA(e.Close, lenMa1).Get(0)
arnUp, arnOsc, arnDn := ta.Aroon(e.High, e.Low, lenMa1)
upX70 := arnUp.Cross(70)
upX30 := arnUp.Cross(30)
upX50 := arnUp.Cross(50)
dnX70 := arnDn.Cross(70)
dnX30 := arnDn.Cross(30)
dnX50 := arnDn.Cross(50)
oscVal := arnOsc.Get(0)
openDirt := 0.0
if len(s.LongOrders) == 0 && cXMa > 0 && oscVal > 0 {
if upX70 == 1 || dnX30 == -1 {
// (1) 当 AROON_UP 上穿 70,并且 AROON>0,说明上涨趋势形成,产生买入信号;
// (4) 当 AROON_DOWN 下穿 30,并且 AROON>0,说明下跌趋势减弱,可能反转上涨,产生买入信号。
openDirt = 1
}
} else if len(s.ShortOrders) == 0 && cXMa < 0 && oscVal < 0 {
if dnX70 == 1 || upX30 == -1 {
//if upX30 == -1 {
//(2) 当 AROON_DOWN 上穿 70,并且 AROON<0,说明下跌趋势形成,产生卖出信号;
//(3) 当 AROON_UP 下穿 30,并且 AROON<0,说明上涨趋势减弱,可能反转下跌,产生卖出信号;
openDirt = -1
}
}
if openDirt != 0 {
com.FastOpen(s, openDirt, 0, 0, 0)
}
closeDirt := 0
if len(s.LongOrders) > 0 && oscVal > 0 && upX50 == -1 {
// 当AROON大于0且AROON_UP死叉50,平多;
closeDirt = 1
}
if len(s.LongOrders) > 0 && oscVal < 0 && dnX50 == -1 {
// 当AROON小于0且AROON_DN死叉50,平空;
closeDirt = -1
}
if closeDirt != 0 {
tag := "xlong"
if closeDirt < 0 {
tag = "xshort"
}
err := s.CloseOrders(&strat.ExitReq{
Tag: tag,
Dirt: closeDirt,
})
if err != nil {
log.Error("close fail", zap.Error(err))
}
}
},
}
}

85
org/sf/03.go Normal file
View File

@@ -0,0 +1,85 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
/*
使用一定周期的变化率均线+价格均线突破作为信号。
原版只有盈利卖出信号。没有止损。
tb测试未复现文章中的净值曲线
*/
func SF03V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 100
lenMa2 = 800
return &strat.TradeStrat{
Version: 1,
WarmupNum: lenMa1 + lenMa2,
MinTfScore: 0.75,
OnBar: func(s *strat.StratJob) {
e := s.Env
ma1 := ta.SMA(e.Close, lenMa2)
ma2 := ta.SMA(ma1, lenMa1)
maSub := ma1.Get(0) - ma2.Get(0)
chg := e.High.To("chg", 0)
if !chg.Cached() {
h, l := e.High.Get(0), e.Low.Get(0)
h1, l1 := e.High.Get(1), e.Low.Get(1)
tr := max(math.Abs(h-h1), math.Abs(l-l1))
dbf, kbf := 0.0, 0.0
if h+l > h1+l1 {
dbf = tr
} else {
kbf = tr
}
chgVal := (dbf - kbf) / (dbf + kbf + float64(lenMa1)*2)
chg.Set(chgVal)
}
maChg := ta.SMA(chg, lenMa1)
maChg2 := ta.EMA(chg, lenMa1)
chgVal := chg.Get(0)
maChgSub := maChg.Get(0) - maChg2.Get(0)
c := e.Close.Get(0)
cSubMa := c - ma1.Get(0)
openDirt := 0.0
stopLoss := 0.0
if len(s.LongOrders) == 0 && cSubMa > 0 && maSub > 0 && chgVal > 0 && maChgSub > 0 {
openDirt = 1
stopLoss = c * 0.95
} else if len(s.ShortOrders) == 0 && cSubMa < 0 && maSub < 0 && chgVal < 0 && maChgSub < 0 {
openDirt = -1
stopLoss = c * 1.05
}
if openDirt != 0 {
com.FastOpen(s, openDirt, stopLoss, stopLoss, 0)
}
if len(s.LongOrders) > 0 && cSubMa < 0 {
for _, od := range s.LongOrders {
if c/od.InitPrice > 1.01 {
_ = s.CloseOrders(&strat.ExitReq{
Tag: "exitL",
OrderID: od.ID,
})
}
}
}
if len(s.ShortOrders) > 0 && cSubMa > 0 {
for _, od := range s.ShortOrders {
if c/od.InitPrice < 0.99 {
_ = s.CloseOrders(&strat.ExitReq{
Tag: "exitS",
OrderID: od.ID,
})
}
}
}
},
}
}

61
org/sf/04.go Normal file
View File

@@ -0,0 +1,61 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
/*
最高价突破上轨,且快线高于慢线时,开多。
使用前n个low作为止损。
*/
func SF04V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 20
lenMa2 = 230
X := 3.0
return &strat.TradeStrat{
Version: 1,
WarmupNum: lenMa1 + lenMa2,
MinTfScore: 0.75,
OnBar: func(s *strat.StratJob) {
e := s.Env
atr := ta.ATR(e.High, e.Low, e.Close, lenMa1)
ma1 := ta.SMA(e.Close, lenMa1)
ma2 := ta.SMA(e.Close, lenMa2)
c := e.Close.Get(0)
upperBand := c + X*atr.Get(0)
lowerBand := c - X*atr.Get(0)
stopLong := e.Low.Get(lenMa2)
stopShort := e.High.Get(lenMa2)
maSub := ma1.Get(0) - ma2.Get(0)
h, h1 := e.High.Get(0), e.High.Get(1)
l, l1 := e.Low.Get(0), e.Low.Get(1)
openPrice := 0.0
if len(s.LongOrders) == 0 && h >= upperBand && maSub > 0 && h >= h1 {
openPrice = max(c, upperBand, e.High.Get(lenMa1))
} else if len(s.ShortOrders) == 0 && l < lowerBand && maSub < 0 && l <= l1 {
openPrice = -min(c, lowerBand, e.Low.Get(lenMa1))
}
if openPrice != 0 {
com.FastOpen(s, openPrice, stopLong, stopShort, math.Abs(openPrice))
}
for _, od := range s.LongOrders {
if l >= od.InitPrice && l <= stopLong {
od.SetStopLoss(&ormo.ExitTrigger{Price: stopLong})
}
}
for _, od := range s.ShortOrders {
if h <= od.InitPrice && h >= stopShort {
od.SetStopLoss(&ormo.ExitTrigger{Price: stopShort})
}
}
},
}
}

83
org/sf/05.go Normal file
View File

@@ -0,0 +1,83 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banexg/log"
ta "github.com/banbox/banta"
"go.uber.org/zap"
"math"
)
/*
策略说明:
基于K线加权均值的支撑阻力线的突破系统
1. 支撑线 = 周期范围内的K线加权均值 - ( 最高价 - K线加权均值)
2. 阻力线 = 周期范围内的K线加权均值 + ( K线加权均值 - 最低价)
入场
1. 当价格向上突破阻力线做多
2. 当价格向下突破支撑线做空
出场
1. 趋势反转即反向突破时出场
2. 基于ATR的一定倍数的止盈
*/
func SF05V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 250
trs := 30.0
return &strat.TradeStrat{
Version: 1,
WarmupNum: lenMa1,
MinTfScore: 0.75,
OnBar: func(s *strat.StratJob) {
e := s.Env
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
avgP := (h + l + c*2) / 4
rsv := e.Close.To("rsv2", 0)
rsv.Set(avgP*2 - l)
rs := ta.Highest(rsv, lenMa1)
stv := e.Close.To("stv", 0)
stv.Set(avgP*2 - h)
st := ta.Lowest(stv, lenMa1)
atr := ta.ATR(e.High, e.Low, e.Close, lenMa1).Get(0)
openPrice := 0.0
if len(s.LongOrders) == 0 && h > rs.Get(0) {
openPrice = max(c, rs.Get(0))
} else if len(s.ShortOrders) == 0 && l < st.Get(0) {
openPrice = -min(c, st.Get(0))
}
slVal := atr * trs
takeLong, takeShort := c+slVal, c-slVal
if openPrice != 0 {
openTag := "long"
takeProfit := takeLong
if openPrice < 0 {
openTag = "short"
takeProfit = takeShort
}
err := s.OpenOrder(&strat.EnterReq{
Tag: openTag,
Short: openPrice < 0,
Limit: math.Abs(openPrice),
TakeProfit: takeProfit,
})
if err != nil {
log.Error("open fail", zap.Error(err))
}
exitDirt := 1
exitTag := "exitL"
if openPrice > 0 {
exitDirt = -1
exitTag = "exitS"
}
_ = s.CloseOrders(&strat.ExitReq{
Tag: exitTag,
Dirt: exitDirt,
})
}
},
}
}

67
org/sf/06.go Normal file
View File

@@ -0,0 +1,67 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
同时突破:两个周期的最高价、均线
跟踪止损退出
*/
func SF06V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 30
lenMaRate = 3
lenMa2 = int(float64(lenMa1) * lenMaRate)
lenAtr = max(15, lenMa1/2)
baseAtrLen := lenAtr * 13 / 5
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenMa2, baseAtrLen),
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(20, 0.5, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
hh1 := ta.Highest(e.High.Back(lenMa1), lenMa1)
hh2 := ta.Highest(e.High.Back(lenMa2), lenMa2)
ll1 := ta.Lowest(e.Low.Back(lenMa1), lenMa1)
ll2 := ta.Lowest(e.Low.Back(lenMa2), lenMa2)
hh1Val, hh2Val, ll1Val, ll2Val := hh1.Get(0), hh2.Get(0), ll1.Get(0), ll2.Get(0)
c, c1 := e.Close.Get(0), e.Close.Get(1)
entLong := c > max(hh1Val, hh2Val, e.Close.Get(lenMa1))
entShort := c < min(ll1Val, ll2Val, e.Close.Get(lenMa1))
fltLong := c1 > min(hh1Val, hh2Val)
fltShort := c1 < max(ll1Val, ll2Val)
m, _ := s.More.(*MTRSDirt)
openDirt := 0.0
if len(s.LongOrders) == 0 && hh1Val > hh2Val && entLong && fltLong {
openDirt = 1
m.TrialLong(c)
} else if len(s.ShortOrders) == 0 && ll1Val < ll2Val && entShort && fltShort {
openDirt = -1
m.TrialShort(c)
}
stopLong, stopShort := m.CalcSL2(s, lenAtr, baseAtrLen, 0.5, 0.5)
if openDirt != 0 {
//log.Info(fmt.Sprintf("open, slVal: %.1f%% trRate: %.2f atr: %.1f%%",
// atrBase*atrRate*100/c, atrRate, atrBase*100/c))
com.FastOpen(s, openDirt, stopLong, stopShort, 0)
}
setAllStopLoss(s, stopLong, stopShort)
},
}
}

75
org/sf/08.go Normal file
View File

@@ -0,0 +1,75 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
func SF08V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = int(pol.Def("ma1", 139, core.PNorm(10, 300)))
lenMaRate = pol.Def("maRate", 2.47, core.PNorm(1.5, 5))
lenMa2 = int(float64(lenMa1) * lenMaRate)
lenExtrm = int(pol.Def("extrm", 30, core.PNorm(10, 300)))
lenAtr = int(pol.Def("atr", 20, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
initSl := pol.Def("initSl", 90, core.PNorm(30, 150))
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenMa2+lenMa1, baseAtrLen),
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(initSl, slMinRate, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
ma := ta.SMA(e.Close, lenMa2).Get(0)
kk, _, krsv := ta.KDJBy(e.High, e.Low, e.Close, lenMa2, lenMa1, lenMa1, "sma")
kdX := krsv.Cross(kk)
hh := ta.Highest(e.High, lenExtrm)
ll := ta.Lowest(e.Low, lenExtrm)
hd := e.Close.To("hd", 0)
ld := e.Close.To("ld", 0)
m, _ := s.More.(*MTRSDirt)
if kdX == 1 {
hd.Set(hh.Get(0))
} else if kdX == -1 {
ld.Set(ll.Get(0))
}
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
hdVal1, ldVal1 := hd.Get(1), ld.Get(1)
openPrice := 0.0
if len(s.LongOrders) == 0 && kdX == 2 && h >= hdVal1 && hdVal1 > 0 && c > ma {
openPrice = hdVal1
m.TrialLong(hdVal1)
} else if len(s.ShortOrders) == 0 && kdX == -2 && l < ldVal1 && ldVal1 > 0 && c < ma {
openPrice = -ldVal1
m.TrialShort(ldVal1)
}
stopLong, stopShort := m.CalcSL2(s, lenAtr, baseAtrLen, slPow, slRate)
if openPrice != 0 {
entPrice := math.Abs(openPrice)
//if (entPrice-c)*openPrice < 0 {
// // 限价入场
// slVal := stopShort - entPrice
// stopLong, stopShort = entPrice-slVal, entPrice+slVal
//}
com.FastOpen(s, openPrice, stopLong, stopShort, entPrice)
}
setAllStopLoss(s, stopLong, stopShort)
},
}
}

72
org/sf/10.go Normal file
View File

@@ -0,0 +1,72 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
type Band10 struct {
Band float64
PBand float64
BandUp float64
BandDn float64
DAtr float64
}
func SF10V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
var lenDayAtr = 30
var k = 1.0
//var slRate = 1.5
//lenAtr = max(15, lenMa1/2)
//baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
return &strat.TradeStrat{
Version: 1,
WarmupNum: 30,
MinTfScore: 0.75,
DrawDownExit: true,
OnStartUp: func(s *strat.StratJob) {
s.More = &Band10{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 30},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*Band10)
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
openDirt := 0.0
if m.Band > m.PBand {
l1, h1 := e.Low.Get(1), e.High.Get(1)
if len(s.LongOrders) == 0 && h >= m.BandUp && l1 < m.BandUp {
openDirt = 1
} else if len(s.ShortOrders) == 0 && l <= m.BandDn && h1 > m.BandDn {
openDirt = -1
}
if openDirt != 0 {
stopLong, stopShort := c-m.Band, c+m.Band
com.FastOpen(s, openDirt, stopLong, stopShort, 0)
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*Band10)
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
m.PBand = m.Band
m.Band = max(h-c, c-l) * k
m.BandUp, m.BandDn = c+m.Band, c-m.Band
m.DAtr = ta.ATR(e.High, e.Low, e.Close, lenDayAtr).Get(0) * 100 / c
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
m, _ := s.More.(*Band10)
//rate := math.Sqrt(m.DAtr)
rate := m.DAtr * 5
return strat.CalcDrawDownExitRate(maxChg / rate)
},
}
}

80
org/sf/14.go Normal file
View File

@@ -0,0 +1,80 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
type More14 struct {
*com.TRS
dirt int
btm float64
top float64
hh float64
ll float64
}
func SF14V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr = 50
atrAlpha := 20.0
atrN := 3.0
lenAtr2 := 15
baseAtrLen := int(math.Round(float64(lenAtr2) * 4.3))
return &strat.TradeStrat{
Version: 1,
WarmupNum: baseAtrLen,
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &More14{
TRS: com.NewTRS(30, 0.5, 5),
dirt: 1,
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*More14)
atrVal := ta.ATR(e.High, e.Low, e.Close, lenAtr).Get(0)
hl2 := (e.High.Get(0) + e.Low.Get(0)) / 2
c, o := e.Close.Get(0), e.Open.Get(0)
h, l := e.High.Get(0), e.Low.Get(0)
curBtm := hl2 - atrVal*atrAlpha
curTop := hl2 + atrVal*atrAlpha
openDirt := 0.0
if m.btm == 0 || math.IsNaN(m.btm) {
m.btm = curBtm
m.top = curTop
} else {
if m.dirt == 1 && len(s.LongOrders) == 0 && h >= m.hh {
openDirt = 1
m.TrialLong(c)
} else if m.dirt == -1 && len(s.ShortOrders) == 0 && l <= m.ll {
openDirt = -1
m.TrialShort(c)
}
if m.dirt == -1 && c > m.top {
m.dirt = 1
} else if m.dirt == 1 && c < m.btm {
m.dirt = -1
}
if c > m.btm {
m.btm = max(m.btm, curBtm)
} else {
m.top = min(m.top, curTop)
}
}
m.hh = o + atrVal*atrN
m.ll = o - atrVal*atrN
slLong, slShort := m.CalcSL2(s, lenAtr2, baseAtrLen, 0.5, 0.5)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
},
}
}

67
org/sf/17.go Normal file
View File

@@ -0,0 +1,67 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
func SF17V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = int(pol.Def("ma1", 62, core.PNorm(10, 300)))
lenMaRate = pol.Def("maRate", 4.34, core.PNorm(1.5, 5))
lenMa2 = int(float64(lenMa1) * lenMaRate)
lenAtr = int(pol.Def("atr", 20, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
initSl := pol.Def("initSl", 101, core.PNorm(30, 150))
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenMa2*2, baseAtrLen),
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(initSl, slMinRate, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
avgPrice := ta.AvgPrice(e)
ma1 := ta.SMA(avgPrice, lenMa1)
ma2 := ta.EMA(ma1, lenMa1)
maLong1 := ta.SMA(avgPrice, lenMa2)
maLong2 := ta.EMA(maLong1, lenMa2)
maRange := ma1.Sub(maLong2)
maRangeE := ta.EMA(maRange, lenMa1)
hh := ta.Highest(e.High, lenMa2)
ll := ta.Lowest(e.Low, lenMa2)
maRangeVal, maRangeEVal := maRange.Get(0), maRangeE.Get(0)
ma1Val, ma2Val, maLong1Val, maLong2Val := ma1.Get(0), ma2.Get(0), maLong1.Get(0), maLong2.Get(0)
maSub, longSub, otherSub := ma1Val-ma2Val, maLong1Val-maLong2Val, ma2Val-maLong2Val
rangeSub := maRangeVal - maRangeEVal
hhSub, llSub := e.High.Get(0)-hh.Get(0), e.Low.Get(0)-ll.Get(0)
m, _ := s.More.(*MTRSDirt)
openDirt := 0.0
if len(s.LongOrders) == 0 && hhSub >= 0 && rangeSub > 0 && maRangeVal > 0 && maSub > 0 && longSub > 0 && otherSub > 0 {
openDirt = 1
m.TrialLong(e.Close.Get(0))
} else if len(s.ShortOrders) == 0 && llSub <= 0 && rangeSub < 0 && maRangeVal < 0 && maSub < 0 && longSub < 0 && otherSub < 0 {
openDirt = -1
m.TrialShort(e.Close.Get(0))
}
if openDirt != 0 {
com.FastOpen(s, openDirt, 0, 0, 0)
}
stopLong, stopShort := m.CalcSL2(s, lenAtr, baseAtrLen, slPow, slRate)
setAllStopLoss(s, stopLong, stopShort)
},
}
}

137
org/sf/18.go Normal file
View File

@@ -0,0 +1,137 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"slices"
)
/*策略思想:
1.使用变量将MACD的快慢均线交叉点记录,
然后获取上次交叉到本次交叉之间的周期数。
计算此周期内的高低点,
当价格突破交叉后的高低点时进场,当MACD金叉(死叉)时出场;
2.当MACD出现顶底背离时,开多开空;
核心计算:1.MACD交叉状态记录
2.构建周期内的高低点区间
3.描述背离状态,同时保存结果;
多头进场:1.最近一个MACD信号是金叉,突破周期内高点;
2. 出现底背离时,开多;
空头进场:1.最近一个MACD信号是死叉,突破周期内低点;
2.出现顶背离时,开空;
2024/05/24 anyongjin
上面是原始逻辑,但测试发现顶底背离时按传统逻辑反而稳定亏损,改成顶背离开多,底背离开空反而盈利
*/
//使用周期:1小时周期
type More18 struct {
*com.TRS
LHNum int // 上次金叉的序号
LLNum int // 上次死叉的序号
XHigh float64 // 上次交叉到本次交叉之间最高点,突破开多
XLow float64 // 上次交叉到本次交叉之间最低点,突破开空
ExmDirt int // 上次突破最高最低的方向
LHPrice float64 // 上次上穿时的价格
LLPrice float64 // 上次下穿时的价格
LHMacd float64 // 上次上穿时macd的值
LLMacd float64 // 上次下穿时macd的值
RevDirt int // 上次背离的方向
}
func SF18V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenN := int(pol.Def("n", 8, core.PNorm(2, 30)))
lenX := int(pol.Def("x", 10, core.PNorm(5, 50)))
lenAtr = int(pol.Def("atr", 15, core.PNorm(7, 40)))
lenAtrB := int(float64(lenAtr) * 4.3)
initSl := pol.Def("initSl", 100, core.PNorm(20, 150))
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenAtrB, lenN*9),
OnStartUp: func(s *strat.StratJob) {
s.More = &More18{
TRS: com.NewTRS(initSl, slMinRate, 8),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
macd, sig := ta.MACD(e.Close, 4*lenN, 9*lenN, 3*lenN)
macdX := macd.Cross(sig)
c := e.Close.Get(0)
m, _ := s.More.(*More18)
openDirt := 0.0
if macdX == 1 {
x2Dist := (e.BarNum - m.LHNum) * 7 / 5
m.XHigh = slices.Max(e.High.Range(1, max(lenX, x2Dist)))
cHMacd := sig.Get(0)
m.LHNum = e.BarNum
if c < m.LHPrice && cHMacd > m.LHMacd && cHMacd < 0 {
// 底背离,但开空
openDirt = -1
}
m.LHPrice = c
m.LHMacd = cHMacd
} else if macdX == -1 {
x2Dist := (e.BarNum - m.LLNum) * 7 / 5
m.XLow = slices.Min(e.Low.Range(1, max(lenX, x2Dist)))
cLMacd := sig.Get(0)
m.LLNum = e.BarNum
if c > m.LLPrice && cLMacd < m.LLMacd && cLMacd > 0 {
// 顶背离,但开多
openDirt = 1
}
m.LLPrice = c
m.LLMacd = cLMacd
}
// 这里是控制是否过滤背离重复开单的。注释掉不过滤的话,开单数增加一倍,利润增加一倍
//if openDirt != 0 {
// if int(openDirt) == m.RevDirt {
// openDirt = 0
// } else {
// m.RevDirt = int(openDirt)
// }
//}
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrVal := atr.Get(0)
if macdX >= 2 && c >= m.XHigh+atrVal*2 && m.XHigh > 0 && m.ExmDirt != 1 {
// 金叉,突破两次交叉高点,开多
openDirt = 1
m.ExmDirt = 1
} else if macdX <= -2 && c <= m.XLow-atrVal*2 && m.XLow > 0 && m.ExmDirt != -1 {
// 死叉,突破两次交叉低点,开空
openDirt = -1
m.ExmDirt = -1
}
if openDirt == 1 { //&& len(s.LongOrders) == 0 {
m.TrialLong(e.Close.Get(0))
} else if openDirt == -1 { //} && len(s.ShortOrders) == 0 {
m.TrialShort(e.Close.Get(0))
} else {
openDirt = 0
}
slLong, slShort := m.CalcSL(s, atr, lenAtr, lenAtrB, slPow, slRate)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
},
}
}

73
org/sf/19.go Normal file
View File

@@ -0,0 +1,73 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
type More19 struct {
*com.TRS
UpHigh float64 // 金叉时最高价
DnLow float64 // 死叉时最低价
}
func SF19V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 30
lenMa2 = lenMa1 * 3
lenExtrm = lenMa1
lenAtr = 15
baseAtrLen := lenAtr * 13 / 5
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(baseAtrLen, lenMa2),
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &More19{
TRS: com.NewTRS(30, 0.5, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
mid := ta.AvgPrice(e)
ma1 := ta.VWMA(mid, e.Volume, lenMa1)
ma2 := ta.VWMA(mid, e.Volume, lenMa2)
crx := ma1.Cross(ma2)
hh, ll := ta.Highest(e.High, lenExtrm), ta.Lowest(e.Low, lenExtrm)
h, l := e.High.Get(0), e.Low.Get(0)
coSub := e.Close.Get(0) - e.Open.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
m, _ := s.More.(*More19)
if crx == 1 {
// 上穿,金叉;
m.UpHigh = hh.Get(0)
} else if crx == -1 {
// 下穿,死叉
m.DnLow = ll.Get(0)
}
openDirt := 0.0
if crx >= 1 && len(s.LongOrders) == 0 && coSub > 0 {
// 金叉,突破最高,当前是阳线
if h >= max(m.UpHigh, hh.Get(0)) {
openDirt = 1
}
} else if crx <= -1 && len(s.ShortOrders) == 0 && coSub < 0 {
// 死叉,突破最低,阴线
if l <= min(m.DnLow, ll.Get(0)) {
openDirt = -1
}
}
slLong, slShort := m.CalcSL(s, atr, lenAtr, baseAtrLen, 0.5, 0.5)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
},
}
}

68
org/sf/21.go Normal file
View File

@@ -0,0 +1,68 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
/*
初始版本:
本质上是简化版RSI,超买做空,超卖做多;vwma跟踪止损出场
修改版本:
RSI在75~93开多;在7-25开空;同时结合ma过滤;跟踪止损出场。
*/
func SF21V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = int(pol.Def("ma1", 10, core.PNorm(10, 300)))
lenMaRate = pol.Def("maRate", 3, core.PNorm(1.5, 5))
lenMa2 = int(float64(lenMa1) * lenMaRate)
lenExtrm = int(pol.Def("extrm", 15, core.PNorm(10, 400)))
lenAtr = int(pol.Def("atr", 15, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
initSl := pol.Def("initSl", 60, core.PNorm(20, 200))
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(baseAtrLen, lenMa2),
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(initSl, slMinRate, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
rsi := ta.RSI50(e.Close, lenExtrm).Get(0)
rsiAbs := math.Abs(rsi)
ma1 := ta.SMA(e.Close, lenMa1)
ma2 := ta.SMA(e.Close, lenMa2)
maSub := ma1.Get(0) - ma2.Get(0)
c := e.Close.Get(0)
m, _ := s.More.(*MTRSDirt)
openDirt := 0.0
if rsiAbs > 25 && rsiAbs < 43 && rsi*maSub > 0 && s.OrderNum == 0 {
if rsi < 0 {
m.TrialShort(c)
openDirt = -1
} else {
m.TrialLong(c)
openDirt = 1
}
}
slLong, slShort := m.CalcSL2(s, lenAtr, baseAtrLen, slPow, slRate)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
},
}
}

75
org/sf/30_v0.go Normal file
View File

@@ -0,0 +1,75 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
/*
原始版本:止损空间TRS使用固定百分比,测试在4h上收益较好,低于4h不够稳定。
*/
func SF30V0(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 100
lenMaRate = 3
lenMa2 = int(float64(lenMa1) * lenMaRate)
var trs = 0.01
return &strat.TradeStrat{
Version: 1,
WarmupNum: lenMa2,
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(1, 0.301, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
p := ta.AvgPrice(e)
ma1 := ta.SMA(p, lenMa1)
slowMa1 := ta.EMA(ma1, lenMa1)
ma2 := ta.SMA(p, lenMa2)
slowMa2 := ta.EMA(ma2, lenMa2)
dlh := slowMa1.Sub(slowMa2)
maDlh := ta.EMA(dlh, lenMa1)
hh := ta.Highest(e.High, lenMa2)
ll := ta.Lowest(e.Low, lenMa2)
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
m, _ := s.More.(*MTRSDirt)
vMa1, vSlowMa1 := ma1.Get(0), slowMa1.Get(0)
vMa2, vSlowMa2 := ma2.Get(0), slowMa2.Get(0)
sub1, sub2, subSlow := vMa1-vSlowMa1, vMa2-vSlowMa2, vSlowMa1-vSlowMa2
vDlh, vMaDlh := dlh.Get(0), maDlh.Get(0)
subDlh := vDlh - vMaDlh
curDirt := 0
if sub1 > 0 && sub2 > 0 && subSlow > 0 && vDlh > 0 && subDlh > 0 {
curDirt = 1
} else if sub1 < 0 && sub2 < 0 && subSlow < 0 && vDlh < 0 && subDlh < 0 {
curDirt = -1
}
openPrice := float64(0)
if m.dirt == 1 && h >= hh.Get(1) && len(s.LongOrders) == 0 {
openPrice = max(e.Open.Get(0), hh.Get(1))
m.TrialLong(min(openPrice, c))
} else if m.dirt == -1 && l <= ll.Get(1) && len(s.ShortOrders) == 0 {
openPrice = min(e.Open.Get(0), ll.Get(1))
m.TrialShort(max(openPrice, c))
openPrice = -openPrice
}
m.dirt = curDirt
stopLong, stopShort := m.Calc(s, c*trs)
if openPrice != 0 {
com.FastOpen(s, openPrice, stopLong, stopShort, math.Abs(openPrice))
}
setAllStopLoss(s, stopLong, stopShort)
},
}
}

78
org/sf/30_v1.go Normal file
View File

@@ -0,0 +1,78 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
func SF30V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = int(pol.Def("ma1", 54, core.PNorm(10, 300)))
lenMaRate = pol.Def("maRate", 1.82, core.PNorm(1.5, 5))
lenMa2 = int(float64(lenMa1) * lenMaRate)
lenAtr = int(pol.Def("atr", 20, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
initSl := pol.Def("initSl", 120, core.PNorm(20, 160))
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenMa2, baseAtrLen),
OnStartUp: func(s *strat.StratJob) {
s.More = &MTRSDirt{
TRS: com.NewTRS(initSl, slMinRate, 5),
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
p := ta.AvgPrice(e)
ma1 := ta.SMA(p, lenMa1)
slowMa1 := ta.EMA(ma1, lenMa1)
ma2 := ta.SMA(p, lenMa2)
slowMa2 := ta.EMA(ma2, lenMa2)
dlh := slowMa1.Sub(slowMa2)
maDlh := ta.EMA(dlh, lenMa1)
hh := ta.Highest(e.High, lenMa2)
ll := ta.Lowest(e.Low, lenMa2)
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
m, _ := s.More.(*MTRSDirt)
vMa1, vSlowMa1 := ma1.Get(0), slowMa1.Get(0)
vMa2, vSlowMa2 := ma2.Get(0), slowMa2.Get(0)
sub1, sub2, subSlow := vMa1-vSlowMa1, vMa2-vSlowMa2, vSlowMa1-vSlowMa2
vDlh, vMaDlh := dlh.Get(0), maDlh.Get(0)
subDlh := vDlh - vMaDlh
curDirt := 0
if sub1 > 0 && sub2 > 0 && subSlow > 0 && vDlh > 0 && subDlh > 0 {
curDirt = 1
} else if sub1 < 0 && sub2 < 0 && subSlow < 0 && vDlh < 0 && subDlh < 0 {
curDirt = -1
}
openPrice := float64(0)
if m.dirt == 1 && h >= hh.Get(1) && len(s.LongOrders) == 0 {
openPrice = max(e.Open.Get(0), hh.Get(1))
m.TrialLong(min(openPrice, c))
} else if m.dirt == -1 && l <= ll.Get(1) && len(s.ShortOrders) == 0 {
openPrice = min(e.Open.Get(0), ll.Get(1))
m.TrialShort(max(openPrice, c))
openPrice = -openPrice
}
m.dirt = curDirt
stopLong, stopShort := m.CalcSL2(s, lenAtr, baseAtrLen, slPow, slRate)
if openPrice != 0 {
//log.Info("open:", zap.Float64("slVal", slVal/c), zap.Float64("trRate", atrRate),
// zap.Float64("atr", atrBase/c))
com.FastOpen(s, openPrice, stopLong, stopShort, math.Abs(openPrice))
}
setAllStopLoss(s, stopLong, stopShort)
},
}
}

103
org/sf/33.go Normal file
View File

@@ -0,0 +1,103 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
type More33 struct {
*com.TRS
openD float64 // 当日开盘价
trend int
}
func SF33V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenBid := int(pol.Def("ma1", 9, core.PNorm(10, 300)))
lenAtr = int(pol.Def("atr", 14, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.0)
lenTit := int(pol.Def("tit", 5, core.PNorm(3, 30)))
wid1 := pol.Def("wid", 1, core.PNorm(0.5, 5))
wid2 := wid1
initSl := pol.Def("initSl", 60, core.PNorm(20, 150))
slMinRate, slPow, slRate := 0.4, 0.3, 0.6
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(baseAtrLen, lenTit, lenBid),
OnStartUp: func(s *strat.StratJob) {
s.More = &More33{
TRS: com.NewTRS(initSl, slMinRate, 5),
}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 2},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
hh := ta.Highest(e.High, lenBid)
ll := ta.Lowest(e.Low, lenBid)
abid := ta.EMA(hh.Sub(ll), lenBid)
mid := ta.EMA(e.High, lenTit).Add(ta.EMA(e.Low, lenTit)).Mul(0.5)
bidN := abid.Mul(wid1)
up := mid.Add(bidN)
dn := mid.Sub(bidN)
m, _ := s.More.(*More33)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
dhh := m.openD + atr.Get(0)*wid2
dll := m.openD - atr.Get(0)*wid2
h, l := e.High.Get(0), e.Low.Get(0)
xLong, xShort := false, false
if m.trend != 1 && h >= max(up.Get(0), hh.Get(0)) {
m.trend = 1
xLong = true
}
if m.trend != -1 && l <= min(dn.Get(0), ll.Get(0)) {
m.trend = -1
xShort = true
}
uppVal := up.Get(0)
dnnVal := dn.Get(0)
// 当trend=1的时候,也就是多头判定后,如果出现dn线比前一个还小情况,那么用前一个大的,不再减小dn线
if !xLong && m.trend > 0 && dnnVal < dn.Get(1) {
dnnVal = dn.Get(1)
}
// 当trend=-1的时候,也就是空头判定后,如果出现up线比前一个还大情况,那么用前一个大的,不再增加up线
if !xShort && m.trend < 0 && uppVal > up.Get(1) {
uppVal = up.Get(1)
}
c := e.Close.Get(0)
openDirt := 0.0
if m.trend == 1 && c > dnnVal && h >= dhh && len(s.LongOrders) == 0 {
openDirt = 1
m.TrialLong(c)
}
if m.trend == -1 && c < uppVal && l < dll && len(s.ShortOrders) == 0 {
openDirt = -1
m.TrialShort(c)
}
slLong, slShort := m.CalcSL(s, atr, lenAtr, baseAtrLen, slPow, slRate)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*More33)
m.openD = e.Open.Get(0)
},
}
}

112
org/sf/35.go Normal file
View File

@@ -0,0 +1,112 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
type More35 struct {
yma float64 // 单边权重均线
openD float64
longMin float64
shortMax float64
dirt float64 // 1超买,-1超卖
*com.EFTRS
}
func SF35V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenSmt := int(pol.Def("ma1", 12, core.PNorm(10, 300)))
lenAtr = int(pol.Def("atr", 14, core.PNorm(7, 40)))
lenAtBig := int(float64(lenAtr) * 4)
mulB := pol.Def("b", 3, core.PNorm(1.2, 10))
mulD := pol.Def("d", 2, core.PNorm(1.2, 10))
slMul := pol.Def("sl", 3, core.PNorm(1.2, 10))
lenEff := int(pol.Def("eff", 10, core.PNorm(3, 100)))
return &strat.TradeStrat{
Version: 1,
WarmupNum: max(lenAtBig, lenSmt),
OnStartUp: func(s *strat.StratJob) {
s.More = &More35{
dirt: 1,
EFTRS: com.NewEFTRS(lenEff),
}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 2},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*More35)
// 计算均线
closes := e.Close.Range(0, lenSmt+1)
c := closes[0]
if len(closes) == 1 || math.IsNaN(c) {
m.yma = c
} else {
upSum, dnSum := float64(0), float64(0)
num := len(closes) - 1
for i, v := range closes[:num] {
sub := v - closes[i+1]
if sub > 0 {
upSum += sub
} else {
dnSum -= sub
}
}
// cmo: 度量单边系数;值域0-1;1表示单边涨或跌,0表示震荡
cmo := math.Abs(upSum-dnSum) / (upSum + dnSum)
weight := 2 * cmo / (1 + float64(lenSmt))
m.yma = c*weight + m.yma*(1-weight)
}
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrMx := ta.Highest(atr, lenAtBig).Get(0)
// 计算上下轨
longMin, shortMax := m.yma-atrMx*mulB, m.yma+atrMx*mulB
if m.yma > m.longMin {
longMin = max(longMin, m.longMin)
}
if m.yma < m.shortMax {
shortMax = min(shortMax, m.shortMax)
}
if m.dirt == -1 && m.yma > m.shortMax {
m.dirt = 1
} else if m.dirt == 1 && m.yma < m.longMin {
m.dirt = -1
}
m.longMin = longMin
m.shortMax = shortMax
hh, ll := m.openD+atrMx*mulD, m.openD-atrMx*mulD
openDirt := 0.0
if m.dirt == 1 && c >= max(hh, longMin) && len(s.LongOrders) == 0 {
openDirt = 1
} else if m.dirt == -1 && c <= min(ll, shortMax) && len(s.ShortOrders) == 0 {
openDirt = -1
}
// 根据ER效率计算止损
slLong, slShort := m.Calc(s, atrMx*slMul)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*More35)
m.openD = e.Open.Get(0)
},
}
}

138
org/sf/36.go Normal file
View File

@@ -0,0 +1,138 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
/*
无输出信号
*/
type More36 struct {
pdmS float64
mdmS float64
pdiS float64
mdiS float64
vma float64
support float64
stress float64
dirt int
openD float64
*com.EFTRS
}
func SF36V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr = 14
lenAtBig := lenAtr * 17 / 4
alpha := 6.0
mulB, mulD, slMul := 2.0, 2.0, 2.0
lenEff := 10
return &strat.TradeStrat{
Version: 1,
WarmupNum: lenAtBig,
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &More36{
dirt: 1,
EFTRS: com.NewEFTRS(lenEff),
}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 2},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*More36)
k := 1 / alpha
c, c1 := e.Close.Get(0), e.Close.Get(1)
pdm := max(c-c1, 0)
mdm := max(c1-c, 0)
m.pdmS = (1-k)*m.pdmS + k*pdm
m.mdmS = (1-k)*m.mdmS + k*mdm
pdi := m.pdmS / (m.pdmS + m.mdmS)
mdi := m.mdmS / (m.pdmS + m.mdmS)
m.pdiS = (1-k)*m.pdiS + k*pdi
m.mdiS = (1-k)*m.mdiS + k*mdi
iS := e.Close.To("iS", 0)
if !iS.Cached() {
if iS.Len() == 0 {
iS.Append(0)
} else {
val := (1-k)*iS.Get(0) + k*math.Abs(m.pdiS-m.mdiS)/(m.pdiS+m.mdiS)
iS.Append(val)
}
}
isVal := iS.Get(0)
hhv := ta.Highest(iS, int(alpha)).Get(0)
llv := ta.Lowest(iS, int(alpha)).Get(0)
vI := (isVal - llv) / (hhv - llv)
if m.vma == 0 {
m.vma = c
} else {
m.vma = (1-k*vI)*m.vma + k*vI*c
}
atr := ta.Lowest(ta.ATR(e.High, e.Low, e.Close, lenAtBig), lenAtr)
atrV, atrV2 := atr.Get(0), atr.Get(1)
support := m.vma - atrV*mulB
stress := m.vma + atrV*mulB
if m.vma > m.support {
support = max(m.support, support)
}
if m.vma < m.stress {
stress = min(m.stress, stress)
}
var dirt = m.dirt
if m.dirt == -1 && m.vma > m.stress {
dirt = 1
} else if m.dirt == 1 && m.vma < m.support {
dirt = -1
}
hh := e.Close.To("hh", 0)
ll := e.Close.To("ll", 0)
if !hh.Cached() {
hh.Append(m.openD + atrV2*mulD)
}
if !ll.Cached() {
ll.Append(m.openD - atrV2*mulD)
}
upHH := e.Close.Cross(hh)
dnLL := e.Close.Cross(ll)
openDirt := 0.0
if m.dirt == 1 && upHH == 2 && c > m.support && len(s.LongOrders) == 0 {
openDirt = 1
} else if m.dirt == -1 && dnLL == -2 && c < m.stress && len(s.ShortOrders) == 0 {
openDirt = -1
}
slLong, slShort := m.Calc(s, atrV2*slMul)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
m.support = support
m.stress = stress
m.dirt = dirt
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*More36)
m.openD = e.Open.Get(0)
},
}
}

97
org/sf/37.go Normal file
View File

@@ -0,0 +1,97 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
交易信号很少
*/
type More37 struct {
tup float64
tdown float64
dirt int
madd float64
openD float64
*com.EFTRS
}
func SF37V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
length := 20
lenMad := 5
mulB, mulD, slMul := 2.0, 2.0, 2.0
lenEff := 10
return &strat.TradeStrat{
Version: 1,
WarmupNum: length,
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &More37{
dirt: 1,
EFTRS: com.NewEFTRS(lenEff),
}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", lenMad},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*More37)
half := (length - 1) / 2
c1 := e.Close.Get(1)
ayami := ta.EMA(e.Close.Add(e.Close.Sub(e.Close.Back(half))), length)
ayaV, ayaV1 := ayami.Get(0), ayami.Get(1)
atr := ta.Highest(ta.ATR(e.High, e.Low, e.Close, length), length).Get(1)
solid := ta.Highest(ta.SMA(e.Close.Sub(e.Open).Abs(), length), length)
up := ayami.Get(0) + mulB*solid.Get(1)
dn := ayami.Get(0) - mulB*solid.Get(1)
tup, tdown, dirt := float64(0), float64(0), m.dirt
if m.tup == 0 || ayaV1 <= m.tup || dn > m.tup {
tup = dn
}
if m.tdown == 0 || ayaV1 >= m.tdown || up < m.tdown {
tdown = up
}
if ayaV > m.tdown {
dirt = 1
} else if ayaV < m.tup {
dirt = -1
}
hh := m.openD + solid.Get(0)*mulD
ll := m.openD - solid.Get(0)*mulD
openDirt := 0.0
if m.dirt == 1 && len(s.LongOrders) == 0 && c1 > max(m.madd, hh) {
openDirt = 1
} else if m.dirt == -1 && len(s.ShortOrders) == 0 && c1 < min(m.madd, ll) {
openDirt = -1
}
slLong, slShort := m.Calc(s, atr*slMul)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
m.tup = tup
m.tdown = tdown
m.dirt = dirt
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*More37)
m.madd = ta.SMA(e.Close, lenMad).Get(0)
m.openD = e.Open.Get(0)
},
}
}

98
org/sf/38.go Normal file
View File

@@ -0,0 +1,98 @@
package sf
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
type More38 struct {
upper float64
lower float64
dirt int
openD float64
*com.EFTRS
}
func SF38V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenMa1 = 4
lenMa2 = 16
lenC := 50
lenMad := 5
lenAtr = 20
length := 20
mulB, mulD, slMul := 2.0, 2.0, 2.0
lenEff := 10
return &strat.TradeStrat{
Version: 1,
WarmupNum: length,
MinTfScore: 0.75,
OnStartUp: func(s *strat.StratJob) {
s.More = &More38{
dirt: 1,
EFTRS: com.NewEFTRS(lenEff),
}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", lenMad},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*More38)
c1 := e.Close.Get(1)
ma1 := ta.SMA(e.Close, lenMa1)
ma2 := ta.SMA(e.Close, lenMa2)
avgMa := e.Close.To("avgMa", 0)
if !avgMa.Cached() {
avgMa.Append((ma1.Get(0) + ma2.Get(0)) / 2)
}
maVal := ta.SMA(avgMa, lenC).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
solid := ta.Highest(ta.SMA(e.Close.Sub(e.Open).Abs(), length), length)
up := maVal + solid.Get(0)*mulB
dn := maVal - solid.Get(0)*mulB
upper, lower := m.upper, m.lower
if c1 > upper && up > upper {
upper = up
}
if c1 < lower && dn < lower {
lower = dn
}
if c1 > lower {
m.dirt = 1
} else if c1 < upper {
m.dirt = -1
}
hh := m.openD + solid.Get(0)*mulD
ll := m.openD - solid.Get(0)*mulD
openDirt := 0.0
if m.dirt == 1 && c1 >= max(hh, upper) && len(s.LongOrders) == 0 {
openDirt = 1
} else if m.dirt == -1 && c1 <= min(ll, lower) && len(s.ShortOrders) == 0 {
openDirt = -1
}
slLong, slShort := m.Calc(s, atr.Get(1)*slMul)
if openDirt != 0 {
com.FastOpen(s, openDirt, slLong, slShort, 0)
}
setAllStopLoss(s, slLong, slShort)
m.upper = upper
m.lower = lower
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*More38)
m.openD = e.Open.Get(0)
},
}
}

50
org/sf/common.go Normal file
View File

@@ -0,0 +1,50 @@
package sf
import (
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
)
var (
lenMa1 = 10 // 快线MA的周期
lenMaRate = 2.0 // 慢线MA相对快线的倍率
lenMa2 = int(float64(lenMa1) * lenMaRate)
lenAtr = 14
lenExtrm = 50 // 查找极值点的周期
)
type MTRSDirt struct {
dirt int // 1开多 -1开空
*com.TRS
}
func init() {
strat.AddStratGroup("sf", map[string]strat.FuncMakeStrat{
"01": SF01V2,
"02": SF02V1,
"03": SF03V1,
"04": SF04V1,
"30": SF30V1,
"05": SF05V1,
"06": SF06V1,
"08": SF08V1,
"10": SF10V1,
"14": SF14V1,
"17": SF17V1,
"18": SF18V1,
"19": SF19V1,
"21": SF21V1,
"33": SF33V1,
"35": SF35V1,
"36": SF36V1,
"37": SF37V1,
"38": SF38V1,
})
}
func setAllStopLoss(s *strat.StratJob, slLong, slShort float64) {
s.SetAllStopLoss(core.OdDirtLong, &ormo.ExitTrigger{Price: slLong})
s.SetAllStopLoss(core.OdDirtShort, &ormo.ExitTrigger{Price: slShort})
}