Merge pull request #1820 from c9s/c9s/record-net-profit

FEATURE: add new migration script to record the net profit values
This commit is contained in:
c9s 2024-11-15 18:11:48 +08:00 committed by GitHub
commit 8e326d9cc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 146 additions and 7 deletions

13
doc/topics/profile.md Normal file
View File

@ -0,0 +1,13 @@
Profiling
===================
```shell
dotenv -f .env.local -- go run -tags pprof ./cmd/bbgo run \
--config ./makemoney-btcusdt.yaml \
--cpu-profile makemoney.pprof \
--enable-profile-server
```
```shell
go tool pprof http://localhost:6060/debug/pprof/heap
```

View File

@ -0,0 +1,17 @@
-- +up
-- +begin
ALTER TABLE `positions`
ADD COLUMN `net_profit` DECIMAL(16, 8) DEFAULT 0.00000000 NOT NULL
;
-- +end
-- +begin
UPDATE positions SET net_profit = profit WHERE net_profit = 0.0;
-- +end
-- +down
-- +begin
ALTER TABLE `positions`
DROP COLUMN `net_profit`
;
-- +end

View File

@ -0,0 +1,15 @@
-- +up
-- +begin
ALTER TABLE `positions`
ADD COLUMN `net_profit` DECIMAL DEFAULT 0.00000000 NOT NULL
;
-- +end
-- +down
-- +begin
ALTER TABLE `positions`
DROP COLUMN `net_profit`
;
-- +end

View File

@ -587,7 +587,7 @@ func (environ *Environment) RecordPosition(position *types.Position, trade types
log.Infof("recordPosition: position = %s, trade = %+v, profit = %+v", position.Base.String(), trade, profit) log.Infof("recordPosition: position = %s, trade = %+v, profit = %+v", position.Base.String(), trade, profit)
if profit != nil { if profit != nil {
if err := environ.PositionService.Insert(position, trade, profit.Profit); err != nil { if err := environ.PositionService.Insert(position, trade, profit.Profit, profit.NetProfit); err != nil {
log.WithError(err).Errorf("can not insert position record") log.WithError(err).Errorf("can not insert position record")
} }
@ -595,7 +595,7 @@ func (environ *Environment) RecordPosition(position *types.Position, trade types
log.WithError(err).Errorf("can not insert profit record: %+v", profit) log.WithError(err).Errorf("can not insert profit record: %+v", profit)
} }
} else { } else {
if err := environ.PositionService.Insert(position, trade, fixedpoint.Zero); err != nil { if err := environ.PositionService.Insert(position, trade, fixedpoint.Zero, fixedpoint.Zero); err != nil {
log.WithError(err).Errorf("can not insert position record") log.WithError(err).Errorf("can not insert position record")
} }
} }

6
pkg/cmd/pprof.go Normal file
View File

@ -0,0 +1,6 @@
//go:build pprof
// +build pprof
package cmd
import _ "net/http/pprof"

View File

