mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
ftx: support account info
This commit is contained in:
parent
9e596a0f63
commit
8a75b21a38
78
pkg/cmd/account.go
Normal file
78
pkg/cmd/account.go
Normal 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
|
||||||
|
},
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
47
pkg/exchange/ftx/rest_account_request.go
Normal file
47
pkg/exchange/ftx/rest_account_request.go
Normal 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
|
||||||
|
}
|
|
@ -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"`
|
||||||
|
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
Loading…
Reference in New Issue
Block a user