all: integrate google spread sheet service

This commit is contained in:
c9s 2023-07-09 13:17:39 +08:00
parent e41d720867
commit 5962742b43
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
6 changed files with 93 additions and 8 deletions

View File

@ -5,6 +5,11 @@ sessions:
makerFeeRate: 0%
takerFeeRate: 0.025%
#services:
# googleSpreadSheet:
# jsonTokenFile: ".credentials/google-cloud/service-account-json-token.json"
# spreadSheetId: "YOUR_SPREADSHEET_ID"
exchangeStrategies:
- on: max
scmaker:

View File

@ -23,6 +23,18 @@ And
<https://developers.google.com/workspace/guides/create-credentials>
Download the JSON token file and store it in a safe place.
### Setting up service account permissions
Go to Google Workspace and Add "Manage Domain Wide Delegation", add you client and with the following scopes:
```
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.readonly
https://www.googleapis.com/auth/spreadsheets
https://www.googleapis.com/auth/spreadsheets.readonly
```

View File

@ -24,6 +24,12 @@ func BootstrapEnvironmentLightweight(ctx context.Context, environ *Environment,
}
}
if userConfig.Service != nil {
if err := environ.ConfigureService(ctx, userConfig.Service); err != nil {
return err
}
}
return nil
}
@ -46,6 +52,12 @@ func BootstrapEnvironment(ctx context.Context, environ *Environment, userConfig
}
}
if userConfig.Service != nil {
if err := environ.ConfigureService(ctx, userConfig.Service); err != nil {
return err
}
}
if err := environ.ConfigureNotificationSystem(ctx, userConfig); err != nil {
return errors.Wrap(err, "notification configure error")
}

View File

