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

36
org/day/01.go Normal file
View File

@@ -0,0 +1,36 @@
package day
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
func D01(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
o, c, h, l := e.Open.Get(0), e.Close.Get(0), e.High.Get(0), e.Low.Get(0)
solid := math.Abs(o - c)
solidRate := solid / math.Abs(h-l)
atr := ta.ATR(e.High, e.Low, e.Close, 15).Get(0)
ma := ta.SMA(e.Close, 20).Get(0)
if len(s.LongOrders) > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "closeL", Dirt: core.OdDirtLong})
} else if len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "closeL", Dirt: core.OdDirtShort})
} else {
if solidRate > 0.7 && solid/atr > 1 {
if o > c && c < ma {
s.OpenOrder(&strat.EnterReq{Tag: "long"})
} else if c > ma {
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true})
}
}
}
},
}
}

62
org/day/02.go Normal file
View File

@@ -0,0 +1,62 @@
package day
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:期市萧何:最简单的交易系统 2025/02/18
80均线向上只开多,向下只开空
当20均线和80均线多头排列,且价格上穿20均线开多;反之做空
前期压力支撑止损,价格再次触碰20均线止盈
最小8h才盈利,且21年到35年间几次回撤时间长达1年左右;
弃用
*/
func MaDirt(p *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr := 20
baseAtrLen := 86
slRate := 2.0
bigThres := 0.2
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
maSml := ta.SMA(e.Close, 20)
maBig := ta.SMA(e.Close, 80)
atr := ta.ATR(e.High, e.Low, e.Close, 14)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
bigChg := (maBig.Get(0) - maBig.Get(3)) / atrBase
smlChg := (maSml.Get(0) - maSml.Get(3)) / atrBase
cSmlX := e.Close.Cross(maSml)
if len(s.LongOrders) > 0 {
if cSmlX == -1 {
// 价格下穿均线止盈
s.CloseOrders(&strat.ExitReq{Tag: "exitL", Dirt: core.OdDirtLong})
}
} else if len(s.ShortOrders) > 0 {
if cSmlX == 1 {
// 价格上穿均线止盈
s.CloseOrders(&strat.ExitReq{Tag: "exitS", Dirt: core.OdDirtShort})
}
} else if bigChg > bigThres {
// 大均线向上
if cSmlX == 1 && maSml.Get(0) > maBig.Get(0) && smlChg > 0 {
// 价格上穿20均线,且均线多头排列
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: atr.Get(0) * slRate})
}
} else if bigChg < -bigThres {
// 大均线向下
if cSmlX == -1 && maSml.Get(0) < maBig.Get(0) && smlChg < 0 {
// 价格下穿20均线,且均线空头排列
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, StopLossVal: atr.Get(0) * slRate})
}
}
},
}
}

47
org/day/03.go Normal file
View File

@@ -0,0 +1,47 @@
package day
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banexg/utils"
ta "github.com/banbox/banta"
)
/*
在大周期4h的前一个小周期入场,检查是否有套利机会。
无法盈利
*/
func D03(p *config.RunPolicyConfig) *strat.TradeStrat {
tfMSecs := int64(utils.TFToSecs("4h") * 1000)
return &strat.TradeStrat{
WarmupNum: 100,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "4h", 10},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = 0
},
OnBar: func(s *strat.StratJob) {
e := s.Env
dirt, _ := s.More.(int)
if len(s.LongOrders) > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
} else if len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
} else if (e.TimeStop+e.TFMSecs)%tfMSecs == 0 {
s.OpenOrder(&strat.EnterReq{Tag: "ent", Short: dirt < 0})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
ma := ta.SMA(e.Close, 10).Get(0)
if e.Close.Get(0) > ma {
s.More = 1
} else {
s.More = -1
}
},
}
}

73
org/day/04.go Normal file
View File

@@ -0,0 +1,73 @@
package day
import (
"fmt"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:山居听雨楼:渣男战法
5日和10日均线,10日均线向上向下确定方向
收盘价小均线金叉,且多头排列,做多;反之做空
效果较差
*/
func D04(p *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr := 20
baseAtrLen := 86
//slRate := 2.0
bigThres := 0.2
upNum, dnNum, zeroNum := 0, 0, 0
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
maSml := ta.SMA(e.Close, 5)
maBig := ta.SMA(e.Close, 10)
atr := ta.ATR(e.High, e.Low, e.Close, 14)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
bigChg := (maBig.Get(0) - maBig.Get(2)) / atrBase
smlChg := (maSml.Get(0) - maSml.Get(2)) / atrBase
cSmlX := e.Close.Cross(maSml)
ph := ta.Highest(e.High, 2).Get(0)
pl := ta.Lowest(e.Low, 2).Get(0)
if len(s.LongOrders) > 0 {
if cSmlX == -1 {
// 价格下穿均线止盈
s.CloseOrders(&strat.ExitReq{Tag: "exitL", Dirt: core.OdDirtLong})
}
} else if len(s.ShortOrders) > 0 {
if cSmlX == 1 {
// 价格上穿均线止盈
s.CloseOrders(&strat.ExitReq{Tag: "exitS", Dirt: core.OdDirtShort})
}
} else if bigChg > bigThres {
// 大均线向上
if cSmlX == 1 && maSml.Get(0) > maBig.Get(0) && smlChg > 0 {
// 价格上穿20均线,且均线多头排列
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: pl})
}
} else if bigChg < -bigThres {
// 大均线向下
if cSmlX == -1 && maSml.Get(0) < maBig.Get(0) && smlChg < 0 {
// 价格下穿20均线,且均线空头排列
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, StopLossVal: ph})
}
}
if bigChg > bigThres {
upNum++
} else if bigChg < -bigThres {
dnNum++
} else {
zeroNum++
}
},
OnShutDown: func(s *strat.StratJob) {
fmt.Printf("up: %d, dn: %d, zero: %d\n", upNum, dnNum, zeroNum)
},
}
}

58
org/day/05.go Normal file
View File

