@@ -12,12 +12,6 @@ import (
1212
1313 "github.com/fatih/color"
1414 "github.com/google/uuid"
15-
16- "github.com/c9s/bbgo/pkg/cmd/cmdutil"
17- "github.com/c9s/bbgo/pkg/core"
18- "github.com/c9s/bbgo/pkg/data/tsv"
19- "github.com/c9s/bbgo/pkg/util"
20-
2115 "github.com/pkg/errors"
2216 log "github.com/sirupsen/logrus"
2317 "github.com/spf13/cobra"
@@ -26,10 +20,14 @@ import (
2620 "github.com/c9s/bbgo/pkg/accounting/pnl"
2721 "github.com/c9s/bbgo/pkg/backtest"
2822 "github.com/c9s/bbgo/pkg/bbgo"
23+ "github.com/c9s/bbgo/pkg/cmd/cmdutil"
24+ "github.com/c9s/bbgo/pkg/core"
25+ "github.com/c9s/bbgo/pkg/data/tsv"
2926 "github.com/c9s/bbgo/pkg/exchange"
3027 "github.com/c9s/bbgo/pkg/fixedpoint"
3128 "github.com/c9s/bbgo/pkg/service"
3229 "github.com/c9s/bbgo/pkg/types"
30+ "github.com/c9s/bbgo/pkg/util"
3331)
3432
3533func init () {
@@ -550,12 +548,11 @@ var BacktestCmd = &cobra.Command{
550548 continue
551549 }
552550
553- tradeState := sessionTradeStats [session.Name ][symbol ]
554- profitFactor := tradeState .ProfitFactor
555- winningRatio := tradeState .WinningRatio
556- intervalProfits := tradeState .IntervalProfits [types .Interval1d ]
557-
558- symbolReport , err := createSymbolReport (userConfig , session , symbol , trades .Copy (), intervalProfits , profitFactor , winningRatio )
551+ // profitFactor := tradeState.ProfitFactor
552+ // winningRatio := tradeState.WinningRatio
553+ // intervalProfits := tradeState.IntervalProfits[types.Interval1d]
554+ tradeStats := sessionTradeStats [session.Name ][symbol ]
555+ symbolReport , err := createSymbolReport (userConfig , session , symbol , trades .Copy (), tradeStats )
559556 if err != nil {
560557 return err
561558 }
@@ -566,8 +563,8 @@ var BacktestCmd = &cobra.Command{
566563 summaryReport .TotalUnrealizedProfit = symbolReport .PnL .UnrealizedProfit
567564 summaryReport .InitialEquityValue = summaryReport .InitialEquityValue .Add (symbolReport .InitialEquityValue ())
568565 summaryReport .FinalEquityValue = summaryReport .FinalEquityValue .Add (symbolReport .FinalEquityValue ())
569- summaryReport .TotalGrossProfit .Add (symbolReport .PnL .GrossProfit )
570- summaryReport .TotalGrossLoss .Add (symbolReport .PnL .GrossLoss )
566+ summaryReport .TotalGrossProfit = summaryReport . TotalGrossProfit .Add (symbolReport .PnL .GrossProfit )
567+ summaryReport .TotalGrossLoss = summaryReport . TotalGrossLoss .Add (symbolReport .PnL .GrossLoss )
571568
572569 // write report to a file
573570 if generatingReport {
@@ -620,14 +617,21 @@ var BacktestCmd = &cobra.Command{
620617 },
621618}
622619
620+ /*
623621func createSymbolReport(
622+
624623 userConfig *bbgo.Config, session *bbgo.ExchangeSession, symbol string, trades []types.Trade,
625624 intervalProfit *types.IntervalProfitCollector,
626625 profitFactor, winningRatio fixedpoint.Value,
626+
627627) (
628- * backtest.SessionSymbolReport ,
629- error ,
630- ) {
628+ */
629+ func createSymbolReport (
630+ userConfig * bbgo.Config , session * bbgo.ExchangeSession , symbol string , trades []types.Trade ,
631+ tradeStats * types.TradeStats ,
632+ ) (* backtest.SessionSymbolReport , error ) {
633+ intervalProfit := tradeStats .IntervalProfits [types .Interval1d ]
634+
631635 backtestExchange , ok := session .Exchange .(* backtest.Exchange )
632636 if ! ok {
633637 return nil , fmt .Errorf ("unexpected error, exchange instance is not a backtest exchange" )
@@ -637,6 +641,11 @@ func createSymbolReport(
637641 if ! ok {
638642 return nil , fmt .Errorf ("market not found: %s, %s" , symbol , session .Exchange .Name ())
639643 }
644+ tStart , tEnd := trades [0 ].Time , trades [len (trades )- 1 ].Time
645+
646+ periodStart := tStart .Time ()
647+ periodEnd := tEnd .Time ()
648+ period := periodEnd .Sub (periodStart )
640649
641650 startPrice , ok := session .StartPrice (symbol )
642651 if ! ok {
@@ -653,29 +662,81 @@ func createSymbolReport(
653662 Market : market ,
654663 }
655664
656- sharpeRatio := fixedpoint .NewFromFloat (intervalProfit .GetSharpe ())
657- sortinoRatio := fixedpoint .NewFromFloat (intervalProfit .GetSortino ())
658-
659665 report := calculator .Calculate (symbol , trades , lastPrice )
660666 accountConfig := userConfig .Backtest .GetAccount (session .Exchange .Name ().String ())
661667 initBalances := accountConfig .Balances .BalanceMap ()
662668 finalBalances := session .GetAccount ().Balances ()
669+ maxProfit := n (intervalProfit .Profits .Max ())
670+ maxLoss := n (intervalProfit .Profits .Min ())
671+ drawdown := types .Drawdown (intervalProfit .Profits )
672+ maxDrawdown := drawdown .Max ()
673+ avgDrawdown := drawdown .Average ()
674+ roundTurnCount := n (float64 (tradeStats .NumOfProfitTrade + tradeStats .NumOfLossTrade ))
675+ roundTurnLength := n (float64 (intervalProfit .Profits .Length ()))
676+ winningCount := n (float64 (tradeStats .NumOfProfitTrade ))
677+ loosingCount := n (float64 (tradeStats .NumOfLossTrade ))
678+ avgProfit := tradeStats .GrossProfit .Div (n (types .NNZ (float64 (tradeStats .NumOfProfitTrade ), 1 )))
679+ avgLoss := tradeStats .GrossLoss .Div (n (types .NNZ (float64 (tradeStats .NumOfLossTrade ), 1 )))
680+
681+ winningPct := winningCount .Div (roundTurnCount )
682+ // losingPct := fixedpoint.One.Sub(winningPct)
683+
684+ sharpeRatio := n (intervalProfit .GetSharpe ())
685+ sortinoRatio := n (intervalProfit .GetSortino ())
686+ annVolHis := n (types .AnnualHistoricVolatility (intervalProfit .Profits ))
687+ totalTimeInMarketSec , avgHoldSec := intervalProfit .GetTimeInMarket ()
688+ statn , stdErr := types .StatN (intervalProfit .Profits )
663689 symbolReport := backtest.SessionSymbolReport {
664- Exchange : session .Exchange .Name (),
665- Symbol : symbol ,
666- Market : market ,
667- LastPrice : lastPrice ,
668- StartPrice : startPrice ,
669- PnL : report ,
670- InitialBalances : initBalances ,
671- FinalBalances : finalBalances ,
672- // Manifests: manifests,
673- Sharpe : sharpeRatio ,
674- Sortino : sortinoRatio ,
675- ProfitFactor : profitFactor ,
676- WinningRatio : winningRatio ,
690+ Exchange : session .Exchange .Name (),
691+ Symbol : symbol ,
692+ Market : market ,
693+ LastPrice : lastPrice ,
694+ StartPrice : startPrice ,
695+ InitialBalances : initBalances ,
696+ FinalBalances : finalBalances ,
697+ TradeCount : fixedpoint .NewFromInt (int64 (len (trades ))),
698+ GrossLoss : tradeStats .GrossLoss ,
699+ GrossProfit : tradeStats .GrossProfit ,
700+ WinningCount : tradeStats .NumOfProfitTrade ,
701+ LosingCount : tradeStats .NumOfLossTrade ,
702+ RoundTurnCount : roundTurnCount ,
703+ WinningRatio : tradeStats .WinningRatio ,
704+ PercentProfitable : winningPct ,
705+ ProfitFactor : tradeStats .ProfitFactor ,
706+ MaxDrawdown : n (maxDrawdown ),
707+ AverageDrawdown : n (avgDrawdown ),
708+ MaxProfit : maxProfit ,
709+ MaxLoss : maxLoss ,
710+ MaxLossStreak : tradeStats .MaximumConsecutiveLosses ,
711+ TotalTimeInMarketSec : totalTimeInMarketSec ,
712+ AvgHoldSec : avgHoldSec ,
713+ AvgProfit : avgProfit ,
714+ AvgLoss : avgLoss ,
715+ AvgNetProfit : tradeStats .TotalNetProfit .Div (roundTurnLength ),
716+ TotalNetProfit : tradeStats .TotalNetProfit ,
717+ AnnualHistoricVolatility : annVolHis ,
718+ PnL : report ,
719+ PRR : types .PRR (tradeStats .GrossProfit , tradeStats .GrossLoss , winningCount , loosingCount ),
720+ Kelly : types .KellyCriterion (tradeStats .ProfitFactor , winningPct ),
721+ OptimalF : types .OptimalF (intervalProfit .Profits ),
722+ StatN : statn ,
723+ StdErr : stdErr ,
724+ Sharpe : sharpeRatio ,
725+ Sortino : sortinoRatio ,
677726 }
678727
728+ cagr := types .NN (
729+ types .CAGR (
730+ symbolReport .InitialEquityValue ().Float64 (),
731+ symbolReport .FinalEquityValue ().Float64 (),
732+ int (period .Hours ())/ 24 ,
733+ ), 0 )
734+
735+ symbolReport .CAGR = n (cagr )
736+ symbolReport .Calmar = n (types .CalmarRatio (cagr , maxDrawdown ))
737+ symbolReport .Sterling = n (types .SterlingRatio (cagr , avgDrawdown ))
738+ symbolReport .Burke = n (types .BurkeRatio (cagr , drawdown .AverageSquared ()))
739+
679740 for _ , s := range session .Subscriptions {
680741 symbolReport .Subscriptions = append (symbolReport .Subscriptions , s )
681742 }
@@ -694,6 +755,10 @@ func createSymbolReport(
694755 return & symbolReport , nil
695756}
696757
758+ func n (v float64 ) fixedpoint.Value {
759+ return fixedpoint .NewFromFloat (v )
760+ }
761+
697762func verify (
698763 userConfig * bbgo.Config , backtestService * service.BacktestService ,
699764 sourceExchanges map [types.ExchangeName ]types.Exchange , startTime , endTime time.Time ,
@@ -704,6 +769,7 @@ func verify(
704769 return err
705770 }
706771 }
772+
707773 return nil
708774}
709775
0 commit comments