@ -21,7 +21,9 @@ import (
// DefaultFeeRate set the fee rate for most cases
// BINANCE uses 0.1% for both maker and taker
// for BNB holders, it's 0.075% for both maker and taker
//
// for BNB holders, it's 0.075% for both maker and taker
//
// MAX uses 0.050% for maker and 0.15% for taker
var DefaultFeeRate = fixedpoint.NewFromFloat(0.075 * 0.01)
@ -312,6 +314,15 @@ type SyncConfig struct {
} `json:"userDataStream,omitempty" yaml:"userDataStream,omitempty"`
}
type GoogleSpreadSheetServiceConfig struct {
JsonTokenFile string `json:"jsonTokenFile" yaml:"jsonTokenFile"`
SpreadSheetID string `json:"spreadSheetId" yaml:"spreadSheetId"`
}
type ServiceConfig struct {
GoogleSpreadSheetService *GoogleSpreadSheetServiceConfig `json:"googleSpreadSheet" yaml:"googleSpreadSheet"`
}
type Config struct {
Build *BuildConfig `json:"build,omitempty" yaml:"build,omitempty"`
@ -327,6 +338,8 @@ type Config struct {
Persistence *PersistenceConfig `json:"persistence,omitempty" yaml:"persistence,omitempty"`
Service *ServiceConfig `json:"services,omitempty" yaml:"services,omitempty"`
Sessions map[string]*ExchangeSession `json:"sessions,omitempty" yaml:"sessions,omitempty"`
RiskControls *RiskControls `json:"riskControls,omitempty" yaml:"riskControls,omitempty"`

View File

@ -26,6 +26,7 @@ import (
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
"github.com/c9s/bbgo/pkg/notifier/telegramnotifier"
"github.com/c9s/bbgo/pkg/service"
googleservice "github.com/c9s/bbgo/pkg/service/google"
"github.com/c9s/bbgo/pkg/slack/slacklog"
"github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/util"
@ -78,6 +79,7 @@ const (
// Environment presents the real exchange data layer
type Environment struct {
// built-in service
DatabaseService *service.DatabaseService
OrderService *service.OrderService
TradeService *service.TradeService
@ -92,6 +94,9 @@ type Environment struct {
DepositService *service.DepositService
PersistentService *service.PersistenceServiceFacade
// external services
GoogleSpreadSheetService *googleservice.SpreadSheetService
// startTime is the time of start point (which is used in the backtest)
startTime time.Time
@ -216,6 +221,14 @@ func (environ *Environment) AddExchange(name string, exchange types.Exchange) (s
return environ.AddExchangeSession(name, session)
}
func (environ *Environment) ConfigureService(ctx context.Context, srvConfig *ServiceConfig) error {
if srvConfig.GoogleSpreadSheetService != nil {
environ.GoogleSpreadSheetService = googleservice.NewSpreadSheetService(ctx, srvConfig.GoogleSpreadSheetService.JsonTokenFile, srvConfig.GoogleSpreadSheetService.SpreadSheetID)
}
return nil
}
func (environ *Environment) ConfigureExchangeSessions(userConfig *Config) error {
// if sessions are not defined, we detect the sessions automatically
if len(userConfig.Sessions) == 0 {

View File

@ -1,24 +1,54 @@
package google
import (
"context"
"fmt"
"reflect"
"time"
"github.com/sirupsen/logrus"
"google.golang.org/api/option"
"google.golang.org/api/sheets/v4"
"github.com/c9s/bbgo/pkg/fixedpoint"
)
var log = logrus.WithField("service", "google")
type SpreadSheetService struct {
SpreadsheetID string
TokenFile string
service *sheets.Service
}
func NewSpreadSheetService(ctx context.Context, tokenFile string, spreadsheetID string) *SpreadSheetService {
if len(tokenFile) == 0 {
log.Panicf("google.SpreadSheetService: jsonTokenFile is not set")
}
srv, err := sheets.NewService(ctx,
option.WithCredentialsFile(tokenFile),
)
if err != nil {
log.Panicf("google.SpreadSheetService: unable to initialize spreadsheet service: %v", err)
}
return &SpreadSheetService{
SpreadsheetID: spreadsheetID,
service: srv,
}
}
func ReadSheetValuesRange(srv *sheets.Service, spreadsheetId, readRange string) (*sheets.ValueRange, error) {
logrus.Infof("ReadSheetValuesRange: %s", readRange)
log.Infof("ReadSheetValuesRange: %s", readRange)
resp, err := srv.Spreadsheets.Values.Get(spreadsheetId, readRange).Do()
return resp, err
}
func AddNewSheet(srv *sheets.Service, spreadsheetId string, title string) (*sheets.BatchUpdateSpreadsheetResponse, error) {
logrus.Infof("AddNewSheet: %s", title)
log.Infof("AddNewSheet: %s", title)
return srv.Spreadsheets.BatchUpdate(spreadsheetId, &sheets.BatchUpdateSpreadsheetRequest{
IncludeSpreadsheetInResponse: false,
Requests: []*sheets.Request{
@ -127,7 +157,7 @@ func AppendRow(srv *sheets.Service, spreadsheetId string, sheetId int64, values
row := &sheets.RowData{}
row.Values = ValuesToCellData(values)
logrus.Infof("AppendRow: %+v", row.Values)
log.Infof("AppendRow: %+v", row.Values)
return srv.Spreadsheets.BatchUpdate(spreadsheetId, &sheets.BatchUpdateSpreadsheetRequest{
Requests: []*sheets.Request{
{
@ -142,7 +172,7 @@ func AppendRow(srv *sheets.Service, spreadsheetId string, sheetId int64, values
}
func DebugBatchUpdateSpreadsheetResponse(resp *sheets.BatchUpdateSpreadsheetResponse) {
logrus.Infof("BatchUpdateSpreadsheetResponse.SpreadsheetId: %+v", resp.SpreadsheetId)
logrus.Infof("BatchUpdateSpreadsheetResponse.UpdatedSpreadsheet: %+v", resp.UpdatedSpreadsheet)
logrus.Infof("BatchUpdateSpreadsheetResponse.Replies: %+v", resp.Replies)
log.Infof("BatchUpdateSpreadsheetResponse.SpreadsheetId: %+v", resp.SpreadsheetId)
log.Infof("BatchUpdateSpreadsheetResponse.UpdatedSpreadsheet: %+v", resp.UpdatedSpreadsheet)
log.Infof("BatchUpdateSpreadsheetResponse.Replies: %+v", resp.Replies)
}