@@ -0,0 +1,58 @@
package day
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:漫谈期事:高手能稳定盈利的交易系统到底有多简单?
截断亏损让利润奔跑
任意阳K第二根开多,开仓k前一根k最低点止损,反之做空
没止损就拿30根bar后平仓
无法盈利
*/
func D05(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
o, c := e.Open.Get(0), e.Close.Get(0)
_ = o
ma := ta.SMA(e.Close, 30).Get(0)
ph := ta.Highest(e.High, 2).Get(0)
pl := ta.Lowest(e.Low, 2).Get(0)
rsi := ta.RSI(e.Close, 4).Get(0)
if len(s.LongOrders) > 0 {
for _, od := range s.LongOrders {
sl := od.GetStopLoss()
if pl > sl.Price {
sl.Price = pl
}
num := e.BarCount(od.EnterAt)
if num > 10 {
s.CloseOrders(&strat.ExitReq{Tag: "exitL", OrderID: od.ID})
}
}
} else if len(s.ShortOrders) > 0 {
for _, od := range s.ShortOrders {
sl := od.GetStopLoss()
if ph < sl.Price {
sl.Price = ph
}
num := e.BarCount(od.EnterAt)
if num > 10 {
s.CloseOrders(&strat.ExitReq{Tag: "exitS", OrderID: od.ID})
}
}
} else if rsi < 10 && c < ma {
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLoss: pl})
} else if rsi > 90 && c > ma {
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, StopLoss: ph})
}
},
}
}

40
org/day/06.go Normal file
View File

@@ -0,0 +1,40 @@
package day
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
bilibili 生财茶馆pro 98%胜率的5分钟终极剥头皮交易策略-测试
很差,一路向下
*/
func d06(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxLong: 1,
EachMaxShort: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 6)
utBot := ta.UTBot(e.Close, atr, 2).Get(0)
stc := ta.STC(e.Close, 80, 27, 50, 0.5)
stcVal := stc.Get(0)
stcUp := stcVal > stc.Get(1)
hma := ta.HMA(e.Close, 55).Get(0)
hh := ta.Highest(e.High, 3).Get(0)
ll := ta.Lowest(e.Low, 3).Get(0)
if utBot > 0 && stcVal < 25 && stcUp && c > hma {
slVal := c - ll
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: slVal, TakeProfitVal: slVal * 1.5})
} else if utBot < 0 && stcVal > 75 && !stcUp && c < hma {
slVal := hh - c
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, StopLossVal: slVal, TakeProfitVal: slVal * 1.5})
}
},
}
}

162
org/day/07.go Normal file
View File

