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+
898931func 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+
10941236type TimeVal struct {
10951237 Time int64
10961238 Value float64
0 commit comments