mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 08:15:15 +00:00
feature: optimizer add profitFactor optimization. Optimization value use float64 instead to save memory and boost performance
This commit is contained in:
parent
7d03c69406
commit
7aaea257df
|
@ -81,6 +81,8 @@ type SessionSymbolReport struct {
|
|||
Manifests Manifests `json:"manifests,omitempty"`
|
||||
Sharpe fixedpoint.Value `json:"sharpeRatio"`
|
||||
Sortino fixedpoint.Value `json:"sortinoRatio"`
|
||||
ProfitFactor fixedpoint.Value `json:"profitFactor"`
|
||||
WinningRatio fixedpoint.Value `json:"winningRatio"`
|
||||
}
|
||||
|
||||
func (r *SessionSymbolReport) InitialEquityValue() fixedpoint.Value {
|
||||
|
|
|
@ -4,11 +4,6 @@ import (
|
|||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/c9s/bbgo/pkg/cmd/cmdutil"
|
||||
"github.com/c9s/bbgo/pkg/data/tsv"
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
"github.com/fatih/color"
|
||||
"github.com/google/uuid"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
@ -16,6 +11,12 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/cmd/cmdutil"
|
||||
"github.com/c9s/bbgo/pkg/data/tsv"
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
"github.com/fatih/color"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -523,8 +524,11 @@ var BacktestCmd = &cobra.Command{
|
|||
|
||||
for _, session := range environ.Sessions() {
|
||||
for symbol, trades := range session.Trades {
|
||||
intervalProfits := sessionTradeStats[session.Name][symbol].IntervalProfits[types.Interval1d]
|
||||
symbolReport, err := createSymbolReport(userConfig, session, symbol, trades.Trades, intervalProfits)
|
||||
tradeState := sessionTradeStats[session.Name][symbol]
|
||||
profitFactor := tradeState.ProfitFactor
|
||||
winningRatio := tradeState.WinningRatio
|
||||
intervalProfits := tradeState.IntervalProfits[types.Interval1d]
|
||||
symbolReport, err := createSymbolReport(userConfig, session, symbol, trades.Trades, intervalProfits, profitFactor, winningRatio)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -615,7 +619,8 @@ func collectSubscriptionIntervals(environ *bbgo.Environment) (allKLineIntervals
|
|||
return allKLineIntervals, requiredInterval, backTestIntervals
|
||||
}
|
||||
|
||||
func createSymbolReport(userConfig *bbgo.Config, session *bbgo.ExchangeSession, symbol string, trades []types.Trade, intervalProfit *types.IntervalProfitCollector) (
|
||||
func createSymbolReport(userConfig *bbgo.Config, session *bbgo.ExchangeSession, symbol string, trades []types.Trade, intervalProfit *types.IntervalProfitCollector,
|
||||
profitFactor, winningRatio fixedpoint.Value) (
|
||||
*backtest.SessionSymbolReport,
|
||||
error,
|
||||
) {
|
||||
|
@ -661,8 +666,10 @@ func createSymbolReport(userConfig *bbgo.Config, session *bbgo.ExchangeSession,
|
|||
InitialBalances: initBalances,
|
||||
FinalBalances: finalBalances,
|
||||
// Manifests: manifests,
|
||||
Sharpe: sharpeRatio,
|
||||
Sortino: sortinoRatio,
|
||||
Sharpe: sharpeRatio,
|
||||
Sortino: sortinoRatio,
|
||||
ProfitFactor: profitFactor,
|
||||
WinningRatio: winningRatio,
|
||||
}
|
||||
|
||||
for _, s := range session.Subscriptions {
|
||||
|
|
|
@ -79,7 +79,7 @@ func LoadConfig(yamlConfigFileName string) (*Config, error) {
|
|||
switch objective := strings.ToLower(optConfig.Objective); objective {
|
||||
case "", "default":
|
||||
optConfig.Objective = HpOptimizerObjectiveEquity
|
||||
case HpOptimizerObjectiveEquity, HpOptimizerObjectiveProfit, HpOptimizerObjectiveVolume:
|
||||
case HpOptimizerObjectiveEquity, HpOptimizerObjectiveProfit, HpOptimizerObjectiveVolume, HpOptimizerObjectiveProfitFactor:
|
||||
optConfig.Objective = objective
|
||||
default:
|
||||
return nil, fmt.Errorf(`unknown objective "%s"`, optConfig.Objective)
|
||||
|
|
|
@ -14,30 +14,43 @@ import (
|
|||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
)
|
||||
|
||||
type MetricValueFunc func(summaryReport *backtest.SummaryReport) fixedpoint.Value
|
||||
type MetricValueFunc func(summaryReport *backtest.SummaryReport) float64
|
||||
|
||||
var TotalProfitMetricValueFunc = func(summaryReport *backtest.SummaryReport) fixedpoint.Value {
|
||||
return summaryReport.TotalProfit
|
||||
var TotalProfitMetricValueFunc = func(summaryReport *backtest.SummaryReport) float64 {
|
||||
return summaryReport.TotalProfit.Float64()
|
||||
}
|
||||
|
||||
var TotalVolume = func(summaryReport *backtest.SummaryReport) fixedpoint.Value {
|
||||
var TotalVolume = func(summaryReport *backtest.SummaryReport) float64 {
|
||||
if len(summaryReport.SymbolReports) == 0 {
|
||||
return fixedpoint.Zero
|
||||
return 0
|
||||
}
|
||||
|
||||
buyVolume := summaryReport.SymbolReports[0].PnL.BuyVolume
|
||||
sellVolume := summaryReport.SymbolReports[0].PnL.SellVolume
|
||||
return buyVolume.Add(sellVolume)
|
||||
buyVolume := summaryReport.SymbolReports[0].PnL.BuyVolume.Float64()
|
||||
sellVolume := summaryReport.SymbolReports[0].PnL.SellVolume.Float64()
|
||||
return buyVolume + sellVolume
|
||||
}
|
||||
|
||||
var TotalEquityDiff = func(summaryReport *backtest.SummaryReport) fixedpoint.Value {
|
||||
var TotalEquityDiff = func(summaryReport *backtest.SummaryReport) float64 {
|
||||
if len(summaryReport.SymbolReports) == 0 {
|
||||
return fixedpoint.Zero
|
||||
return 0
|
||||
}
|
||||
|
||||
initEquity := summaryReport.InitialEquityValue
|
||||
finalEquity := summaryReport.FinalEquityValue
|
||||
return finalEquity.Sub(initEquity)
|
||||
initEquity := summaryReport.InitialEquityValue.Float64()
|
||||
finalEquity := summaryReport.FinalEquityValue.Float64()
|
||||
return finalEquity - initEquity
|
||||
}
|
||||
|
||||
var ProfitFactorMetricValueFunc = func(summaryReport *backtest.SummaryReport) float64 {
|
||||
if len(summaryReport.SymbolReports) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(summaryReport.SymbolReports) > 1 {
|
||||
panic("multiple symbols' profitfactor optimization not supported")
|
||||
}
|
||||
report := summaryReport.SymbolReports[0]
|
||||
pf := report.ProfitFactor.Float64()
|
||||
win := report.WinningRatio.Float64()
|
||||
return pf*0.9 + win*0.1
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
|
@ -51,7 +64,7 @@ type Metric struct {
|
|||
Key string `json:"key"`
|
||||
|
||||
// Value is the metric value of the metric
|
||||
Value fixedpoint.Value `json:"value,omitempty"`
|
||||
Value float64 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func copyParams(params []interface{}) []interface{} {
|
||||
|
@ -199,6 +212,7 @@ func (o *GridOptimizer) Run(executor Executor, configJson []byte) (map[string][]
|
|||
"totalProfit": TotalProfitMetricValueFunc,
|
||||
"totalVolume": TotalVolume,
|
||||
"totalEquityDiff": TotalEquityDiff,
|
||||
"profitFactor": ProfitFactorMetricValueFunc,
|
||||
}
|
||||
var metrics = map[string][]Metric{}
|
||||
|
||||
|
@ -287,7 +301,7 @@ func (o *GridOptimizer) Run(executor Executor, configJson []byte) (map[string][]
|
|||
sort.Slice(metrics[n], func(i, j int) bool {
|
||||
a := metrics[n][i].Value
|
||||
b := metrics[n][j].Value
|
||||
return a.Compare(b) > 0
|
||||
return a > b
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ package optimizer
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/c-bata/goptuna"
|
||||
goptunaCMAES "github.com/c-bata/goptuna/cmaes"
|
||||
goptunaSOBOL "github.com/c-bata/goptuna/sobol"
|
||||
|
@ -11,10 +14,9 @@ import (
|
|||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// WARNING: the text here could only be lower cases
|
||||
const (
|
||||
// HpOptimizerObjectiveEquity optimize the parameters to maximize equity gain
|
||||
HpOptimizerObjectiveEquity = "equity"
|
||||
|
@ -22,6 +24,8 @@ const (
|
|||
HpOptimizerObjectiveProfit = "profit"
|
||||
// HpOptimizerObjectiveVolume optimize the parameters to maximize trading volume
|
||||
HpOptimizerObjectiveVolume = "volume"
|
||||
// HpOptimizerObjectiveProfitFactor optimize the parameters to maximize profit factor
|
||||
HpOptimizerObjectiveProfitFactor = "profitfactor"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -198,6 +202,8 @@ func (o *HyperparameterOptimizer) buildObjective(executor Executor, configJson [
|
|||
metricValueFunc = TotalVolume
|
||||
case HpOptimizerObjectiveEquity:
|
||||
metricValueFunc = TotalEquityDiff
|
||||
case HpOptimizerObjectiveProfitFactor:
|
||||
metricValueFunc = ProfitFactorMetricValueFunc
|
||||
}
|
||||
|
||||
return func(trial goptuna.Trial) (float64, error) {
|
||||
|
@ -225,7 +231,7 @@ func (o *HyperparameterOptimizer) buildObjective(executor Executor, configJson [
|
|||
return 0.0, err
|
||||
}
|
||||
// By config, the Goptuna optimize the parameters by maximize the objective output.
|
||||
return metricValueFunc(summary).Float64(), nil
|
||||
return metricValueFunc(summary), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user