@@ -0,0 +1,162 @@
package day
import (
"fmt"
"github.com/banbox/banbot/btime"
"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"
"sort"
"sync"
)
func D07(p *config.RunPolicyConfig) *strat.TradeStrat {
symVols := make(map[int32]float64) // 成交量记录
allowSyms := make(map[int32]bool) // 允许交易的品种sid
timeDirts := make(map[int32]*TimeDirt) // 记录每个品种的触发时间和方向,只做顺势信号
holds := make(map[int32]int) // 各个品种持仓情况
var lock sync.Mutex
var bigTime int64
var allowConfirm bool // allowSyms是否已刷新
const volRateThs = 1.1 // 成交量最低倍数
const topNRate = 0.1 // 交易前n个品种比例
return &strat.TradeStrat{
WarmupNum: 100,
DrawDownExit: true,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1h", 1},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
if !allowConfirm && e.TimeStart > bigTime {
// 确定当前小时,可交易的品种
allowConfirm = true
topNum := int(math.Round(float64(len(symVols)) * topNRate))
allowSyms = GetTopNKeys(symVols, topNum)
}
sid := s.Symbol.ID
_, allow := allowSyms[sid]
hold, hasPos := holds[sid]
if hasPos {
if hold > 0 {
if len(s.LongOrders) == 0 {
delete(holds, sid)
}
} else if len(s.ShortOrders) == 0 {
delete(holds, sid)
}
}
// 要求最近3bar成交量加速,实体颜色一致,且实体至少70%;最新成交量是平均成交量2倍
volMa := ta.SMA(e.Volume, 100).Get(0)
v0, v1, v2 := e.Volume.Get(0), e.Volume.Get(1), e.Volume.Get(2)
prevVolRate := v1 / v2
if v0 > volMa*2 && prevVolRate > volRateThs && v0/v1 > prevVolRate*volRateThs {
// 成交量爆发
flag0, solid0 := BarStat(e, 0)
flag1, solid1 := BarStat(e, 1)
flag2, solid2 := BarStat(e, 2)
if flag0 == flag1 && flag1 == flag2 && min(solid0, solid1, solid2) > 0.7 {
// 颜色一致,且实体至少70%
lock.Lock()
timeDirts[sid] = &TimeDirt{Time: e.TimeStart, Dirt: flag0}
lock.Unlock()
if allow && expDirt(timeDirts, e.TimeStart-e.TFMSecs) == flag0 {
dateStr := btime.ToDateStr(e.TimeStart, core.DefaultDateFmt)
fmt.Printf("[%s] enter %s dirt: %d\n", dateStr, s.Symbol.Symbol, flag0)
// 只交易成交量top,且顺应大趋势的
if len(s.ShortOrders) == 0 && len(s.LongOrders) == 0 && len(holds) <= 1 {
holds[sid] = flag0
s.OpenOrder(&strat.EnterReq{
Tag: "enter",
Short: flag0 < 0,
})
}
}
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
lock.Lock()
if e.TimeStop > bigTime {
symVols = make(map[int32]float64)
bigTime = e.TimeStop
allowConfirm = false
}
// 计算所有品种过去1小时成交量
avgPrice := ta.AvgPrice(e).Get(0)
symVols[s.Symbol.ID] = e.Volume.Get(0) * avgPrice
lock.Unlock()
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
return 0.4
},
}
}
func expDirt(dirts map[int32]*TimeDirt, minStamp int64) int {
up, dn := 0, 0
for k, d := range dirts {
if d.Time < minStamp {
delete(dirts, k)
continue
}
if d.Dirt > 0 {
up++
} else {
dn++
}
}
if up+dn >= 3 {
if up >= dn*2 {
return 1
} else if dn >= up*2 {
return -1
}
}
return 0
}
func BarStat(e *ta.BarEnv, i int) (int, float64) {
o, h, l, c := e.Open.Get(i), e.High.Get(i), e.Low.Get(i), e.Close.Get(i)
solid := float64(0)
if h > l {
solid = math.Abs(c-o) / (h - l)
}
flag := 1
if o > c {
flag = -1
}
return flag, solid
}
type TimeDirt struct {
Time int64
Dirt int
}
type kv struct {
key int32
value float64
}
func GetTopNKeys(symVols map[int32]float64, n int) map[int32]bool {
pairs := make([]kv, 0, len(symVols))
for k, v := range symVols {
pairs = append(pairs, kv{k, v})
}
sort.Slice(pairs, func(i, j int) bool {
return pairs[i].value > pairs[j].value
})
keys := make(map[int32]bool)
for i := 0; i < n && i < len(pairs); i++ {
keys[pairs[i].key] = true
}
return keys
}

15
org/day/main.go Normal file
View File

@@ -0,0 +1,15 @@
package day
import "github.com/banbox/banbot/strat"
func init() {
strat.AddStratGroup("day", map[string]strat.FuncMakeStrat{
"01": D01,
"02": MaDirt,
"03": D03,
"04": D04,
"05": D05,
"06": d06,
"07": D07,
})
}

33
org/digo/common.go Normal file
View File

@@ -0,0 +1,33 @@
package digo
import (
"github.com/banbox/banbot/strat"
"math"
)
func init() {
strat.AddStratGroup("digo", map[string]strat.FuncMakeStrat{
"v2": v2,
"v4": v4,
})
}
var (
trendFilter = true // 是否启用趋势过滤(逆趋势开单降低权重)
goodWeight = float64(1) // 顺趋势开单权重,默认1
badWeight = float64(0) // 逆趋势开单权重,默认0不开单
badMaxRate = -0.05 // 开单后允许趋势相反最大价格比率
goodMaxRate = 0.005
stopLossRate = 0.02
)
func calcFactor(pFac float64) float64 {
odNum := math.Log2(pFac) + 1
return math.Pow(2, odNum)
}
type MoreType struct {
bigDirt int // 1牛市,0不确定,1熊市
maBig float64 // 大周期MA,用于判断趋势
signal float64 // 最新bar是否有信号,1开多,-1开空
}

209
org/digo/v1.go Normal file
View File

@@ -0,0 +1,209 @@
package digo
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
"github.com/banbox/banexg/log"
ta "github.com/banbox/banta"
"go.uber.org/zap"
"math"
"slices"
)
func openOrder(s *strat.StratJob, m *MoreType, signal float64) {
odWeight := goodWeight
if trendFilter && m.bigDirt != int(signal) {
// 启用趋势过滤,且是逆趋势
odWeight = badWeight
}
if odWeight == 0 {
return
}
allOrders := s.GetOrders(signal)
orders := make([]*ormo.InOutOrder, 0, len(allOrders))
for _, od := range allOrders {
if od.EnterTag != core.EnterTagThird {
orders = append(orders, od)
}
}
enteredAmt := float64(0)
for _, od := range orders {
enteredAmt += od.Enter.Filled
}
c := s.Env.Close.Get(0)
basePrice := max(c, m.maBig)
if signal > 0 {
basePrice = min(c, m.maBig)
}
stopPrice := basePrice * (1 - signal*stopLossRate)
if enteredAmt == 0 {
// 没有打开的订单,直接下单
err := s.OpenOrder(&strat.EnterReq{
Tag: "enter",
Short: signal < 0,
CostRate: odWeight,
StopLoss: stopPrice,
})
if err != nil {
log.Error("open order fail", zap.Error(err))
}
return
}
slices.SortFunc(orders, func(a, b *ormo.InOutOrder) int {
return int(a.RealEnterMS() - b.RealEnterMS())
})
prevOd := orders[len(orders)-1]
// 检查价格是否背离订单5%
chgRate := c/prevOd.InitPrice - 1
if signal*chgRate >= badMaxRate {
// 价格背离未超过5%,不加仓
return
}
// 以上一个订单的两倍开单
baseAmt := s.Strat.GetStakeAmount(s)
prevFac := prevOd.GetInfoFloat64(ormo.OdInfoLegalCost) / baseAmt
costRate := calcFactor(prevFac)
err := s.OpenOrder(&strat.EnterReq{
Tag: "enter",
Short: signal < 0,
CostRate: odWeight * costRate,
StopLoss: stopPrice,
})
if err != nil {
log.Error("open order fail", zap.Error(err))
}
}
func closeOrders(s *strat.StratJob, signal float64) {
allOrders := s.GetOrders(signal)
orders := make([]*ormo.InOutOrder, 0, len(allOrders))
totalProfit := float64(0)
for _, od := range allOrders {
if od.EnterTag != core.EnterTagThird {
orders = append(orders, od)
totalProfit += od.Profit
}
}
if len(orders) < 3 {
return
}
if totalProfit > 0 {
err := s.CloseOrders(&strat.ExitReq{
Tag: "exit",
Dirt: int(signal),
})
if err != nil {
log.Error("close orders fail", zap.Error(err))
}
}
}
func MainV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
trendFilter = true
goodWeight = 1
badWeight = 0
stopLossRate = 0.02
badMaxRate = -0.05
goodMaxRate = 0.005
return &strat.TradeStrat{
Version: 1,
WarmupNum: 361,
MinTfScore: 0.75,
DrawDownExit: true,
StopEnterBars: 10,
//OnPairInfos: func(s *strategy.StratJob) []*strategy.PairSub {
// return []*strategy.PairSub{
// {
// Key: "_cur_",
// TimeFrame: "1d",
// WarmupNum: 60,
// },
// }
//},
OnStartUp: func(s *strat.StratJob) {
s.More = &MoreType{}
},
//OnInfoBar: func(s *strategy.StratJob, pair, tf string) {
// m, _ := s.More.(*MoreType)
// m.maBig = ta.SMA(s.Env.Close, 60).Get(0)
//},
OnBar: func(s *strat.StratJob) {
e := s.Env
_, d, _ := ta.KDJBy(e.High, e.Low, e.Close, 13, 3, 3, "sma")
ma3_d := ta.SMA(d, 3)
//fmt.Printf("%s: %.3f %.3f %.3f\n", btime.ToDateStr(e.TimeStart, ""),
// k.Get(0), d.Get(0), ma3_d.Get(0))
c := e.Close.Get(0)
m, _ := s.More.(*MoreType)
m.maBig = ta.EMA(e.Close, 360).Get(0)
if math.IsNaN(m.maBig) {
m.bigDirt = 0
} else {
m.bigDirt = -1
if c >= m.maBig {
// K线高于大周期均线,牛市
m.bigDirt = 1
}
}
zhicheng := ma3_d.Cross(20) == -1
yali := ma3_d.Cross(80.5) == 1
m.signal = float64(0)
if yali {
m.signal = -1
} else if zhicheng {
m.signal = 1
} else {
return
}
if m.bigDirt != 0 {
openOrder(s, m, m.signal)
}
closeOrders(s, m.signal)
},
OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq {
odDirt := float64(1)
if od.Short {
odDirt = -1
}
m, _ := s.More.(*MoreType)
c := s.Env.Close.Get(0)
basePrice := max(od.InitPrice, m.maBig)
if odDirt > 0 {
basePrice = min(od.InitPrice, m.maBig)
}
stopPrice := basePrice * (1 - odDirt*stopLossRate)
od.SetStopLoss(&ormo.ExitTrigger{Price: stopPrice})
priceBk := c - stopPrice
if odDirt*priceBk < 0 {
// 触发止损,立刻卖出
return &strat.ExitReq{
Tag: core.ExitTagStopLoss,
OrderID: od.ID,
}
}
if m.signal == 0 || m.signal == odDirt {
// 没有信号,或顺趋势信号,退出
return nil
}
// 出现逆趋势信号
entPrice := od.InitPrice
if od.Enter.Price != 0 {
entPrice = od.Enter.Price
}
chgRate := c/entPrice - 1
if odDirt*chgRate >= goodMaxRate {
// 价格盈利超过阈值,卖出止盈
return &strat.ExitReq{
Tag: "stop_win",
OrderID: od.ID,
}
}
return nil
},
}
}

