mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
engine/exchanges: Add exchange currency state subsystem (#774)
* state: Add management system (init) * linter: fix * engine: gofmt * gct: after merge fixup * documentation: add * rpc: implement services for testing * gctcli: gofmt state_management.go * documentation: reinstate lost information * state: Add pair check to determine trading operation * exchanges: add interface for specific state scoped subsystem functionality * engine/order_man: reduce code footprint using new method * RPC: implement pair trading request and change exported name to something specific to state * engine: add tests * engine: Add to withdraw manager * documentation: reinstate soxipy in contrib. list * engine: const fake name * Glorious: NITERINOS * merge: fix issues * engine: csm incorporate service name into log output * engine: fix linter issues * gct: fix tests * currencystate: remove management type * rpc: fix tests * backtester: fix tests * Update engine/currency_state_manager.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update engine/currency_state_manager.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/currencystate/currency_state.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/alert/alert.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/alert/alert.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * config: integrate with config and remove flag delay adjustment * gctcli: fix issues after name changes * engine: gofmt manager file * Update engine/rpcserver.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * engine: Add enable/disable manager functions, add default popoulation for potential assets * linter: fix * engine/test: bump subsystem count * Update engine/currency_state_manager.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/bithumb/bithumb.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits addressed * alert: fix commenting for its generalized purpose * glorious: nits * engine: use standard string in log output * bitfinex: apply patch, thanks @thrasher- * bitfinex: fix spelling * engine/currencystate: Add logs/fix logs Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
@@ -10,26 +10,26 @@ Rots | https://github.com/Rots
|
||||
vazha | https://github.com/vazha
|
||||
ermalguni | https://github.com/ermalguni
|
||||
MadCozBadd | https://github.com/MadCozBadd
|
||||
ydm | https://github.com/ydm
|
||||
vadimzhukck | https://github.com/vadimzhukck
|
||||
140am | https://github.com/140am
|
||||
marcofranssen | https://github.com/marcofranssen
|
||||
ydm | https://github.com/ydm
|
||||
lrascao | https://github.com/lrascao
|
||||
dackroyd | https://github.com/dackroyd
|
||||
cranktakular | https://github.com/cranktakular
|
||||
woshidama323 | https://github.com/woshidama323
|
||||
yangrq1018 | https://github.com/yangrq1018
|
||||
crackcomm | https://github.com/crackcomm
|
||||
azhang | https://github.com/azhang
|
||||
andreygrehov | https://github.com/andreygrehov
|
||||
bretep | https://github.com/bretep
|
||||
Christian-Achilli | https://github.com/Christian-Achilli
|
||||
lrascao | https://github.com/lrascao
|
||||
MarkDzulko | https://github.com/MarkDzulko
|
||||
yangrq1018 | https://github.com/yangrq1018
|
||||
TaltaM | https://github.com/TaltaM
|
||||
gam-phon | https://github.com/gam-phon
|
||||
cornelk | https://github.com/cornelk
|
||||
if1live | https://github.com/if1live
|
||||
lozdog245 | https://github.com/lozdog245
|
||||
soxipy | https://github.com/soxipy
|
||||
tk42 | https://github.com/tk42
|
||||
mshogin | https://github.com/mshogin
|
||||
herenow | https://github.com/herenow
|
||||
@@ -50,3 +50,4 @@ CodeLingoTeam | https://github.com/CodeLingoTeam
|
||||
Daanikus | https://github.com/Daanikus
|
||||
CodeLingoBot | https://github.com/CodeLingoBot
|
||||
blombard | https://github.com/blombard
|
||||
soxipy | https://github.com/soxipy
|
||||
|
||||
17
README.md
17
README.md
@@ -142,36 +142,36 @@ Binaries will be published once the codebase reaches a stable condition.
|
||||
|
||||
|User|Contribution Amount|
|
||||
|--|--|
|
||||
| [thrasher-](https://github.com/thrasher-) | 656 |
|
||||
| [shazbert](https://github.com/shazbert) | 214 |
|
||||
| [gloriousCode](https://github.com/gloriousCode) | 189 |
|
||||
| [thrasher-](https://github.com/thrasher-) | 658 |
|
||||
| [shazbert](https://github.com/shazbert) | 222 |
|
||||
| [gloriousCode](https://github.com/gloriousCode) | 190 |
|
||||
| [dependabot-preview[bot]](https://github.com/apps/dependabot-preview) | 88 |
|
||||
| [xtda](https://github.com/xtda) | 47 |
|
||||
| [dependabot[bot]](https://github.com/apps/dependabot) | 20 |
|
||||
| [dependabot[bot]](https://github.com/apps/dependabot) | 22 |
|
||||
| [Rots](https://github.com/Rots) | 15 |
|
||||
| [vazha](https://github.com/vazha) | 15 |
|
||||
| [ermalguni](https://github.com/ermalguni) | 14 |
|
||||
| [MadCozBadd](https://github.com/MadCozBadd) | 13 |
|
||||
| [ydm](https://github.com/ydm) | 11 |
|
||||
| [vadimzhukck](https://github.com/vadimzhukck) | 10 |
|
||||
| [140am](https://github.com/140am) | 8 |
|
||||
| [marcofranssen](https://github.com/marcofranssen) | 8 |
|
||||
| [ydm](https://github.com/ydm) | 8 |
|
||||
| [lrascao](https://github.com/lrascao) | 6 |
|
||||
| [dackroyd](https://github.com/dackroyd) | 5 |
|
||||
| [cranktakular](https://github.com/cranktakular) | 5 |
|
||||
| [woshidama323](https://github.com/woshidama323) | 3 |
|
||||
| [yangrq1018](https://github.com/yangrq1018) | 3 |
|
||||
| [crackcomm](https://github.com/crackcomm) | 3 |
|
||||
| [azhang](https://github.com/azhang) | 2 |
|
||||
| [andreygrehov](https://github.com/andreygrehov) | 2 |
|
||||
| [bretep](https://github.com/bretep) | 2 |
|
||||
| [Christian-Achilli](https://github.com/Christian-Achilli) | 2 |
|
||||
| [lrascao](https://github.com/lrascao) | 2 |
|
||||
| [MarkDzulko](https://github.com/MarkDzulko) | 2 |
|
||||
| [yangrq1018](https://github.com/yangrq1018) | 2 |
|
||||
| [TaltaM](https://github.com/TaltaM) | 2 |
|
||||
| [gam-phon](https://github.com/gam-phon) | 2 |
|
||||
| [cornelk](https://github.com/cornelk) | 2 |
|
||||
| [if1live](https://github.com/if1live) | 2 |
|
||||
| [lozdog245](https://github.com/lozdog245) | 2 |
|
||||
| [soxipy](https://github.com/soxipy) | 2 |
|
||||
| [tk42](https://github.com/tk42) | 2 |
|
||||
| [mshogin](https://github.com/mshogin) | 2 |
|
||||
| [herenow](https://github.com/herenow) | 2 |
|
||||
@@ -192,3 +192,4 @@ Binaries will be published once the codebase reaches a stable condition.
|
||||
| [Daanikus](https://github.com/Daanikus) | 1 |
|
||||
| [CodeLingoBot](https://github.com/CodeLingoBot) | 1 |
|
||||
| [blombard](https://github.com/blombard) | 1 |
|
||||
| [soxipy](https://github.com/soxipy) | 2 |
|
||||
|
||||
@@ -141,6 +141,14 @@ func TestPlaceOrder(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exch.SetDefaults()
|
||||
cfg, err := exch.GetDefaultConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exch.Setup(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
em.Add(exch)
|
||||
bot.ExchangeManager = em
|
||||
bot.OrderManager, err = engine.SetupOrderManager(em, &engine.CommunicationManager{}, &bot.ServicesWG, false)
|
||||
@@ -191,6 +199,14 @@ func TestExecuteOrder(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exch.SetDefaults()
|
||||
cfg, err := exch.GetDefaultConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exch.Setup(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
em.Add(exch)
|
||||
bot.ExchangeManager = em
|
||||
bot.OrderManager, err = engine.SetupOrderManager(em, &engine.CommunicationManager{}, &bot.ServicesWG, false)
|
||||
@@ -287,6 +303,15 @@ func TestExecuteOrderBuySellSizeLimit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exch.SetDefaults()
|
||||
cfg, err := exch.GetDefaultConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exch.Setup(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
em.Add(exch)
|
||||
bot.ExchangeManager = em
|
||||
bot.OrderManager, err = engine.SetupOrderManager(em, &engine.CommunicationManager{}, &bot.ServicesWG, false)
|
||||
|
||||
@@ -273,6 +273,11 @@ func main() {
|
||||
URL: "https://github.com/blombard",
|
||||
Contributions: 1,
|
||||
},
|
||||
{
|
||||
Login: "soxipy",
|
||||
URL: "https://github.com/soxipy",
|
||||
Contributions: 2,
|
||||
},
|
||||
}...)
|
||||
|
||||
if verbose {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{{define "engine currency_state_manager" -}}
|
||||
{{template "header" .}}
|
||||
## Current Features for {{.CapitalName}}
|
||||
+ The state manager keeps currency states up to date, which include:
|
||||
* Withdrawal - Determines if the currency is allowed to be withdrawn from the exchange.
|
||||
* Deposit - Determines if the currency is allowed to be deposited to an exchange.
|
||||
* Trading - Determines if the currency is allowed to be traded on the exchange.
|
||||
|
||||
+ This allows for an internal state check to compliment internal and external
|
||||
strategies.
|
||||
|
||||
{{template "contributions"}}
|
||||
{{template "donations" .}}
|
||||
{{end}}
|
||||
@@ -11,6 +11,11 @@ implementation
|
||||
|
||||
+ A guide on implementing API support for a new exchange can be found [here](../docs/ADD_NEW_EXCHANGE.md)
|
||||
|
||||
## websocket notes
|
||||
|
||||
+ If contributing websocket improvements, please make sure order reports
|
||||
follow [these rules](../docs/WS_ORDER_EVENTS.md).
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
{{template "contributions"}}
|
||||
{{template "donations" .}}
|
||||
|
||||
300
cmd/gctcli/currency_state_management.go
Normal file
300
cmd/gctcli/currency_state_management.go
Normal file
@@ -0,0 +1,300 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/thrasher-corp/gocryptotrader/gctrpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var currencyStateManagementCommand = &cli.Command{
|
||||
Name: "currencystate",
|
||||
Usage: "execute exchange currency state management command",
|
||||
ArgsUsage: "<command> <args>",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "getall",
|
||||
Usage: "fetch all currency states associated with an exchange",
|
||||
ArgsUsage: "<exchange>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "exchange",
|
||||
Usage: "the exchange to act on",
|
||||
},
|
||||
},
|
||||
Action: stateGetAll,
|
||||
},
|
||||
{
|
||||
Name: "withdraw",
|
||||
Usage: "returns if the currency can be withdrawn from the exchange",
|
||||
ArgsUsage: "<exchange> <code> <asset>",
|
||||
Flags: stateFlags,
|
||||
Action: stateGetWithdrawal,
|
||||
},
|
||||
{
|
||||
Name: "deposit",
|
||||
Usage: "returns if the currency can be deposited onto an exchange",
|
||||
ArgsUsage: "<exchange> <code> <asset>",
|
||||
Flags: stateFlags,
|
||||
Action: stateGetDeposit,
|
||||
},
|
||||
{
|
||||
Name: "trade",
|
||||
Usage: "returns if the currency can be traded on the exchange",
|
||||
ArgsUsage: "<exchange> <code> <asset>",
|
||||
Flags: stateFlags,
|
||||
Action: stateGetTrading,
|
||||
},
|
||||
{
|
||||
Name: "tradepair",
|
||||
Usage: "returns if the currency pair can be traded on the exchange",
|
||||
ArgsUsage: "<exchange> <pair> <asset>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "exchange",
|
||||
Usage: "the exchange to act on",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pair",
|
||||
Usage: "the currency pair e.g. btc-usd",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "asset",
|
||||
Usage: "the asset type",
|
||||
},
|
||||
},
|
||||
Action: stateGetPairTrading,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var stateFlags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "exchange",
|
||||
Usage: "the exchange to act on",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "code",
|
||||
Usage: "the currency code",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "asset",
|
||||
Usage: "the asset type",
|
||||
},
|
||||
}
|
||||
|
||||
func stateGetAll(c *cli.Context) error {
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
|
||||
var exchange string
|
||||
if c.IsSet("exchange") {
|
||||
exchange = c.String("exchange")
|
||||
} else {
|
||||
exchange = c.Args().First()
|
||||
}
|
||||
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
client := gctrpc.NewGoCryptoTraderClient(conn)
|
||||
result, err := client.CurrencyStateGetAll(c.Context,
|
||||
&gctrpc.CurrencyStateGetAllRequest{Exchange: exchange},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
jsonOutput(result)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func stateGetDeposit(c *cli.Context) error {
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
|
||||
var exchange string
|
||||
if c.IsSet("exchange") {
|
||||
exchange = c.String("exchange")
|
||||
} else {
|
||||
exchange = c.Args().First()
|
||||
}
|
||||
|
||||
var code string
|
||||
if c.IsSet("code") {
|
||||
code = c.String("code")
|
||||
} else {
|
||||
code = c.Args().Get(1)
|
||||
}
|
||||
|
||||
var a string
|
||||
if c.IsSet("asset") {
|
||||
a = c.String("asset")
|
||||
} else {
|
||||
a = 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.CurrencyStateDeposit(c.Context,
|
||||
&gctrpc.CurrencyStateDepositRequest{
|
||||
Exchange: exchange,
|
||||
Code: code,
|
||||
Asset: a},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
func stateGetWithdrawal(c *cli.Context) error {
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
|
||||
var exchange string
|
||||
if c.IsSet("exchange") {
|
||||
exchange = c.String("exchange")
|
||||
} else {
|
||||
exchange = c.Args().First()
|
||||
}
|
||||
|
||||
var code string
|
||||
if c.IsSet("code") {
|
||||
code = c.String("code")
|
||||
} else {
|
||||
code = c.Args().Get(1)
|
||||
}
|
||||
|
||||
var a string
|
||||
if c.IsSet("asset") {
|
||||
a = c.String("asset")
|
||||
} else {
|
||||
a = 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.CurrencyStateWithdraw(c.Context,
|
||||
&gctrpc.CurrencyStateWithdrawRequest{
|
||||
Exchange: exchange,
|
||||
Code: code,
|
||||
Asset: a},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
func stateGetTrading(c *cli.Context) error {
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
|
||||
var exchange string
|
||||
if c.IsSet("exchange") {
|
||||
exchange = c.String("exchange")
|
||||
} else {
|
||||
exchange = c.Args().First()
|
||||
}
|
||||
|
||||
var code string
|
||||
if c.IsSet("code") {
|
||||
code = c.String("code")
|
||||
} else {
|
||||
code = c.Args().Get(1)
|
||||
}
|
||||
|
||||
var a string
|
||||
if c.IsSet("asset") {
|
||||
a = c.String("asset")
|
||||
} else {
|
||||
a = 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.CurrencyStateTrading(c.Context,
|
||||
&gctrpc.CurrencyStateTradingRequest{
|
||||
Exchange: exchange,
|
||||
Code: code,
|
||||
Asset: a},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
func stateGetPairTrading(c *cli.Context) error {
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
|
||||
var exchange string
|
||||
if c.IsSet("exchange") {
|
||||
exchange = c.String("exchange")
|
||||
} else {
|
||||
exchange = c.Args().First()
|
||||
}
|
||||
|
||||
var pair string
|
||||
if c.IsSet("pair") {
|
||||
pair = c.String("pair")
|
||||
} else {
|
||||
pair = c.Args().Get(1)
|
||||
}
|
||||
|
||||
var a string
|
||||
if c.IsSet("asset") {
|
||||
a = c.String("asset")
|
||||
} else {
|
||||
a = 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.CurrencyStateTradingPair(c.Context,
|
||||
&gctrpc.CurrencyStateTradingPairRequest{
|
||||
Exchange: exchange,
|
||||
Pair: pair,
|
||||
Asset: a},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
@@ -161,6 +161,7 @@ func main() {
|
||||
websocketManagerCommand,
|
||||
tradeCommand,
|
||||
dataHistoryCommands,
|
||||
currencyStateManagementCommand,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@@ -1422,6 +1422,19 @@ func (c *Config) CheckDataHistoryMonitorConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
// CheckCurrencyStateManager ensures the currency state config is valid, or sets
|
||||
// default values
|
||||
func (c *Config) CheckCurrencyStateManager() {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
if c.CurrencyStateManager.Delay <= 0 {
|
||||
c.CurrencyStateManager.Delay = defaultCurrencyStateManagerDelay
|
||||
}
|
||||
if c.CurrencyStateManager.Enabled == nil { // default on, when being upgraded
|
||||
c.CurrencyStateManager.Enabled = convert.BoolPtr(true)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckConnectionMonitorConfig checks and if zero value assigns default values
|
||||
func (c *Config) CheckConnectionMonitorConfig() {
|
||||
m.Lock()
|
||||
@@ -1769,6 +1782,7 @@ func (c *Config) CheckConfig() error {
|
||||
|
||||
c.CheckConnectionMonitorConfig()
|
||||
c.CheckDataHistoryMonitorConfig()
|
||||
c.CheckCurrencyStateManager()
|
||||
c.CheckCommunicationsConfig()
|
||||
c.CheckClientBankAccounts()
|
||||
c.CheckBankAccountConfig()
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
DefaultAPISecret = "Secret"
|
||||
DefaultAPIClientID = "ClientID"
|
||||
defaultDataHistoryMonitorCheckTimer = time.Minute
|
||||
defaultCurrencyStateManagerDelay = time.Minute
|
||||
defaultMaxJobsPerCycle = 5
|
||||
)
|
||||
|
||||
@@ -72,23 +73,24 @@ var (
|
||||
// prestart management of Portfolio, Communications, Webserver and Enabled
|
||||
// Exchanges
|
||||
type Config struct {
|
||||
Name string `json:"name"`
|
||||
DataDirectory string `json:"dataDirectory"`
|
||||
EncryptConfig int `json:"encryptConfig"`
|
||||
GlobalHTTPTimeout time.Duration `json:"globalHTTPTimeout"`
|
||||
Database database.Config `json:"database"`
|
||||
Logging log.Config `json:"logging"`
|
||||
ConnectionMonitor ConnectionMonitorConfig `json:"connectionMonitor"`
|
||||
DataHistoryManager DataHistoryManager `json:"dataHistoryManager"`
|
||||
Profiler Profiler `json:"profiler"`
|
||||
NTPClient NTPClientConfig `json:"ntpclient"`
|
||||
GCTScript gctscript.Config `json:"gctscript"`
|
||||
Currency CurrencyConfig `json:"currencyConfig"`
|
||||
Communications base.CommunicationsConfig `json:"communications"`
|
||||
RemoteControl RemoteControlConfig `json:"remoteControl"`
|
||||
Portfolio portfolio.Base `json:"portfolioAddresses"`
|
||||
Exchanges []ExchangeConfig `json:"exchanges"`
|
||||
BankAccounts []banking.Account `json:"bankAccounts"`
|
||||
Name string `json:"name"`
|
||||
DataDirectory string `json:"dataDirectory"`
|
||||
EncryptConfig int `json:"encryptConfig"`
|
||||
GlobalHTTPTimeout time.Duration `json:"globalHTTPTimeout"`
|
||||
Database database.Config `json:"database"`
|
||||
Logging log.Config `json:"logging"`
|
||||
ConnectionMonitor ConnectionMonitorConfig `json:"connectionMonitor"`
|
||||
DataHistoryManager DataHistoryManager `json:"dataHistoryManager"`
|
||||
CurrencyStateManager CurrencyStateManager `json:"currencyStateManager"`
|
||||
Profiler Profiler `json:"profiler"`
|
||||
NTPClient NTPClientConfig `json:"ntpclient"`
|
||||
GCTScript gctscript.Config `json:"gctscript"`
|
||||
Currency CurrencyConfig `json:"currencyConfig"`
|
||||
Communications base.CommunicationsConfig `json:"communications"`
|
||||
RemoteControl RemoteControlConfig `json:"remoteControl"`
|
||||
Portfolio portfolio.Base `json:"portfolioAddresses"`
|
||||
Exchanges []ExchangeConfig `json:"exchanges"`
|
||||
BankAccounts []banking.Account `json:"bankAccounts"`
|
||||
|
||||
// Deprecated config settings, will be removed at a future date
|
||||
Webserver *WebserverConfig `json:"webserver,omitempty"`
|
||||
@@ -110,6 +112,13 @@ type DataHistoryManager struct {
|
||||
Verbose bool `json:"verbose"`
|
||||
}
|
||||
|
||||
// CurrencyStateManager defines a set of configuration options for the currency
|
||||
// state manager
|
||||
type CurrencyStateManager struct {
|
||||
Enabled *bool `json:"enabled"`
|
||||
Delay time.Duration `json:"delay"`
|
||||
}
|
||||
|
||||
// ConnectionMonitorConfig defines the connection monitor variables to ensure
|
||||
// that there is internet connectivity
|
||||
type ConnectionMonitorConfig struct {
|
||||
|
||||
276
engine/currency_state_manager.go
Normal file
276
engine/currency_state_manager.go
Normal file
@@ -0,0 +1,276 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctrpc"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// CurrencyStateManagementName defines the manager name string
|
||||
CurrencyStateManagementName = "currency_state_manager"
|
||||
// DefaultStateManagerDelay defines the default duration when the manager
|
||||
// fetches and updates each exchange for its currency state
|
||||
DefaultStateManagerDelay = time.Minute
|
||||
)
|
||||
|
||||
var enabled = &gctrpc.GenericResponse{Status: "enabled"}
|
||||
|
||||
// CurrencyStateManager manages currency states
|
||||
type CurrencyStateManager struct {
|
||||
started int32
|
||||
shutdown chan struct{}
|
||||
wg sync.WaitGroup
|
||||
iExchangeManager
|
||||
sleep time.Duration
|
||||
}
|
||||
|
||||
// SetupCurrencyStateManager applies configuration parameters before running
|
||||
func SetupCurrencyStateManager(interval time.Duration, em iExchangeManager) (*CurrencyStateManager, error) {
|
||||
if em == nil {
|
||||
return nil, errNilExchangeManager
|
||||
}
|
||||
var c CurrencyStateManager
|
||||
if interval <= 0 {
|
||||
log.Warnf(log.ExchangeSys,
|
||||
"Currency state manager interval is invalid, defaulting to: %s",
|
||||
DefaultStateManagerDelay)
|
||||
interval = DefaultStateManagerDelay
|
||||
}
|
||||
c.sleep = interval
|
||||
c.iExchangeManager = em
|
||||
c.shutdown = make(chan struct{})
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// Start runs the subsystem
|
||||
func (c *CurrencyStateManager) Start() error {
|
||||
log.Debugln(log.ExchangeSys, "Currency state manager starting...")
|
||||
if c == nil {
|
||||
return fmt.Errorf("%s %w", CurrencyStateManagementName, ErrNilSubsystem)
|
||||
}
|
||||
|
||||
if !atomic.CompareAndSwapInt32(&c.started, 0, 1) {
|
||||
return fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemAlreadyStarted)
|
||||
}
|
||||
c.wg.Add(1)
|
||||
go c.monitor()
|
||||
log.Debugln(log.ExchangeSys, "Currency state manager started.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the subsystem
|
||||
func (c *CurrencyStateManager) Stop() error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("%s %w", CurrencyStateManagementName, ErrNilSubsystem)
|
||||
}
|
||||
if atomic.LoadInt32(&c.started) == 0 {
|
||||
return fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
log.Debugf(log.ExchangeSys, "Currency state manager %s", MsgSubSystemShuttingDown)
|
||||
close(c.shutdown)
|
||||
c.wg.Wait()
|
||||
c.shutdown = make(chan struct{})
|
||||
log.Debugf(log.ExchangeSys, "Currency state manager %s", MsgSubSystemShutdown)
|
||||
atomic.StoreInt32(&c.started, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning safely checks whether the subsystem is running
|
||||
func (c *CurrencyStateManager) IsRunning() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return atomic.LoadInt32(&c.started) == 1
|
||||
}
|
||||
|
||||
func (c *CurrencyStateManager) monitor() {
|
||||
defer c.wg.Done()
|
||||
timer := time.NewTimer(0) // Prime firing of channel for initial sync.
|
||||
for {
|
||||
select {
|
||||
case <-c.shutdown:
|
||||
return
|
||||
case <-timer.C:
|
||||
var wg sync.WaitGroup
|
||||
exchs, err := c.GetExchanges()
|
||||
if err != nil {
|
||||
log.Errorf(log.Global,
|
||||
"Currency state manager failed to get exchanges error: %v",
|
||||
err)
|
||||
}
|
||||
for x := range exchs {
|
||||
wg.Add(1)
|
||||
go c.update(exchs[x], &wg, exchs[x].GetAssetTypes(true))
|
||||
}
|
||||
wg.Wait() // This causes some variability in the timer due to
|
||||
// longest length of request time. Can do time.Ticker but don't
|
||||
// want routines to stack behind, this is more uniform.
|
||||
timer.Reset(c.sleep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CurrencyStateManager) update(exch exchange.IBotExchange, wg *sync.WaitGroup, enabledAssets asset.Items) {
|
||||
defer wg.Done()
|
||||
for y := range enabledAssets {
|
||||
err := exch.UpdateCurrencyStates(context.TODO(), enabledAssets[y])
|
||||
if err != nil {
|
||||
if errors.Is(err, common.ErrNotYetImplemented) {
|
||||
// Deploy default values for outbound gRPC aspects.
|
||||
var pairs currency.Pairs
|
||||
pairs, err = exch.GetAvailablePairs(enabledAssets[y])
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "Currency state manager %s %s: %v",
|
||||
exch.GetName(),
|
||||
enabledAssets[y],
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
// Deploys a full spectrum supported list for the currency states
|
||||
update := map[currency.Code]currencystate.Options{}
|
||||
for x := range pairs {
|
||||
update[pairs[x].Base] = currencystate.Options{}
|
||||
update[pairs[x].Quote] = currencystate.Options{}
|
||||
}
|
||||
|
||||
b := exch.GetBase()
|
||||
if b == nil {
|
||||
log.Errorf(log.ExchangeSys, "Currency state manager %s %s: %v",
|
||||
exch.GetName(),
|
||||
enabledAssets[y],
|
||||
"cannot update because base is nil")
|
||||
return
|
||||
}
|
||||
err = b.States.UpdateAll(enabledAssets[y], update)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "Currency state manager %s %s: %v",
|
||||
exch.GetName(),
|
||||
enabledAssets[y],
|
||||
err)
|
||||
}
|
||||
return
|
||||
}
|
||||
log.Errorf(log.ExchangeSys, "Currency state manager %s %s: %v",
|
||||
exch.GetName(),
|
||||
enabledAssets[y],
|
||||
err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllRPC returns a full snapshot of currency states, whether they are able
|
||||
// to be withdrawn, deposited or traded on an exchange for RPC.
|
||||
func (c *CurrencyStateManager) GetAllRPC(exchName string) (*gctrpc.CurrencyStateResponse, error) {
|
||||
if !c.IsRunning() {
|
||||
return nil, fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemNotStarted)
|
||||
}
|
||||
exch, err := c.GetExchangeByName(exchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sh, err := exch.GetCurrencyStateSnapshot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp = &gctrpc.CurrencyStateResponse{}
|
||||
for x := range sh {
|
||||
resp.CurrencyStates = append(resp.CurrencyStates, &gctrpc.CurrencyState{
|
||||
Currency: sh[x].Code.String(),
|
||||
Asset: sh[x].Asset.String(),
|
||||
WithdrawEnabled: sh[x].Withdraw == nil || *sh[x].Withdraw,
|
||||
DepositEnabled: sh[x].Deposit == nil || *sh[x].Deposit,
|
||||
TradingEnabled: sh[x].Trade == nil || *sh[x].Trade,
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// CanWithdrawRPC determines if the currency code is operational for withdrawal
|
||||
// from an exchange for RPC
|
||||
func (c *CurrencyStateManager) CanWithdrawRPC(exchName string, cc currency.Code, a asset.Item) (*gctrpc.GenericResponse, error) {
|
||||
if !c.IsRunning() {
|
||||
return nil, fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
exch, err := c.GetExchangeByName(exchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = exch.CanWithdraw(cc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enabled, nil
|
||||
}
|
||||
|
||||
// CanDepositRPC determines if the currency code is operational for depositing
|
||||
// to an exchange for RPC
|
||||
func (c *CurrencyStateManager) CanDepositRPC(exchName string, cc currency.Code, a asset.Item) (*gctrpc.GenericResponse, error) {
|
||||
if !c.IsRunning() {
|
||||
return nil, fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
exch, err := c.GetExchangeByName(exchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = exch.CanDeposit(cc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enabled, nil
|
||||
}
|
||||
|
||||
// CanTradeRPC determines if the currency code is operational for trading for
|
||||
// RPC
|
||||
func (c *CurrencyStateManager) CanTradeRPC(exchName string, cc currency.Code, a asset.Item) (*gctrpc.GenericResponse, error) {
|
||||
if !c.IsRunning() {
|
||||
return nil, fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
exch, err := c.GetExchangeByName(exchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = exch.CanTrade(cc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enabled, nil
|
||||
}
|
||||
|
||||
// CanTradePairRPC determines if the pair is operational for trading for RPC
|
||||
func (c *CurrencyStateManager) CanTradePairRPC(exchName string, pair currency.Pair, a asset.Item) (*gctrpc.GenericResponse, error) {
|
||||
if !c.IsRunning() {
|
||||
return nil, fmt.Errorf("%s %w", CurrencyStateManagementName, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
exch, err := c.GetExchangeByName(exchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = exch.CanTradePair(pair, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enabled, nil
|
||||
}
|
||||
48
engine/currency_state_manager.md
Normal file
48
engine/currency_state_manager.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# GoCryptoTrader package State manager
|
||||
|
||||
<img src="/common/gctlogo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/engine/state_manager)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This state_manager package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progress on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk)
|
||||
|
||||
## Current Features for State manager
|
||||
+ The state manager keeps currency states up to date, which include:
|
||||
* Withdrawal - Determines if the currency is allowed to be withdrawn from the exchange.
|
||||
* Deposit - Determines if the currency is allowed to be deposited to an exchange.
|
||||
* Trading - Determines if the currency is allowed to be traded on the exchange.
|
||||
|
||||
+ This allows for an internal state check to compliment internal and external
|
||||
strategies.
|
||||
|
||||
|
||||
## Contribution
|
||||
|
||||
Please feel free to submit any pull requests or suggest any desired features to be added.
|
||||
|
||||
When submitting a PR, please abide by our coding guidelines:
|
||||
|
||||
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***
|
||||
376
engine/currency_state_manager_test.go
Normal file
376
engine/currency_state_manager_test.go
Normal file
@@ -0,0 +1,376 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
)
|
||||
|
||||
func TestSetupCurrencyStateManager(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := SetupCurrencyStateManager(0, nil)
|
||||
if !errors.Is(err, errNilExchangeManager) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNilExchangeManager)
|
||||
}
|
||||
|
||||
cm, err := SetupCurrencyStateManager(0, &ExchangeManager{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
if cm.sleep != DefaultStateManagerDelay {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errManager = errors.New("manager level error")
|
||||
errExchange = errors.New("exchange level error")
|
||||
)
|
||||
|
||||
type fakeExchangeManagerino struct {
|
||||
ErrorMeOne bool
|
||||
ErrorMeTwo bool
|
||||
}
|
||||
|
||||
func (f *fakeExchangeManagerino) GetExchanges() ([]exchange.IBotExchange, error) {
|
||||
if f.ErrorMeOne {
|
||||
return nil, errManager
|
||||
}
|
||||
return []exchange.IBotExchange{&fakerino{errorMe: f.ErrorMeTwo}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeExchangeManagerino) GetExchangeByName(_ string) (exchange.IBotExchange, error) {
|
||||
if f.ErrorMeOne {
|
||||
return nil, errManager
|
||||
}
|
||||
return &fakerino{errorMe: f.ErrorMeTwo}, nil
|
||||
}
|
||||
|
||||
type fakerino struct {
|
||||
exchange.IBotExchange
|
||||
errorMe bool
|
||||
GetAvailablePairsError bool
|
||||
GetBaseError bool
|
||||
}
|
||||
|
||||
func (f *fakerino) UpdateCurrencyStates(_ context.Context, _ asset.Item) error {
|
||||
if f.errorMe {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakerino) GetAssetTypes(_ bool) asset.Items {
|
||||
return asset.Items{asset.Spot}
|
||||
}
|
||||
|
||||
func (f *fakerino) GetName() string {
|
||||
return "testssssssssssssss"
|
||||
}
|
||||
|
||||
func (f *fakerino) GetCurrencyStateSnapshot() ([]currencystate.Snapshot, error) {
|
||||
if f.errorMe {
|
||||
return nil, errExchange
|
||||
}
|
||||
return []currencystate.Snapshot{
|
||||
{Code: currency.SHORTY, Asset: asset.Spot},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *fakerino) CanWithdraw(c currency.Code, a asset.Item) error {
|
||||
if f.errorMe {
|
||||
return errExchange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakerino) CanDeposit(c currency.Code, a asset.Item) error {
|
||||
if f.errorMe {
|
||||
return errExchange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakerino) CanTrade(c currency.Code, a asset.Item) error {
|
||||
if f.errorMe {
|
||||
return errExchange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakerino) CanTradePair(p currency.Pair, a asset.Item) error {
|
||||
if f.errorMe {
|
||||
return errExchange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakerino) GetAvailablePairs(a asset.Item) (currency.Pairs, error) {
|
||||
if f.GetAvailablePairsError {
|
||||
return nil, errExchange
|
||||
}
|
||||
return currency.Pairs{currency.NewPair(currency.BTC, currency.USD)}, nil
|
||||
}
|
||||
|
||||
func (f *fakerino) GetBase() *exchange.Base {
|
||||
if f.GetBaseError {
|
||||
return nil
|
||||
}
|
||||
return &exchange.Base{States: currencystate.NewCurrencyStates()}
|
||||
}
|
||||
|
||||
func TestCurrencyStateManagerIsRunning(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*CurrencyStateManager)(nil).Stop()
|
||||
if !errors.Is(err, ErrNilSubsystem) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrNilSubsystem)
|
||||
}
|
||||
|
||||
err = (&CurrencyStateManager{}).Stop()
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
err = (&CurrencyStateManager{started: 1, shutdown: make(chan struct{})}).Stop()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
err = (*CurrencyStateManager)(nil).Start()
|
||||
if !errors.Is(err, ErrNilSubsystem) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrNilSubsystem)
|
||||
}
|
||||
|
||||
err = (&CurrencyStateManager{started: 1}).Start()
|
||||
if !errors.Is(err, ErrSubSystemAlreadyStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemAlreadyStarted)
|
||||
}
|
||||
|
||||
man := &CurrencyStateManager{
|
||||
shutdown: make(chan struct{}),
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeOne: true},
|
||||
sleep: time.Minute}
|
||||
err = man.Start()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
err = man.Stop()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
man.iExchangeManager = &fakeExchangeManagerino{ErrorMeOne: true}
|
||||
err = man.Start()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
err = man.Stop()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
man.iExchangeManager = &fakeExchangeManagerino{ErrorMeOne: true}
|
||||
err = man.Start()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
if !man.IsRunning() {
|
||||
t.Fatal("this should be running")
|
||||
}
|
||||
|
||||
err = man.Stop()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
if man.IsRunning() {
|
||||
t.Fatal("this should be stopped")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllRPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*CurrencyStateManager)(nil).GetAllRPC("")
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeOne: true},
|
||||
}).GetAllRPC("")
|
||||
if !errors.Is(err, errManager) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errManager)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeTwo: true},
|
||||
}).GetAllRPC("")
|
||||
if !errors.Is(err, errExchange) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errExchange)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{},
|
||||
}).GetAllRPC("")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanWithdrawRPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*CurrencyStateManager)(nil).CanWithdrawRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeOne: true},
|
||||
}).CanWithdrawRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, errManager) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errManager)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeTwo: true},
|
||||
}).CanWithdrawRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, errExchange) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errExchange)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{},
|
||||
}).CanWithdrawRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanDepositRPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*CurrencyStateManager)(nil).CanDepositRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeOne: true},
|
||||
}).CanDepositRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, errManager) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errManager)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeTwo: true},
|
||||
}).CanDepositRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, errExchange) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errExchange)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{},
|
||||
}).CanDepositRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanTradeRPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*CurrencyStateManager)(nil).CanTradeRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeOne: true},
|
||||
}).CanTradeRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, errManager) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errManager)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeTwo: true},
|
||||
}).CanTradeRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, errExchange) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errExchange)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{},
|
||||
}).CanTradeRPC("", currency.Code{}, "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanTradePairRPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*CurrencyStateManager)(nil).CanTradePairRPC("", currency.Pair{}, "")
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeOne: true},
|
||||
}).CanTradePairRPC("", currency.Pair{}, "")
|
||||
if !errors.Is(err, errManager) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errManager)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{ErrorMeTwo: true},
|
||||
}).CanTradePairRPC("", currency.Pair{}, "")
|
||||
if !errors.Is(err, errExchange) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errExchange)
|
||||
}
|
||||
|
||||
_, err = (&CurrencyStateManager{
|
||||
started: 1,
|
||||
iExchangeManager: &fakeExchangeManagerino{},
|
||||
}).CanTradePairRPC("", currency.Pair{}, "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
man := &CurrencyStateManager{}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(3)
|
||||
man.update(&fakerino{errorMe: true, GetAvailablePairsError: true}, &wg, asset.Items{asset.Spot})
|
||||
man.update(&fakerino{errorMe: true, GetBaseError: true}, &wg, asset.Items{asset.Spot})
|
||||
man.update(&fakerino{errorMe: true}, &wg, asset.Items{asset.Spot})
|
||||
}
|
||||
@@ -46,6 +46,7 @@ type Engine struct {
|
||||
websocketRoutineManager *websocketRoutineManager
|
||||
WithdrawManager *WithdrawManager
|
||||
dataHistoryManager *DataHistoryManager
|
||||
currencyStateManager *CurrencyStateManager
|
||||
Settings Settings
|
||||
uptime time.Time
|
||||
ServicesWG sync.WaitGroup
|
||||
@@ -145,13 +146,17 @@ func validateSettings(b *Engine, s *Settings, flagSet map[string]bool) {
|
||||
|
||||
b.Settings.EnableDataHistoryManager = (flagSet["datahistorymanager"] && b.Settings.EnableDatabaseManager) || b.Config.DataHistoryManager.Enabled
|
||||
|
||||
b.Settings.EnableCurrencyStateManager = (flagSet["currencystatemanager"] &&
|
||||
b.Settings.EnableCurrencyStateManager) ||
|
||||
b.Config.CurrencyStateManager.Enabled != nil &&
|
||||
*b.Config.CurrencyStateManager.Enabled
|
||||
|
||||
b.Settings.EnableGCTScriptManager = b.Settings.EnableGCTScriptManager &&
|
||||
(flagSet["gctscriptmanager"] || b.Config.GCTScript.Enabled)
|
||||
|
||||
if b.Settings.EnablePortfolioManager {
|
||||
if b.Settings.PortfolioManagerDelay <= 0 {
|
||||
b.Settings.PortfolioManagerDelay = PortfolioSleepDelay
|
||||
}
|
||||
if b.Settings.EnablePortfolioManager &&
|
||||
b.Settings.PortfolioManagerDelay <= 0 {
|
||||
b.Settings.PortfolioManagerDelay = PortfolioSleepDelay
|
||||
}
|
||||
|
||||
if !flagSet["grpc"] {
|
||||
@@ -242,6 +247,7 @@ func PrintSettings(s *Settings) {
|
||||
gctlog.Debugf(gctlog.Global, "\t Enable coinmarketcap analaysis: %v", s.EnableCoinmarketcapAnalysis)
|
||||
gctlog.Debugf(gctlog.Global, "\t Enable portfolio manager: %v", s.EnablePortfolioManager)
|
||||
gctlog.Debugf(gctlog.Global, "\t Enable data history manager: %v", s.EnableDataHistoryManager)
|
||||
gctlog.Debugf(gctlog.Global, "\t Enable currency state manager: %v", s.EnableCurrencyStateManager)
|
||||
gctlog.Debugf(gctlog.Global, "\t Portfolio manager sleep delay: %v\n", s.PortfolioManagerDelay)
|
||||
gctlog.Debugf(gctlog.Global, "\t Enable gPRC: %v", s.EnableGRPC)
|
||||
gctlog.Debugf(gctlog.Global, "\t Enable gRPC Proxy: %v", s.EnableGRPCProxy)
|
||||
@@ -460,8 +466,7 @@ func (bot *Engine) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if bot.Settings.EnableDeprecatedRPC ||
|
||||
bot.Settings.EnableWebsocketRPC {
|
||||
if bot.Settings.EnableDeprecatedRPC || bot.Settings.EnableWebsocketRPC {
|
||||
var filePath string
|
||||
filePath, err = config.GetAndMigrateDefaultPath(bot.Settings.ConfigFile)
|
||||
if err != nil {
|
||||
@@ -570,11 +575,30 @@ func (bot *Engine) Start() error {
|
||||
if err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "failed to create script manager. Err: %s", err)
|
||||
}
|
||||
if err := bot.gctScriptManager.Start(&bot.ServicesWG); err != nil {
|
||||
if err = bot.gctScriptManager.Start(&bot.ServicesWG); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "GCTScript manager unable to start: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.Settings.EnableCurrencyStateManager {
|
||||
bot.currencyStateManager, err = SetupCurrencyStateManager(
|
||||
bot.Config.CurrencyStateManager.Delay,
|
||||
bot.ExchangeManager)
|
||||
if err != nil {
|
||||
gctlog.Errorf(gctlog.Global,
|
||||
"%s unable to setup: %s",
|
||||
CurrencyStateManagementName,
|
||||
err)
|
||||
} else {
|
||||
err = bot.currencyStateManager.Start()
|
||||
if err != nil {
|
||||
gctlog.Errorf(gctlog.Global,
|
||||
"%s unable to start: %s",
|
||||
CurrencyStateManagementName,
|
||||
err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -599,61 +623,51 @@ func (bot *Engine) Stop() {
|
||||
gctlog.Errorf(gctlog.Global, "Order manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.eventManager.IsRunning() {
|
||||
if err := bot.eventManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "event manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.ntpManager.IsRunning() {
|
||||
if err := bot.ntpManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "NTP manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.CommunicationsManager.IsRunning() {
|
||||
if err := bot.CommunicationsManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "Communication manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.portfolioManager.IsRunning() {
|
||||
if err := bot.portfolioManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "Fund manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.connectionManager.IsRunning() {
|
||||
if err := bot.connectionManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "Connection manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.apiServer.IsRESTServerRunning() {
|
||||
if err := bot.apiServer.StopRESTServer(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "API Server unable to stop REST server. Error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.apiServer.IsWebsocketServerRunning() {
|
||||
if err := bot.apiServer.StopWebsocketServer(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "API Server unable to stop websocket server. Error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.dataHistoryManager.IsRunning() {
|
||||
if err := bot.dataHistoryManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.DataHistory, "data history manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.DatabaseManager.IsRunning() {
|
||||
if err := bot.DatabaseManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global, "Database manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if dispatch.IsRunning() {
|
||||
if err := dispatch.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.DispatchMgr, "Dispatch system unable to stop. Error: %v", err)
|
||||
@@ -664,6 +678,13 @@ func (bot *Engine) Stop() {
|
||||
gctlog.Errorf(gctlog.Global, "websocket routine manager unable to stop. Error: %v", err)
|
||||
}
|
||||
}
|
||||
if bot.currencyStateManager.IsRunning() {
|
||||
if err := bot.currencyStateManager.Stop(); err != nil {
|
||||
gctlog.Errorf(gctlog.Global,
|
||||
"currency state manager unable to stop. Error: %v",
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
if bot.Settings.EnableCoinmarketcapAnalysis ||
|
||||
bot.Settings.EnableCurrencyConverter ||
|
||||
|
||||
@@ -36,6 +36,7 @@ type Settings struct {
|
||||
EnableGCTScriptManager bool
|
||||
EnableNTPClient bool
|
||||
EnableWebsocketRoutine bool
|
||||
EnableCurrencyStateManager bool
|
||||
EventManagerDelay time.Duration
|
||||
Verbose bool
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ func (bot *Engine) GetSubsystemsStatus() map[string]bool {
|
||||
WebsocketName: bot.Settings.EnableWebsocketRPC,
|
||||
dispatch.Name: dispatch.IsRunning(),
|
||||
dataHistoryManagerName: bot.dataHistoryManager.IsRunning(),
|
||||
CurrencyStateManagementName: bot.currencyStateManager.IsRunning(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +265,19 @@ func (bot *Engine) SetSubsystem(subSystemName string, enable bool) error {
|
||||
return bot.gctScriptManager.Start(&bot.ServicesWG)
|
||||
}
|
||||
return bot.gctScriptManager.Stop()
|
||||
case strings.ToLower(CurrencyStateManagementName):
|
||||
if enable {
|
||||
if bot.currencyStateManager == nil {
|
||||
bot.currencyStateManager, err = SetupCurrencyStateManager(
|
||||
bot.Config.CurrencyStateManager.Delay,
|
||||
bot.ExchangeManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bot.currencyStateManager.Start()
|
||||
}
|
||||
return bot.currencyStateManager.Stop()
|
||||
}
|
||||
return fmt.Errorf("%s: %w", subSystemName, errSubsystemNotFound)
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func CreateTestBot(t *testing.T) *Engine {
|
||||
|
||||
func TestGetSubsystemsStatus(t *testing.T) {
|
||||
m := (&Engine{}).GetSubsystemsStatus()
|
||||
if len(m) != 14 {
|
||||
if len(m) != 15 {
|
||||
t.Fatalf("subsystem count is wrong expecting: %d but received: %d", 14, len(m))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,6 +393,17 @@ func (m *OrderManager) Submit(ctx context.Context, newOrder *order.Submit) (*Ord
|
||||
err)
|
||||
}
|
||||
|
||||
// Determines if current trading activity is turned off by the exchange for
|
||||
// the currency pair
|
||||
err = exch.CanTradePair(newOrder.Pair, newOrder.AssetType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("order manager: exchange %s cannot trade pair %s %s: %w",
|
||||
newOrder.Exchange,
|
||||
newOrder.Pair,
|
||||
newOrder.AssetType,
|
||||
err)
|
||||
}
|
||||
|
||||
result, err := exch.SubmitOrder(ctx, newOrder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -190,6 +190,16 @@ func OrdersSetup(t *testing.T) *OrderManager {
|
||||
}
|
||||
exch.SetDefaults()
|
||||
|
||||
cfg, err := exch.GetDefaultConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = exch.Setup(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fakeExchange := omfExchange{
|
||||
IBotExchange: exch,
|
||||
}
|
||||
|
||||
@@ -3889,3 +3889,59 @@ func (s *RPCServer) UpdateDataHistoryJobPrerequisite(_ context.Context, r *gctrp
|
||||
}
|
||||
return &gctrpc.GenericResponse{Status: status, Data: fmt.Sprintf("Set job '%v' prerequisite job to '%v' and set status to paused", r.Nickname, r.PrerequisiteJobNickname)}, nil
|
||||
}
|
||||
|
||||
// CurrencyStateGetAll returns a full snapshot of currency states, whether they
|
||||
// are able to be withdrawn, deposited or traded on an exchange.
|
||||
func (s *RPCServer) CurrencyStateGetAll(_ context.Context, r *gctrpc.CurrencyStateGetAllRequest) (*gctrpc.CurrencyStateResponse, error) {
|
||||
return s.currencyStateManager.GetAllRPC(r.Exchange)
|
||||
}
|
||||
|
||||
// CurrencyStateWithdraw determines via RPC if the currency code is operational for
|
||||
// withdrawal from an exchange
|
||||
func (s *RPCServer) CurrencyStateWithdraw(_ context.Context, r *gctrpc.CurrencyStateWithdrawRequest) (*gctrpc.GenericResponse, error) {
|
||||
return s.currencyStateManager.CanWithdrawRPC(r.Exchange,
|
||||
currency.NewCode(r.Code),
|
||||
asset.Item(r.Asset))
|
||||
}
|
||||
|
||||
// CurrencyStateDeposit determines via RPC if the currency code is operational for
|
||||
// depositing to an exchange
|
||||
func (s *RPCServer) CurrencyStateDeposit(_ context.Context, r *gctrpc.CurrencyStateDepositRequest) (*gctrpc.GenericResponse, error) {
|
||||
return s.currencyStateManager.CanDepositRPC(r.Exchange,
|
||||
currency.NewCode(r.Code),
|
||||
asset.Item(r.Asset))
|
||||
}
|
||||
|
||||
// CurrencyStateTrading determines via RPC if the currency code is operational for trading
|
||||
func (s *RPCServer) CurrencyStateTrading(_ context.Context, r *gctrpc.CurrencyStateTradingRequest) (*gctrpc.GenericResponse, error) {
|
||||
return s.currencyStateManager.CanTradeRPC(r.Exchange,
|
||||
currency.NewCode(r.Code),
|
||||
asset.Item(r.Asset))
|
||||
}
|
||||
|
||||
// CurrencyStateTradingPair determines via RPC if the pair is operational for trading
|
||||
func (s *RPCServer) CurrencyStateTradingPair(_ context.Context, r *gctrpc.CurrencyStateTradingPairRequest) (*gctrpc.GenericResponse, error) {
|
||||
exch, err := s.GetExchangeByName(r.Exchange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cp, err := currency.NewPairFromString(r.Pair)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a := asset.Item(r.Asset)
|
||||
err = checkParams(r.Exchange, exch, a, cp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = exch.CanTradePair(cp, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.currencyStateManager.CanTradePairRPC(r.Exchange,
|
||||
cp,
|
||||
asset.Item(r.Asset))
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/binance"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
@@ -43,6 +44,7 @@ const (
|
||||
unexpectedLackOfError = "unexpected lack of error"
|
||||
migrationsFolder = "migrations"
|
||||
databaseFolder = "database"
|
||||
fakeExchangeName = "fake"
|
||||
)
|
||||
|
||||
// fExchange is a fake exchange with function overrides
|
||||
@@ -53,7 +55,7 @@ type fExchange struct {
|
||||
|
||||
func (f fExchange) GetHistoricCandles(ctx context.Context, p currency.Pair, a asset.Item, timeStart, _ time.Time, interval kline.Interval) (kline.Item, error) {
|
||||
return kline.Item{
|
||||
Exchange: "fake",
|
||||
Exchange: fakeExchangeName,
|
||||
Pair: p,
|
||||
Asset: a,
|
||||
Interval: interval,
|
||||
@@ -72,7 +74,7 @@ func (f fExchange) GetHistoricCandles(ctx context.Context, p currency.Pair, a as
|
||||
|
||||
func (f fExchange) GetHistoricCandlesExtended(ctx context.Context, p currency.Pair, a asset.Item, timeStart, _ time.Time, interval kline.Interval) (kline.Item, error) {
|
||||
return kline.Item{
|
||||
Exchange: "fake",
|
||||
Exchange: fakeExchangeName,
|
||||
Pair: p,
|
||||
Asset: a,
|
||||
Interval: interval,
|
||||
@@ -122,6 +124,36 @@ func (f fExchange) UpdateAccountInfo(ctx context.Context, a asset.Item) (account
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetCurrencyStateSnapshot overrides interface function
|
||||
func (f fExchange) GetCurrencyStateSnapshot() ([]currencystate.Snapshot, error) {
|
||||
return []currencystate.Snapshot{
|
||||
{
|
||||
Code: currency.BTC,
|
||||
Asset: asset.Spot,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CanTradePair overrides interface function
|
||||
func (f fExchange) CanTradePair(p currency.Pair, a asset.Item) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanTrade overrides interface function
|
||||
func (f fExchange) CanTrade(c currency.Code, a asset.Item) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanWithdraw overrides interface function
|
||||
func (f fExchange) CanWithdraw(c currency.Code, a asset.Item) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanDeposit overrides interface function
|
||||
func (f fExchange) CanDeposit(c currency.Code, a asset.Item) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sets up everything required to run any function inside rpcserver
|
||||
// Only use if you require a database, this makes tests slow
|
||||
func RPCTestSetup(t *testing.T) *Engine {
|
||||
@@ -238,7 +270,7 @@ func TestGetSavedTrades(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = s.GetSavedTrades(context.Background(), &gctrpc.GetSavedTradesRequest{
|
||||
Exchange: "fake",
|
||||
Exchange: fakeExchangeName,
|
||||
Pair: &gctrpc.CurrencyPair{
|
||||
Delimiter: currency.DashDelimiter,
|
||||
Base: currency.BTC.String(),
|
||||
@@ -849,7 +881,7 @@ func TestGetRecentTrades(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = s.GetRecentTrades(context.Background(), &gctrpc.GetSavedTradesRequest{
|
||||
Exchange: "fake",
|
||||
Exchange: fakeExchangeName,
|
||||
Pair: &gctrpc.CurrencyPair{
|
||||
Delimiter: currency.DashDelimiter,
|
||||
Base: currency.BTC.String(),
|
||||
@@ -897,7 +929,7 @@ func TestGetHistoricTrades(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
err = s.GetHistoricTrades(&gctrpc.GetSavedTradesRequest{
|
||||
Exchange: "fake",
|
||||
Exchange: fakeExchangeName,
|
||||
Pair: &gctrpc.CurrencyPair{
|
||||
Delimiter: currency.DashDelimiter,
|
||||
Base: currency.BTC.String(),
|
||||
@@ -934,7 +966,7 @@ func TestGetAccountInfo(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := exch.GetBase()
|
||||
b.Name = "fake"
|
||||
b.Name = fakeExchangeName
|
||||
b.Enabled = true
|
||||
b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
|
||||
b.CurrencyPairs.Pairs[asset.Spot] = ¤cy.PairStore{
|
||||
@@ -945,7 +977,7 @@ func TestGetAccountInfo(t *testing.T) {
|
||||
}
|
||||
em.Add(fakeExchange)
|
||||
s := RPCServer{Engine: &Engine{ExchangeManager: em}}
|
||||
_, err = s.GetAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: "fake", AssetType: asset.Spot.String()})
|
||||
_, err = s.GetAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: fakeExchangeName, AssetType: asset.Spot.String()})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v', expected '%v'", err, nil)
|
||||
}
|
||||
@@ -959,7 +991,7 @@ func TestUpdateAccountInfo(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := exch.GetBase()
|
||||
b.Name = "fake"
|
||||
b.Name = fakeExchangeName
|
||||
b.Enabled = true
|
||||
b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
|
||||
b.CurrencyPairs.Pairs[asset.Spot] = ¤cy.PairStore{
|
||||
@@ -971,18 +1003,18 @@ func TestUpdateAccountInfo(t *testing.T) {
|
||||
em.Add(fakeExchange)
|
||||
s := RPCServer{Engine: &Engine{ExchangeManager: em}}
|
||||
|
||||
_, err = s.GetAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: "fake", AssetType: asset.Spot.String()})
|
||||
_, err = s.GetAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: fakeExchangeName, AssetType: asset.Spot.String()})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v', expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = s.UpdateAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: "fake", AssetType: asset.Futures.String()})
|
||||
_, err = s.UpdateAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: fakeExchangeName, AssetType: asset.Futures.String()})
|
||||
if !errors.Is(err, errAssetTypeDisabled) {
|
||||
t.Errorf("received '%v', expected '%v'", err, errAssetTypeDisabled)
|
||||
}
|
||||
|
||||
_, err = s.UpdateAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{
|
||||
Exchange: "fake",
|
||||
Exchange: fakeExchangeName,
|
||||
AssetType: asset.Spot.String(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -1862,3 +1894,87 @@ func TestUpdateDataHistoryJobPrerequisite(t *testing.T) {
|
||||
t.Errorf("received %v, expected %v", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrencyStateGetAll(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (&RPCServer{Engine: &Engine{}}).CurrencyStateGetAll(context.Background(),
|
||||
&gctrpc.CurrencyStateGetAllRequest{Exchange: fakeExchangeName})
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Errorf("received %v, expected %v", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrencyStateWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (&RPCServer{
|
||||
Engine: &Engine{},
|
||||
}).CurrencyStateWithdraw(context.Background(),
|
||||
&gctrpc.CurrencyStateWithdrawRequest{
|
||||
Exchange: "wow"})
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrencyStateDeposit(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (&RPCServer{
|
||||
Engine: &Engine{},
|
||||
}).CurrencyStateDeposit(context.Background(),
|
||||
&gctrpc.CurrencyStateDepositRequest{Exchange: "wow"})
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrencyStateTrading(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (&RPCServer{
|
||||
Engine: &Engine{},
|
||||
}).CurrencyStateTrading(context.Background(),
|
||||
&gctrpc.CurrencyStateTradingRequest{Exchange: "wow"})
|
||||
if !errors.Is(err, ErrSubSystemNotStarted) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, ErrSubSystemNotStarted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrencyStateTradingPair(t *testing.T) {
|
||||
t.Parallel()
|
||||
em := SetupExchangeManager()
|
||||
exch, err := em.NewExchangeByName(testExchange)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := exch.GetBase()
|
||||
b.Name = fakeExchangeName
|
||||
b.Enabled = true
|
||||
|
||||
cp, err := currency.NewPairFromString("btc-usd")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
|
||||
b.CurrencyPairs.Pairs[asset.Spot] = ¤cy.PairStore{
|
||||
AssetEnabled: convert.BoolPtr(true),
|
||||
ConfigFormat: ¤cy.PairFormat{},
|
||||
Available: currency.Pairs{cp},
|
||||
Enabled: currency.Pairs{cp},
|
||||
}
|
||||
fakeExchange := fExchange{
|
||||
IBotExchange: exch,
|
||||
}
|
||||
em.Add(fakeExchange)
|
||||
s := RPCServer{Engine: &Engine{ExchangeManager: em,
|
||||
currencyStateManager: &CurrencyStateManager{started: 1, iExchangeManager: em}}}
|
||||
|
||||
_, err = s.CurrencyStateTradingPair(context.Background(),
|
||||
&gctrpc.CurrencyStateTradingPairRequest{
|
||||
Exchange: fakeExchangeName,
|
||||
Pair: "btc-usd",
|
||||
Asset: "spot",
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
dbwithdraw "github.com/thrasher-corp/gocryptotrader/database/repository/withdraw"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
@@ -45,6 +47,12 @@ func (m *WithdrawManager) SubmitWithdrawal(ctx context.Context, req *withdraw.Re
|
||||
RequestDetails: *req,
|
||||
}
|
||||
|
||||
// Determines if the currency can be withdrawn from the exchange
|
||||
errF := exch.CanWithdraw(req.Currency, asset.Spot)
|
||||
if errF != nil && !errors.Is(errF, currencystate.ErrCurrencyStateNotFound) { // Suppress not found error
|
||||
return nil, errF
|
||||
}
|
||||
|
||||
if m.isDryRun {
|
||||
log.Warnln(log.Global, "Dry run enabled, no withdrawal request will be submitted or have an event created")
|
||||
resp.ID = withdraw.DryRunID
|
||||
|
||||
@@ -25,6 +25,14 @@ func withdrawManagerTestHelper(t *testing.T) (*ExchangeManager, *portfolioManage
|
||||
em := SetupExchangeManager()
|
||||
b := new(binance.Binance)
|
||||
b.SetDefaults()
|
||||
cfg, err := b.GetDefaultConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = b.Setup(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
em.Add(b)
|
||||
pm, err := setupPortfolioManager(em, 0, &portfolio.Base{Addresses: []portfolio.Address{}})
|
||||
if err != nil {
|
||||
|
||||
@@ -29,6 +29,11 @@ implementation
|
||||
|
||||
+ A guide on implementing API support for a new exchange can be found [here](../docs/ADD_NEW_EXCHANGE.md)
|
||||
|
||||
## websocket notes
|
||||
|
||||
+ If contributing websocket improvements, please make sure order reports
|
||||
follow [these rules](../docs/WS_ORDER_EVENTS.md).
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
|
||||
## Contribution
|
||||
@@ -42,9 +47,6 @@ When submitting a PR, please abide by our coding guidelines:
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
If contributing websocket improvements, please make sure order reports
|
||||
follow [these rules](../docs/WS_ORDER_EVENTS.md).
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
83
exchanges/alert/alert.go
Normal file
83
exchanges/alert/alert.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package alert
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Notice defines fields required to alert sub-systems of a change of state so a
|
||||
// routine can re-check in memory data
|
||||
type Notice struct {
|
||||
// Channel to wait for an alert on.
|
||||
forAlert chan struct{}
|
||||
// Lets the updater functions know if there are any routines waiting for an
|
||||
// alert.
|
||||
sema uint32
|
||||
// After closing the forAlert channel this will notify when all the routines
|
||||
// that have waited, have completed their checks.
|
||||
wg sync.WaitGroup
|
||||
// Segregated lock only for waiting routines, so as this does not interfere
|
||||
// with the main calling lock, this acts as a rolling gate.
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
// Alert establishes a state change on the required struct.
|
||||
func (n *Notice) Alert() {
|
||||
// CompareAndSwap is used to swap from 1 -> 2 so we don't keep actuating
|
||||
// the opposing compare and swap in method wait. This function can return
|
||||
// freely when an alert operation is in process.
|
||||
if !atomic.CompareAndSwapUint32(&n.sema, 1, 2) {
|
||||
// Return if no waiting routines or currently alerting.
|
||||
return
|
||||
}
|
||||
go n.actuate()
|
||||
}
|
||||
|
||||
// Actuate lock in a different routine, as alerting is a second order priority
|
||||
// compared to updating and releasing calling routine.
|
||||
func (n *Notice) actuate() {
|
||||
n.m.Lock()
|
||||
// Closing; alerts many waiting routines.
|
||||
close(n.forAlert)
|
||||
// Wait for waiting routines to receive alert and return.
|
||||
n.wg.Wait()
|
||||
atomic.SwapUint32(&n.sema, 0) // Swap back to neutral state.
|
||||
n.m.Unlock()
|
||||
}
|
||||
|
||||
// Wait pauses calling routine until change of state has been established via
|
||||
// notice method Alert. Kick allows for cancellation of waiting or when the
|
||||
// caller has been shut down, if this is not needed it can be set to nil. This
|
||||
// returns a channel so strategies can cleanly wait on a select statement case.
|
||||
func (n *Notice) Wait(kick <-chan struct{}) <-chan bool {
|
||||
reply := make(chan bool)
|
||||
n.m.Lock()
|
||||
n.wg.Add(1)
|
||||
if atomic.CompareAndSwapUint32(&n.sema, 0, 1) {
|
||||
n.forAlert = make(chan struct{})
|
||||
}
|
||||
go n.hold(reply, kick)
|
||||
n.m.Unlock()
|
||||
return reply
|
||||
}
|
||||
|
||||
// hold waits on either channel in the event that the routine has
|
||||
// finished/cancelled or an alert from an update has occurred.
|
||||
func (n *Notice) hold(ch chan<- bool, kick <-chan struct{}) {
|
||||
select {
|
||||
// In a select statement, if by chance there is no receiver or its late,
|
||||
// we can still close and return, limiting dead-lock potential.
|
||||
case <-n.forAlert: // Main waiting channel from alert
|
||||
select {
|
||||
case ch <- false:
|
||||
default:
|
||||
}
|
||||
case <-kick: // This can be nil.
|
||||
select {
|
||||
case ch <- true:
|
||||
default:
|
||||
}
|
||||
}
|
||||
n.wg.Done()
|
||||
close(ch)
|
||||
}
|
||||
92
exchanges/alert/alert_test.go
Normal file
92
exchanges/alert/alert_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package alert
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWait(t *testing.T) {
|
||||
wait := Notice{}
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// standard alert
|
||||
wg.Add(100)
|
||||
for x := 0; x < 100; x++ {
|
||||
go func() {
|
||||
w := wait.Wait(nil)
|
||||
wg.Done()
|
||||
if <-w {
|
||||
log.Fatal("incorrect routine wait response for alert expecting false")
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
wg.Add(100)
|
||||
isLeaky(&wait, nil, t)
|
||||
wait.Alert()
|
||||
wg.Wait()
|
||||
isLeaky(&wait, nil, t)
|
||||
|
||||
// use kick
|
||||
ch := make(chan struct{})
|
||||
wg.Add(100)
|
||||
for x := 0; x < 100; x++ {
|
||||
go func() {
|
||||
w := wait.Wait(ch)
|
||||
wg.Done()
|
||||
if !<-w {
|
||||
log.Fatal("incorrect routine wait response for kick expecting true")
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
wg.Add(100)
|
||||
isLeaky(&wait, ch, t)
|
||||
close(ch)
|
||||
wg.Wait()
|
||||
ch = make(chan struct{})
|
||||
isLeaky(&wait, ch, t)
|
||||
|
||||
// late receivers
|
||||
wg.Add(100)
|
||||
for x := 0; x < 100; x++ {
|
||||
go func(x int) {
|
||||
bb := wait.Wait(ch)
|
||||
wg.Done()
|
||||
if x%2 == 0 {
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
}
|
||||
b := <-bb
|
||||
if b {
|
||||
log.Fatal("incorrect routine wait response since we call alert below; expecting false")
|
||||
}
|
||||
wg.Done()
|
||||
}(x)
|
||||
}
|
||||
wg.Wait()
|
||||
wg.Add(100)
|
||||
isLeaky(&wait, ch, t)
|
||||
wait.Alert()
|
||||
wg.Wait()
|
||||
isLeaky(&wait, ch, t)
|
||||
}
|
||||
|
||||
// isLeaky tests to see if the wait functionality is returning an abnormal
|
||||
// channel that is operational when it shouldn't be.
|
||||
func isLeaky(a *Notice, ch chan struct{}, t *testing.T) {
|
||||
t.Helper()
|
||||
check := a.Wait(ch)
|
||||
time.Sleep(time.Millisecond * 5) // When we call wait a routine for hold is
|
||||
// spawned, so for a test we need to add in a time for goschedular to allow
|
||||
// routine to actually wait on the forAlert and kick channels
|
||||
select {
|
||||
case <-check:
|
||||
t.Fatal("leaky waiter")
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -480,7 +480,7 @@ func (b *Bitfinex) GetDerivativeStatusInfo(ctx context.Context, keys, startTime,
|
||||
if response.NextFundingEventTS, ok = result[z][8].(float64); !ok {
|
||||
return finalResp, fmt.Errorf("%v GetDerivativeStatusInfo: %w for NextFundingEventTS", b.Name, errTypeAssert)
|
||||
}
|
||||
if response.NextFundingAccured, ok = result[z][9].(float64); !ok {
|
||||
if response.NextFundingAccrued, ok = result[z][9].(float64); !ok {
|
||||
return finalResp, fmt.Errorf("%v GetDerivativeStatusInfo: %w for NextFundingAccrued", b.Name, errTypeAssert)
|
||||
}
|
||||
if response.NextFundingStep, ok = result[z][10].(float64); !ok {
|
||||
@@ -493,8 +493,17 @@ func (b *Bitfinex) GetDerivativeStatusInfo(ctx context.Context, keys, startTime,
|
||||
return finalResp, fmt.Errorf("%v GetDerivativeStatusInfo: %w for MarkPrice", b.Name, errTypeAssert)
|
||||
}
|
||||
|
||||
if response.OpenInterest, ok = result[z][18].(float64); !ok {
|
||||
return finalResp, fmt.Errorf("%v GetDerivativeStatusInfo: %w for OpenInterest", b.Name, errTypeAssert)
|
||||
switch t := result[z][18].(type) {
|
||||
case float64:
|
||||
response.OpenInterest = t
|
||||
case nil:
|
||||
break // OpenInterest will default to 0
|
||||
default:
|
||||
return finalResp, fmt.Errorf("%v GetDerivativeStatusInfo: %w for OpenInterest. Type received: %v",
|
||||
b.Name,
|
||||
errTypeAssert,
|
||||
t,
|
||||
)
|
||||
}
|
||||
finalResp = append(finalResp, response)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ type DerivativeDataResponse struct {
|
||||
MarkPrice float64
|
||||
InsuranceFundBalance float64
|
||||
NextFundingEventTS float64
|
||||
NextFundingAccured float64
|
||||
NextFundingAccrued float64
|
||||
NextFundingStep float64
|
||||
CurrentFunding float64
|
||||
OpenInterest float64
|
||||
|
||||
@@ -150,6 +150,21 @@ func (b *Bithumb) GetAssetStatus(ctx context.Context, symbol string) (*Status, e
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// GetAssetStatusAll returns the withdrawal and deposit status for all symbols
|
||||
func (b *Bithumb) GetAssetStatusAll(ctx context.Context) (*StatusAll, error) {
|
||||
var response StatusAll
|
||||
err := b.SendHTTPRequest(ctx, exchange.RestSpot, publicAssetStatus+"ALL", &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.Status != noError {
|
||||
return nil, errors.New(response.Message)
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// GetTransactionHistory returns recent transactions
|
||||
//
|
||||
// symbol e.g. "btc"
|
||||
|
||||
@@ -741,3 +741,19 @@ func TestGetAssetStatus(t *testing.T) {
|
||||
t.Fatalf("received: %v but expected: %v", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAssetStatusAll(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := b.GetAssetStatusAll(context.Background())
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v but expected: %v", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateCurrencyStates(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := b.UpdateCurrencyStates(context.Background(), asset.Spot)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v but expected: %v", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,3 +301,14 @@ type Status struct {
|
||||
} `json:"data"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// StatusAll defines the current exchange allowance to deposit or withdraw a
|
||||
// currency
|
||||
type StatusAll struct {
|
||||
Status string `json:"status"`
|
||||
Data map[string]struct {
|
||||
DepositStatus int64 `json:"deposit_status"`
|
||||
WithdrawalStatus int64 `json:"withdrawal_status"`
|
||||
} `json:"data"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
@@ -891,3 +893,20 @@ func (b *Bithumb) UpdateOrderExecutionLimits(ctx context.Context, _ asset.Item)
|
||||
}
|
||||
return b.LoadLimits(limits)
|
||||
}
|
||||
|
||||
// UpdateCurrencyStates updates currency states for exchange
|
||||
func (b *Bithumb) UpdateCurrencyStates(ctx context.Context, a asset.Item) error {
|
||||
status, err := b.GetAssetStatusAll(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
payload := make(map[currency.Code]currencystate.Options)
|
||||
for coin, options := range status.Data {
|
||||
payload[currency.NewCode(coin)] = currencystate.Options{
|
||||
Withdraw: convert.BoolPtr(options.WithdrawalStatus == 1),
|
||||
Deposit: convert.BoolPtr(options.DepositStatus == 1),
|
||||
}
|
||||
}
|
||||
return b.States.UpdateAll(a, payload)
|
||||
}
|
||||
|
||||
312
exchanges/currencystate/currency_state.go
Normal file
312
exchanges/currencystate/currency_state.go
Normal file
@@ -0,0 +1,312 @@
|
||||
package currencystate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/alert"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyCurrency = errors.New("empty currency")
|
||||
errUpdatesAreNil = errors.New("updates are nil")
|
||||
errNilStates = errors.New("states is not started or set up")
|
||||
|
||||
// Specific operational errors
|
||||
errDepositNotAllowed = errors.New("depositing not allowed")
|
||||
errWithdrawalsNotAllowed = errors.New("withdrawals not allowed")
|
||||
errTradingNotAllowed = errors.New("trading not allowed")
|
||||
|
||||
// ErrCurrencyStateNotFound is an error when the currency state has not been
|
||||
// found
|
||||
ErrCurrencyStateNotFound = errors.New("currency state not found")
|
||||
)
|
||||
|
||||
// NewCurrencyStates gets a new type for tracking exchange currency states
|
||||
func NewCurrencyStates() *States {
|
||||
return &States{m: make(map[asset.Item]map[*currency.Item]*Currency)}
|
||||
}
|
||||
|
||||
// States defines all currency states for an exchange
|
||||
type States struct {
|
||||
m map[asset.Item]map[*currency.Item]*Currency
|
||||
mtx sync.RWMutex
|
||||
}
|
||||
|
||||
// GetCurrencyStateSnapshot returns the exchange currency state snapshot
|
||||
func (s *States) GetCurrencyStateSnapshot() ([]Snapshot, error) {
|
||||
if s == nil {
|
||||
return nil, errNilStates
|
||||
}
|
||||
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
var sh []Snapshot
|
||||
for a, m1 := range s.m {
|
||||
for c, val := range m1 {
|
||||
sh = append(sh, Snapshot{
|
||||
Code: currency.Code{Item: c},
|
||||
Asset: a,
|
||||
Options: val.GetState(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
// CanTradePair returns if the currency pair is currently tradeable for this
|
||||
// exchange. If there are no states loaded for a specific currency, this will
|
||||
// assume the currency pair is operational. NOTE: Future exchanges will have
|
||||
// functionality specific to a currency.Pair, can upgrade this when needed.
|
||||
func (s *States) CanTradePair(pair currency.Pair, a asset.Item) error {
|
||||
err := s.CanTrade(pair.Base, a)
|
||||
if err != nil && err != ErrCurrencyStateNotFound {
|
||||
return fmt.Errorf("cannot trade base currency %s %s: %w",
|
||||
pair.Base, a, err)
|
||||
}
|
||||
err = s.CanTrade(pair.Quote, a)
|
||||
if err != nil && err != ErrCurrencyStateNotFound {
|
||||
return fmt.Errorf("cannot trade quote currency %s %s: %w",
|
||||
pair.Base, a, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanTrade returns if the currency is currently tradeable for this exchange
|
||||
func (s *States) CanTrade(c currency.Code, a asset.Item) error {
|
||||
if s == nil {
|
||||
return errNilStates
|
||||
}
|
||||
|
||||
p, err := s.Get(c, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.CanTrade() {
|
||||
return errTradingNotAllowed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanWithdraw returns if the currency can be withdrawn from this exchange
|
||||
func (s *States) CanWithdraw(c currency.Code, a asset.Item) error {
|
||||
if s == nil {
|
||||
return errNilStates
|
||||
}
|
||||
|
||||
p, err := s.Get(c, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.CanWithdraw() {
|
||||
return errWithdrawalsNotAllowed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanDeposit returns if the currency can be deposited onto this exchange
|
||||
func (s *States) CanDeposit(c currency.Code, a asset.Item) error {
|
||||
if s == nil {
|
||||
return errNilStates
|
||||
}
|
||||
|
||||
p, err := s.Get(c, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.CanDeposit() {
|
||||
return errDepositNotAllowed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAll updates the full currency state, used for REST calls
|
||||
func (s *States) UpdateAll(a asset.Item, updates map[currency.Code]Options) error {
|
||||
if s == nil {
|
||||
return errNilStates
|
||||
}
|
||||
|
||||
if !a.IsValid() {
|
||||
return fmt.Errorf("%s %w", a, asset.ErrNotSupported)
|
||||
}
|
||||
if updates == nil {
|
||||
return errUpdatesAreNil
|
||||
}
|
||||
s.mtx.Lock()
|
||||
for code, option := range updates {
|
||||
s.update(code, a, option)
|
||||
}
|
||||
s.mtx.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates a singular currency state, primarily used for singular
|
||||
// websocket updates or alerts.
|
||||
func (s *States) Update(c currency.Code, a asset.Item, o Options) error {
|
||||
if s == nil {
|
||||
return errNilStates
|
||||
}
|
||||
|
||||
if c.String() == "" {
|
||||
return errEmptyCurrency
|
||||
}
|
||||
if !a.IsValid() {
|
||||
return fmt.Errorf("%s, %w", a, asset.ErrNotSupported)
|
||||
}
|
||||
s.mtx.Lock()
|
||||
s.update(c, a, o)
|
||||
s.mtx.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// update updates a singular currency state without protection
|
||||
func (s *States) update(c currency.Code, a asset.Item, o Options) {
|
||||
m1, ok := s.m[a]
|
||||
if !ok {
|
||||
m1 = make(map[*currency.Item]*Currency)
|
||||
s.m[a] = m1
|
||||
}
|
||||
|
||||
p, ok := m1[c.Item]
|
||||
if !ok {
|
||||
p = &Currency{}
|
||||
m1[c.Item] = p
|
||||
}
|
||||
p.update(o)
|
||||
}
|
||||
|
||||
// Get returns the currency state by currency code
|
||||
func (s *States) Get(c currency.Code, a asset.Item) (*Currency, error) {
|
||||
if s == nil {
|
||||
return nil, errNilStates
|
||||
}
|
||||
|
||||
if c.String() == "" {
|
||||
return nil, errEmptyCurrency
|
||||
}
|
||||
|
||||
if !a.IsValid() {
|
||||
return nil, fmt.Errorf("%s %w", a, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
s.mtx.RLock()
|
||||
defer s.mtx.RUnlock()
|
||||
cs, ok := s.m[a][c.Item]
|
||||
if !ok {
|
||||
return nil, ErrCurrencyStateNotFound
|
||||
}
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
// Currency defines the state of currency operations
|
||||
type Currency struct {
|
||||
withdrawals bool
|
||||
withdrawAlerts alert.Notice
|
||||
deposits bool
|
||||
depositAlerts alert.Notice
|
||||
trading bool
|
||||
tradingAlerts alert.Notice
|
||||
mtx sync.RWMutex
|
||||
}
|
||||
|
||||
// update updates the underlying values
|
||||
func (c *Currency) update(o Options) {
|
||||
c.mtx.Lock()
|
||||
if o.Withdraw == nil {
|
||||
c.withdrawals = true
|
||||
c.withdrawAlerts.Alert()
|
||||
} else if c.withdrawals != *o.Withdraw {
|
||||
c.withdrawals = *o.Withdraw
|
||||
c.withdrawAlerts.Alert()
|
||||
}
|
||||
|
||||
if o.Deposit == nil {
|
||||
c.deposits = true
|
||||
c.depositAlerts.Alert()
|
||||
} else if c.deposits != *o.Deposit {
|
||||
c.deposits = *o.Deposit
|
||||
c.depositAlerts.Alert()
|
||||
}
|
||||
|
||||
if o.Trade == nil {
|
||||
c.trading = true
|
||||
c.tradingAlerts.Alert()
|
||||
} else if c.trading != *o.Trade {
|
||||
c.trading = *o.Trade
|
||||
c.tradingAlerts.Alert()
|
||||
}
|
||||
c.mtx.Unlock()
|
||||
}
|
||||
|
||||
// CanTrade returns if the currency is currently tradeable
|
||||
func (c *Currency) CanTrade() bool {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return c.trading
|
||||
}
|
||||
|
||||
// CanWithdraw returns if the currency can be withdrawn from the exchange
|
||||
func (c *Currency) CanWithdraw() bool {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return c.withdrawals
|
||||
}
|
||||
|
||||
// CanDeposit returns if the currency can be deposited onto an exchange
|
||||
func (c *Currency) CanDeposit() bool {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return c.deposits
|
||||
}
|
||||
|
||||
// WaitTrading allows a routine to wait until a trading change of state occurs
|
||||
func (c *Currency) WaitTrading(kick <-chan struct{}) <-chan bool {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return c.tradingAlerts.Wait(kick)
|
||||
}
|
||||
|
||||
// WaitDeposit allows a routine to wait until a deposit change of state occurs
|
||||
func (c *Currency) WaitDeposit(kick <-chan struct{}) <-chan bool {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return c.depositAlerts.Wait(kick)
|
||||
}
|
||||
|
||||
// WaitWithdraw allows a routine to wait until a withdraw change of state occurs
|
||||
func (c *Currency) WaitWithdraw(kick <-chan struct{}) <-chan bool {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return c.withdrawAlerts.Wait(kick)
|
||||
}
|
||||
|
||||
// GetState returns the internal state of the currency
|
||||
func (c *Currency) GetState() Options {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
return Options{
|
||||
Withdraw: convert.BoolPtr(c.withdrawals),
|
||||
Deposit: convert.BoolPtr(c.deposits),
|
||||
Trade: convert.BoolPtr(c.trading),
|
||||
}
|
||||
}
|
||||
|
||||
// Options defines the current allowable options for a currency, using a bool
|
||||
// pointer for optional setting for incomplete data, so we can default to true
|
||||
// on nil values.
|
||||
type Options struct {
|
||||
Withdraw *bool
|
||||
Deposit *bool
|
||||
Trade *bool
|
||||
}
|
||||
|
||||
// Snapshot defines a snapshot of the internal asset for exportation
|
||||
type Snapshot struct {
|
||||
Code currency.Code
|
||||
Asset asset.Item
|
||||
Options
|
||||
}
|
||||
324
exchanges/currencystate/currency_state_test.go
Normal file
324
exchanges/currencystate/currency_state_test.go
Normal file
@@ -0,0 +1,324 @@
|
||||
package currencystate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
)
|
||||
|
||||
func TestNewCurrencyStates(t *testing.T) {
|
||||
if NewCurrencyStates() == nil {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSnapshot(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*States)(nil).GetCurrencyStateSnapshot()
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
|
||||
o, err := (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {currency.BTC.Item: {
|
||||
withdrawals: true,
|
||||
deposits: true,
|
||||
trading: true,
|
||||
}},
|
||||
},
|
||||
}).GetCurrencyStateSnapshot()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
if o == nil {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanTradePair(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*States)(nil).CanTradePair(currency.Pair{}, "")
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
|
||||
err = (&States{}).CanTradePair(currency.Pair{}, "")
|
||||
if !errors.Is(err, errEmptyCurrency) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
|
||||
}
|
||||
|
||||
cp := currency.NewPair(currency.BTC, currency.USD)
|
||||
err = (&States{}).CanTradePair(cp, "")
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
err = (&States{}).CanTradePair(cp, asset.Spot)
|
||||
if !errors.Is(err, nil) { // not found but default to operational
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {trading: true},
|
||||
currency.USD.Item: {trading: true},
|
||||
},
|
||||
},
|
||||
}).CanTradePair(cp, asset.Spot)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {trading: false},
|
||||
currency.USD.Item: {trading: true},
|
||||
},
|
||||
},
|
||||
}).CanTradePair(cp, asset.Spot)
|
||||
if !errors.Is(err, errTradingNotAllowed) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errTradingNotAllowed)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {trading: true},
|
||||
currency.USD.Item: {trading: false},
|
||||
},
|
||||
},
|
||||
}).CanTradePair(cp, asset.Spot)
|
||||
if !errors.Is(err, errTradingNotAllowed) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errTradingNotAllowed)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {trading: false},
|
||||
currency.USD.Item: {trading: false},
|
||||
},
|
||||
},
|
||||
}).CanTradePair(cp, asset.Spot)
|
||||
if !errors.Is(err, errTradingNotAllowed) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errTradingNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatesCanTrade(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*States)(nil).CanTrade(currency.Code{}, "")
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
err = (&States{}).CanTrade(currency.Code{}, "")
|
||||
if !errors.Is(err, errEmptyCurrency) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatesCanWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*States)(nil).CanWithdraw(currency.Code{}, "")
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
err = (&States{}).CanWithdraw(currency.Code{}, "")
|
||||
if !errors.Is(err, errEmptyCurrency) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {withdrawals: true},
|
||||
},
|
||||
},
|
||||
}).CanWithdraw(currency.BTC, asset.Spot)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {},
|
||||
},
|
||||
},
|
||||
}).CanWithdraw(currency.BTC, asset.Spot)
|
||||
if !errors.Is(err, errWithdrawalsNotAllowed) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errWithdrawalsNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatesCanDeposit(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*States)(nil).CanDeposit(currency.Code{}, "")
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
err = (&States{}).CanDeposit(currency.Code{}, "")
|
||||
if !errors.Is(err, errEmptyCurrency) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {deposits: true},
|
||||
},
|
||||
},
|
||||
}).CanDeposit(currency.BTC, asset.Spot)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {
|
||||
currency.BTC.Item: {},
|
||||
},
|
||||
},
|
||||
}).CanDeposit(currency.BTC, asset.Spot)
|
||||
if !errors.Is(err, errDepositNotAllowed) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errDepositNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatesUpdateAll(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*States)(nil).UpdateAll("", nil)
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
|
||||
err = (&States{}).UpdateAll("", nil)
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
err = (&States{}).UpdateAll(asset.Spot, nil)
|
||||
if !errors.Is(err, errUpdatesAreNil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errUpdatesAreNil)
|
||||
}
|
||||
|
||||
s := &States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{},
|
||||
}
|
||||
|
||||
err = s.UpdateAll(asset.Spot, map[currency.Code]Options{
|
||||
currency.BTC: {
|
||||
Withdraw: convert.BoolPtr(true),
|
||||
Trade: convert.BoolPtr(true),
|
||||
Deposit: convert.BoolPtr(true)},
|
||||
})
|
||||
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
err = s.UpdateAll(asset.Spot, map[currency.Code]Options{currency.BTC: {
|
||||
Withdraw: convert.BoolPtr(false),
|
||||
Deposit: convert.BoolPtr(false),
|
||||
Trade: convert.BoolPtr(false),
|
||||
}})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
c, err := s.Get(currency.BTC, asset.Spot)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
if c.CanDeposit() || c.CanTrade() || c.CanWithdraw() {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatesUpdate(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := (*States)(nil).Update(currency.Code{}, "", Options{})
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
|
||||
err = (&States{}).Update(currency.Code{}, "", Options{})
|
||||
if !errors.Is(err, errEmptyCurrency) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
|
||||
}
|
||||
|
||||
err = (&States{}).Update(currency.BTC, "", Options{})
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
err = (&States{
|
||||
m: map[asset.Item]map[*currency.Item]*Currency{
|
||||
asset.Spot: {currency.BTC.Item: &Currency{}},
|
||||
},
|
||||
}).Update(currency.BTC, asset.Spot, Options{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatesGet(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := (*States)(nil).Get(currency.Code{}, "")
|
||||
if !errors.Is(err, errNilStates) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
|
||||
}
|
||||
|
||||
_, err = (&States{}).Get(currency.Code{}, "")
|
||||
if !errors.Is(err, errEmptyCurrency) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
|
||||
}
|
||||
|
||||
_, err = (&States{}).Get(currency.BTC, "")
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
_, err = (&States{}).Get(currency.BTC, asset.Spot)
|
||||
if !errors.Is(err, ErrCurrencyStateNotFound) {
|
||||
t.Fatalf("received: %v, but expected: %v", err, ErrCurrencyStateNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrencyGetState(t *testing.T) {
|
||||
o := (&Currency{}).GetState()
|
||||
if *o.Deposit || *o.Trade || *o.Withdraw {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlerting(t *testing.T) {
|
||||
c := Currency{}
|
||||
var start, finish sync.WaitGroup
|
||||
start.Add(3)
|
||||
finish.Add(3)
|
||||
go waitForAlert(c.WaitTrading(nil), &start, &finish)
|
||||
go waitForAlert(c.WaitDeposit(nil), &start, &finish)
|
||||
go waitForAlert(c.WaitWithdraw(nil), &start, &finish)
|
||||
start.Wait()
|
||||
c.update(Options{
|
||||
Trade: convert.BoolPtr(true),
|
||||
Withdraw: convert.BoolPtr(true),
|
||||
Deposit: convert.BoolPtr(true)})
|
||||
finish.Wait()
|
||||
}
|
||||
|
||||
func waitForAlert(ch <-chan bool, start, finish *sync.WaitGroup) {
|
||||
defer finish.Done()
|
||||
start.Done()
|
||||
<-ch
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
@@ -115,8 +116,7 @@ func (b *Base) SetClientProxyAddress(addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFeatureDefaults sets the exchanges default feature
|
||||
// support set
|
||||
// SetFeatureDefaults sets the exchanges default feature support set
|
||||
func (b *Base) SetFeatureDefaults() {
|
||||
if b.Config.Features == nil {
|
||||
s := &config.FeaturesConfig{
|
||||
@@ -620,7 +620,8 @@ func (b *Base) SetupDefaults(exch *config.ExchangeConfig) error {
|
||||
b.Name)
|
||||
}
|
||||
b.CanVerifyOrderbook = !exch.OrderbookConfig.VerificationBypass
|
||||
return nil
|
||||
b.States = currencystate.NewCurrencyStates()
|
||||
return err
|
||||
}
|
||||
|
||||
// AllowAuthenticatedRequest checks to see if the required fields have been set
|
||||
@@ -1385,3 +1386,8 @@ func (a *AssetWebsocketSupport) IsAssetWebsocketSupported(aType asset.Item) bool
|
||||
defer a.m.RUnlock()
|
||||
return a.unsupported == nil || !a.unsupported[aType]
|
||||
}
|
||||
|
||||
// UpdateCurrencyStates updates currency states
|
||||
func (b *Base) UpdateCurrencyStates(ctx context.Context, a asset.Item) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -1267,7 +1267,7 @@ func TestSetAPIKeys(t *testing.T) {
|
||||
func TestSetupDefaults(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var b Base
|
||||
var b = Base{Name: "awesomeTest"}
|
||||
cfg := config.ExchangeConfig{
|
||||
HTTPTimeout: time.Duration(-1),
|
||||
API: config.APIConfig{
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
@@ -231,6 +232,7 @@ type Base struct {
|
||||
order.ExecutionLimits
|
||||
|
||||
AssetWebsocketSupport
|
||||
*currencystate.States
|
||||
}
|
||||
|
||||
// url lookup consts
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
@@ -90,4 +91,16 @@ type IBotExchange interface {
|
||||
GetOrderExecutionLimits(a asset.Item, cp currency.Pair) (*order.Limits, error)
|
||||
CheckOrderExecutionLimits(a asset.Item, cp currency.Pair, price, amount float64, orderType order.Type) error
|
||||
UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error
|
||||
|
||||
CurrencyStateManagement
|
||||
}
|
||||
|
||||
// CurrencyStateManagement defines functionality for currency state management
|
||||
type CurrencyStateManagement interface {
|
||||
GetCurrencyStateSnapshot() ([]currencystate.Snapshot, error)
|
||||
UpdateCurrencyStates(ctx context.Context, a asset.Item) error
|
||||
CanTradePair(p currency.Pair, a asset.Item) error
|
||||
CanTrade(c currency.Code, a asset.Item) error
|
||||
CanWithdraw(c currency.Code, a asset.Item) error
|
||||
CanDeposit(c currency.Code, a asset.Item) error
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package orderbook
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/dispatch"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/alert"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ type Depth struct {
|
||||
// unexported stack of nodes
|
||||
stack *stack
|
||||
|
||||
Alert
|
||||
alert.Notice
|
||||
|
||||
mux *dispatch.Mux
|
||||
id uuid.UUID
|
||||
@@ -101,7 +101,7 @@ func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated
|
||||
d.restSnapshot = updateByREST
|
||||
d.bids.load(bids, d.stack)
|
||||
d.asks.load(asks, d.stack)
|
||||
d.alert()
|
||||
d.Alert()
|
||||
d.m.Unlock()
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (d *Depth) Flush() {
|
||||
d.lastUpdated = time.Time{}
|
||||
d.bids.load(nil, d.stack)
|
||||
d.asks.load(nil, d.stack)
|
||||
d.alert()
|
||||
d.Alert()
|
||||
d.m.Unlock()
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func (d *Depth) UpdateBidAskByPrice(bidUpdts, askUpdts Items, maxDepth int, last
|
||||
if len(askUpdts) != 0 {
|
||||
d.asks.updateInsertByPrice(askUpdts, d.stack, maxDepth, tn)
|
||||
}
|
||||
d.alert()
|
||||
d.Alert()
|
||||
d.m.Unlock()
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ func (d *Depth) UpdateBidAskByID(bidUpdts, askUpdts Items, lastUpdateID int64, l
|
||||
}
|
||||
d.lastUpdateID = lastUpdateID
|
||||
d.lastUpdated = lastUpdated
|
||||
d.alert()
|
||||
d.Alert()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func (d *Depth) DeleteBidAskByID(bidUpdts, askUpdts Items, bypassErr bool, lastU
|
||||
}
|
||||
d.lastUpdateID = lastUpdateID
|
||||
d.lastUpdated = lastUpdated
|
||||
d.alert()
|
||||
d.Alert()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ func (d *Depth) InsertBidAskByID(bidUpdts, askUpdts Items, lastUpdateID int64, l
|
||||
}
|
||||
d.lastUpdateID = lastUpdateID
|
||||
d.lastUpdated = lastUpdated
|
||||
d.alert()
|
||||
d.Alert()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ func (d *Depth) UpdateInsertByID(bidUpdts, askUpdts Items, lastUpdateID int64, l
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.alert()
|
||||
d.Alert()
|
||||
d.lastUpdateID = lastUpdateID
|
||||
d.lastUpdated = lastUpdated
|
||||
return nil
|
||||
@@ -281,79 +281,3 @@ func (d *Depth) IsFundingRate() bool {
|
||||
defer d.m.Unlock()
|
||||
return d.isFundingRate
|
||||
}
|
||||
|
||||
// Alert defines fields required to alert sub-systems of a change of state to
|
||||
// re-check depth list
|
||||
type Alert struct {
|
||||
// Channel to wait for an alert on.
|
||||
forAlert chan struct{}
|
||||
// Lets the updater functions know if there are any routines waiting for an
|
||||
// alert.
|
||||
sema uint32
|
||||
// After closing the forAlert channel this will notify when all the routines
|
||||
// that have waited, have either checked the orderbook depth or finished.
|
||||
wg sync.WaitGroup
|
||||
// Segregated lock only for waiting routines, so as this does not interfere
|
||||
// with the main depth lock, acts as a rolling gate.
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
// alert establishes a state change on the orderbook depth.
|
||||
func (a *Alert) alert() {
|
||||
// CompareAndSwap is used to swap from 1 -> 2 so we don't keep actuating
|
||||
// the opposing compare and swap in method wait. This function can return
|
||||
// freely when an alert operation is in process.
|
||||
if !atomic.CompareAndSwapUint32(&a.sema, 1, 2) {
|
||||
// Return if no waiting routines or currently alerting.
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Actuate lock in a different routine, as alerting is a second order
|
||||
// priority compared to updating and releasing calling routine.
|
||||
a.m.Lock()
|
||||
// Closing; alerts many waiting routines.
|
||||
close(a.forAlert)
|
||||
// Wait for waiting routines to receive alert and return.
|
||||
a.wg.Wait()
|
||||
atomic.SwapUint32(&a.sema, 0) // Swap back to neutral state.
|
||||
a.m.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait pauses calling routine until depth change has been established via depth
|
||||
// method alert. Kick allows for cancellation of waiting or when the caller has
|
||||
// has been shut down, if this is not needed it can be set to nil. This
|
||||
// returns a channel so strategies can cleanly wait on a select statement case.
|
||||
func (a *Alert) Wait(kick <-chan struct{}) <-chan bool {
|
||||
reply := make(chan bool)
|
||||
a.m.Lock()
|
||||
a.wg.Add(1)
|
||||
if atomic.CompareAndSwapUint32(&a.sema, 0, 1) {
|
||||
a.forAlert = make(chan struct{})
|
||||
}
|
||||
go a.hold(reply, kick)
|
||||
a.m.Unlock()
|
||||
return reply
|
||||
}
|
||||
|
||||
// hold waits on either channel in the event that the routine has finished or an
|
||||
// alert from a depth update has occurred.
|
||||
func (a *Alert) hold(ch chan<- bool, kick <-chan struct{}) {
|
||||
select {
|
||||
// In a select statement, if by chance there is no receiver or its late,
|
||||
// we can still close and return, limiting dead-lock potential.
|
||||
case <-a.forAlert: // Main waiting channel from alert
|
||||
select {
|
||||
case ch <- false:
|
||||
default:
|
||||
}
|
||||
case <-kick: // This can be nil.
|
||||
select {
|
||||
case ch <- true:
|
||||
default:
|
||||
}
|
||||
}
|
||||
a.wg.Done()
|
||||
close(ch)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ package orderbook
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -307,87 +305,3 @@ func TestPublish(t *testing.T) {
|
||||
d := Depth{}
|
||||
d.Publish()
|
||||
}
|
||||
|
||||
func TestWait(t *testing.T) {
|
||||
wait := Alert{}
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// standard alert
|
||||
wg.Add(100)
|
||||
for x := 0; x < 100; x++ {
|
||||
go func() {
|
||||
w := wait.Wait(nil)
|
||||
wg.Done()
|
||||
if <-w {
|
||||
log.Fatal("incorrect routine wait response for alert expecting false")
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
wg.Add(100)
|
||||
isLeaky(&wait, nil, t)
|
||||
wait.alert()
|
||||
wg.Wait()
|
||||
isLeaky(&wait, nil, t)
|
||||
|
||||
// use kick
|
||||
ch := make(chan struct{})
|
||||
wg.Add(100)
|
||||
for x := 0; x < 100; x++ {
|
||||
go func() {
|
||||
w := wait.Wait(ch)
|
||||
wg.Done()
|
||||
if !<-w {
|
||||
log.Fatal("incorrect routine wait response for kick expecting true")
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
wg.Add(100)
|
||||
isLeaky(&wait, ch, t)
|
||||
close(ch)
|
||||
wg.Wait()
|
||||
ch = make(chan struct{})
|
||||
isLeaky(&wait, ch, t)
|
||||
|
||||
// late receivers
|
||||
wg.Add(100)
|
||||
for x := 0; x < 100; x++ {
|
||||
go func(x int) {
|
||||
bb := wait.Wait(ch)
|
||||
wg.Done()
|
||||
if x%2 == 0 {
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
}
|
||||
b := <-bb
|
||||
if b {
|
||||
log.Fatal("incorrect routine wait response since we call alert below; expecting false")
|
||||
}
|
||||
wg.Done()
|
||||
}(x)
|
||||
}
|
||||
wg.Wait()
|
||||
wg.Add(100)
|
||||
isLeaky(&wait, ch, t)
|
||||
wait.alert()
|
||||
wg.Wait()
|
||||
isLeaky(&wait, ch, t)
|
||||
}
|
||||
|
||||
// isLeaky tests to see if the wait functionality is returning an abnormal
|
||||
// channel that is operational when it shouldn't be.
|
||||
func isLeaky(a *Alert, ch chan struct{}, t *testing.T) {
|
||||
t.Helper()
|
||||
check := a.Wait(ch)
|
||||
time.Sleep(time.Millisecond * 5) // When we call wait a routine for hold is
|
||||
// spawned, so for a test we need to add in a time for goschedular to allow
|
||||
// routine to actually wait on the forAlert and kick channels
|
||||
select {
|
||||
case <-check:
|
||||
t.Fatal("leaky waiter")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package orderbook
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/alert"
|
||||
)
|
||||
|
||||
// Unsafe is an exported linked list reference to the current bid/ask heads and
|
||||
@@ -20,7 +22,7 @@ type Unsafe struct {
|
||||
// protocol then this book is not considered live and cannot be trusted.
|
||||
UpdatedViaREST *bool
|
||||
LastUpdated *time.Time
|
||||
*Alert
|
||||
*alert.Notice
|
||||
}
|
||||
|
||||
// Lock locks down the underlying linked list which inhibits all pending updates
|
||||
@@ -55,7 +57,7 @@ func (d *Depth) GetUnsafe() Unsafe {
|
||||
BidHead: &d.bids.linkedList.head,
|
||||
AskHead: &d.asks.linkedList.head,
|
||||
m: &d.m,
|
||||
Alert: &d.Alert,
|
||||
Notice: &d.Notice,
|
||||
UpdatedViaREST: &d.options.restSnapshot,
|
||||
LastUpdated: &d.options.lastUpdated,
|
||||
}
|
||||
|
||||
2348
gctrpc/rpc.pb.go
2348
gctrpc/rpc.pb.go
File diff suppressed because it is too large
Load Diff
@@ -2809,6 +2809,186 @@ func local_request_GoCryptoTrader_ModifyOrder_0(ctx context.Context, marshaler r
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_GoCryptoTrader_CurrencyStateGetAll_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_GoCryptoTrader_CurrencyStateGetAll_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateGetAllRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateGetAll_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CurrencyStateGetAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_GoCryptoTrader_CurrencyStateGetAll_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateGetAllRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateGetAll_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CurrencyStateGetAll(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_GoCryptoTrader_CurrencyStateTrading_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_GoCryptoTrader_CurrencyStateTrading_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateTradingRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateTrading_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CurrencyStateTrading(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_GoCryptoTrader_CurrencyStateTrading_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateTradingRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateTrading_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CurrencyStateTrading(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_GoCryptoTrader_CurrencyStateDeposit_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_GoCryptoTrader_CurrencyStateDeposit_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateDepositRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateDeposit_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CurrencyStateDeposit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_GoCryptoTrader_CurrencyStateDeposit_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateDepositRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateDeposit_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CurrencyStateDeposit(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_GoCryptoTrader_CurrencyStateWithdraw_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_GoCryptoTrader_CurrencyStateWithdraw_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateWithdrawRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateWithdraw_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CurrencyStateWithdraw(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_GoCryptoTrader_CurrencyStateWithdraw_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateWithdrawRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateWithdraw_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CurrencyStateWithdraw(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_GoCryptoTrader_CurrencyStateTradingPair_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_GoCryptoTrader_CurrencyStateTradingPair_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateTradingPairRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateTradingPair_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CurrencyStateTradingPair(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_GoCryptoTrader_CurrencyStateTradingPair_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CurrencyStateTradingPairRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_CurrencyStateTradingPair_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CurrencyStateTradingPair(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterGoCryptoTraderHandlerServer registers the http handlers for service GoCryptoTrader to "mux".
|
||||
// UnaryRPC :call GoCryptoTraderServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
@@ -4743,6 +4923,121 @@ func RegisterGoCryptoTraderHandlerServer(ctx context.Context, mux *runtime.Serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateGetAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateGetAll", runtime.WithHTTPPathPattern("/v1/currencystategetall"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_GoCryptoTrader_CurrencyStateGetAll_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateGetAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateTrading_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateTrading", runtime.WithHTTPPathPattern("/v1/currencystatetrading"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_GoCryptoTrader_CurrencyStateTrading_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateTrading_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateDeposit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateDeposit", runtime.WithHTTPPathPattern("/v1/currencystatedeposit"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_GoCryptoTrader_CurrencyStateDeposit_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateDeposit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateWithdraw_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateWithdraw", runtime.WithHTTPPathPattern("/v1/currencystatewithdraw"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_GoCryptoTrader_CurrencyStateWithdraw_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateWithdraw_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateTradingPair_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateTradingPair", runtime.WithHTTPPathPattern("/v1/currencystatetradingpair"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_GoCryptoTrader_CurrencyStateTradingPair_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateTradingPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6544,6 +6839,106 @@ func RegisterGoCryptoTraderHandlerClient(ctx context.Context, mux *runtime.Serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateGetAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateGetAll", runtime.WithHTTPPathPattern("/v1/currencystategetall"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_GoCryptoTrader_CurrencyStateGetAll_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateGetAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateTrading_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateTrading", runtime.WithHTTPPathPattern("/v1/currencystatetrading"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_GoCryptoTrader_CurrencyStateTrading_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateTrading_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateDeposit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateDeposit", runtime.WithHTTPPathPattern("/v1/currencystatedeposit"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_GoCryptoTrader_CurrencyStateDeposit_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateDeposit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateWithdraw_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateWithdraw", runtime.WithHTTPPathPattern("/v1/currencystatewithdraw"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_GoCryptoTrader_CurrencyStateWithdraw_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateWithdraw_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_GoCryptoTrader_CurrencyStateTradingPair_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/CurrencyStateTradingPair", runtime.WithHTTPPathPattern("/v1/currencystatetradingpair"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_GoCryptoTrader_CurrencyStateTradingPair_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateTradingPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6723,6 +7118,16 @@ var (
|
||||
pattern_GoCryptoTrader_GetManagedOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getmanagedorders"}, ""))
|
||||
|
||||
pattern_GoCryptoTrader_ModifyOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "modifyorder"}, ""))
|
||||
|
||||
pattern_GoCryptoTrader_CurrencyStateGetAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "currencystategetall"}, ""))
|
||||
|
||||
pattern_GoCryptoTrader_CurrencyStateTrading_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "currencystatetrading"}, ""))
|
||||
|
||||
pattern_GoCryptoTrader_CurrencyStateDeposit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "currencystatedeposit"}, ""))
|
||||
|
||||
pattern_GoCryptoTrader_CurrencyStateWithdraw_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "currencystatewithdraw"}, ""))
|
||||
|
||||
pattern_GoCryptoTrader_CurrencyStateTradingPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "currencystatetradingpair"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -6901,4 +7306,14 @@ var (
|
||||
forward_GoCryptoTrader_GetManagedOrders_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_GoCryptoTrader_ModifyOrder_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateGetAll_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateTrading_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateDeposit_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateWithdraw_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_GoCryptoTrader_CurrencyStateTradingPair_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
||||
@@ -960,6 +960,46 @@ message ModifyOrderResponse {
|
||||
string modified_order_id = 1;
|
||||
}
|
||||
|
||||
message CurrencyStateGetAllRequest {
|
||||
string exchange = 1;
|
||||
}
|
||||
|
||||
message CurrencyStateTradingRequest {
|
||||
string exchange = 1;
|
||||
string code = 2;
|
||||
string asset = 3;
|
||||
}
|
||||
|
||||
message CurrencyStateTradingPairRequest {
|
||||
string exchange = 1;
|
||||
string pair = 2;
|
||||
string asset = 3;
|
||||
}
|
||||
|
||||
message CurrencyStateWithdrawRequest {
|
||||
string exchange = 1;
|
||||
string code = 2;
|
||||
string asset = 3;
|
||||
}
|
||||
|
||||
message CurrencyStateDepositRequest {
|
||||
string exchange = 1;
|
||||
string code = 2;
|
||||
string asset = 3;
|
||||
}
|
||||
|
||||
message CurrencyStateResponse {
|
||||
repeated CurrencyState currency_states = 1;
|
||||
}
|
||||
|
||||
message CurrencyState {
|
||||
string currency = 1;
|
||||
string asset = 2;
|
||||
bool withdraw_enabled = 3;
|
||||
bool deposit_enabled = 4;
|
||||
bool trading_enabled = 5;
|
||||
}
|
||||
|
||||
service GoCryptoTrader {
|
||||
rpc GetInfo (GetInfoRequest) returns (GetInfoResponse) {
|
||||
option (google.api.http) = {
|
||||
@@ -1517,4 +1557,30 @@ service GoCryptoTrader {
|
||||
get: "/v1/modifyorder"
|
||||
};
|
||||
}
|
||||
|
||||
rpc CurrencyStateGetAll (CurrencyStateGetAllRequest) returns (CurrencyStateResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/currencystategetall"
|
||||
};
|
||||
}
|
||||
rpc CurrencyStateTrading (CurrencyStateTradingRequest) returns (GenericResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/currencystatetrading"
|
||||
};
|
||||
}
|
||||
rpc CurrencyStateDeposit (CurrencyStateDepositRequest) returns (GenericResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/currencystatedeposit"
|
||||
};
|
||||
}
|
||||
rpc CurrencyStateWithdraw (CurrencyStateWithdrawRequest) returns (GenericResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/currencystatewithdraw"
|
||||
};
|
||||
}
|
||||
rpc CurrencyStateTradingPair (CurrencyStateTradingPairRequest) returns (GenericResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/currencystatetradingpair"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +261,204 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/currencystatedeposit": {
|
||||
"get": {
|
||||
"operationId": "GoCryptoTrader_CurrencyStateDeposit",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gctrpcGenericResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "exchange",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "code",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "asset",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"GoCryptoTrader"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/currencystategetall": {
|
||||
"get": {
|
||||
"operationId": "GoCryptoTrader_CurrencyStateGetAll",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gctrpcCurrencyStateResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "exchange",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"GoCryptoTrader"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/currencystatetrading": {
|
||||
"get": {
|
||||
"operationId": "GoCryptoTrader_CurrencyStateTrading",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gctrpcGenericResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "exchange",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "code",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "asset",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"GoCryptoTrader"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/currencystatetradingpair": {
|
||||
"get": {
|
||||
"operationId": "GoCryptoTrader_CurrencyStateTradingPair",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gctrpcGenericResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "exchange",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "pair",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "asset",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"GoCryptoTrader"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/currencystatewithdraw": {
|
||||
"get": {
|
||||
"operationId": "GoCryptoTrader_CurrencyStateWithdraw",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gctrpcGenericResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "exchange",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "code",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "asset",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"GoCryptoTrader"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/disableexchange": {
|
||||
"post": {
|
||||
"operationId": "GoCryptoTrader_DisableExchange",
|
||||
@@ -3312,6 +3510,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"gctrpcCurrencyState": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"currency": {
|
||||
"type": "string"
|
||||
},
|
||||
"asset": {
|
||||
"type": "string"
|
||||
},
|
||||
"withdrawEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"depositEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tradingEnabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gctrpcCurrencyStateResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"currencyStates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gctrpcCurrencyState"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gctrpcDataHistoryJob": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -106,6 +106,11 @@ type GoCryptoTraderClient interface {
|
||||
UpdateDataHistoryJobPrerequisite(ctx context.Context, in *UpdateDataHistoryJobPrerequisiteRequest, opts ...grpc.CallOption) (*GenericResponse, error)
|
||||
GetManagedOrders(ctx context.Context, in *GetOrdersRequest, opts ...grpc.CallOption) (*GetOrdersResponse, error)
|
||||
ModifyOrder(ctx context.Context, in *ModifyOrderRequest, opts ...grpc.CallOption) (*ModifyOrderResponse, error)
|
||||
CurrencyStateGetAll(ctx context.Context, in *CurrencyStateGetAllRequest, opts ...grpc.CallOption) (*CurrencyStateResponse, error)
|
||||
CurrencyStateTrading(ctx context.Context, in *CurrencyStateTradingRequest, opts ...grpc.CallOption) (*GenericResponse, error)
|
||||
CurrencyStateDeposit(ctx context.Context, in *CurrencyStateDepositRequest, opts ...grpc.CallOption) (*GenericResponse, error)
|
||||
CurrencyStateWithdraw(ctx context.Context, in *CurrencyStateWithdrawRequest, opts ...grpc.CallOption) (*GenericResponse, error)
|
||||
CurrencyStateTradingPair(ctx context.Context, in *CurrencyStateTradingPairRequest, opts ...grpc.CallOption) (*GenericResponse, error)
|
||||
}
|
||||
|
||||
type goCryptoTraderClient struct {
|
||||
@@ -1046,6 +1051,51 @@ func (c *goCryptoTraderClient) ModifyOrder(ctx context.Context, in *ModifyOrderR
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *goCryptoTraderClient) CurrencyStateGetAll(ctx context.Context, in *CurrencyStateGetAllRequest, opts ...grpc.CallOption) (*CurrencyStateResponse, error) {
|
||||
out := new(CurrencyStateResponse)
|
||||
err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/CurrencyStateGetAll", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *goCryptoTraderClient) CurrencyStateTrading(ctx context.Context, in *CurrencyStateTradingRequest, opts ...grpc.CallOption) (*GenericResponse, error) {
|
||||
out := new(GenericResponse)
|
||||
err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/CurrencyStateTrading", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *goCryptoTraderClient) CurrencyStateDeposit(ctx context.Context, in *CurrencyStateDepositRequest, opts ...grpc.CallOption) (*GenericResponse, error) {
|
||||
out := new(GenericResponse)
|
||||
err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/CurrencyStateDeposit", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *goCryptoTraderClient) CurrencyStateWithdraw(ctx context.Context, in *CurrencyStateWithdrawRequest, opts ...grpc.CallOption) (*GenericResponse, error) {
|
||||
out := new(GenericResponse)
|
||||
err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/CurrencyStateWithdraw", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *goCryptoTraderClient) CurrencyStateTradingPair(ctx context.Context, in *CurrencyStateTradingPairRequest, opts ...grpc.CallOption) (*GenericResponse, error) {
|
||||
out := new(GenericResponse)
|
||||
err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/CurrencyStateTradingPair", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GoCryptoTraderServer is the server API for GoCryptoTrader service.
|
||||
// All implementations must embed UnimplementedGoCryptoTraderServer
|
||||
// for forward compatibility
|
||||
@@ -1138,6 +1188,11 @@ type GoCryptoTraderServer interface {
|
||||
UpdateDataHistoryJobPrerequisite(context.Context, *UpdateDataHistoryJobPrerequisiteRequest) (*GenericResponse, error)
|
||||
GetManagedOrders(context.Context, *GetOrdersRequest) (*GetOrdersResponse, error)
|
||||
ModifyOrder(context.Context, *ModifyOrderRequest) (*ModifyOrderResponse, error)
|
||||
CurrencyStateGetAll(context.Context, *CurrencyStateGetAllRequest) (*CurrencyStateResponse, error)
|
||||
CurrencyStateTrading(context.Context, *CurrencyStateTradingRequest) (*GenericResponse, error)
|
||||
CurrencyStateDeposit(context.Context, *CurrencyStateDepositRequest) (*GenericResponse, error)
|
||||
CurrencyStateWithdraw(context.Context, *CurrencyStateWithdrawRequest) (*GenericResponse, error)
|
||||
CurrencyStateTradingPair(context.Context, *CurrencyStateTradingPairRequest) (*GenericResponse, error)
|
||||
mustEmbedUnimplementedGoCryptoTraderServer()
|
||||
}
|
||||
|
||||
@@ -1409,6 +1464,21 @@ func (UnimplementedGoCryptoTraderServer) GetManagedOrders(context.Context, *GetO
|
||||
func (UnimplementedGoCryptoTraderServer) ModifyOrder(context.Context, *ModifyOrderRequest) (*ModifyOrderResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ModifyOrder not implemented")
|
||||
}
|
||||
func (UnimplementedGoCryptoTraderServer) CurrencyStateGetAll(context.Context, *CurrencyStateGetAllRequest) (*CurrencyStateResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CurrencyStateGetAll not implemented")
|
||||
}
|
||||
func (UnimplementedGoCryptoTraderServer) CurrencyStateTrading(context.Context, *CurrencyStateTradingRequest) (*GenericResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CurrencyStateTrading not implemented")
|
||||
}
|
||||
func (UnimplementedGoCryptoTraderServer) CurrencyStateDeposit(context.Context, *CurrencyStateDepositRequest) (*GenericResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CurrencyStateDeposit not implemented")
|
||||
}
|
||||
func (UnimplementedGoCryptoTraderServer) CurrencyStateWithdraw(context.Context, *CurrencyStateWithdrawRequest) (*GenericResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CurrencyStateWithdraw not implemented")
|
||||
}
|
||||
func (UnimplementedGoCryptoTraderServer) CurrencyStateTradingPair(context.Context, *CurrencyStateTradingPairRequest) (*GenericResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CurrencyStateTradingPair not implemented")
|
||||
}
|
||||
func (UnimplementedGoCryptoTraderServer) mustEmbedUnimplementedGoCryptoTraderServer() {}
|
||||
|
||||
// UnsafeGoCryptoTraderServer may be embedded to opt out of forward compatibility for this service.
|
||||
@@ -3024,6 +3094,96 @@ func _GoCryptoTrader_ModifyOrder_Handler(srv interface{}, ctx context.Context, d
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GoCryptoTrader_CurrencyStateGetAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CurrencyStateGetAllRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateGetAll(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/gctrpc.GoCryptoTrader/CurrencyStateGetAll",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateGetAll(ctx, req.(*CurrencyStateGetAllRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GoCryptoTrader_CurrencyStateTrading_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CurrencyStateTradingRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateTrading(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/gctrpc.GoCryptoTrader/CurrencyStateTrading",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateTrading(ctx, req.(*CurrencyStateTradingRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GoCryptoTrader_CurrencyStateDeposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CurrencyStateDepositRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateDeposit(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/gctrpc.GoCryptoTrader/CurrencyStateDeposit",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateDeposit(ctx, req.(*CurrencyStateDepositRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GoCryptoTrader_CurrencyStateWithdraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CurrencyStateWithdrawRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateWithdraw(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/gctrpc.GoCryptoTrader/CurrencyStateWithdraw",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateWithdraw(ctx, req.(*CurrencyStateWithdrawRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GoCryptoTrader_CurrencyStateTradingPair_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CurrencyStateTradingPairRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateTradingPair(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/gctrpc.GoCryptoTrader/CurrencyStateTradingPair",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GoCryptoTraderServer).CurrencyStateTradingPair(ctx, req.(*CurrencyStateTradingPairRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// GoCryptoTrader_ServiceDesc is the grpc.ServiceDesc for GoCryptoTrader service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -3359,6 +3519,26 @@ var GoCryptoTrader_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ModifyOrder",
|
||||
Handler: _GoCryptoTrader_ModifyOrder_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CurrencyStateGetAll",
|
||||
Handler: _GoCryptoTrader_CurrencyStateGetAll_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CurrencyStateTrading",
|
||||
Handler: _GoCryptoTrader_CurrencyStateTrading_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CurrencyStateDeposit",
|
||||
Handler: _GoCryptoTrader_CurrencyStateDeposit_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CurrencyStateWithdraw",
|
||||
Handler: _GoCryptoTrader_CurrencyStateWithdraw_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CurrencyStateTradingPair",
|
||||
Handler: _GoCryptoTrader_CurrencyStateTradingPair_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
||||
@@ -37,6 +37,14 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(1)
|
||||
}
|
||||
exch.SetDefaults()
|
||||
cfg, err := exch.GetDefaultConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = exch.Setup(cfg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
em.Add(exch)
|
||||
engine.Bot.ExchangeManager = em
|
||||
engine.Bot.WithdrawManager, err = engine.SetupWithdrawManager(em, nil, true)
|
||||
|
||||
1
main.go
1
main.go
@@ -55,6 +55,7 @@ func main() {
|
||||
flag.DurationVar(&settings.EventManagerDelay, "eventmanagerdelay", time.Duration(0), "sets the event managers sleep delay between event checking")
|
||||
flag.BoolVar(&settings.EnableNTPClient, "ntpclient", true, "enables the NTP client to check system clock drift")
|
||||
flag.BoolVar(&settings.EnableDispatcher, "dispatch", true, "enables the dispatch system")
|
||||
flag.BoolVar(&settings.EnableCurrencyStateManager, "currencystatemanager", true, "enables the currency state manager")
|
||||
flag.IntVar(&settings.DispatchMaxWorkerAmount, "dispatchworkers", dispatch.DefaultMaxWorkers, "sets the dispatch package max worker generation limit")
|
||||
flag.IntVar(&settings.DispatchJobsLimit, "dispatchjobslimit", dispatch.DefaultJobsLimit, "sets the dispatch package max jobs limit")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user