mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 01:01:56 +00:00
all: integrate google spread sheet service
This commit is contained in:
parent
e41d720867
commit
5962742b43
|
@ -5,6 +5,11 @@ sessions:
|
||||||
makerFeeRate: 0%
|
makerFeeRate: 0%
|
||||||
takerFeeRate: 0.025%
|
takerFeeRate: 0.025%
|
||||||
|
|
||||||
|
#services:
|
||||||
|
# googleSpreadSheet:
|
||||||
|
# jsonTokenFile: ".credentials/google-cloud/service-account-json-token.json"
|
||||||
|
# spreadSheetId: "YOUR_SPREADSHEET_ID"
|
||||||
|
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
- on: max
|
- on: max
|
||||||
scmaker:
|
scmaker:
|
||||||
|
|
|
@ -23,6 +23,18 @@ And
|
||||||
|
|
||||||
<https://developers.google.com/workspace/guides/create-credentials>
|
<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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
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 {
|
if err := environ.ConfigureNotificationSystem(ctx, userConfig); err != nil {
|
||||||
return errors.Wrap(err, "notification configure error")
|
return errors.Wrap(err, "notification configure error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,9 @@ import (
|
||||||
|
|
||||||
// DefaultFeeRate set the fee rate for most cases
|
// DefaultFeeRate set the fee rate for most cases
|
||||||
// BINANCE uses 0.1% for both maker and taker
|
// 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
|
// MAX uses 0.050% for maker and 0.15% for taker
|
||||||
var DefaultFeeRate = fixedpoint.NewFromFloat(0.075 * 0.01)
|
var DefaultFeeRate = fixedpoint.NewFromFloat(0.075 * 0.01)
|
||||||
|
|
||||||
|
@ -312,6 +314,15 @@ type SyncConfig struct {
|
||||||
} `json:"userDataStream,omitempty" yaml:"userDataStream,omitempty"`
|
} `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 {
|
type Config struct {
|
||||||
Build *BuildConfig `json:"build,omitempty" yaml:"build,omitempty"`
|
Build *BuildConfig `json:"build,omitempty" yaml:"build,omitempty"`
|
||||||
|
|
||||||
|
@ -327,6 +338,8 @@ type Config struct {
|
||||||
|
|
||||||
Persistence *PersistenceConfig `json:"persistence,omitempty" yaml:"persistence,omitempty"`
|
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"`
|
Sessions map[string]*ExchangeSession `json:"sessions,omitempty" yaml:"sessions,omitempty"`
|
||||||
|
|
||||||
RiskControls *RiskControls `json:"riskControls,omitempty" yaml:"riskControls,omitempty"`
|
RiskControls *RiskControls `json:"riskControls,omitempty" yaml:"riskControls,omitempty"`
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
|
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
|
||||||
"github.com/c9s/bbgo/pkg/notifier/telegramnotifier"
|
"github.com/c9s/bbgo/pkg/notifier/telegramnotifier"
|
||||||
"github.com/c9s/bbgo/pkg/service"
|
"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/slack/slacklog"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
|
@ -78,6 +79,7 @@ const (
|
||||||
|
|
||||||
// Environment presents the real exchange data layer
|
// Environment presents the real exchange data layer
|
||||||
type Environment struct {
|
type Environment struct {
|
||||||
|
// built-in service
|
||||||
DatabaseService *service.DatabaseService
|
DatabaseService *service.DatabaseService
|
||||||
OrderService *service.OrderService
|
OrderService *service.OrderService
|
||||||
TradeService *service.TradeService
|
TradeService *service.TradeService
|
||||||
|
@ -92,6 +94,9 @@ type Environment struct {
|
||||||
DepositService *service.DepositService
|
DepositService *service.DepositService
|
||||||
PersistentService *service.PersistenceServiceFacade
|
PersistentService *service.PersistenceServiceFacade
|
||||||
|
|
||||||
|
// external services
|
||||||
|
GoogleSpreadSheetService *googleservice.SpreadSheetService
|
||||||
|
|
||||||
// startTime is the time of start point (which is used in the backtest)
|
// startTime is the time of start point (which is used in the backtest)
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
|
|
||||||
|
@ -216,6 +221,14 @@ func (environ *Environment) AddExchange(name string, exchange types.Exchange) (s
|
||||||
return environ.AddExchangeSession(name, session)
|
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 {
|
func (environ *Environment) ConfigureExchangeSessions(userConfig *Config) error {
|
||||||
// if sessions are not defined, we detect the sessions automatically
|
// if sessions are not defined, we detect the sessions automatically
|
||||||
if len(userConfig.Sessions) == 0 {
|
if len(userConfig.Sessions) == 0 {
|
||||||
|
|
|
@ -1,24 +1,54 @@
|
||||||
package google
|
package google
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"google.golang.org/api/option"
|
||||||
"google.golang.org/api/sheets/v4"
|
"google.golang.org/api/sheets/v4"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"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) {
|
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()
|
resp, err := srv.Spreadsheets.Values.Get(spreadsheetId, readRange).Do()
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddNewSheet(srv *sheets.Service, spreadsheetId string, title string) (*sheets.BatchUpdateSpreadsheetResponse, error) {
|
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{
|
return srv.Spreadsheets.BatchUpdate(spreadsheetId, &sheets.BatchUpdateSpreadsheetRequest{
|
||||||
IncludeSpreadsheetInResponse: false,
|
IncludeSpreadsheetInResponse: false,
|
||||||
Requests: []*sheets.Request{
|
Requests: []*sheets.Request{
|
||||||
|
@ -127,7 +157,7 @@ func AppendRow(srv *sheets.Service, spreadsheetId string, sheetId int64, values
|
||||||
row := &sheets.RowData{}
|
row := &sheets.RowData{}
|
||||||
row.Values = ValuesToCellData(values)
|
row.Values = ValuesToCellData(values)
|
||||||
|
|
||||||
logrus.Infof("AppendRow: %+v", row.Values)
|
log.Infof("AppendRow: %+v", row.Values)
|
||||||
return srv.Spreadsheets.BatchUpdate(spreadsheetId, &sheets.BatchUpdateSpreadsheetRequest{
|
return srv.Spreadsheets.BatchUpdate(spreadsheetId, &sheets.BatchUpdateSpreadsheetRequest{
|
||||||
Requests: []*sheets.Request{
|
Requests: []*sheets.Request{
|
||||||
{
|
{
|
||||||
|
@ -142,7 +172,7 @@ func AppendRow(srv *sheets.Service, spreadsheetId string, sheetId int64, values
|
||||||
}
|
}
|
||||||
|
|
||||||
func DebugBatchUpdateSpreadsheetResponse(resp *sheets.BatchUpdateSpreadsheetResponse) {
|
func DebugBatchUpdateSpreadsheetResponse(resp *sheets.BatchUpdateSpreadsheetResponse) {
|
||||||
logrus.Infof("BatchUpdateSpreadsheetResponse.SpreadsheetId: %+v", resp.SpreadsheetId)
|
log.Infof("BatchUpdateSpreadsheetResponse.SpreadsheetId: %+v", resp.SpreadsheetId)
|
||||||
logrus.Infof("BatchUpdateSpreadsheetResponse.UpdatedSpreadsheet: %+v", resp.UpdatedSpreadsheet)
|
log.Infof("BatchUpdateSpreadsheetResponse.UpdatedSpreadsheet: %+v", resp.UpdatedSpreadsheet)
|
||||||
logrus.Infof("BatchUpdateSpreadsheetResponse.Replies: %+v", resp.Replies)
|
log.Infof("BatchUpdateSpreadsheetResponse.Replies: %+v", resp.Replies)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user