181
org/digo/v2.go Normal file
View File

@@ -0,0 +1,181 @@
package digo
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 MoreV2 struct {
bigEma199 float64
}
/*
# 趋势判断
趋势多头 = EMA360 > 日线EMA199 且 当前价格 > EMA360
趋势空头 = EMA360 < 日线EMA199 且 当前价格 < EMA360
# 震荡判断
震荡偏多 = min(EMA360, 当前价格) > 日线EMA199 且 当前价格 < EMA360
震荡偏空 = max(EMA360, 当前价格) < 日线EMA199 且 当前价格 > EMA360
如果是震荡偏多市场:
在支撑位:开多单(1倍杠杆),平掉空单
在压力位:开小仓位空单(0.5倍杠杆),平掉多单
如果是震荡偏空市场:
在支撑位:开小仓位多单(0.5倍杠杆),平掉空单
在压力位:开空单(1倍杠杆),平掉多单
止损逐bar更新:
震荡偏空/震荡偏多:
多单止损:min(ema360, bigEma199)下方2个点
空单止损:max(ema360, bigEma199)上方2个点
*/
func v2(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义策略参数
smoothK := int(pol.Def("smoothK", 13, core.PUniform(8, 20)))
smoothD := int(pol.Def("smoothD", 3, core.PUniform(2, 5)))
//bSmaLen := int(pol.Def("bSmaLen", 9, core.PUniform(5, 15)))
//bSmaDev := 2.0
slRate := 0.02
return &strat.TradeStrat{
WarmupNum: 600, // 需要足够的预热周期来计算EMA360
EachMaxLong: 1, // 最多同时持有1笔多单
EachMaxShort: 1,
OnStartUp: func(s *strat.StratJob) {
s.More = &MoreV2{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 360},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*MoreV2)
c := e.Close.Get(0)
ema360 := ta.EMA(e.Close, 360).Get(0)
var trend = 0 // 2 多头, 1 震荡偏多, 0 不确定, -1 震荡偏空 -2 空头
if c > ema360 && ema360 > m.bigEma199 {
// 多头排列
trend = 2
} else if c < ema360 && ema360 < m.bigEma199 {
// 空头排列
trend = -2
} else if min(c, ema360) > m.bigEma199 && c < ema360 {
// 震荡偏多,
trend = 1
} else if max(c, ema360) < m.bigEma199 && c > ema360 {
// 震荡偏空
trend = -1
}
_, d, _ := ta.KDJBy(e.High, e.Low, e.Close, smoothK, 3, smoothD, "sma")
dSMA := ta.SMA(d, 3)
// 判断支撑压力
isUpp := dSMA.Cross(20) == -1 // crossunder
isDww := dSMA.Cross(80.5) == 1 // crossover
// 计算布林带
//bbCols := ta.BBANDS(e.Close, bSmaLen, bSmaDev, bSmaDev).Cols
//bbUpper, bbLower := bbCols[0].Get(0), bbCols[2].Get(0)
//h := e.High.Get(0)
isYali := isDww // && h > bbUpper*1.08
isZhicheng := isUpp // && c < bbLower*1.08
// 计算止损
slLong, slShort := 0.0, 0.0
if trend == 1 || trend == -1 {
slLong = min(ema360, m.bigEma199) * (1 - slRate)
slShort = max(ema360, m.bigEma199) * (1 + slRate)
for _, od := range s.LongOrders {
od.SetStopLoss(&ormo.ExitTrigger{
Price: slLong,
})
}
for _, od := range s.ShortOrders {
od.SetStopLoss(&ormo.ExitTrigger{
Price: slShort,
})
}
}
// 开仓和平仓逻辑
longRate, shortRate := 1.0, 1.0
if trend == 1 {
// 震荡偏多
longRate, shortRate = 1, 0.5
} else if trend == -1 {
// 震荡偏空
longRate, shortRate = 0.5, 1
}
if trend == 1 || trend == -1 {
if isZhicheng {
// 支撑位开多
s.OpenOrder(&strat.EnterReq{
Tag: "longZC1",
CostRate: longRate,
StopLoss: slLong,
})
s.CloseOrders(&strat.ExitReq{
Tag: "zc1",
Dirt: core.OdDirtShort,
})
} else if isYali {
//_ = shortRate
// 压力位半仓开空
s.OpenOrder(&strat.EnterReq{
Tag: "shortYL1",
CostRate: shortRate,
Short: true,
StopLoss: slShort,
})
s.CloseOrders(&strat.ExitReq{
Tag: "yl1",
Dirt: core.OdDirtLong,
})
}
}
//if isZhicheng && trend == 2 && s.OrderNum == 0 {
// // 支撑位开多
// s.OpenOrder(&strat.EnterReq{
// Tag: "support_long",
// Short: false,
// })
//} else if isYali && trend == 2 && s.OrderNum > 0 {
// // 压力位平多
// s.CloseOrders(&strat.ExitReq{
// Tag: "resistance_close",
// EnterTag: "support_long",
// Dirt: core.OdDirtLong,
// })
//}
//if trend == -2 && isYali && s.OrderNum == 0 {
// // 顺势空,压力位开空
// s.OpenOrder(&strat.EnterReq{
// Tag: "resi_short",
// Short: true,
// })
//} else if trend == -2 && isZhicheng && s.OrderNum > 0 {
// s.CloseOrders(&strat.ExitReq{
// Tag: "supp_close",
// EnterTag: "resi_short",
// Dirt: core.OdDirtShort,
// })
//}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*MoreV2)
m.bigEma199 = ta.EMA(e.Close, 199).Get(0)
},
}
}

