mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
* orderbook/buffer: data integrity and resubscription pass * btcmarkets: REMOVE THAT LIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIINE!!!!!!!!!!!!!!!!! * buffer: reinstate publish, refaactor, invalidate more and comments * buffer/orderbook: improve update and snapshot performance. Move Update type to orderbook package to util. pointer through entire function calls. (cleanup). Change action string to uint8 for easier comparison. Add parsing helper. Update current test benchmark comments. * dispatch: change publish func to variadic id param * dispatch: remove sender receiver wait time as this adds overhead and complexity. update tests. * dispatch: don't create pointers for every job container * rpcserver: fix assertion issues with data publishing change * linter: fixes * glorious: nits addr * depth: change validation handling to incorporate and store err * linter: fix more issues * dispatch: fix race * travis: update before fetching * depth: wrap and return wrapped error in invalidate call and fix tests * btcmarkets: fix commenting * workflow: check * workflow: check * orderbook: check error * buffer/depth: return invalidation error and fix tests * gctcli: display errors on orderbook streams * buffer: remove unused types * orderbook/bitmex: shift function to bitmex * orderbook: Add specific comments to unexported functions that don't have locking require locking. * orderbook: restrict published data functionality to orderbook.Outbound interface * common: add assertion failure helper for error * dispatch: remove atomics, add mutex protection, remove add/remove worker, redo main tests * dispatch: export function * engine: revert and change sub logger to manager * engine: remove old test * dispatch: add common variable ;) * btcmarket: don't overflow int in tests on 32bit systems * ci: force 1.17.7 usage for go * Revert "ci: force 1.17.7 usage for go" This reverts commit af2f95563bf218cf2b9f36a9fcf3258e2c6a2d91. * golangci: bump version add and remove linter items * Revert "golangci: bump version add and remove linter items" This reverts commit 3c98bffc9d030e39faca0387ea40c151df2ab06b. * dispatch: remove unsused mutex from mux * order: slight optimizations * nits: glorious * dispatch: fix regression on uuid generation and input inline with master * linter: fix * linter: fix * glorious: nit - rm slice segration * account: fix test after merge * coinbasepro: revert change * account: close channel instead of needing a receiver, push alert in routine to prepare for waiter. Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
5040 lines
105 KiB
Go
5040 lines
105 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/gctrpc"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
var startTime, endTime, orderingDirection string
|
|
var limit int
|
|
|
|
var getInfoCommand = &cli.Command{
|
|
Name: "getinfo",
|
|
Usage: "gets GoCryptoTrader info",
|
|
Action: getInfo,
|
|
}
|
|
|
|
func getInfo(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetInfo(c.Context,
|
|
&gctrpc.GetInfoRequest{},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getSubsystemsCommand = &cli.Command{
|
|
Name: "getsubsystems",
|
|
Usage: "gets GoCryptoTrader subsystems and their status",
|
|
Action: getSubsystems,
|
|
}
|
|
|
|
func getSubsystems(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetSubsystems(c.Context,
|
|
&gctrpc.GetSubsystemsRequest{},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var enableSubsystemCommand = &cli.Command{
|
|
Name: "enablesubsystem",
|
|
Usage: "enables an engine subsystem",
|
|
ArgsUsage: "<subsystem>",
|
|
Action: enableSubsystem,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "subsystem",
|
|
Usage: "the subsystem to enable",
|
|
},
|
|
},
|
|
}
|
|
|
|
func enableSubsystem(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "enablesubsystem")
|
|
}
|
|
|
|
var subsystemName string
|
|
if c.IsSet("subsystem") {
|
|
subsystemName = c.String("subsystem")
|
|
} else {
|
|
subsystemName = c.Args().First()
|
|
}
|
|
|
|
if subsystemName == "" {
|
|
return errors.New("invalid subsystem supplied")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.EnableSubsystem(c.Context,
|
|
&gctrpc.GenericSubsystemRequest{
|
|
Subsystem: subsystemName,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var disableSubsystemCommand = &cli.Command{
|
|
Name: "disablesubsystem",
|
|
Usage: "disables an engine subsystem",
|
|
ArgsUsage: "<subsystem>",
|
|
Action: disableSubsystem,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "subsystem",
|
|
Usage: "the subsystem to disable",
|
|
},
|
|
},
|
|
}
|
|
|
|
func disableSubsystem(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "disablesubsystem")
|
|
}
|
|
|
|
var subsystemName string
|
|
if c.IsSet("subsystem") {
|
|
subsystemName = c.String("subsystem")
|
|
} else {
|
|
subsystemName = c.Args().First()
|
|
}
|
|
|
|
if subsystemName == "" {
|
|
return errors.New("invalid subsystem supplied")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.DisableSubsystem(c.Context,
|
|
&gctrpc.GenericSubsystemRequest{
|
|
Subsystem: subsystemName,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getRPCEndpointsCommand = &cli.Command{
|
|
Name: "getrpcendpoints",
|
|
Usage: "gets GoCryptoTrader endpoints info",
|
|
Action: getRPCEndpoints,
|
|
}
|
|
|
|
func getRPCEndpoints(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetRPCEndpoints(c.Context,
|
|
&gctrpc.GetRPCEndpointsRequest{},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getCommunicationRelayersCommand = &cli.Command{
|
|
Name: "getcommsrelayers",
|
|
Usage: "gets GoCryptoTrader communication relayers",
|
|
Action: getCommunicationRelayers,
|
|
}
|
|
|
|
func getCommunicationRelayers(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetCommunicationRelayers(c.Context,
|
|
&gctrpc.GetCommunicationRelayersRequest{},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getExchangesCommand = &cli.Command{
|
|
Name: "getexchanges",
|
|
Usage: "gets a list of enabled or available exchanges",
|
|
ArgsUsage: "<enabled>",
|
|
Action: getExchanges,
|
|
Flags: []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: "enabled",
|
|
Usage: "whether to list enabled exchanges or not",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getExchanges(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
var enabledOnly bool
|
|
if c.IsSet("enabled") {
|
|
enabledOnly = c.Bool("enabled")
|
|
}
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetExchanges(c.Context,
|
|
&gctrpc.GetExchangesRequest{
|
|
Enabled: enabledOnly,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var enableExchangeCommand = &cli.Command{
|
|
Name: "enableexchange",
|
|
Usage: "enables an exchange",
|
|
ArgsUsage: "<exchange>",
|
|
Action: enableExchange,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to enable",
|
|
},
|
|
},
|
|
}
|
|
|
|
func enableExchange(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "enableexchange")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.EnableExchange(c.Context,
|
|
&gctrpc.GenericExchangeNameRequest{
|
|
Exchange: exchangeName,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var disableExchangeCommand = &cli.Command{
|
|
Name: "disableexchange",
|
|
Usage: "disables an exchange",
|
|
ArgsUsage: "<exchange>",
|
|
Action: disableExchange,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to disable",
|
|
},
|
|
},
|
|
}
|
|
|
|
func disableExchange(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "disableexchange")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.DisableExchange(c.Context,
|
|
&gctrpc.GenericExchangeNameRequest{
|
|
Exchange: exchangeName,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getExchangeOTPCommand = &cli.Command{
|
|
Name: "getexchangeotp",
|
|
Usage: "gets a specific exchange OTP code",
|
|
ArgsUsage: "<exchange>",
|
|
Action: getExchangeOTPCode,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the OTP code for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getExchangeOTPCode(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getexchangeotp")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetExchangeOTPCode(c.Context,
|
|
&gctrpc.GenericExchangeNameRequest{
|
|
Exchange: exchangeName,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getExchangeOTPsCommand = &cli.Command{
|
|
Name: "getexchangeotps",
|
|
Usage: "gets all exchange OTP codes",
|
|
Action: getExchangeOTPCodes,
|
|
}
|
|
|
|
func getExchangeOTPCodes(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetExchangeOTPCodes(c.Context,
|
|
&gctrpc.GetExchangeOTPsRequest{})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getExchangeInfoCommand = &cli.Command{
|
|
Name: "getexchangeinfo",
|
|
Usage: "gets a specific exchanges info",
|
|
ArgsUsage: "<exchange>",
|
|
Action: getExchangeInfo,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the info for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getExchangeInfo(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getexchangeinfo")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetExchangeInfo(c.Context,
|
|
&gctrpc.GenericExchangeNameRequest{
|
|
Exchange: exchangeName,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getTickerCommand = &cli.Command{
|
|
Name: "getticker",
|
|
Usage: "gets the ticker for a specific currency pair and exchange",
|
|
ArgsUsage: "<exchange> <pair> <asset>",
|
|
Action: getTicker,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the ticker for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to get the ticker for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type of the currency pair to get the ticker for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getTicker(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getticker")
|
|
}
|
|
|
|
var exchangeName string
|
|
var currencyPair string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetTicker(c.Context,
|
|
&gctrpc.GetTickerRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getTickersCommand = &cli.Command{
|
|
Name: "gettickers",
|
|
Usage: "gets all tickers for all enabled exchanges and currency pairs",
|
|
Action: getTickers,
|
|
}
|
|
|
|
func getTickers(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetTickers(c.Context, &gctrpc.GetTickersRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getOrderbookCommand = &cli.Command{
|
|
Name: "getorderbook",
|
|
Usage: "gets the orderbook for a specific currency pair and exchange",
|
|
ArgsUsage: "<exchange> <pair> <asset>",
|
|
Action: getOrderbook,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the orderbook for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to get the orderbook for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type of the currency pair to get the orderbook for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getOrderbook(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getorderbook")
|
|
}
|
|
|
|
var exchangeName string
|
|
var currencyPair string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetOrderbook(c.Context,
|
|
&gctrpc.GetOrderbookRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getOrderbooksCommand = &cli.Command{
|
|
Name: "getorderbooks",
|
|
Usage: "gets all orderbooks for all enabled exchanges and currency pairs",
|
|
Action: getOrderbooks,
|
|
}
|
|
|
|
func getOrderbooks(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetOrderbooks(c.Context, &gctrpc.GetOrderbooksRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getAccountInfoCommand = &cli.Command{
|
|
Name: "getaccountinfo",
|
|
Usage: "gets the exchange account balance info",
|
|
ArgsUsage: "<exchange> <asset>",
|
|
Action: getAccountInfo,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the account info for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type to get the account info for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getAccountInfo(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getaccountinfo")
|
|
}
|
|
|
|
var exchange string
|
|
if c.IsSet("exchange") {
|
|
exchange = c.String("exchange")
|
|
} else {
|
|
exchange = c.Args().First()
|
|
}
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetAccountInfo(c.Context,
|
|
&gctrpc.GetAccountInfoRequest{
|
|
Exchange: exchange,
|
|
AssetType: assetType,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getAccountInfoStreamCommand = &cli.Command{
|
|
Name: "getaccountinfostream",
|
|
Usage: "gets the account info stream for a specific exchange",
|
|
ArgsUsage: "<exchange> <asset>",
|
|
Action: getAccountInfoStream,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the account info stream from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type to get the account info stream for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getAccountInfoStream(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getaccountinfostream")
|
|
}
|
|
|
|
var exchangeName string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetAccountInfoStream(c.Context,
|
|
&gctrpc.GetAccountInfoRequest{Exchange: exchangeName, AssetType: assetType})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
resp, err := result.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = clearScreen()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Account balance stream for %s:\n\n", exchangeName)
|
|
|
|
fmt.Printf("%+v", resp)
|
|
}
|
|
}
|
|
|
|
var updateAccountInfoCommand = &cli.Command{
|
|
Name: "updateaccountinfo",
|
|
Usage: "updates the exchange account balance info",
|
|
ArgsUsage: "<exchange> <asset>",
|
|
Action: updateAccountInfo,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the account info for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type to get the account info for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func updateAccountInfo(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "updateaccountinfo")
|
|
}
|
|
|
|
var exchange string
|
|
if c.IsSet("exchange") {
|
|
exchange = c.String("exchange")
|
|
} else {
|
|
exchange = c.Args().First()
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.UpdateAccountInfo(c.Context,
|
|
&gctrpc.GetAccountInfoRequest{
|
|
Exchange: exchange,
|
|
AssetType: assetType,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getConfigCommand = &cli.Command{
|
|
Name: "getconfig",
|
|
Usage: "gets the config",
|
|
Action: getConfig,
|
|
}
|
|
|
|
func getConfig(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetConfig(c.Context, &gctrpc.GetConfigRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getPortfolioCommand = &cli.Command{
|
|
Name: "getportfolio",
|
|
Usage: "gets the portfolio",
|
|
Action: getPortfolio,
|
|
}
|
|
|
|
func getPortfolio(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetPortfolio(c.Context, &gctrpc.GetPortfolioRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getPortfolioSummaryCommand = &cli.Command{
|
|
Name: "getportfoliosummary",
|
|
Usage: "gets the portfolio summary",
|
|
Action: getPortfolioSummary,
|
|
}
|
|
|
|
func getPortfolioSummary(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetPortfolioSummary(c.Context, &gctrpc.GetPortfolioSummaryRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var addPortfolioAddressCommand = &cli.Command{
|
|
Name: "addportfolioaddress",
|
|
Usage: "adds an address to the portfolio",
|
|
ArgsUsage: "<address> <coin_type> <description> <balance> <cold_storage> <supported_exchanges> ",
|
|
Action: addPortfolioAddress,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "address",
|
|
Usage: "the address to add to the portfolio",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "coin_type",
|
|
Usage: "the coin type e.g ('BTC')",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "description",
|
|
Usage: "description of the address",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "balance",
|
|
Usage: "balance of the address",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "cold_storage",
|
|
Usage: "true/false if address is cold storage",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "supported_exchanges",
|
|
Usage: "common separated list of exchanges supported by this address for withdrawals",
|
|
},
|
|
},
|
|
}
|
|
|
|
func addPortfolioAddress(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "addportfolioaddress")
|
|
}
|
|
|
|
var address string
|
|
var coinType string
|
|
var description string
|
|
var balance float64
|
|
var supportedExchanges string
|
|
var coldstorage bool
|
|
|
|
if c.IsSet("address") {
|
|
address = c.String("address")
|
|
} else {
|
|
address = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("coin_type") {
|
|
coinType = c.String("coin_type")
|
|
} else {
|
|
coinType = c.Args().Get(1)
|
|
}
|
|
|
|
if c.IsSet("description") {
|
|
description = c.String("description")
|
|
} else {
|
|
description = c.Args().Get(2)
|
|
}
|
|
var err error
|
|
if c.IsSet("balance") {
|
|
balance = c.Float64("balance")
|
|
} else if c.Args().Get(3) != "" {
|
|
balance, err = strconv.ParseFloat(c.Args().Get(3), 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if c.IsSet("cold_storage") {
|
|
coldstorage = c.Bool("cold_storage")
|
|
} else {
|
|
tv, errBool := strconv.ParseBool(c.Args().Get(4))
|
|
if errBool == nil {
|
|
coldstorage = tv
|
|
}
|
|
}
|
|
|
|
if c.IsSet("supported_exchanges") {
|
|
supportedExchanges = c.String("supported_exchanges")
|
|
} else {
|
|
supportedExchanges = c.Args().Get(5)
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.AddPortfolioAddress(c.Context,
|
|
&gctrpc.AddPortfolioAddressRequest{
|
|
Address: address,
|
|
CoinType: coinType,
|
|
Description: description,
|
|
Balance: balance,
|
|
SupportedExchanges: supportedExchanges,
|
|
ColdStorage: coldstorage,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var removePortfolioAddressCommand = &cli.Command{
|
|
Name: "removeportfolioaddress",
|
|
Usage: "removes an address from the portfolio",
|
|
ArgsUsage: "<address> <coin_type> <description>",
|
|
Action: removePortfolioAddress,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "address",
|
|
Usage: "the address to add to the portfolio",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "coin_type",
|
|
Usage: "the coin type e.g ('BTC')",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "description",
|
|
Usage: "description of the address",
|
|
},
|
|
},
|
|
}
|
|
|
|
func removePortfolioAddress(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "removeportfolioaddress")
|
|
}
|
|
|
|
var address string
|
|
var coinType string
|
|
var description string
|
|
|
|
if c.IsSet("address") {
|
|
address = c.String("address")
|
|
} else {
|
|
address = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("coin_type") {
|
|
coinType = c.String("coin_type")
|
|
} else {
|
|
coinType = c.Args().Get(1)
|
|
}
|
|
|
|
if c.IsSet("description") {
|
|
description = c.String("description")
|
|
} else {
|
|
description = c.Args().Get(2)
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.RemovePortfolioAddress(c.Context,
|
|
&gctrpc.RemovePortfolioAddressRequest{
|
|
Address: address,
|
|
CoinType: coinType,
|
|
Description: description,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getForexProvidersCommand = &cli.Command{
|
|
Name: "getforexproviders",
|
|
Usage: "gets the available forex providers",
|
|
Action: getForexProviders,
|
|
}
|
|
|
|
func getForexProviders(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetForexProviders(c.Context, &gctrpc.GetForexProvidersRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getForexRatesCommand = &cli.Command{
|
|
Name: "getforexrates",
|
|
Usage: "gets forex rates",
|
|
Action: getForexRates,
|
|
}
|
|
|
|
func getForexRates(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetForexRates(c.Context, &gctrpc.GetForexRatesRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getOrdersCommand = &cli.Command{
|
|
Name: "getorders",
|
|
Usage: "gets the open orders",
|
|
ArgsUsage: "<exchange> <asset> <pair> <start> <end>",
|
|
Action: getOrders,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get orders for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type to get orders for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to get orders for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "start",
|
|
Usage: "start date, optional. Will filter any results before this date",
|
|
Value: time.Now().AddDate(0, -1, 0).Format(common.SimpleTimeFormat),
|
|
Destination: &startTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "end",
|
|
Usage: "end date, optional. Will filter any results after this date",
|
|
Value: time.Now().Format(common.SimpleTimeFormat),
|
|
Destination: &endTime,
|
|
},
|
|
},
|
|
}
|
|
|
|
func getOrders(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getorders")
|
|
}
|
|
|
|
var exchangeName string
|
|
var assetType string
|
|
var currencyPair string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(2)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !c.IsSet("start") {
|
|
if c.Args().Get(3) != "" {
|
|
startTime = c.Args().Get(3)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("end") {
|
|
if c.Args().Get(4) != "" {
|
|
endTime = c.Args().Get(4)
|
|
}
|
|
}
|
|
var s, e time.Time
|
|
s, err = time.Parse(common.SimpleTimeFormat, startTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for start: %v", err)
|
|
}
|
|
e, err = time.Parse(common.SimpleTimeFormat, endTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for end: %v", err)
|
|
}
|
|
|
|
if e.Before(s) {
|
|
return errors.New("start cannot be after end")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetOrders(c.Context, &gctrpc.GetOrdersRequest{
|
|
Exchange: exchangeName,
|
|
AssetType: assetType,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
StartDate: negateLocalOffset(s),
|
|
EndDate: negateLocalOffset(e),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getManagedOrdersCommand = &cli.Command{
|
|
Name: "getmanagedorders",
|
|
Usage: "gets the current orders from the order manager",
|
|
ArgsUsage: "<exchange> <asset> <pair>",
|
|
Action: getManagedOrders,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get orders for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type to get orders for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to get orders for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getManagedOrders(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getmanagedorders")
|
|
}
|
|
|
|
var exchangeName string
|
|
var assetType string
|
|
var currencyPair string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(2)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetManagedOrders(c.Context, &gctrpc.GetOrdersRequest{
|
|
Exchange: exchangeName,
|
|
AssetType: assetType,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getOrderCommand = &cli.Command{
|
|
Name: "getorder",
|
|
Usage: "gets the specified order info",
|
|
ArgsUsage: "<exchange> <asset> <pair> <order_id>",
|
|
Action: getOrder,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "required asset type",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the pair to retrieve",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "order_id",
|
|
Usage: "the order id to retrieve",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getOrder(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getorder")
|
|
}
|
|
|
|
var exchangeName string
|
|
var orderID string
|
|
var currencyPair string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(2)
|
|
}
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.IsSet("order_id") {
|
|
orderID = c.String("order_id")
|
|
} else {
|
|
orderID = c.Args().Get(3)
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetOrder(c.Context, &gctrpc.GetOrderRequest{
|
|
Exchange: exchangeName,
|
|
OrderId: orderID,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
Asset: assetType,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var submitOrderCommand = &cli.Command{
|
|
Name: "submitorder",
|
|
Usage: "submit order submits an exchange order",
|
|
ArgsUsage: "<exchange> <pair> <side> <type> <amount> <price> <client_id>",
|
|
Action: submitOrder,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to submit the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "side",
|
|
Usage: "the order side to use (BUY OR SELL)",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "type",
|
|
Usage: "the order type (MARKET OR LIMIT)",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "amount",
|
|
Usage: "the amount for the order",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "price",
|
|
Usage: "the price for the order",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "client_id",
|
|
Usage: "the optional client order ID",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "required asset type",
|
|
},
|
|
},
|
|
}
|
|
|
|
func submitOrder(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "submitorder")
|
|
}
|
|
|
|
var exchangeName string
|
|
var currencyPair string
|
|
var orderSide string
|
|
var orderType string
|
|
var amount float64
|
|
var price float64
|
|
var clientID string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("side") {
|
|
orderSide = c.String("side")
|
|
} else {
|
|
orderSide = c.Args().Get(2)
|
|
}
|
|
|
|
if orderSide == "" {
|
|
return errors.New("order side must be set")
|
|
}
|
|
|
|
if c.IsSet("type") {
|
|
orderType = c.String("type")
|
|
} else {
|
|
orderType = c.Args().Get(3)
|
|
}
|
|
|
|
if orderType == "" {
|
|
return errors.New("order type must be set")
|
|
}
|
|
|
|
if c.IsSet("amount") {
|
|
amount = c.Float64("amount")
|
|
} else if c.Args().Get(4) != "" {
|
|
var err error
|
|
amount, err = strconv.ParseFloat(c.Args().Get(4), 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if amount == 0 {
|
|
return errors.New("amount must be set")
|
|
}
|
|
|
|
// price is optional for market orders
|
|
if c.IsSet("price") {
|
|
price = c.Float64("price")
|
|
} else if c.Args().Get(5) != "" {
|
|
var err error
|
|
price, err = strconv.ParseFloat(c.Args().Get(5), 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if c.IsSet("client_id") {
|
|
clientID = c.String("client_id")
|
|
} else {
|
|
clientID = c.Args().Get(6)
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(7)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.SubmitOrder(c.Context, &gctrpc.SubmitOrderRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
Side: orderSide,
|
|
OrderType: orderType,
|
|
Amount: amount,
|
|
Price: price,
|
|
ClientId: clientID,
|
|
AssetType: assetType,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var simulateOrderCommand = &cli.Command{
|
|
Name: "simulateorder",
|
|
Usage: "simulate order simulates an exchange order",
|
|
ArgsUsage: "<exchange> <pair> <side> <amount>",
|
|
Action: simulateOrder,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to simulate the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "side",
|
|
Usage: "the order side to use (BUY OR SELL)",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "amount",
|
|
Usage: "the amount for the order",
|
|
},
|
|
},
|
|
}
|
|
|
|
func simulateOrder(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "simulateorder")
|
|
}
|
|
|
|
var exchangeName string
|
|
var currencyPair string
|
|
var orderSide string
|
|
var amount float64
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("side") {
|
|
orderSide = c.String("side")
|
|
} else {
|
|
orderSide = c.Args().Get(2)
|
|
}
|
|
|
|
if orderSide == "" {
|
|
return errors.New("side must be set")
|
|
}
|
|
|
|
if c.IsSet("amount") {
|
|
amount = c.Float64("amount")
|
|
} else if c.Args().Get(3) != "" {
|
|
var err error
|
|
amount, err = strconv.ParseFloat(c.Args().Get(3), 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if amount == 0 {
|
|
return errors.New("amount must be set")
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.SimulateOrder(c.Context, &gctrpc.SimulateOrderRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
Side: orderSide,
|
|
Amount: amount,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var whaleBombCommand = &cli.Command{
|
|
Name: "whalebomb",
|
|
Usage: "whale bomb finds the amount required to reach a price target",
|
|
ArgsUsage: "<exchange> <pair> <side> <price>",
|
|
Action: whaleBomb,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to whale bomb",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "side",
|
|
Usage: "the order side to use (BUY OR SELL)",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "price",
|
|
Usage: "the price target",
|
|
},
|
|
},
|
|
}
|
|
|
|
func whaleBomb(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "whalebomb")
|
|
}
|
|
|
|
var exchangeName string
|
|
var currencyPair string
|
|
var orderSide string
|
|
var price float64
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("side") {
|
|
orderSide = c.String("side")
|
|
} else {
|
|
orderSide = c.Args().Get(2)
|
|
}
|
|
|
|
if orderSide == "" {
|
|
return errors.New("order side must be set")
|
|
}
|
|
|
|
if c.IsSet("price") {
|
|
price = c.Float64("price")
|
|
} else if c.Args().Get(3) != "" {
|
|
var err error
|
|
price, err = strconv.ParseFloat(c.Args().Get(3), 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.WhaleBomb(c.Context, &gctrpc.WhaleBombRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
Side: orderSide,
|
|
PriceTarget: price,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var cancelOrderCommand = &cli.Command{
|
|
Name: "cancelorder",
|
|
Usage: "cancel order cancels an exchange order",
|
|
ArgsUsage: "<exchange> <account_id> <order_id> <pair> <asset> <wallet_address> <side>",
|
|
Action: cancelOrder,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to cancel the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "account_id",
|
|
Usage: "the account id",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "order_id",
|
|
Usage: "the order id",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to cancel the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "wallet_address",
|
|
Usage: "the wallet address",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "side",
|
|
Usage: "the order side",
|
|
},
|
|
},
|
|
}
|
|
|
|
func cancelOrder(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "cancelorder")
|
|
}
|
|
|
|
var exchangeName string
|
|
var accountID string
|
|
var orderID string
|
|
var currencyPair string
|
|
var assetType string
|
|
var walletAddress string
|
|
var orderSide string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("account_id") {
|
|
accountID = c.String("account_id")
|
|
} else {
|
|
accountID = c.Args().Get(1)
|
|
}
|
|
|
|
if c.IsSet("order_id") {
|
|
orderID = c.String("order_id")
|
|
} else {
|
|
orderID = c.Args().Get(2)
|
|
}
|
|
|
|
if orderID == "" {
|
|
return errors.New("an order ID must be set")
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(3)
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(4)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("wallet_address") {
|
|
walletAddress = c.String("wallet_address")
|
|
} else {
|
|
walletAddress = c.Args().Get(5)
|
|
}
|
|
|
|
if c.IsSet("side") {
|
|
orderSide = c.String("side")
|
|
} else {
|
|
orderSide = c.Args().Get(6)
|
|
}
|
|
|
|
// pair is optional, but if it's set, do a validity check
|
|
var p currency.Pair
|
|
if len(currencyPair) > 0 {
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
var err error
|
|
p, err = currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.CancelOrder(c.Context, &gctrpc.CancelOrderRequest{
|
|
Exchange: exchangeName,
|
|
AccountId: accountID,
|
|
OrderId: orderID,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
WalletAddress: walletAddress,
|
|
Side: orderSide,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var cancelBatchOrdersCommand = &cli.Command{
|
|
Name: "cancelbatchorders",
|
|
Usage: "cancel batch orders cancels a list of exchange orders (comma separated)",
|
|
ArgsUsage: "<exchange> <account_id> <order_ids> <pair> <asset> <wallet_address> <side>",
|
|
Action: cancelBatchOrders,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to cancel the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "account_id",
|
|
Usage: "the account id",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "order_ids",
|
|
Usage: "the comma separated orders id-s",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to cancel the order for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "wallet_address",
|
|
Usage: "the wallet address",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "side",
|
|
Usage: "the order side",
|
|
},
|
|
},
|
|
}
|
|
|
|
func cancelBatchOrders(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "cancelbatchorders")
|
|
}
|
|
|
|
var exchangeName string
|
|
var accountID string
|
|
var orderID string
|
|
var currencyPair string
|
|
var assetType string
|
|
var walletAddress string
|
|
var orderSide string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("account_id") {
|
|
accountID = c.String("account_id")
|
|
} else {
|
|
accountID = c.Args().Get(1)
|
|
}
|
|
|
|
if c.IsSet("order_ids") {
|
|
orderID = c.String("order_ids")
|
|
} else {
|
|
orderID = c.Args().Get(2)
|
|
}
|
|
|
|
if orderID == "" {
|
|
return errors.New("an order ID must be set")
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(3)
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(4)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("wallet_address") {
|
|
walletAddress = c.String("wallet_address")
|
|
} else {
|
|
walletAddress = c.Args().Get(5)
|
|
}
|
|
|
|
if c.IsSet("side") {
|
|
orderSide = c.String("side")
|
|
} else {
|
|
orderSide = c.Args().Get(6)
|
|
}
|
|
|
|
// pair is optional, but if it's set, do a validity check
|
|
var p currency.Pair
|
|
if len(currencyPair) > 0 {
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
var err error
|
|
p, err = currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.CancelBatchOrders(c.Context, &gctrpc.CancelBatchOrdersRequest{
|
|
Exchange: exchangeName,
|
|
AccountId: accountID,
|
|
OrdersId: orderID,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
WalletAddress: walletAddress,
|
|
Side: orderSide,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var cancelAllOrdersCommand = &cli.Command{
|
|
Name: "cancelallorders",
|
|
Usage: "cancels all orders (all or by exchange name)",
|
|
ArgsUsage: "<exchange>",
|
|
Action: cancelAllOrders,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to cancel all orders on",
|
|
},
|
|
},
|
|
}
|
|
|
|
var modifyOrderCommand = &cli.Command{
|
|
Name: "modifyorder",
|
|
Usage: "modify price and/or amount of a previously submitted order",
|
|
ArgsUsage: "<exchange> <asset> <pair> <order_id>",
|
|
Action: modifyOrder,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "exchange this order is submitted to",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "required asset type",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "required trading pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "order_id",
|
|
Usage: "id of the order to be modified",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "price",
|
|
Usage: "new order price",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "amount",
|
|
Usage: "new order amount",
|
|
},
|
|
},
|
|
}
|
|
|
|
func cancelAllOrders(c *cli.Context) error {
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.CancelAllOrders(c.Context, &gctrpc.CancelAllOrdersRequest{
|
|
Exchange: exchangeName,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
func modifyOrder(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "modifyorder")
|
|
}
|
|
|
|
// Parse positional arguments.
|
|
var exchangeName string
|
|
var orderID string
|
|
var currencyPair string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(2)
|
|
}
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.IsSet("order_id") {
|
|
orderID = c.String("order_id")
|
|
} else {
|
|
orderID = c.Args().Get(3)
|
|
}
|
|
|
|
// Parse optional flags.
|
|
var price float64
|
|
var amount float64
|
|
|
|
if c.IsSet("price") {
|
|
price = c.Float64("price")
|
|
}
|
|
if c.IsSet("amount") {
|
|
amount = c.Float64("amount")
|
|
}
|
|
if price == 0 && amount == 0 {
|
|
return errors.New("either --price or --amount should be present")
|
|
}
|
|
|
|
// Setup gRPC, make a request and display response.
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.ModifyOrder(c.Context, &gctrpc.ModifyOrderRequest{
|
|
Exchange: exchangeName,
|
|
OrderId: orderID,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
Asset: assetType,
|
|
Price: price,
|
|
Amount: amount,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getEventsCommand = &cli.Command{
|
|
Name: "getevents",
|
|
Usage: "gets all events",
|
|
Action: getEvents,
|
|
}
|
|
|
|
func getEvents(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetEvents(c.Context, &gctrpc.GetEventsRequest{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var addEventCommand = &cli.Command{
|
|
Name: "addevent",
|
|
Usage: "adds an event",
|
|
ArgsUsage: "<exchange> <item> <condition> <price> <check_bids> <check_bids_and_asks> <orderbook_amount> <pair> <asset> <action>",
|
|
Action: addEvent,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to add an event for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "item",
|
|
Usage: "the item to trigger the event",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "condition",
|
|
Usage: "the condition for the event",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "price",
|
|
Usage: "the price to trigger the event",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "check_bids",
|
|
Usage: "whether to check the bids",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "check_asks",
|
|
Usage: "whether to check the asks",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "orderbook_amount",
|
|
Usage: "the orderbook amount to trigger the event",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "action",
|
|
Usage: "the action for the event to perform upon trigger",
|
|
},
|
|
},
|
|
}
|
|
|
|
func addEvent(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "addevent")
|
|
}
|
|
|
|
var exchangeName string
|
|
var item string
|
|
var condition string
|
|
var price float64
|
|
var checkBids bool
|
|
var checkAsks bool
|
|
var orderbookAmount float64
|
|
var currencyPair string
|
|
var assetType string
|
|
var action string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
return fmt.Errorf("exchange name is required")
|
|
}
|
|
|
|
if c.IsSet("item") {
|
|
item = c.String("item")
|
|
} else {
|
|
return fmt.Errorf("item is required")
|
|
}
|
|
|
|
if c.IsSet("condition") {
|
|
condition = c.String("condition")
|
|
} else {
|
|
return fmt.Errorf("condition is required")
|
|
}
|
|
|
|
if c.IsSet("price") {
|
|
price = c.Float64("price")
|
|
}
|
|
|
|
if c.IsSet("check_bids") {
|
|
checkBids = c.Bool("check_bids")
|
|
}
|
|
|
|
if c.IsSet("check_asks") {
|
|
checkAsks = c.Bool("check_asks")
|
|
}
|
|
|
|
if c.IsSet("orderbook_amount") {
|
|
orderbookAmount = c.Float64("orderbook_amount")
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
return fmt.Errorf("currency pair is required")
|
|
}
|
|
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("action") {
|
|
action = c.String("action")
|
|
} else {
|
|
return fmt.Errorf("action is required")
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.AddEvent(c.Context, &gctrpc.AddEventRequest{
|
|
Exchange: exchangeName,
|
|
Item: item,
|
|
ConditionParams: &gctrpc.ConditionParams{
|
|
Condition: condition,
|
|
Price: price,
|
|
CheckBids: checkBids,
|
|
CheckAsks: checkAsks,
|
|
OrderbookAmount: orderbookAmount,
|
|
},
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
Action: action,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var removeEventCommand = &cli.Command{
|
|
Name: "removeevent",
|
|
Usage: "removes an event",
|
|
ArgsUsage: "<event_id>",
|
|
Action: removeEvent,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "event_id",
|
|
Usage: "the event id to remove",
|
|
},
|
|
},
|
|
}
|
|
|
|
func removeEvent(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "removeevent")
|
|
}
|
|
|
|
var eventID int64
|
|
if c.IsSet("event_id") {
|
|
eventID = c.Int64("event_id")
|
|
} else if c.Args().Get(0) != "" {
|
|
var err error
|
|
eventID, err = strconv.ParseInt(c.Args().Get(0), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if eventID == 0 {
|
|
return errors.New("event id must be specified")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.RemoveEvent(c.Context,
|
|
&gctrpc.RemoveEventRequest{Id: eventID})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getCryptocurrencyDepositAddressesCommand = &cli.Command{
|
|
Name: "getcryptocurrencydepositaddresses",
|
|
Usage: "gets the cryptocurrency deposit addresses for an exchange",
|
|
ArgsUsage: "<exchange>",
|
|
Action: getCryptocurrencyDepositAddresses,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the cryptocurrency deposit addresses for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getCryptocurrencyDepositAddresses(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getcryptocurrencydepositaddresses")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetCryptocurrencyDepositAddresses(c.Context,
|
|
&gctrpc.GetCryptocurrencyDepositAddressesRequest{Exchange: exchangeName})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getCryptocurrencyDepositAddressCommand = &cli.Command{
|
|
Name: "getcryptocurrencydepositaddress",
|
|
Usage: "gets the cryptocurrency deposit address for an exchange and cryptocurrency",
|
|
ArgsUsage: "<exchange> <cryptocurrency> <chain> <bypass>",
|
|
Action: getCryptocurrencyDepositAddress,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the cryptocurrency deposit address for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "cryptocurrency",
|
|
Usage: "the cryptocurrency to get the deposit address for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "chain",
|
|
Usage: "the chain to use for the deposit",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "bypass",
|
|
Usage: "whether to bypass the deposit address manager cache if enabled",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getCryptocurrencyDepositAddress(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getcryptocurrencydepositaddress")
|
|
}
|
|
|
|
var exchangeName string
|
|
var cryptocurrency string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("cryptocurrency") {
|
|
cryptocurrency = c.String("cryptocurrency")
|
|
} else if c.Args().Get(1) != "" {
|
|
cryptocurrency = c.Args().Get(1)
|
|
}
|
|
|
|
if cryptocurrency == "" {
|
|
return errors.New("cryptocurrency must be set")
|
|
}
|
|
|
|
var chain string
|
|
if c.IsSet("chain") {
|
|
chain = c.String("chain")
|
|
} else if c.Args().Get(2) != "" {
|
|
chain = c.Args().Get(2)
|
|
}
|
|
|
|
var bypass bool
|
|
if c.IsSet("bypass") {
|
|
bypass = c.Bool("bypass")
|
|
} else if c.Args().Get(3) != "" {
|
|
b, err := strconv.ParseBool(c.Args().Get(3))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bypass = b
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetCryptocurrencyDepositAddress(c.Context,
|
|
&gctrpc.GetCryptocurrencyDepositAddressRequest{
|
|
Exchange: exchangeName,
|
|
Cryptocurrency: cryptocurrency,
|
|
Chain: chain,
|
|
Bypass: bypass,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getAvailableTransferChainsCommand = &cli.Command{
|
|
Name: "getavailabletransferchains",
|
|
Usage: "gets the available transfer chains (deposits and withdrawals) for the desired exchange and cryptocurrency",
|
|
ArgsUsage: "<exchange> <cryptocurrency>",
|
|
Action: getAvailableTransferChains,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the available transfer chains",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "cryptocurrency",
|
|
Usage: "the cryptocurrency to get the available transfer chains for",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getAvailableTransferChains(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getavailabletransferchains")
|
|
}
|
|
|
|
var exchangeName string
|
|
var cryptocurrency string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("cryptocurrency") {
|
|
cryptocurrency = c.String("cryptocurrency")
|
|
} else if c.Args().Get(1) != "" {
|
|
cryptocurrency = c.Args().Get(1)
|
|
}
|
|
|
|
if cryptocurrency == "" {
|
|
return errors.New("cryptocurrency must be set")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetAvailableTransferChains(c.Context,
|
|
&gctrpc.GetAvailableTransferChainsRequest{
|
|
Exchange: exchangeName,
|
|
Cryptocurrency: cryptocurrency,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var withdrawCryptocurrencyFundsCommand = &cli.Command{
|
|
Name: "withdrawcryptofunds",
|
|
Usage: "withdraws cryptocurrency funds from the desired exchange",
|
|
ArgsUsage: "<exchange> <currency> <amount> <address> <addresstag> <fee> <description> <chain>",
|
|
Action: withdrawCryptocurrencyFunds,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to withdraw from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "currency",
|
|
Usage: "the cryptocurrency to withdraw funds from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "address",
|
|
Usage: "address to withdraw to",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "addresstag",
|
|
Usage: "address tag/memo",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "amount",
|
|
Usage: "amount of funds to withdraw",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "fee",
|
|
Usage: "fee to submit with request",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "description",
|
|
Usage: "description to submit with request",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "chain",
|
|
Usage: "chain to use for the withdrawal",
|
|
},
|
|
},
|
|
}
|
|
|
|
func withdrawCryptocurrencyFunds(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "withdrawcryptofunds")
|
|
}
|
|
|
|
var exchange, cur, address, addressTag, chain, description string
|
|
var amount, fee float64
|
|
|
|
if c.IsSet("exchange") {
|
|
exchange = c.String("exchange")
|
|
} else if c.Args().Get(0) != "" {
|
|
exchange = c.Args().Get(0)
|
|
}
|
|
|
|
if c.IsSet("currency") {
|
|
cur = c.String("currency")
|
|
} else if c.Args().Get(1) != "" {
|
|
cur = c.Args().Get(1)
|
|
}
|
|
|
|
if c.IsSet("amount") {
|
|
amount = c.Float64("amount")
|
|
} else if c.Args().Get(2) != "" {
|
|
amountStr, err := strconv.ParseFloat(c.Args().Get(2), 64)
|
|
if err == nil {
|
|
amount = amountStr
|
|
}
|
|
}
|
|
|
|
if c.IsSet("address") {
|
|
address = c.String("address")
|
|
} else if c.Args().Get(3) != "" {
|
|
address = c.Args().Get(3)
|
|
}
|
|
|
|
if c.IsSet("addresstag") {
|
|
addressTag = c.String("addresstag")
|
|
} else if c.Args().Get(4) != "" {
|
|
addressTag = c.Args().Get(4)
|
|
}
|
|
|
|
if c.IsSet("fee") {
|
|
fee = c.Float64("fee")
|
|
} else if c.Args().Get(5) != "" {
|
|
feeStr, err := strconv.ParseFloat(c.Args().Get(5), 64)
|
|
if err == nil {
|
|
fee = feeStr
|
|
}
|
|
}
|
|
|
|
if c.IsSet("description") {
|
|
description = c.String("description")
|
|
} else if c.Args().Get(6) != "" {
|
|
description = c.Args().Get(6)
|
|
}
|
|
|
|
if c.IsSet("chain") {
|
|
chain = c.String("chain")
|
|
} else if c.Args().Get(7) != "" {
|
|
chain = c.Args().Get(7)
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
result, err := client.WithdrawCryptocurrencyFunds(c.Context,
|
|
&gctrpc.WithdrawCryptoRequest{
|
|
Exchange: exchange,
|
|
Currency: cur,
|
|
Address: address,
|
|
AddressTag: addressTag,
|
|
Amount: amount,
|
|
Fee: fee,
|
|
Description: description,
|
|
Chain: chain,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var withdrawFiatFundsCommand = &cli.Command{
|
|
Name: "withdrawfiatfunds",
|
|
Usage: "withdraws fiat funds from the desired exchange",
|
|
ArgsUsage: "<exchange> <currency> <amount> <bankaccount id> <description>",
|
|
Action: withdrawFiatFunds,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to withdraw from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "currency",
|
|
Usage: "the fiat currency to withdraw funds from",
|
|
},
|
|
&cli.Float64Flag{
|
|
Name: "amount",
|
|
Usage: "amount of funds to withdraw",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "bankaccountid",
|
|
Usage: "ID of bank account to use",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "description",
|
|
Usage: "description to submit with request",
|
|
},
|
|
},
|
|
}
|
|
|
|
func withdrawFiatFunds(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "withdrawfiatfunds")
|
|
}
|
|
|
|
var exchange, cur, description, bankAccountID string
|
|
var amount float64
|
|
|
|
if c.IsSet("exchange") {
|
|
exchange = c.String("exchange")
|
|
} else if c.Args().Get(0) != "" {
|
|
exchange = c.Args().Get(0)
|
|
}
|
|
|
|
if c.IsSet("currency") {
|
|
cur = c.String("currency")
|
|
} else if c.Args().Get(1) != "" {
|
|
cur = c.Args().Get(1)
|
|
}
|
|
|
|
if c.IsSet("amount") {
|
|
amount = c.Float64("amount")
|
|
} else if c.Args().Get(2) != "" {
|
|
amountStr, err := strconv.ParseFloat(c.Args().Get(2), 64)
|
|
if err == nil {
|
|
amount = amountStr
|
|
}
|
|
}
|
|
|
|
if c.IsSet("bankaccountid") {
|
|
bankAccountID = c.String("bankaccountid")
|
|
} else if c.Args().Get(3) != "" {
|
|
bankAccountID = c.Args().Get(3)
|
|
}
|
|
|
|
if c.IsSet("description") {
|
|
description = c.String("description")
|
|
} else if c.Args().Get(4) != "" {
|
|
description = c.Args().Get(4)
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.WithdrawFiatFunds(c.Context,
|
|
&gctrpc.WithdrawFiatRequest{
|
|
Exchange: exchange,
|
|
Currency: cur,
|
|
Amount: amount,
|
|
Description: description,
|
|
BankAccountId: bankAccountID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var withdrawalRequestCommand = &cli.Command{
|
|
Name: "withdrawalrequesthistory",
|
|
Usage: "retrieve previous withdrawal request details",
|
|
ArgsUsage: "<type> <args>",
|
|
Subcommands: []*cli.Command{
|
|
{
|
|
Name: "byid",
|
|
Usage: "id",
|
|
ArgsUsage: "<id>",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "id",
|
|
Usage: "withdrawal id",
|
|
},
|
|
},
|
|
Action: withdrawlRequestByID,
|
|
},
|
|
{
|
|
Name: "byexchangeid",
|
|
Usage: "exchange id",
|
|
ArgsUsage: "<id>",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "exchange name",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "id",
|
|
Usage: "withdrawal id",
|
|
},
|
|
},
|
|
Action: withdrawlRequestByExchangeID,
|
|
},
|
|
{
|
|
Name: "byexchange",
|
|
Usage: "exchange limit",
|
|
ArgsUsage: "<id>",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "exchange name",
|
|
},
|
|
&cli.Int64Flag{
|
|
Name: "limit",
|
|
Usage: "max number of withdrawals to return",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "currency",
|
|
Usage: "<currency>",
|
|
},
|
|
},
|
|
Action: withdrawlRequestByExchangeID,
|
|
},
|
|
{
|
|
Name: "bydate",
|
|
Usage: "exchange start end limit",
|
|
ArgsUsage: "<exchange> <start> <end> <limit>",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the currency used in to withdraw",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "start",
|
|
Usage: "the start date to get withdrawals from. Any withdrawal before this date will be filtered",
|
|
Value: time.Now().AddDate(0, -1, 0).Format(common.SimpleTimeFormat),
|
|
Destination: &startTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "end",
|
|
Usage: "the end date to get withdrawals from. Any withdrawal after this date will be filtered",
|
|
Value: time.Now().Format(common.SimpleTimeFormat),
|
|
Destination: &endTime,
|
|
},
|
|
&cli.Int64Flag{
|
|
Name: "limit",
|
|
Usage: "max number of withdrawals to return",
|
|
},
|
|
},
|
|
Action: withdrawlRequestByDate,
|
|
},
|
|
},
|
|
}
|
|
|
|
func withdrawlRequestByID(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
var ID string
|
|
if c.IsSet("id") {
|
|
ID = c.String("id")
|
|
} else {
|
|
ID = c.Args().First()
|
|
}
|
|
|
|
if ID == "" {
|
|
return errors.New("an ID must be specified")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
result, err := client.WithdrawalEventByID(c.Context,
|
|
&gctrpc.WithdrawalEventByIDRequest{
|
|
Id: ID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
func withdrawlRequestByExchangeID(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
var exchange, currency string
|
|
if c.IsSet("exchange") {
|
|
exchange = c.String("exchange")
|
|
} else {
|
|
exchange = c.Args().First()
|
|
}
|
|
|
|
var limit, limitStr int64
|
|
var ID string
|
|
var err error
|
|
if c.Command.Name == "byexchangeid" {
|
|
if c.IsSet("id") {
|
|
ID = c.String("id")
|
|
} else {
|
|
ID = c.Args().Get(1)
|
|
}
|
|
if ID == "" {
|
|
return errors.New("an ID must be specified")
|
|
}
|
|
limit = 1
|
|
} else {
|
|
if c.IsSet("limit") {
|
|
limit = c.Int64("limit")
|
|
} else if c.Args().Get(1) != "" {
|
|
limitStr, err = strconv.ParseInt(c.Args().Get(1), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if limitStr > math.MaxInt32 {
|
|
return fmt.Errorf("limit greater than max size: %v", math.MaxInt32)
|
|
}
|
|
limit = limitStr
|
|
}
|
|
|
|
if c.IsSet("currency") {
|
|
currency = c.String("currency")
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
result, err := client.WithdrawalEventsByExchange(c.Context,
|
|
&gctrpc.WithdrawalEventsByExchangeRequest{
|
|
Exchange: exchange,
|
|
Id: ID,
|
|
Limit: int32(limit),
|
|
Currency: currency,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
func withdrawlRequestByDate(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
var exchange string
|
|
var limit, limitStr int64
|
|
var err error
|
|
if c.IsSet("exchange") {
|
|
exchange = c.String("exchange")
|
|
} else {
|
|
exchange = c.Args().First()
|
|
}
|
|
|
|
if !c.IsSet("start") {
|
|
if c.Args().Get(1) != "" {
|
|
startTime = c.Args().Get(1)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("end") {
|
|
if c.Args().Get(2) != "" {
|
|
endTime = c.Args().Get(2)
|
|
}
|
|
}
|
|
|
|
if c.IsSet("limit") {
|
|
limit = c.Int64("limit")
|
|
} else if c.Args().Get(3) != "" {
|
|
limitStr, err = strconv.ParseInt(c.Args().Get(3), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if limitStr > math.MaxInt32 {
|
|
return fmt.Errorf("limit greater than max size: %v", math.MaxInt32)
|
|
}
|
|
limit = limitStr
|
|
}
|
|
|
|
s, err := time.Parse(common.SimpleTimeFormat, startTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for start: %v", err)
|
|
}
|
|
e, err := time.Parse(common.SimpleTimeFormat, endTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for end: %v", err)
|
|
}
|
|
|
|
if e.Before(s) {
|
|
return errors.New("start cannot be after end")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.WithdrawalEventsByDate(c.Context,
|
|
&gctrpc.WithdrawalEventsByDateRequest{
|
|
Exchange: exchange,
|
|
Start: negateLocalOffset(s),
|
|
End: negateLocalOffset(e),
|
|
Limit: int32(limit),
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getLoggerDetailsCommand = &cli.Command{
|
|
Name: "getloggerdetails",
|
|
Usage: "gets an individual loggers details",
|
|
ArgsUsage: "<logger>",
|
|
Action: getLoggerDetails,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "logger",
|
|
Usage: "logger to get level details of",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getLoggerDetails(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getloggerdetails")
|
|
}
|
|
|
|
var logger string
|
|
if c.IsSet("logger") {
|
|
logger = c.String("logger")
|
|
} else {
|
|
logger = c.Args().First()
|
|
}
|
|
|
|
if logger == "" {
|
|
return errors.New("a logger must be specified")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
result, err := client.GetLoggerDetails(c.Context,
|
|
&gctrpc.GetLoggerDetailsRequest{
|
|
Logger: logger,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var setLoggerDetailsCommand = &cli.Command{
|
|
Name: "setloggerdetails",
|
|
Usage: "sets an individual loggers details",
|
|
ArgsUsage: "<logger> <flags>",
|
|
Action: setLoggerDetails,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "logger",
|
|
Usage: "logger to get level details of",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "flags",
|
|
Usage: "pipe separated value of loggers e.g INFO|WARN",
|
|
},
|
|
},
|
|
}
|
|
|
|
func setLoggerDetails(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "setloggerdetails")
|
|
}
|
|
|
|
var logger string
|
|
var level string
|
|
|
|
if c.IsSet("logger") {
|
|
logger = c.String("logger")
|
|
} else {
|
|
logger = c.Args().First()
|
|
}
|
|
|
|
if logger == "" {
|
|
return errors.New("a logger must be specified")
|
|
}
|
|
|
|
if c.IsSet("level") {
|
|
level = c.String("level")
|
|
} else {
|
|
level = c.Args().Get(1)
|
|
}
|
|
|
|
if level == "" {
|
|
return errors.New("level must be specified")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
result, err := client.SetLoggerDetails(c.Context,
|
|
&gctrpc.SetLoggerDetailsRequest{
|
|
Logger: logger,
|
|
Level: level,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getOrderbookStreamCommand = &cli.Command{
|
|
Name: "getorderbookstream",
|
|
Usage: "gets the orderbook stream for a specific currency pair and exchange",
|
|
ArgsUsage: "<exchange> <pair> <asset>",
|
|
Action: getOrderbookStream,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the orderbook from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type of the currency pair",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getOrderbookStream(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getorderbookstream")
|
|
}
|
|
|
|
var exchangeName string
|
|
var pair string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
pair = c.String("pair")
|
|
} else {
|
|
pair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(pair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(pair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetOrderbookStream(c.Context,
|
|
&gctrpc.GetOrderbookStreamRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
Delimiter: p.Delimiter,
|
|
},
|
|
AssetType: assetType,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
resp, err := result.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = clearScreen()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Orderbook stream for %s %s:\n\n", exchangeName, resp.Pair)
|
|
if resp.Error != "" {
|
|
fmt.Printf("%s\n", resp.Error)
|
|
continue
|
|
}
|
|
|
|
fmt.Println("\t\tBids\t\t\t\tAsks")
|
|
fmt.Println()
|
|
|
|
bidLen := len(resp.Bids) - 1
|
|
askLen := len(resp.Asks) - 1
|
|
|
|
var maxLen int
|
|
if bidLen >= askLen {
|
|
maxLen = bidLen
|
|
} else {
|
|
maxLen = askLen
|
|
}
|
|
|
|
for i := 0; i < maxLen; i++ {
|
|
var bidAmount, bidPrice float64
|
|
if i <= bidLen {
|
|
bidAmount = resp.Bids[i].Amount
|
|
bidPrice = resp.Bids[i].Price
|
|
}
|
|
|
|
var askAmount, askPrice float64
|
|
if i <= askLen {
|
|
askAmount = resp.Asks[i].Amount
|
|
askPrice = resp.Asks[i].Price
|
|
}
|
|
|
|
fmt.Printf("%.8f %s @ %.8f %s\t\t%.8f %s @ %.8f %s\n",
|
|
bidAmount,
|
|
resp.Pair.Base,
|
|
bidPrice,
|
|
resp.Pair.Quote,
|
|
askAmount,
|
|
resp.Pair.Base,
|
|
askPrice,
|
|
resp.Pair.Quote)
|
|
|
|
if i >= 49 {
|
|
// limits orderbook display output
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var getExchangeOrderbookStreamCommand = &cli.Command{
|
|
Name: "getexchangeorderbookstream",
|
|
Usage: "gets a stream for all orderbooks associated with an exchange",
|
|
ArgsUsage: "<exchange>",
|
|
Action: getExchangeOrderbookStream,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the orderbook from",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getExchangeOrderbookStream(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getexchangeorderbookstream")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetExchangeOrderbookStream(c.Context,
|
|
&gctrpc.GetExchangeOrderbookStreamRequest{
|
|
Exchange: exchangeName,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
resp, err := result.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = clearScreen()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Orderbook streamed for %s %s", exchangeName, resp.Pair)
|
|
if resp.Error != "" {
|
|
fmt.Printf("%s\n", resp.Error)
|
|
}
|
|
}
|
|
}
|
|
|
|
var getTickerStreamCommand = &cli.Command{
|
|
Name: "gettickerstream",
|
|
Usage: "gets the ticker stream for a specific currency pair and exchange",
|
|
ArgsUsage: "<exchange> <pair> <asset>",
|
|
Action: getTickerStream,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the ticker from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type of the currency pair",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getTickerStream(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "gettickerstream")
|
|
}
|
|
|
|
var exchangeName string
|
|
var pair string
|
|
var assetType string
|
|
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
if c.IsSet("pair") {
|
|
pair = c.String("pair")
|
|
} else {
|
|
pair = c.Args().Get(1)
|
|
}
|
|
|
|
if !validPair(pair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
assetType = strings.ToLower(assetType)
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(pair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetTickerStream(c.Context,
|
|
&gctrpc.GetTickerStreamRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
Delimiter: p.Delimiter,
|
|
},
|
|
AssetType: assetType,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
resp, err := result.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = clearScreen()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Ticker stream for %s %s:\n", exchangeName,
|
|
resp.Pair.String())
|
|
fmt.Println()
|
|
|
|
fmt.Printf("LAST: %f\n HIGH: %f\n LOW: %f\n BID: %f\n ASK: %f\n VOLUME: %f\n PRICEATH: %f\n LASTUPDATED: %d\n",
|
|
resp.Last,
|
|
resp.High,
|
|
resp.Low,
|
|
resp.Bid,
|
|
resp.Ask,
|
|
resp.Volume,
|
|
resp.PriceAth,
|
|
resp.LastUpdated)
|
|
}
|
|
}
|
|
|
|
var getExchangeTickerStreamCommand = &cli.Command{
|
|
Name: "getexchangetickerstream",
|
|
Usage: "gets a stream for all tickers associated with an exchange",
|
|
ArgsUsage: "<exchange>",
|
|
Action: getExchangeTickerStream,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Usage: "the exchange to get the ticker from",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getExchangeTickerStream(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getexchangetickerstream")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetExchangeTickerStream(c.Context,
|
|
&gctrpc.GetExchangeTickerStreamRequest{
|
|
Exchange: exchangeName,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
resp, err := result.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Ticker stream for %s %s:\n",
|
|
exchangeName,
|
|
resp.Pair.String())
|
|
|
|
fmt.Printf("LAST: %f HIGH: %f LOW: %f BID: %f ASK: %f VOLUME: %f PRICEATH: %f LASTUPDATED: %d\n",
|
|
resp.Last,
|
|
resp.High,
|
|
resp.Low,
|
|
resp.Bid,
|
|
resp.Ask,
|
|
resp.Volume,
|
|
resp.PriceAth,
|
|
resp.LastUpdated)
|
|
}
|
|
}
|
|
|
|
var getAuditEventCommand = &cli.Command{
|
|
Name: "getauditevent",
|
|
Usage: "gets audit events matching query parameters",
|
|
ArgsUsage: "<starttime> <endtime> <orderby> <limit>",
|
|
Action: getAuditEvent,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "start",
|
|
Aliases: []string{"s"},
|
|
Usage: "start date to search",
|
|
Value: time.Now().Add(-time.Hour).Format(common.SimpleTimeFormat),
|
|
Destination: &startTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "end",
|
|
Aliases: []string{"e"},
|
|
Usage: "end time to search",
|
|
Value: time.Now().Format(common.SimpleTimeFormat),
|
|
Destination: &endTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "order",
|
|
Aliases: []string{"o"},
|
|
Usage: "order results by ascending/descending",
|
|
Value: "asc",
|
|
Destination: &orderingDirection,
|
|
},
|
|
&cli.IntFlag{
|
|
Name: "limit",
|
|
Aliases: []string{"l"},
|
|
Usage: "how many results to retrieve",
|
|
Value: 100,
|
|
Destination: &limit,
|
|
},
|
|
},
|
|
}
|
|
|
|
func getAuditEvent(c *cli.Context) error {
|
|
if !c.IsSet("start") {
|
|
if c.Args().Get(0) != "" {
|
|
startTime = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("end") {
|
|
if c.Args().Get(1) != "" {
|
|
endTime = c.Args().Get(1)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("order") {
|
|
if c.Args().Get(2) != "" {
|
|
orderingDirection = c.Args().Get(2)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("limit") {
|
|
if c.Args().Get(3) != "" {
|
|
limitStr, err := strconv.ParseInt(c.Args().Get(3), 10, 64)
|
|
if err == nil {
|
|
limit = int(limitStr)
|
|
}
|
|
}
|
|
}
|
|
|
|
s, err := time.Parse(common.SimpleTimeFormat, startTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for start: %v", err)
|
|
}
|
|
|
|
e, err := time.Parse(common.SimpleTimeFormat, endTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for end: %v", err)
|
|
}
|
|
|
|
if e.Before(s) {
|
|
return errors.New("start cannot be after end")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
result, err := client.GetAuditEvent(c.Context,
|
|
&gctrpc.GetAuditEventRequest{
|
|
StartDate: negateLocalOffset(s),
|
|
EndDate: negateLocalOffset(e),
|
|
Limit: int32(limit),
|
|
OrderBy: orderingDirection,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var uuid, filename, path string
|
|
var gctScriptCommand = &cli.Command{
|
|
Name: "script",
|
|
Usage: "execute scripting management command",
|
|
ArgsUsage: "<command> <args>",
|
|
Subcommands: []*cli.Command{
|
|
{
|
|
Name: "execute",
|
|
Usage: "execute script filename",
|
|
ArgsUsage: "<filename> <path>",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "filename",
|
|
Usage: "the script filename",
|
|
Destination: &filename,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "path",
|
|
Usage: "the directory of the script file",
|
|
Destination: &path,
|
|
},
|
|
},
|
|
Action: gctScriptExecute,
|
|
},
|
|
{
|
|
Name: "query",
|
|
Usage: "query running virtual machine",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "uuid",
|
|
Usage: "the unique id of the script in memory",
|
|
Destination: &uuid,
|
|
},
|
|
},
|
|
Action: gctScriptQuery,
|
|
},
|
|
{
|
|
Name: "read",
|
|
Usage: "read script",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "name",
|
|
Usage: "the script name",
|
|
Destination: &uuid,
|
|
},
|
|
},
|
|
Action: gctScriptRead,
|
|
},
|
|
{
|
|
Name: "status",
|
|
Usage: "get status of running scripts",
|
|
Action: gctScriptStatus,
|
|
},
|
|
{
|
|
Name: "list",
|
|
Usage: "lists all scripts in default scriptpath",
|
|
Action: gctScriptList,
|
|
},
|
|
{
|
|
Name: "stop",
|
|
Usage: "terminate running script",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "uuid",
|
|
Usage: "the unique id of the script in memory",
|
|
Destination: &uuid,
|
|
},
|
|
},
|
|
Action: gctScriptStop,
|
|
},
|
|
{
|
|
Name: "stopall",
|
|
Usage: "terminate running script",
|
|
Action: gctScriptStopAll,
|
|
},
|
|
{
|
|
Name: "upload",
|
|
Usage: "upload a new script/archive",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "path",
|
|
Usage: "<path> to single script or zip collection",
|
|
Destination: &filename,
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "overwrite",
|
|
Usage: "<true/false>",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "archived",
|
|
Usage: "<true/false>",
|
|
},
|
|
},
|
|
Action: gctScriptUpload,
|
|
},
|
|
{
|
|
Name: "autoload",
|
|
Usage: "add or remove script from autoload list",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "command",
|
|
Usage: "<add/remove>",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "script",
|
|
Usage: "<script name>",
|
|
},
|
|
},
|
|
Action: gctScriptAutoload,
|
|
},
|
|
},
|
|
}
|
|
|
|
func gctScriptAutoload(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
var command, script string
|
|
var status bool
|
|
if !c.IsSet("command") {
|
|
if c.Args().Get(0) != "" {
|
|
command = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("script") {
|
|
if c.Args().Get(1) != "" {
|
|
script = c.Args().Get(1)
|
|
}
|
|
}
|
|
|
|
switch command {
|
|
case "add":
|
|
status = false
|
|
case "remove":
|
|
status = true
|
|
default:
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptAutoLoadToggle(c.Context,
|
|
&gctrpc.GCTScriptAutoLoadRequest{
|
|
Script: script,
|
|
Status: status,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
return nil
|
|
}
|
|
|
|
func gctScriptExecute(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
if !c.IsSet("filename") {
|
|
if c.Args().Get(0) != "" {
|
|
filename = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("path") {
|
|
if c.Args().Get(1) != "" {
|
|
path = c.Args().Get(1)
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptExecute(c.Context,
|
|
&gctrpc.GCTScriptExecuteRequest{
|
|
Script: &gctrpc.GCTScript{
|
|
Name: filename,
|
|
Path: path,
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
|
|
return nil
|
|
}
|
|
|
|
func gctScriptStatus(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptStatus(c.Context,
|
|
&gctrpc.GCTScriptStatusRequest{})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
return nil
|
|
}
|
|
|
|
func gctScriptList(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptListAll(c.Context,
|
|
&gctrpc.GCTScriptListAllRequest{})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
return nil
|
|
}
|
|
|
|
func gctScriptStop(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
if !c.IsSet("uuid") {
|
|
if c.Args().Get(0) != "" {
|
|
uuid = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptStop(c.Context,
|
|
&gctrpc.GCTScriptStopRequest{
|
|
Script: &gctrpc.GCTScript{UUID: uuid},
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
return nil
|
|
}
|
|
|
|
func gctScriptStopAll(c *cli.Context) error {
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptStopAll(c.Context,
|
|
&gctrpc.GCTScriptStopAllRequest{})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
return nil
|
|
}
|
|
|
|
func gctScriptRead(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
if !c.IsSet("name") {
|
|
if c.Args().Get(0) != "" {
|
|
uuid = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptReadScript(c.Context,
|
|
&gctrpc.GCTScriptReadScriptRequest{
|
|
Script: &gctrpc.GCTScript{
|
|
Name: uuid,
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
return nil
|
|
}
|
|
|
|
func gctScriptQuery(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
if !c.IsSet("uuid") {
|
|
if c.Args().Get(0) != "" {
|
|
uuid = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
executeCommand, err := client.GCTScriptQuery(c.Context,
|
|
&gctrpc.GCTScriptQueryRequest{
|
|
Script: &gctrpc.GCTScript{
|
|
UUID: uuid,
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(executeCommand)
|
|
|
|
return nil
|
|
}
|
|
|
|
func gctScriptUpload(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowSubcommandHelp(c)
|
|
}
|
|
|
|
var overwrite bool
|
|
var archived bool
|
|
if !c.IsSet("path") {
|
|
if c.Args().Get(0) != "" {
|
|
filename = c.Args().Get(0)
|
|
}
|
|
}
|
|
|
|
if c.IsSet("overwrite") {
|
|
overwrite = c.Bool("overwrite")
|
|
} else {
|
|
ow, err := strconv.ParseBool(c.Args().Get(1))
|
|
if err == nil {
|
|
overwrite = ow
|
|
}
|
|
}
|
|
|
|
if c.IsSet("archived") {
|
|
archived = c.Bool("archived")
|
|
} else {
|
|
ow, err := strconv.ParseBool(c.Args().Get(1))
|
|
if err == nil {
|
|
archived = ow
|
|
}
|
|
}
|
|
|
|
if filepath.Ext(filename) != common.GctExt && filepath.Ext(filename) != ".zip" {
|
|
return errors.New("file type must be gct or zip")
|
|
}
|
|
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
|
|
data, err := io.ReadAll(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
uploadCommand, err := client.GCTScriptUpload(c.Context,
|
|
&gctrpc.GCTScriptUploadRequest{
|
|
ScriptName: filepath.Base(file.Name()),
|
|
Data: data,
|
|
Archived: archived,
|
|
Overwrite: overwrite,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(uploadCommand)
|
|
return nil
|
|
}
|
|
|
|
const klineMessage = `interval in seconds. supported values are: 15, 60(1min), 180(3min), 300(5min), 600(10min),
|
|
900(15min) 1800(30min), 3600(1h), 7200(2h), 14400(4h), 21600(6h), 28800(8h), 43200(12h),
|
|
86400(1d), 259200(3d) 604800(1w), 1209600(2w), 1296000(15d), 2592000(1M), 31536000(1Y)`
|
|
|
|
var candleRangeSize, candleGranularity int64
|
|
var getHistoricCandlesCommand = &cli.Command{
|
|
Name: "gethistoriccandles",
|
|
Usage: "gets historical candles for the specified granularity up to range size time from now.",
|
|
ArgsUsage: "<exchange> <pair> <asset> <rangesize> <granularity>",
|
|
Action: getHistoricCandles,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Aliases: []string{"e"},
|
|
Usage: "the exchange to get the candles from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Usage: "the currency pair to get the candles for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Usage: "the asset type of the currency pair",
|
|
},
|
|
&cli.Int64Flag{
|
|
Name: "rangesize",
|
|
Aliases: []string{"r"},
|
|
Usage: "the amount of time to go back from now to fetch candles in the given granularity",
|
|
Value: 10,
|
|
Destination: &candleRangeSize,
|
|
},
|
|
&cli.Int64Flag{
|
|
Name: "granularity",
|
|
Aliases: []string{"g"},
|
|
Usage: klineMessage,
|
|
Value: 86400,
|
|
Destination: &candleGranularity,
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "fillmissingdatawithtrades, fill",
|
|
Usage: "will create candles for missing intervals using stored trade data <true/false>",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getHistoricCandles(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "gethistoriccandles")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
var currencyPair string
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("rangesize") {
|
|
candleRangeSize = c.Int64("rangesize")
|
|
} else if c.Args().Get(3) != "" {
|
|
candleRangeSize, err = strconv.ParseInt(c.Args().Get(3), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if c.IsSet("granularity") {
|
|
candleGranularity = c.Int64("granularity")
|
|
} else if c.Args().Get(4) != "" {
|
|
candleGranularity, err = strconv.ParseInt(c.Args().Get(4), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var fillMissingData bool
|
|
if c.IsSet("fillmissingdatawithtrades") {
|
|
fillMissingData = c.Bool("fillmissingdatawithtrades")
|
|
} else if c.IsSet("fill") {
|
|
fillMissingData = c.Bool("fill")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
candleInterval := time.Duration(candleGranularity) * time.Second
|
|
|
|
e := time.Now().Truncate(candleInterval)
|
|
s := e.Add(-candleInterval * time.Duration(candleRangeSize))
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetHistoricCandles(c.Context,
|
|
&gctrpc.GetHistoricCandlesRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
Start: negateLocalOffset(s),
|
|
End: negateLocalOffset(e),
|
|
TimeInterval: int64(candleInterval),
|
|
FillMissingWithTrades: fillMissingData,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getHistoricCandlesExtendedCommand = &cli.Command{
|
|
Name: "gethistoriccandlesextended",
|
|
Usage: "gets historical candles for the specified pair, asset, interval & date range",
|
|
ArgsUsage: "<exchange> <pair> <asset> <interval> <start> <end>",
|
|
Action: getHistoricCandlesExtended,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Aliases: []string{"e"},
|
|
Usage: "the exchange to get the candles from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Aliases: []string{"p"},
|
|
Usage: "the currency pair to get the candles for",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Aliases: []string{"a"},
|
|
Usage: "the asset type of the currency pair",
|
|
},
|
|
&cli.Int64Flag{
|
|
Name: "interval",
|
|
Aliases: []string{"i"},
|
|
Usage: klineMessage,
|
|
Value: 86400,
|
|
Destination: &candleGranularity,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "start",
|
|
Usage: "the date to begin retrieveing candles. Any candles before this date will be filtered",
|
|
Value: time.Now().AddDate(0, -1, 0).Format(common.SimpleTimeFormat),
|
|
Destination: &startTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "end",
|
|
Usage: "the date to end retrieveing candles. Any candles after this date will be filtered",
|
|
Value: time.Now().Format(common.SimpleTimeFormat),
|
|
Destination: &endTime,
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "sync",
|
|
Usage: "<true/false>",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "force",
|
|
Usage: "will overwrite any conflicting candle data on save <true/false>",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "db",
|
|
Usage: "source data from database <true/false>",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "fillmissingdatawithtrades",
|
|
Aliases: []string{"fill"},
|
|
Usage: "will create candles for missing intervals using stored trade data <true/false>",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getHistoricCandlesExtended(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "gethistoriccandlesextended")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
var currencyPair string
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("interval") {
|
|
candleGranularity = c.Int64("interval")
|
|
} else if c.Args().Get(3) != "" {
|
|
candleGranularity, err = strconv.ParseInt(c.Args().Get(3), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("start") {
|
|
if c.Args().Get(4) != "" {
|
|
startTime = c.Args().Get(4)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("end") {
|
|
if c.Args().Get(5) != "" {
|
|
endTime = c.Args().Get(5)
|
|
}
|
|
}
|
|
|
|
var sync bool
|
|
if c.IsSet("sync") {
|
|
sync = c.Bool("sync")
|
|
}
|
|
|
|
var useDB bool
|
|
if c.IsSet("db") {
|
|
useDB = c.Bool("db")
|
|
}
|
|
|
|
var fillMissingData bool
|
|
if c.IsSet("fillmissingdatawithtrades") {
|
|
fillMissingData = c.Bool("fillmissingdatawithtrades")
|
|
} else if c.IsSet("fill") {
|
|
fillMissingData = c.Bool("fill")
|
|
}
|
|
|
|
var force bool
|
|
if c.IsSet("force") {
|
|
force = c.Bool("force")
|
|
}
|
|
|
|
if force && !sync {
|
|
return errors.New("cannot forcefully overwrite without sync")
|
|
}
|
|
|
|
candleInterval := time.Duration(candleGranularity) * time.Second
|
|
var s, e time.Time
|
|
s, err = time.Parse(common.SimpleTimeFormat, startTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for start: %v", err)
|
|
}
|
|
e, err = time.Parse(common.SimpleTimeFormat, endTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for end: %v", err)
|
|
}
|
|
|
|
if e.Before(s) {
|
|
return errors.New("start cannot be after end")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetHistoricCandles(c.Context,
|
|
&gctrpc.GetHistoricCandlesRequest{
|
|
Exchange: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
Start: negateLocalOffset(s),
|
|
End: negateLocalOffset(e),
|
|
TimeInterval: int64(candleInterval),
|
|
ExRequest: true,
|
|
Sync: sync,
|
|
UseDb: useDB,
|
|
FillMissingWithTrades: fillMissingData,
|
|
Force: force,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var findMissingSavedCandleIntervalsCommand = &cli.Command{
|
|
Name: "findmissingsavedcandleintervals",
|
|
Usage: "will highlight any interval that is missing candle data so you can fill that gap",
|
|
ArgsUsage: "<exchange> <pair> <asset> <interval> <start> <end>",
|
|
Action: findMissingSavedCandleIntervals,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Aliases: []string{"e"},
|
|
Usage: "the exchange to find the missing candles",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Aliases: []string{"p"},
|
|
Usage: "the currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Aliases: []string{"a"},
|
|
Usage: "the asset type of the currency pair",
|
|
},
|
|
&cli.Int64Flag{
|
|
Name: "interval",
|
|
Aliases: []string{"i"},
|
|
Usage: klineMessage,
|
|
Value: 86400,
|
|
Destination: &candleGranularity,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "start",
|
|
Usage: "<start> rounded down to the nearest hour",
|
|
Value: time.Now().AddDate(0, -1, 0).Truncate(time.Hour).Format(common.SimpleTimeFormat),
|
|
Destination: &startTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "end",
|
|
Usage: "<end> rounded down to the nearest hour",
|
|
Value: time.Now().Truncate(time.Hour).Format(common.SimpleTimeFormat),
|
|
Destination: &endTime,
|
|
},
|
|
},
|
|
}
|
|
|
|
func findMissingSavedCandleIntervals(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "findmissingsavedcandleintervals")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
var currencyPair string
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(1)
|
|
}
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(2)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
if c.IsSet("interval") {
|
|
candleGranularity = c.Int64("interval")
|
|
} else if c.Args().Get(3) != "" {
|
|
candleGranularity, err = strconv.ParseInt(c.Args().Get(3), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("start") {
|
|
if c.Args().Get(4) != "" {
|
|
startTime = c.Args().Get(4)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("end") {
|
|
if c.Args().Get(5) != "" {
|
|
endTime = c.Args().Get(5)
|
|
}
|
|
}
|
|
|
|
candleInterval := time.Duration(candleGranularity) * time.Second
|
|
var s, e time.Time
|
|
s, err = time.Parse(common.SimpleTimeFormat, startTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for start: %v", err)
|
|
}
|
|
e, err = time.Parse(common.SimpleTimeFormat, endTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for end: %v", err)
|
|
}
|
|
|
|
if e.Before(s) {
|
|
return errors.New("start cannot be after end")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.FindMissingSavedCandleIntervals(c.Context,
|
|
&gctrpc.FindMissingCandlePeriodsRequest{
|
|
ExchangeName: exchangeName,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
AssetType: assetType,
|
|
Start: negateLocalOffset(s),
|
|
End: negateLocalOffset(e),
|
|
Interval: int64(candleInterval),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getFuturesPositionsCommand = &cli.Command{
|
|
Name: "getfuturesposition",
|
|
Usage: "will retrieve all futures positions in a timeframe, then calculate PNL based on that. Note, the dates have an impact on PNL calculations, ensure your start date is not after a new position is opened",
|
|
ArgsUsage: "<exchange> <pair> <asset> <start> <end> <limit> <status> <verbose> <overwrite>",
|
|
Action: getFuturesPositions,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Aliases: []string{"e"},
|
|
Usage: "the exchange to retrieve futures positions from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Aliases: []string{"a"},
|
|
Usage: "the asset type of the currency pair, must be a futures type",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "pair",
|
|
Aliases: []string{"p"},
|
|
Usage: "the currency pair",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "start",
|
|
Aliases: []string{"sd"},
|
|
Usage: "<start> rounded down to the nearest hour, ensure your starting position is within this window for accurate calculations",
|
|
Value: time.Now().AddDate(-1, 0, 0).Truncate(time.Hour).Format(common.SimpleTimeFormat),
|
|
Destination: &startTime,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "end",
|
|
Aliases: []string{"ed"},
|
|
Usage: "<end> rounded down to the nearest hour, ensure your last position is within this window for accurate calculations",
|
|
Value: time.Now().Format(common.SimpleTimeFormat),
|
|
Destination: &endTime,
|
|
},
|
|
&cli.IntFlag{
|
|
Name: "limit",
|
|
Aliases: []string{"l"},
|
|
Usage: "the number of positions (not orders) to return",
|
|
Value: 86400,
|
|
Destination: &limit,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "status",
|
|
Aliases: []string{"s"},
|
|
Usage: "limit return to position statuses - open, closed, any",
|
|
Value: "ANY",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "verbose",
|
|
Aliases: []string{"v"},
|
|
Usage: "includes all orders that make up a position in the response",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "overwrite",
|
|
Aliases: []string{"o"},
|
|
Usage: "if true, will overwrite futures results for the provided exchange, asset, pair",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getFuturesPositions(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, "getfuturesposition")
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
var currencyPair string
|
|
if c.IsSet("pair") {
|
|
currencyPair = c.String("pair")
|
|
} else {
|
|
currencyPair = c.Args().Get(2)
|
|
}
|
|
if !validPair(currencyPair) {
|
|
return errInvalidPair
|
|
}
|
|
|
|
p, err := currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !c.IsSet("start") {
|
|
if c.Args().Get(3) != "" {
|
|
startTime = c.Args().Get(3)
|
|
}
|
|
}
|
|
|
|
if !c.IsSet("end") {
|
|
if c.Args().Get(4) != "" {
|
|
endTime = c.Args().Get(4)
|
|
}
|
|
}
|
|
if c.IsSet("limit") {
|
|
limit = c.Int("limit")
|
|
} else if c.Args().Get(5) != "" {
|
|
var limit64 int64
|
|
limit64, err = strconv.ParseInt(c.Args().Get(5), 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
limit = int(limit64)
|
|
}
|
|
|
|
var status string
|
|
if c.IsSet("status") {
|
|
status = c.String("status")
|
|
} else if c.Args().Get(6) != "" {
|
|
status = c.Args().Get(6)
|
|
}
|
|
if !strings.EqualFold(status, "any") &&
|
|
!strings.EqualFold(status, "open") &&
|
|
!strings.EqualFold(status, "closed") &&
|
|
status != "" {
|
|
return errors.New("unrecognised status")
|
|
}
|
|
|
|
var verbose bool
|
|
if c.IsSet("verbose") {
|
|
verbose = c.Bool("verbose")
|
|
} else if c.Args().Get(7) != "" {
|
|
verbose, err = strconv.ParseBool(c.Args().Get(7))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var overwrite bool
|
|
if c.IsSet("overwrite") {
|
|
overwrite = c.Bool("overwrite")
|
|
} else if c.Args().Get(8) != "" {
|
|
overwrite, err = strconv.ParseBool(c.Args().Get(8))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var s, e time.Time
|
|
s, err = time.Parse(common.SimpleTimeFormat, startTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for start: %v", err)
|
|
}
|
|
e, err = time.Parse(common.SimpleTimeFormat, endTime)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid time format for end: %v", err)
|
|
}
|
|
|
|
if e.Before(s) {
|
|
return errors.New("start cannot be after end")
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetFuturesPositions(c.Context,
|
|
&gctrpc.GetFuturesPositionsRequest{
|
|
Exchange: exchangeName,
|
|
Asset: assetType,
|
|
Pair: &gctrpc.CurrencyPair{
|
|
Delimiter: p.Delimiter,
|
|
Base: p.Base.String(),
|
|
Quote: p.Quote.String(),
|
|
},
|
|
StartDate: negateLocalOffset(s),
|
|
EndDate: negateLocalOffset(e),
|
|
Status: status,
|
|
PositionLimit: int64(limit),
|
|
Verbose: verbose,
|
|
Overwrite: overwrite,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|
|
|
|
var getCollateralCommand = &cli.Command{
|
|
Name: "getcollateral",
|
|
Usage: "returns total collateral for an exchange asset, with optional per currency breakdown",
|
|
ArgsUsage: "<exchange> <asset> <calculateoffline> <includebreakdown> <includezerovalues>",
|
|
Action: getCollateral,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "exchange",
|
|
Aliases: []string{"e"},
|
|
Usage: "the exchange to retrieve futures positions from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "asset",
|
|
Aliases: []string{"a"},
|
|
Usage: "the asset type of the currency pair, must be a futures type",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "calculateoffline",
|
|
Aliases: []string{"c"},
|
|
Usage: "use local scaling calculations instead of requesting the collateral values directly, depending on individual exchange support",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "includebreakdown",
|
|
Aliases: []string{"i"},
|
|
Usage: "include a list of each held currency and its contribution to the overall collateral value",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "includezerovalues",
|
|
Aliases: []string{"z"},
|
|
Usage: "include collateral values that are zero",
|
|
},
|
|
},
|
|
}
|
|
|
|
func getCollateral(c *cli.Context) error {
|
|
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
return cli.ShowCommandHelp(c, c.Command.Name)
|
|
}
|
|
|
|
var exchangeName string
|
|
if c.IsSet("exchange") {
|
|
exchangeName = c.String("exchange")
|
|
} else {
|
|
exchangeName = c.Args().First()
|
|
}
|
|
|
|
var assetType string
|
|
if c.IsSet("asset") {
|
|
assetType = c.String("asset")
|
|
} else {
|
|
assetType = c.Args().Get(1)
|
|
}
|
|
|
|
if !validAsset(assetType) {
|
|
return errInvalidAsset
|
|
}
|
|
|
|
var err error
|
|
var calculateOffline bool
|
|
if c.IsSet("calculateoffline") {
|
|
calculateOffline = c.Bool("calculateoffline")
|
|
} else if c.Args().Get(2) != "" {
|
|
calculateOffline, err = strconv.ParseBool(c.Args().Get(2))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var includeBreakdown bool
|
|
if c.IsSet("includebreakdown") {
|
|
includeBreakdown = c.Bool("includebreakdown")
|
|
} else if c.Args().Get(3) != "" {
|
|
includeBreakdown, err = strconv.ParseBool(c.Args().Get(3))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var includeZeroValues bool
|
|
if c.IsSet("includezerovalues") {
|
|
includeZeroValues = c.Bool("includezerovalues")
|
|
} else if c.Args().Get(4) != "" {
|
|
includeZeroValues, err = strconv.ParseBool(c.Args().Get(4))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
conn, cancel, err := setupClient(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeConn(conn, cancel)
|
|
|
|
client := gctrpc.NewGoCryptoTraderClient(conn)
|
|
result, err := client.GetCollateral(c.Context,
|
|
&gctrpc.GetCollateralRequest{
|
|
Exchange: exchangeName,
|
|
Asset: assetType,
|
|
IncludeBreakdown: includeBreakdown,
|
|
CalculateOffline: calculateOffline,
|
|
IncludeZeroValues: includeZeroValues,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonOutput(result)
|
|
return nil
|
|
}
|