@ -7,6 +7,7 @@ import (
"runtime/pprof" "runtime/pprof"
"strings" "strings"
"time" "time"
_ "time/tzdata"
"github.com/heroku/rollrus" "github.com/heroku/rollrus"
"github.com/joho/godotenv" "github.com/joho/godotenv"
@ -20,8 +21,6 @@ import (
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/util" "github.com/c9s/bbgo/pkg/util"
_ "time/tzdata"
) )
var cpuProfileFile *os.File var cpuProfileFile *os.File
@ -81,6 +80,24 @@ var RootCmd = &cobra.Command{
}() }()
} }
enableProfileServer, err := cmd.Flags().GetBool("enable-profile-server")
if err != nil {
return err
}
if enableProfileServer {
profileServerBind, err := cmd.Flags().GetString("profile-server-bind")
if err != nil {
return err
}
go func() {
if err := http.ListenAndServe(profileServerBind, nil); err != nil {
log.WithError(err).Errorf("profile server error")
}
}()
}
cpuProfile, err := cmd.Flags().GetString("cpu-profile") cpuProfile, err := cmd.Flags().GetString("cpu-profile")
if err != nil { if err != nil {
return err return err
@ -195,6 +212,8 @@ func init() {
RootCmd.PersistentFlags().String("max-api-secret", "", "max api secret") RootCmd.PersistentFlags().String("max-api-secret", "", "max api secret")
RootCmd.PersistentFlags().String("cpu-profile", "", "cpu profile") RootCmd.PersistentFlags().String("cpu-profile", "", "cpu profile")
RootCmd.PersistentFlags().Bool("enable-profile-server", false, "enable profile server binding")
RootCmd.PersistentFlags().String("profile-server-bind", "localhost:6060", "profile server binding")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))

View File

@ -0,0 +1,33 @@
package mysql
import (
"context"
"github.com/c9s/rockhopper/v2"
)
func init() {
AddMigration("main", up_main_addNetProfitColumn, down_main_addNetProfitColumn)
}
func up_main_addNetProfitColumn(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
// This code is executed when the migration is applied.
_, err = tx.ExecContext(ctx, "ALTER TABLE `positions`\n ADD COLUMN `net_profit` DECIMAL(16, 8) DEFAULT 0.00000000 NOT NULL\n;")
if err != nil {
return err
}
_, err = tx.ExecContext(ctx, "UPDATE positions SET net_profit = profit WHERE net_profit = 0.0;")
if err != nil {
return err
}
return err
}
func down_main_addNetProfitColumn(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
// This code is executed when the migration is rolled back.
_, err = tx.ExecContext(ctx, "ALTER TABLE `positions`\nDROP COLUMN `net_profit`\n;")
if err != nil {
return err
}
return err
}

View File

@ -0,0 +1,29 @@
package sqlite3
import (
"context"
"github.com/c9s/rockhopper/v2"
)
func init() {
AddMigration("main", up_main_addNetProfitColumn, down_main_addNetProfitColumn)
}
func up_main_addNetProfitColumn(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
// This code is executed when the migration is applied.
_, err = tx.ExecContext(ctx, "ALTER TABLE `positions`\n ADD COLUMN `net_profit` DECIMAL DEFAULT 0.00000000 NOT NULL\n;")
if err != nil {
return err
}
return err
}
func down_main_addNetProfitColumn(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
// This code is executed when the migration is rolled back.
_, err = tx.ExecContext(ctx, "ALTER TABLE `positions`\nDROP COLUMN `net_profit`\n;")
if err != nil {
return err
}
return err
}

View File

@ -51,7 +51,11 @@ func (s *PositionService) scanRows(rows *sqlx.Rows) (positions []types.Position,
return positions, rows.Err() return positions, rows.Err()
} }
func (s *PositionService) Insert(position *types.Position, trade types.Trade, profit fixedpoint.Value) error { func (s *PositionService) Insert(
position *types.Position,
trade types.Trade,
profit, netProfit fixedpoint.Value,
) error {
_, err := s.DB.NamedExec(` _, err := s.DB.NamedExec(`
INSERT INTO positions ( INSERT INTO positions (
strategy, strategy,
@ -63,6 +67,7 @@ func (s *PositionService) Insert(position *types.Position, trade types.Trade, pr
base, base,
quote, quote,
profit, profit,
net_profit,
trade_id, trade_id,
exchange, exchange,
side, side,
@ -77,6 +82,7 @@ func (s *PositionService) Insert(position *types.Position, trade types.Trade, pr
:base, :base,
:quote, :quote,
:profit, :profit,
:net_profit,
:trade_id, :trade_id,
:exchange, :exchange,
:side, :side,
@ -92,6 +98,7 @@ func (s *PositionService) Insert(position *types.Position, trade types.Trade, pr
"base": position.Base, "base": position.Base,
"quote": position.Quote, "quote": position.Quote,
"profit": profit, "profit": profit,
"net_profit": netProfit,
"trade_id": trade.ID, "trade_id": trade.ID,
"exchange": trade.Exchange, "exchange": trade.Exchange,
"side": trade.Side, "side": trade.Side,

View File

@ -34,7 +34,7 @@ func TestPositionService(t *testing.T) {
ChangedAt: time.Now(), ChangedAt: time.Now(),
}, types.Trade{ }, types.Trade{
Time: types.Time(time.Now()), Time: types.Time(time.Now()),
}, fixedpoint.Zero) }, fixedpoint.Zero, fixedpoint.Zero)
assert.NoError(t, err) assert.NoError(t, err)
}) })
@ -54,7 +54,7 @@ func TestPositionService(t *testing.T) {
Exchange: types.ExchangeBinance, Exchange: types.ExchangeBinance,
Side: types.SideTypeSell, Side: types.SideTypeSell,
Time: types.Time(time.Now()), Time: types.Time(time.Now()),
}, fixedpoint.NewFromFloat(10.9)) }, fixedpoint.NewFromFloat(10.9), fixedpoint.NewFromFloat(8.1))
assert.NoError(t, err) assert.NoError(t, err)
}) })