112
org/digo/v4.go Normal file
View File

@@ -0,0 +1,112 @@
package digo
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"
)
/*
# 趋势判断
趋势多头 = EMA360 > 日线EMA199 且 当前价格 > EMA360
趋势空头 = EMA360 < 日线EMA199 且 当前价格 < EMA360
# 震荡判断
震荡偏多 = min(EMA360, 当前价格) > 日线EMA199 且 当前价格 < EMA360
震荡偏空 = max(EMA360, 当前价格) < 日线EMA199 且 当前价格 > EMA360
如果是震荡偏多市场:
在支撑位:开多单(1倍杠杆),平掉空单
在压力位:开小仓位空单(0.5倍杠杆),平掉多单
如果是震荡偏空市场:
在支撑位:开小仓位多单(0.5倍杠杆),平掉空单
在压力位:开空单(1倍杠杆),平掉多单
止损逐bar更新:
震荡偏空/震荡偏多:
多单止损:min(ema360, bigEma199)下方2个点
空单止损:max(ema360, bigEma199)上方2个点
*/
func v4(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义策略参数
smoothK := int(pol.Def("smoothK", 13, core.PUniform(8, 20)))
smoothD := int(pol.Def("smoothD", 3, core.PUniform(2, 5)))
//bSmaLen := int(pol.Def("bSmaLen", 9, core.PUniform(5, 15)))
//bSmaDev := 2.0
slRate := 0.05
tpRate := 0.05
return &strat.TradeStrat{
WarmupNum: 600, // 需要足够的预热周期来计算EMA360
EachMaxLong: 1, // 最多同时持有1笔多单
EachMaxShort: 1,
OnStartUp: func(s *strat.StratJob) {
s.More = &MoreV2{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 360},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*MoreV2)
c := e.Close.Get(0)
ema360 := ta.EMA(e.Close, 360).Get(0)
ema169 := ta.EMA(e.Close, 169).Get(0)
var isLong = false
if ema169 > m.bigEma199 && c > ema360 {
//顺势偏多
isLong = true
}
// 收盘价偏离ema169的百分比
devRangePct := math.Abs(c-ema169) * 100 / ema169
_, d, _ := ta.KDJBy(e.High, e.Low, e.Close, smoothK, 3, smoothD, "sma")
dSMA := ta.SMA(d, 3)
// 判断支撑压力
isUpp := dSMA.Cross(20) == -1 // crossunder
isDww := dSMA.Cross(80.5) == 1 // crossover
isYali := isDww // && h > bbUpper*1.08
isZhicheng := isUpp // && c < bbLower*1.08
// 计算止损
slLong := ema169 * (1 - slRate)
slShort := ema169 * (1 + slRate)
for _, od := range s.LongOrders {
od.SetStopLoss(&ormo.ExitTrigger{
Price: slLong,
})
}
for _, od := range s.ShortOrders {
od.SetStopLoss(&ormo.ExitTrigger{
Price: slShort,
})
}
_ = isYali
if isLong && isZhicheng && devRangePct < 5 {
s.OpenOrder(&strat.EnterReq{
Tag: "longZC1",
StopLoss: slLong,
TakeProfit: c * (1 + tpRate),
})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*MoreV2)
m.bigEma199 = ta.EMA(e.Close, 199).Get(0)
},
}
}

64
org/fmz/BearMACD.go Normal file
View File

@@ -0,0 +1,64 @@
package fmz
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"
)
/*
https://www.fmz.com/strategy/426836
该策略专注于熊市下跌行情中的做空交易,同时确保资产处于大周期下行通道中,然后在进一步下跌后止盈退出。
测试在48个品种,210101-250101, 1h,收益296%,回撤17%,夏普7.42
空头优化620轮,取25%位置,maS: 7 maSLen: 191 rate: 2.35
多头优化182轮,取22%位置,maL: 1 maLLen: 219 rate: 2.33
后续优化方向:
止损止盈的倍率,开单倍率
*/
func BearMACD(p *config.RunPolicyConfig) *strat.TradeStrat {
// short: 7 191 2.35
// long: 1 219 2.33
maSType := com.DefMaType(p, "maS", com.MaALMA)
maSLen := int(p.Def("maSLen", 191, core.PNormF(30, 800, 230, 0)))
maLType := com.DefMaType(p, "maL", com.MaEMA)
maLLen := int(p.Def("maLLen", 219, core.PNormF(30, 800, 230, 0)))
rate := p.Def("rate", 2.35, core.PNormF(0.5, 3, 1.6, 0))
mc1 := int(math.Round(12 * rate))
mc2 := int(math.Round(26 * rate))
mc3 := int(math.Round(9 * rate))
return &strat.TradeStrat{
WarmupNum: max(maSLen, maLLen),
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
maS := com.GetMA(e.Close, e.Volume, maSType, maSLen).Get(0)
maL := com.GetMA(e.Close, e.Volume, maLType, maLLen).Get(0)
macd, signal := ta.MACD(e.Close, mc1, mc2, mc3)
macdX := macd.Cross(signal)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
if s.OrderNum > 0 {
return
}
if macdX == -1 && c < maS {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
StopLossVal: atr * 1.3,
TakeProfitVal: atr * 4,
})
} else if macdX == 1 && c > maL {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
StopLossVal: atr * 1.3,
TakeProfitVal: atr * 6,
})
}
},
}
}

