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

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