ftx: support account info

This commit is contained in:
ycdesu 2021-03-18 08:33:14 +08:00
parent 9e596a0f63
commit 8a75b21a38
6 changed files with 237 additions and 1 deletions

78
pkg/cmd/account.go Normal file
View File

@ -0,0 +1,78 @@
package cmd
import (
"context"
"fmt"
"os"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/c9s/bbgo/pkg/bbgo"
)
func init() {
accountCmd.Flags().String("session", "", "the exchange session name for querying information")
RootCmd.AddCommand(accountCmd)
}
// go run ./cmd/bbgo account --session=ftx --config=config/bbgo.yaml
var accountCmd = &cobra.Command{
Use: "account",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
configFile, err := cmd.Flags().GetString("config")
if err != nil {
return err
}
if len(configFile) == 0 {
return errors.New("--config option is required")
}
var userConfig *bbgo.Config
if _, err := os.Stat(configFile); err == nil {
// load successfully
userConfig, err = bbgo.Load(configFile, false)
if err != nil {
return err
}
} else if os.IsNotExist(err) {
// config file doesn't exist
userConfig = &bbgo.Config{}
} else {
// other error
return err
}
environ := bbgo.NewEnvironment()
if err := environ.ConfigureDatabase(ctx); err != nil {
return err
}
if err := environ.ConfigureExchangeSessions(userConfig); err != nil {
return err
}
sessionName, err := cmd.Flags().GetString("session")
if err != nil {
return err
}
session, ok := environ.Session(sessionName)
if !ok {
return fmt.Errorf("session %s not found", sessionName)
}
a, err := session.Exchange.QueryAccount(ctx)
if err != nil {
return err
}
log.Infof("account info: %+v", a)
return nil
},
}

View File

@ -65,7 +65,27 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
} }
func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) { func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) {
panic("implement me") resp, err := e.newRest().Account(ctx)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("ftx returns querying balances failure")
}
// TODO
a := &types.Account{
MakerCommission: 0,
TakerCommission: 0,
}
balances, err := e.QueryAccountBalances(ctx)
if err != nil {
return nil, err
}
a.UpdateBalances(balances)
return a, nil
} }
func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap, error) { func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap, error) {

View File

@ -21,6 +21,7 @@ import (
type restRequest struct { type restRequest struct {
*balanceRequest *balanceRequest
*orderRequest *orderRequest
*accountRequest
key, secret string key, secret string
// Optional sub-account name // Optional sub-account name
@ -42,6 +43,7 @@ func newRestRequest(c *http.Client, baseURL *url.URL) *restRequest {
baseURL: baseURL, baseURL: baseURL,
} }
r.accountRequest = &accountRequest{restRequest: r}
r.balanceRequest = &balanceRequest{restRequest: r} r.balanceRequest = &balanceRequest{restRequest: r}
r.orderRequest = &orderRequest{restRequest: r} r.orderRequest = &orderRequest{restRequest: r}
return r return r

View File

@ -0,0 +1,47 @@
package ftx
import (
"context"
"encoding/json"
"fmt"
)
type accountRequest struct {
*restRequest
}
func (r *accountRequest) Account(ctx context.Context) (accountResponse, error) {
resp, err := r.
Method("GET").
ReferenceURL("api/account").
DoAuthenticatedRequest(ctx)
if err != nil {
return accountResponse{}, err
}
var a accountResponse
if err := json.Unmarshal(resp.Body, &a); err != nil {
return accountResponse{}, fmt.Errorf("failed to unmarshal account response body to json: %w", err)
}
return a, nil
}
func (r *accountRequest) Positions(ctx context.Context) (positionsResponse, error) {
resp, err := r.
Method("GET").
ReferenceURL("api/positions").
DoAuthenticatedRequest(ctx)
if err != nil {
return positionsResponse{}, err
}
var p positionsResponse
if err := json.Unmarshal(resp.Body, &p); err != nil {
return positionsResponse{}, fmt.Errorf("failed to unmarshal position response body to json: %w", err)
}
return p, nil
}

View File

@ -2,6 +2,94 @@ package ftx
import "time" import "time"
/*
{
"success": true,
"result": {
"backstopProvider": true,
"collateral": 3568181.02691129,
"freeCollateral": 1786071.456884368,
"initialMarginRequirement": 0.12222384240257728,
"leverage": 10,
"liquidating": false,
"maintenanceMarginRequirement": 0.07177992558058484,
"makerFee": 0.0002,
"marginFraction": 0.5588433331419503,
"openMarginFraction": 0.2447194090423075,
"takerFee": 0.0005,
"totalAccountValue": 3568180.98341129,
"totalPositionSize": 6384939.6992,
"username": "user@domain.com",
"positions": [
{
"cost": -31.7906,
"entryPrice": 138.22,
"future": "ETH-PERP",
"initialMarginRequirement": 0.1,
"longOrderSize": 1744.55,
"maintenanceMarginRequirement": 0.04,
"netSize": -0.23,
"openSize": 1744.32,
"realizedPnl": 3.39441714,
"shortOrderSize": 1732.09,
"side": "sell",
"size": 0.23,
"unrealizedPnl": 0
}
]
}
}
*/
type accountResponse struct {
Success bool `json:"success"`
Result account `json:"result"`
}
type account struct {
}
type positionsResponse struct {
Success bool `json:"success"`
Result []position `json:"result"`
}
/*
{
"cost": -31.7906,
"entryPrice": 138.22,
"estimatedLiquidationPrice": 152.1,
"future": "ETH-PERP",
"initialMarginRequirement": 0.1,
"longOrderSize": 1744.55,
"maintenanceMarginRequirement": 0.04,
"netSize": -0.23,
"openSize": 1744.32,
"realizedPnl": 3.39441714,
"shortOrderSize": 1732.09,
"side": "sell",
"size": 0.23,
"unrealizedPnl": 0,
"collateralUsed": 3.17906
}
*/
type position struct {
Cost float64 `json:"cost"`
EntryPrice float64 `json:"entryPrice"`
EstimatedLiquidationPrice float64 `json:"estimatedLiquidationPrice"`
Future string `json:"future"`
InitialMarginRequirement float64 `json:"initialMarginRequirement"`
LongOrderSize float64 `json:"longOrderSize"`
MaintenanceMarginRequirement float64 `json:"maintenanceMarginRequirement"`
NetSize float64 `json:"netSize"`
OpenSize float64 `json:"openSize"`
RealizedPnl float64 `json:"realizedPnl"`
ShortOrderSize float64 `json:"shortOrderSize"`
Side string `json:"Side"`
Size float64 `json:"size"`
UnrealizedPnl float64 `json:"unrealizedPnl"`
CollateralUsed float64 `json:"collateralUsed"`
}
type balances struct { type balances struct {
Success bool `json:"success"` Success bool `json:"success"`

View File

@ -102,6 +102,7 @@ func (m BalanceMap) Print() {
type Account struct { type Account struct {
sync.Mutex `json:"-"` sync.Mutex `json:"-"`
// bps. 0.15% fee will be 15.
MakerCommission int `json:"makerCommission,omitempty"` MakerCommission int `json:"makerCommission,omitempty"`
TakerCommission int `json:"takerCommission,omitempty"` TakerCommission int `json:"takerCommission,omitempty"`
AccountType string `json:"accountType,omitempty"` AccountType string `json:"accountType,omitempty"`