91
org/fmz/ComboMaBear.go Normal file
View File

@@ -0,0 +1,91 @@
package fmz
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
"strconv"
)
/*
https://www.fmz.com/strategy/429466
本策略结合了均线先行指标和熊强力指标,形成短期看跌方向信号的组合策略。均线先行指标判断趋势,熊强力指标确定做空时机。策略适合短线操作,追踪市场调整行情。
在48个品种,210101-241101上,表现很差
4h,1h,15m均震荡严重
*/
type CMA struct {
maPos float64
bpPos float64
}
func ComboMaBear(p *config.RunPolicyConfig) *strat.TradeStrat {
bpShort := 4.0
bpLong := 0.3
return &strat.TradeStrat{
WarmupNum: 50,
OnStartUp: func(s *strat.StratJob) {
s.More = &CMA{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
o, h, l, c, c1 := e.Open.Get(0), e.High.Get(0), e.Low.Get(0), e.Close.Get(0), e.Close.Get(1)
m, _ := s.More.(*CMA)
ma := ta.EMA(e.Close, 14).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
hh := max(e.High.Get(0), e.High.Get(1))
ll := min(e.Low.Get(0), e.Low.Get(1))
nXS := hh
if ll > ma || hh < ma {
nXS = ll
}
xsDiff := nXS - c1
if xsDiff < 0 {
m.maPos = 1
} else if xsDiff > 0 {
m.maPos = -1
}
var bp float64
solRate := math.Abs(c-o) / (h - l)
var isBear bool
if solRate < 0.1 {
// 实体不足10%,看上下影线
isBear = h-c > c-l
} else {
// 实体较大,直接判断
isBear = c < o
}
if isBear {
// 阴线取全部
bp = h - l
} else {
// 阳线取较大影线
bp = max(h-c, c-l)
}
bpRate := bp / atr
if bpRate > bpShort {
m.bpPos = -1
} else if bpRate < bpLong {
m.bpPos = 1
}
openDirt := 0
if m.maPos == 1 && m.bpPos == 1 {
openDirt = 1
} else if m.maPos == -1 && m.bpPos == -1 {
openDirt = -1
} else if s.OrderNum > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
}
if openDirt != 0 && s.OrderNum == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: strconv.Itoa(openDirt),
Short: openDirt < 0,
})
}
},
}
}

10
org/fmz/common.go Normal file
View File

@@ -0,0 +1,10 @@
package fmz
import "github.com/banbox/banbot/strat"
func init() {
strat.AddStratGroup("fmz", map[string]strat.FuncMakeStrat{
"ComboMaBear": ComboMaBear,
"BearMACD": BearMACD,
})
}

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

109
org/jesse/AlligatorAi.go Normal file
View File

@@ -0,0 +1,109 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"gonum.org/v1/gonum/floats"
"math"
"strconv"
)
/*
https://jesse.trade/strategies/alligatorai-by-o1-preview-model
原始版本:
BTC/USDT 30m
仅对BTC有较好的表现,略小回撤。对48个品种收益很不稳定
*/
func smma(obj *ta.Series, period int) *ta.Series {
res := obj.To("_smma", period)
if res.Cached() {
return res
}
val := obj.Get(0)
alpha := 1 / float64(period)
old := res.Get(0)
if !math.IsNaN(val) && !math.IsNaN(old) {
return res.Append(alpha*val + old*(1-alpha))
}
old = floats.Sum(obj.Range(0, period)) * alpha
if math.IsNaN(old) {
return res.Append(math.NaN())
}
for i := period - 1; i >= 0; i-- {
val = obj.Get(i)
old = alpha*val + old*(1-alpha)
}
return res.Append(old)
}
func alligatorTrend(e *ta.BarEnv, c float64) int {
obj := ta.HL2(e.High, e.Low)
jaw := smma(obj, 13).Back(8)
teeth := smma(obj, 8).Back(5)
lips := smma(obj, 5).Back(3)
jawV, teethV, lipsV := jaw.Get(0), teeth.Get(0), lips.Get(0)
trend := 0
if c > lipsV && lipsV > teethV && teethV > jawV {
trend = 1
} else if c < lipsV && lipsV < teethV && teethV < jawV {
trend = -1
}
return trend
}
type alliga struct {
bigMALong bool
bigTrend int
}
func AlligatorAI(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 200,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
bigTf := "4h"
if s.TimeFrame == "4h" {
bigTf = "8h"
}
return []*strat.PairSub{
{"_cur_", bigTf, 200},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = &alliga{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*alliga)
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
trend := alligatorTrend(e, c)
adxVal := ta.ADX(e.High, e.Low, e.Close, 14).Get(0)
adx := adxVal > 30
cmo := ta.CMO(e.Close, 14).Get(0)
srsiC, _ := ta.StochRSI(e.Close, 14, 14, 3, 3)
srsi := srsiC.Get(0)
dirt := 0
if trend == 1 && adx && m.bigTrend == 1 && m.bigMALong && cmo > 20 && srsi < 20 {
dirt = 1
} else if trend == -1 && adx && m.bigTrend == -1 && !m.bigMALong && cmo < -20 && srsi > 80 {
dirt = -1
}
if dirt != 0 {
s.OpenOrder(&strat.EnterReq{
Tag: strconv.Itoa(dirt),
Short: dirt < 0,
StopLossVal: atr * 2,
TakeProfitVal: atr * 2,
})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*alliga)
c := e.Close.Get(0)
m.bigTrend = alligatorTrend(e, c)
m.bigMALong = e.Close.Get(0) > ta.EMA(e.Close, 100).Get(0)
},
}
}

20
org/jesse/IFR2.go Normal file
View File

@@ -0,0 +1,20 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
)
/*
使用了talib.HT_TRENDMODE指标,太复杂,暂不实现
*/
func IFR2(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
//e := s.Env
},
}
}

View File

