Skip to content

Commit fe1daca

Browse files
committed
启动时按账户输出策略任务
解决Dashboard余额显示不正确 解决CallStratSymbols返回顺序错乱问题 update InOutOrder.SetEnterLimit
1 parent 3183a8a commit fe1daca

File tree

26 files changed

+597
-222
lines changed

26 files changed

+597
-222
lines changed

biz/biz.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func RefreshJobs(pairs []string, pairTfScores map[string]map[string]float64, sho
141141
}
142142
}
143143
if showLog {
144-
core.PrintStratGroups()
144+
strat.PrintStratGroups()
145145
}
146146
if pBar != nil {
147147
pBar.SetProgress("loadJobs", 1)

core/data.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ var (
4848
NewNumInSim int // 撮合时创建新订单的数量
4949

5050
ConcurNum = 2 // The maximum number of K-line tasks to be downloaded at the same time. If it is too high, a 429 current limit will occur. 最大同时下载K线任务数,过大会出现429限流
51-
Version = "v0.2.15-beta.4"
52-
UIVersion = "v0.2.15-beta.4"
51+
Version = "v0.2.15-beta.5"
52+
UIVersion = "v0.2.15-beta.5"
5353
SysLang string // language code for current system 当前系统语言设置
5454
LogFile string
5555
DevDbPath string

core/utils.go

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package core
22

33
import (
44
"fmt"
5-
"github.com/banbox/banexg/log"
65
"github.com/banbox/banexg/utils"
76
"regexp"
87
"slices"
@@ -15,18 +14,22 @@ format `[key]:pairs...` as below
1514
【key】
1615
Quote: Base1 Base2 ...
1716
*/
18-
func GroupByPairQuotes(items map[string][]string) string {
17+
func GroupByPairQuotes(items map[string][]string, doSort bool) string {
1918
res := make(map[string]map[string][]string)
2019
for key, arr := range items {
21-
slices.Sort(arr)
20+
if doSort {
21+
slices.Sort(arr)
22+
}
2223
quoteMap := make(map[string][]string)
2324
for _, pair := range arr {
2425
baseCode, quoteCode, _, _ := SplitSymbol(pair)
2526
baseList, _ := quoteMap[quoteCode]
2627
quoteMap[quoteCode] = append(baseList, baseCode)
2728
}
2829
for quote, baseList := range quoteMap {
29-
slices.Sort(baseList)
30+
if doSort {
31+
slices.Sort(baseList)
32+
}
3033
quoteMap[quote] = baseList
3134
}
3235
res[key] = quoteMap
@@ -42,34 +45,6 @@ func GroupByPairQuotes(items map[string][]string) string {
4245
return b.String()
4346
}
4447

45-
/*
46-
PrintStratGroups
47-
print strategy+timeframe from `core.StgPairTfs`
48-
从core.StgPairTfs输出策略+时间周期的币种信息到控制台
49-
*/
50-
func PrintStratGroups() {
51-
allows := make(map[string][]string)
52-
disables := make(map[string][]string)
53-
for stagy, pairMap := range StgPairTfs {
54-
for pair, tf := range pairMap {
55-
key := fmt.Sprintf("%s_%s", stagy, tf)
56-
if ok, _ := PairsMap[pair]; ok {
57-
arr, _ := allows[key]
58-
allows[key] = append(arr, pair)
59-
} else {
60-
arr, _ := disables[key]
61-
disables[key] = append(arr, pair)
62-
}
63-
}
64-
}
65-
text := GroupByPairQuotes(allows)
66-
log.Info("group pairs by strat_tf:\n" + text)
67-
if len(disables) > 0 {
68-
text = GroupByPairQuotes(disables)
69-
log.Info("group disable pairs by strat_tf:\n" + text)
70-
}
71-
}
72-
7348
var (
7449
reCoinSplit = regexp.MustCompile("[/:-]")
7550
splitCache = map[string][4]string{}

entry/common.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,12 @@ func init() {
266266
RunRaw: strat.ListStrats,
267267
Help: "list registered strategies",
268268
})
269+
AddCmdJob(&CmdJob{
270+
Name: "bt_factor",
271+
Parent: "tool",
272+
RunRaw: opt.BtFactors,
273+
Help: "backtest factors with orders",
274+
})
269275

270276
AddCmdJob(&CmdJob{
271277
Name: "down_order",

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.23.0
44

55
require (
66
github.com/anyongjin/go-bayesopt v1.0.2
7-
github.com/banbox/banexg v0.2.27
7+
github.com/banbox/banexg v0.2.28-beta.2
88
github.com/banbox/banta v0.2.1
99
github.com/c-bata/goptuna v0.9.0
1010
github.com/dgraph-io/ristretto v0.2.0

go.sum

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7X
33
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
44
github.com/anyongjin/go-bayesopt v1.0.2 h1:845NHAdxk4x1FxeOS5McoaWO33ZfE2AR434j9lnEHAM=
55
github.com/anyongjin/go-bayesopt v1.0.2/go.mod h1:KB64n3O9sPBql6pPnOKh0w8bnOSG1TIMNb+9c/9iQs0=
6-
github.com/banbox/banexg v0.2.27-beta.4 h1:86dpKXWgkakAiEHJvXxxlE5LlKuoGoGWQmrvFFReTXw=
7-
github.com/banbox/banexg v0.2.27-beta.4/go.mod h1:OW31oCQoMsPjetaPgtTgHZvBzn34t2CzYYA4iW3TWIs=
8-
github.com/banbox/banexg v0.2.27/go.mod h1:OW31oCQoMsPjetaPgtTgHZvBzn34t2CzYYA4iW3TWIs=
9-
github.com/banbox/banta v0.2.1-beta.2 h1:dEB9HRne6xpBMu0sCvxkrb2nvcKnYD4ZwCPnrDgkX80=
10-
github.com/banbox/banta v0.2.1-beta.2/go.mod h1:+9PG7f4QZtfpJfKpGp7aToOUg2ByatDosHjjvGFjaVc=
6+
github.com/banbox/banexg v0.2.28-beta.2 h1:CgoGY8llCHBxPJ214HYF9d1/bgIHeRvoUWf9rYkLT6c=
7+
github.com/banbox/banexg v0.2.28-beta.2/go.mod h1:OW31oCQoMsPjetaPgtTgHZvBzn34t2CzYYA4iW3TWIs=
8+
github.com/banbox/banta v0.2.1 h1:g/xfYCYtd9PWckBZUqhzpIiPbOHUilDhz8sFo4kT4bk=
119
github.com/banbox/banta v0.2.1/go.mod h1:+9PG7f4QZtfpJfKpGp7aToOUg2ByatDosHjjvGFjaVc=
1210
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
1311
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=

live/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func CronKlineDelays() {
135135
fails[timeoutMin] = append(arr, pair)
136136
}
137137
if len(fails) > 0 {
138-
failText := core.GroupByPairQuotes(fails)
138+
failText := core.GroupByPairQuotes(fails, false)
139139
logDelay("Listen to the spider kline timeout:" + failText)
140140
}
141141
})
@@ -161,7 +161,7 @@ func CronKlineSummary() {
161161
core.TfPairHits[tf] = make(map[string]int)
162162
}
163163
if len(pairGroups) > 0 {
164-
staText := core.GroupByPairQuotes(pairGroups)
164+
staText := core.GroupByPairQuotes(pairGroups, true)
165165
log.Info(fmt.Sprintf("receive bars in 10 mins:\n%s", staText))
166166
}
167167
core.TfPairHitsLock.Unlock()

opt/backtest.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -340,38 +340,6 @@ func (b *BackTest) logState(startMS, timeMS int64) {
340340
b.logPlot(wallets, startMS, odNum, totalLegal)
341341
}
342342

343-
func (b *BackTest) logPlot(wallets *biz.BanWallets, timeMS int64, odNum int, totalLegal float64) {
344-
if odNum < 0 {
345-
odNum = ormo.OpenNum(config.DefAcc, ormo.InOutStatusPartEnter)
346-
}
347-
jobNum := 0
348-
jobMap := strat.GetJobs(wallets.Account)
349-
for _, jobs := range jobMap {
350-
for _, j := range jobs {
351-
if j.CheckMS+j.Env.TFMSecs >= timeMS {
352-
jobNum += 1
353-
}
354-
}
355-
}
356-
if totalLegal < 0 {
357-
totalLegal = wallets.TotalLegal(nil, true)
358-
}
359-
avaLegal := wallets.AvaLegal(nil)
360-
profitLegal := wallets.UnrealizedPOLLegal(nil)
361-
drawLegal := wallets.GetWithdrawLegal(nil)
362-
curDate := btime.ToDateStr(timeMS, "")
363-
b.donePftLegal += ormo.LegalDoneProfits(b.histOdOff)
364-
b.histOdOff = len(ormo.HistODs)
365-
b.Plots.Labels = append(b.Plots.Labels, curDate)
366-
b.Plots.OdNum = append(b.Plots.OdNum, odNum)
367-
b.Plots.JobNum = append(b.Plots.JobNum, jobNum)
368-
b.Plots.Real = append(b.Plots.Real, totalLegal)
369-
b.Plots.Available = append(b.Plots.Available, avaLegal)
370-
b.Plots.Profit = append(b.Plots.Profit, b.donePftLegal)
371-
b.Plots.UnrealizedPOL = append(b.Plots.UnrealizedPOL, profitLegal)
372-
b.Plots.WithDraw = append(b.Plots.WithDraw, drawLegal)
373-
}
374-
375343
func (b *BackTest) cronDumpBtStatus() {
376344
b.lastDumpMs = btime.UTCStamp()
377345
_, err_ := core.Cron.AddFunc("30 * * * * *", func() {

opt/reports.go

Lines changed: 151 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"github.com/banbox/banbot/orm"
10+
"github.com/banbox/banexg"
1011
"math"
1112
"os"
1213
"path/filepath"
@@ -895,6 +896,38 @@ func (r *BTResult) DelBigObjects() {
895896
}
896897
}
897898

899+
func (r *BTResult) logPlot(wallets *biz.BanWallets, timeMS int64, odNum int, totalLegal float64) {
900+
if odNum < 0 {
901+
odNum = ormo.OpenNum(config.DefAcc, ormo.InOutStatusPartEnter)
902+
}
903+
jobNum := 0
904+
jobMap := strat.GetJobs(wallets.Account)
905+
for _, jobs := range jobMap {
906+
for _, j := range jobs {
907+
if j.CheckMS+j.Env.TFMSecs >= timeMS {
908+
jobNum += 1
909+
}
910+
}
911+
}
912+
if totalLegal < 0 {
913+
totalLegal = wallets.TotalLegal(nil, true)
914+
}
915+
avaLegal := wallets.AvaLegal(nil)
916+
profitLegal := wallets.UnrealizedPOLLegal(nil)
917+
drawLegal := wallets.GetWithdrawLegal(nil)
918+
curDate := btime.ToDateStr(timeMS, "")
919+
r.donePftLegal += ormo.LegalDoneProfits(r.histOdOff)
920+
r.histOdOff = len(ormo.HistODs)
921+
r.Plots.Labels = append(r.Plots.Labels, curDate)
922+
r.Plots.OdNum = append(r.Plots.OdNum, odNum)
923+
r.Plots.JobNum = append(r.Plots.JobNum, jobNum)
924+
r.Plots.Real = append(r.Plots.Real, totalLegal)
925+
r.Plots.Available = append(r.Plots.Available, avaLegal)
926+
r.Plots.Profit = append(r.Plots.Profit, r.donePftLegal)
927+
r.Plots.UnrealizedPOL = append(r.Plots.UnrealizedPOL, profitLegal)
928+
r.Plots.WithDraw = append(r.Plots.WithDraw, drawLegal)
929+
}
930+
898931
func selectPairs(r *BTResult, name string) []string {
899932
fn, ok := PairPickers[name]
900933
if !ok {
@@ -1059,18 +1092,10 @@ func calcCumCurve(pairOrders map[string][]*ormo.InOutOrder, startMS, endMS int64
10591092
tfMSecs := int64(utils2.TFToSecs(tf) * 1000)
10601093
for pair, orders := range pairOrders {
10611094
exs := orm.GetExSymbol2(core.ExgName, core.Market, pair)
1062-
_, bars, err := orm.GetOHLCV(exs, tf, startMS, endMS, 0, false)
1095+
_, closes, err := getOHLCVNoLack(exs, tf, startMS, endMS, tfMSecs)
10631096
if err != nil {
10641097
return nil, err
10651098
}
1066-
var closes []float64
1067-
if len(bars) > 0 {
1068-
bars, _ = utils.FillOHLCVLacks(bars, startMS, endMS, tfMSecs)
1069-
closes = make([]float64, len(bars))
1070-
for i, b := range bars {
1071-
closes[i] = b.Close
1072-
}
1073-
}
10741099
// 计算每日回报
10751100
returns, _, _ := ormo.CalcUnitReturns(orders, closes, startMS, endMS, tfMSecs)
10761101
if glbRets == nil {
@@ -1091,6 +1116,123 @@ func calcCumCurve(pairOrders map[string][]*ormo.InOutOrder, startMS, endMS int64
10911116
return cumRets, nil
10921117
}
10931118

1119+
func getOHLCVNoLack(exs *orm.ExSymbol, tf string, startMS, endMS, tfMSecs int64) ([]*banexg.Kline, []float64, *errs.Error) {
1120+
_, bars, err := orm.GetOHLCV(exs, tf, startMS, endMS, 0, false)
1121+
if err != nil {
1122+
return nil, nil, err
1123+
}
1124+
var closes []float64
1125+
if len(bars) > 0 {
1126+
bars, _ = utils.FillOHLCVLacks(bars, startMS, endMS, tfMSecs)
1127+
closes = make([]float64, len(bars))
1128+
for i, b := range bars {
1129+
closes[i] = b.Close
1130+
}
1131+
}
1132+
return bars, closes, nil
1133+
}
1134+
1135+
func BuildBtResult(odList []*ormo.InOutOrder, funds map[string]float64) (*BTResult, *errs.Error) {
1136+
btRes := NewBTResult()
1137+
if len(odList) == 0 {
1138+
return btRes, nil
1139+
}
1140+
backUp := biz.BackupVars()
1141+
biz.ResetVars()
1142+
defer func() {
1143+
biz.RestoreVars(backUp)
1144+
}()
1145+
wallets := biz.GetWallets(config.DefAcc)
1146+
wallets.SetWallets(funds)
1147+
wallets.TryUpdateStakePctAmt()
1148+
totalLegal := wallets.TotalLegal(nil, false)
1149+
if totalLegal == 0 {
1150+
return nil, errs.NewMsg(errs.CodeRunTime, "TotalLegal of wallets is empty")
1151+
}
1152+
// 更新起止时间、最小周期
1153+
var startMS = odList[0].RealEnterMS()
1154+
var endMS = odList[0].ExitAt
1155+
var tfSecs = utils2.TFToSecs(odList[0].Timeframe)
1156+
for _, od := range odList {
1157+
enterAt := od.RealEnterMS()
1158+
if enterAt > 0 && enterAt < startMS {
1159+
startMS = enterAt
1160+
}
1161+
endMS = max(endMS, od.ExitAt)
1162+
curSecs := utils2.TFToSecs(od.Timeframe)
1163+
tfSecs = min(tfSecs, curSecs)
1164+
}
1165+
tfMSecs := int64(tfSecs * 1000)
1166+
startMS = utils2.AlignTfMSecs(startMS, tfMSecs)
1167+
endMS = utils2.AlignTfMSecs(endMS, tfMSecs) + tfMSecs
1168+
btRes.StartMS = startMS
1169+
btRes.EndMS = endMS
1170+
btRes.OrderNum = len(odList)
1171+
tf := utils2.SecsToTF(tfSecs)
1172+
totalBarNum := int((endMS - startMS) / tfMSecs)
1173+
// 获取各个品种信息
1174+
pairOrders := make(map[string][]*ormo.InOutOrder)
1175+
for _, od := range odList {
1176+
items, _ := pairOrders[od.Symbol]
1177+
pairOrders[od.Symbol] = append(items, od)
1178+
}
1179+
pairStats, err := calcPairStats(pairOrders, startMS, endMS, tf)
1180+
if err != nil {
1181+
return nil, err
1182+
}
1183+
sort.Slice(odList, func(i, j int) bool {
1184+
return odList[i].RealEnterMS() < odList[j].RealEnterMS()
1185+
})
1186+
openOds := make(map[int64]*ormo.InOutOrder)
1187+
btRes.PlotEvery = int(math.Round(float64(totalBarNum) / float64(ShowNum)))
1188+
btRes.logPlot(wallets, startMS, 0, totalLegal)
1189+
curMS := startMS + tfMSecs
1190+
nextOd := 0
1191+
for {
1192+
for nextOd < len(odList) {
1193+
next := odList[nextOd]
1194+
if next.RealEnterMS() < curMS {
1195+
openOds[next.ID] = next
1196+
nextOd += 1
1197+
} else {
1198+
break
1199+
}
1200+
}
1201+
}
1202+
_ = pairStats
1203+
return nil, nil
1204+
}
1205+
1206+
type PairStat struct {
1207+
Orders []*ormo.InOutOrder
1208+
Exs *orm.ExSymbol
1209+
Bars []*banexg.Kline
1210+
Returns []float64
1211+
Prices []float64
1212+
}
1213+
1214+
func calcPairStats(pairOrders map[string][]*ormo.InOutOrder, startMS, endMS int64, tf string) (map[string]*PairStat, *errs.Error) {
1215+
tfMSecs := int64(utils2.TFToSecs(tf) * 1000)
1216+
var result = make(map[string]*PairStat)
1217+
for pair, orders := range pairOrders {
1218+
exs := orm.GetExSymbol2(core.ExgName, core.Market, pair)
1219+
bars, closes, err := getOHLCVNoLack(exs, tf, startMS, endMS, tfMSecs)
1220+
if err != nil {
1221+
return nil, err
1222+
}
1223+
// 计算每日回报
1224+
returns, _, _ := ormo.CalcUnitReturns(orders, closes, startMS, endMS, tfMSecs)
1225+
result[pair] = &PairStat{
1226+
Orders: orders,
1227+
Exs: exs,
1228+
Bars: bars,
1229+
Returns: returns,
1230+
Prices: closes,
1231+
}
1232+
}
1233+
return result, nil
1234+
}
1235+
10941236
type TimeVal struct {
10951237
Time int64
10961238
Value float64

0 commit comments

Comments
 (0)