@@ -0,0 +1,53 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
https://jesse.trade/strategies/ichimokucloud
在48个品种上表现很不稳定
*/
func IchimokuCloud(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
ichi := com.IchimokuCloud(e, 9, 26, 52, 26).Cols
adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0) > 50
chop := ta.CHOP(e, 14).Get(0) < 50
ichiSub1 := ichi[0].Get(0) - ichi[1].Get(0)
ichiSub2 := ichi[2].Get(0) - ichi[3].Get(0)
doClose := false
if len(s.LongOrders) > 0 {
if ichiSub1 < 0 {
doClose = true
}
} else if len(s.ShortOrders) > 0 {
if ichiSub1 > 0 {
doClose = true
}
} else if ichiSub1*ichiSub2 > 0 && adx && chop {
dirt := float64(1)
tag := "long"
if ichiSub1 < 0 {
dirt = -1
tag = "short"
}
s.OpenOrder(&strat.EnterReq{
Tag: tag,
Short: dirt < 0,
StopLossVal: atr * 2.5 * dirt,
})
}
if doClose {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
}
},
}
}

View File

@@ -0,0 +1,72 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"strconv"
)
/*
https://jesse.trade/strategies/kama-trendfollowing
只适合btc,在15m上回测表现良好。
其他品种表现很不稳定。
*/
type KamaTrdSta struct {
bigKama float64
lastExit int
}
func KamaTrendFollow(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "4h", 100},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = &KamaTrdSta{}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*KamaTrdSta)
c := e.Close.Get(0)
kama := ta.KAMA(e.Close, 30).Get(0)
bbUp, bbMid, bbDn := ta.BBANDS(e.Close, 20, 2, 2)
bbWidth := (bbUp.Get(0) - bbDn.Get(0)) * 100 / bbMid.Get(0)
adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0)
chop := ta.CHOP(e, 14).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
if adx > 50 && chop < 50 && bbWidth < 7 && e.BarNum-m.lastExit >= 10 && s.OrderNum == 0 {
dirt := 0
if c > max(kama, m.bigKama) {
dirt = 1
} else if c < min(kama, m.bigKama) {
dirt = -1
}
if dirt != 0 {
s.OpenOrder(&strat.EnterReq{
Tag: strconv.Itoa(dirt),
Short: dirt < 0,
StopLossVal: atr * 2.5,
TakeProfitVal: atr * 2.5,
})
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*KamaTrdSta)
m.bigKama = ta.KAMA(e.Close, 30).Get(0)
},
OnOrderChange: func(s *strat.StratJob, od *ormo.InOutOrder, chgType int) {
m, _ := s.More.(*KamaTrdSta)
if chgType == strat.OdChgExitFill && od.Enter.Filled > 0 {
m.lastExit = s.Env.BarNum
}
},
}
}

37
org/jesse/MACDEMA.go Normal file
View File

@@ -0,0 +1,37 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://jesse.trade/strategies/macd-ema
适合4h,在1h级别震荡严重
21年到241101,累计收益1555%,回撤28.4%
TODO: 考虑加入做空,提高夏普比率
*/
func MACDEMA(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
ema := ta.EMA(e.Close, 100).Get(0)
macdC, signalC := ta.MACD(e.Close, 12, 26, 9)
macd, signal := macdC.Get(0), signalC.Get(0)
if s.OrderNum > 0 {
if macd < signal && c < ema {
s.CloseOrders(&strat.ExitReq{Tag: "close"})
}
} else if c > ema && macd > signal {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
},
}
}

42
org/jesse/RSITrend.go Normal file
View File

@@ -0,0 +1,42 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://jesse.trade/strategies/rsi-trend
过于简单,无法盈利
*/
func RSITrend(p *config.RunPolicyConfig) *strat.TradeStrat {
//lenAtr := int(p.Def("atr", 14, core.PNorm(7, 40)))
//baseAtrLen := int(float64(lenAtr) * 4.3)
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
rsi := ta.RSI(e.Close, 5)
rsiX35 := rsi.Cross(35)
rsiX75 := rsi.Cross(75)
rsiX10 := rsi.Cross(10)
//atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
//atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
if s.OrderNum > 0 {
if rsiX75 == -1 || rsiX10 == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
}
} else if rsiX35 == 1 {
c := e.Close.Get(0)
s.OpenOrder(&strat.EnterReq{
Tag: "long",
StopLossVal: c * 0.95,
TakeProfitVal: c * 1.1,
})
}
},
}
}

View File

@@ -0,0 +1,36 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
https://jesse.trade/strategies/simple-bollinger-bands-strategy
适合4h,在1h级别收益很不稳定
21年到241101,收益804%,回撤13%
22年到241101,收益364%,回撤36%
*/
func SimpleBollinger(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
hl2 := ta.HL2(e.High, e.Low)
bbUp, bbMid, _ := ta.BBANDS(hl2, 20, 2, 2)
ichiCols := com.IchimokuCloud(e, 9, 26, 52, 26).Cols
if c < bbMid.Get(0) {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
} else if c > max(bbUp.Get(0), ichiCols[2].Get(0), ichiCols[3].Get(0)) {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
},
}
}

View File

@@ -0,0 +1,52 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"strconv"
)
/*
https://jesse.trade/strategies/ttmsqueezewithalma
alma实现和jesse中不完全一致,在48个品种,4h级别上震荡严重。
*/
func ttmSqueeze(e *ta.BarEnv, period int, bbMul, kcMul float64) bool {
bbUp, _, bbDn := ta.BBANDS(e.Close, period, bbMul, bbMul)
ma := ta.SMA(e.Close, period).Get(0)
atr := ta.SMA(ta.TR(e.High, e.Low, e.Close), period).Get(0)
thres := atr * kcMul
return bbDn.Get(0) < ma-thres || bbUp.Get(0) > ma+thres
}
func TTMSqueezeWithAlma(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
alma := ta.ALMA(e.Close, 50, 6, 0.85).Get(0)
stiff := ta.Stiffness(e.Close, 100, 60, 3).Get(0) > 25
ttms := ttmSqueeze(e, 20, 2, 2)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
if s.OrderNum > 0 {
return
}
if stiff && ttms {
dirt := 1
if c < alma {
dirt = -1
}
s.OpenOrder(&strat.EnterReq{
Tag: strconv.Itoa(dirt),
Short: dirt < 0,
StopLossVal: atr * 2,
TakeProfitVal: atr * 2.5,
})
}
},
}
}

73
org/jesse/TrendSwingV1.go Normal file
View File

@@ -0,0 +1,73 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"strconv"
)
/*
https://jesse.trade/strategies/trendswingtrader-v1
多均线结合ADX。
原始版本基于4h市价单入场
改为0.5倍atr限价入场后1h略好于4h
在48个交易对20210101-20241101
4h, 收益442%回撤20%
1h, 收益404%回撤19%
*/
func TrendSwingV1(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 300,
EachMaxShort: 1,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0)
maSml := ta.EMA(e.Close, 21).Get(0)
maMid := ta.EMA(e.Close, 50).Get(0)
maBig := ta.EMA(e.Close, 100).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
trend := 0
if maBig < maMid && maMid < maSml && maSml < c {
trend = 1
} else if maBig > maMid && maMid > maSml && maSml > c {
trend = -1
}
if len(s.LongOrders) > 0 {
for _, od := range s.LongOrders {
tp := od.GetTakeProfit()
if tp == nil {
// 止盈为nil表示已部分止盈退出
od.SetStopLoss(&ormo.ExitTrigger{
Price: max(c-atr*2, od.InitPrice),
})
}
}
} else if len(s.ShortOrders) > 0 {
for _, od := range s.ShortOrders {
tp := od.GetTakeProfit()
if tp == nil {
// 止盈为nil表示已部分止盈退出
od.SetStopLoss(&ormo.ExitTrigger{
Price: min(c+atr*2, od.InitPrice),
})
}
}
} else if adx > 25 && trend != 0 {
s.OpenOrder(&strat.EnterReq{
Tag: strconv.Itoa(trend),
Limit: c - atr*float64(trend)*0.5,
StopLossVal: atr * 2,
Short: trend < 0,
TakeProfitVal: atr * 3,
TakeProfitRate: 0.5,
StopBars: 4,
})
}
},
}
}

82
org/jesse/TurtleAI.go Normal file
View File

@@ -0,0 +1,82 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"strconv"
)
/*
https://jesse.trade/strategies/turtleai-by-o1-preview-model
初始版本基于btcusdt 1h
测试在48个品种上表现很不稳定
*/
func TurtleAI(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxLong: 1,
EachMaxShort: 1,
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "12h", 200},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = float64(0)
},
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
bigMa, _ := s.More.(float64)
hh := ta.Highest(e.High, 20).Get(1)
ll := ta.Lowest(e.Low, 20).Get(1)
//ma := ta.SMA(e.Close, 200).Get(0)
adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0) > 30
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
chopVal := ta.CHOP(e, 14).Get(0)
chop := chopVal < 40
if len(s.LongOrders) > 0 {
newSL := c - atr*2.5
for _, od := range s.LongOrders {
sl := od.GetStopLoss()
if newSL > sl.Price {
od.SetStopLoss(&ormo.ExitTrigger{
Price: newSL,
})
}
}
} else if len(s.ShortOrders) > 0 {
newSL := c + atr*2.5
for _, od := range s.LongOrders {
sl := od.GetStopLoss()
if newSL < sl.Price {
od.SetStopLoss(&ormo.ExitTrigger{
Price: newSL,
})
}
}
} else if adx && chop {
dirt := 0
if c > max(bigMa, hh) {
dirt = 1
} else if c < min(bigMa, ll) {
dirt = -1
}
if dirt != 0 {
s.OpenOrder(&strat.EnterReq{
Tag: strconv.Itoa(dirt),
Short: dirt < 0,
StopLossVal: atr * 2.5,
})
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
s.More = ta.SMA(e.Close, 200).Get(0)
},
}
}

18
org/jesse/common.go Normal file
View File

@@ -0,0 +1,18 @@
package jesse
import "github.com/banbox/banbot/strat"
func init() {
strat.AddStratGroup("jesse", map[string]strat.FuncMakeStrat{
"TrendSwingV1": TrendSwingV1,
"donchian": donchian,
"AlligatorAI": AlligatorAI,
"TurtleAI": TurtleAI,
"SimpleBollinger": SimpleBollinger,
"MACDEMA": MACDEMA,
"RSITrend": RSITrend,
"IchimokuCloud": IchimokuCloud,
"TTMSqueezeWithAlma": TTMSqueezeWithAlma,
"KamaTrendFollow": KamaTrendFollow,
})
}

39
org/jesse/donchian.go Normal file
View File

@@ -0,0 +1,39 @@
package jesse
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
https://jesse.trade/strategies/simple-donchian-strategy
唐安奇通道,默认周期20
适用周期:2h,4h
*/
func donchian(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
hh := ta.Highest(e.High, 25).Get(1)
ll := ta.Lowest(e.Low, 25).Get(1)
ma := ta.SMA(e.Close, 200).Get(0)
//atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
if len(s.LongOrders) > 0 {
if c < ll {
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
}
} else if c > max(ma, hh) {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
//TakeProfitVal: atr * 20,
//TakeProfitRate: 0.5,
})
}
},
}
}

40
org/jesse/jesse_test.go Normal file
View File

@@ -0,0 +1,40 @@
package jesse
import (
"fmt"
"github.com/banbox/banta"
"testing"
)
var env = &banta.BarEnv{
TimeFrame: "1d",
TFMSecs: 86400000,
Exchange: "binance",
MarketType: "future",
}
var DataKline = []banta.Kline{
{1688169600000, 1, 1, 1, 1, 1, 0},
{1688256000000, 2, 2, 2, 2, 2, 0},
{1688342400000, 3, 3, 3, 3, 3, 0},
{1688428800000, 4, 4, 4, 4, 4, 0},
{1688515200000, 5, 5, 5, 5, 5, 0},
{1688601600000, 6, 6, 6, 6, 6, 0},
{1688688000000, 7, 7, 7, 7, 7, 0},
{1688774400000, 8, 8, 8, 8, 8, 0},
{1688860800000, 9, 9, 9, 9, 9, 0},
{1688947200000, 10, 10, 10, 10, 10, 0},
{1689033600000, 11, 11, 11, 11, 11, 0},
{1689120000000, 12, 12, 12, 12, 12, 0},
}
func TestSMMA(t *testing.T) {
env.Reset()
var res []float64
for _, bar := range DataKline {
env.OnBar(bar.Time, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume, bar.Info)
ma := smma(env.Close, 4)
res = append(res, ma.Get(0))
}
fmt.Printf("%v", res)
}

7
org/llm/common.go Normal file
View File

@@ -0,0 +1,7 @@
package llm
import "github.com/banbox/banbot/strat"
func init() {
strat.AddStratGroup("llm", map[string]strat.FuncMakeStrat{})
}

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