mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
script: implementation of error insertion on return (#986)
* exchanges/account: shift credentials to account package and segregate funds to keys * merge: fixes * linter: fix * Update exchanges/account/account.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits + protection for string panic * glorious_suggestion: add method for matching keys * linter: fix tests * account: add protected method for credentials minimizing access, display full account details to rpc. * linter: spelling kweeeeeeen * accounts/portfolio: clean/check portfolio code and quickly check balances from change. Add protected method for future matching. * accounts: theres no point in pointerising everything * linter: ok pointerise this then... * exchanges: fix regression add in little notes. * glorious: nits * Update exchanges/account/credentials.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/account/credentials_test.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/account/credentials_test.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * gloriously: fix glorious glorious test gloriously * script: initial implementation of error insertion on return * script: make script context aware(ish) and update error handle in examples * script: add tests * script: add syntax highlighting to readme * Update gctscript/vm/vm.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/vm/vm.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/examples/exchange/account_info.gct Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/examples/exchange/cancel_order.gct Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/examples/verbose.gct Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct_test.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * rm: bros * scripts: handle errors in examples when they are going to use the data after fetching * linter: fix rides again * SCOTT_SPELL_CHECK_LINTER: fix * gctscript: fix tests * glorious: niiiiiiiiiiiiits * scriptmodules/gct: standardize runtime errors * Update gctscript/modules/gct/exchange.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/exchange.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/exchange.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/exchange.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update gctscript/modules/gct/gct.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits/reverts * go mod: tidy Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
@@ -67,7 +67,7 @@ func IsRunning() bool {
|
||||
return dispatcher.isRunning()
|
||||
}
|
||||
|
||||
// start compares atomic running value, sets defaults, overides with
|
||||
// start compares atomic running value, sets defaults, overrides with
|
||||
// configuration, then spawns workers
|
||||
func (d *Dispatcher) start(workers, channelCapacity int) error {
|
||||
if d == nil {
|
||||
|
||||
@@ -150,7 +150,7 @@ func loadConfigWithSettings(settings *Settings, flagSet map[string]bool) (*confi
|
||||
// FlagSet defines set flags from command line args for comparison methods
|
||||
type FlagSet map[string]bool
|
||||
|
||||
// WithBool checks the supplied flag. If set it will overide the config boolean
|
||||
// WithBool checks the supplied flag. If set it will override the config boolean
|
||||
// value as a command line takes precedence. If not set will fall back to config
|
||||
// options.
|
||||
func (f FlagSet) WithBool(key string, flagValue *bool, configValue bool) {
|
||||
|
||||
@@ -271,7 +271,7 @@ func TestFlagSetWith(t *testing.T) {
|
||||
|
||||
flags["IS SET"] = true
|
||||
isRunning = true
|
||||
// Flag set true which will overide config
|
||||
// Flag set true which will override config
|
||||
flags.WithBool("IS SET", &isRunning, true)
|
||||
if !isRunning {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", isRunning, true)
|
||||
@@ -283,7 +283,7 @@ func TestFlagSetWith(t *testing.T) {
|
||||
|
||||
flags["IS SET"] = true
|
||||
isRunning = false
|
||||
// Flag set false which will overide config
|
||||
// Flag set false which will override config
|
||||
flags.WithBool("IS SET", &isRunning, true)
|
||||
if isRunning {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", isRunning, false)
|
||||
|
||||
@@ -190,7 +190,7 @@ func ParseCredentialsMetadata(ctx context.Context, md metadata.MD) (context.Cont
|
||||
}
|
||||
if ctxCreds.IsEmpty() && subAccountHere != "" {
|
||||
// This will override default sub account details if needed.
|
||||
return deploySubAccountOverrideToContext(ctx, subAccountHere), nil
|
||||
return DeploySubAccountOverrideToContext(ctx, subAccountHere), nil
|
||||
}
|
||||
// merge sub account to main context credentials
|
||||
ctxCreds.SubAccount = subAccountHere
|
||||
@@ -204,9 +204,9 @@ func DeployCredentialsToContext(ctx context.Context, creds *Credentials) context
|
||||
return context.WithValue(ctx, flag, store)
|
||||
}
|
||||
|
||||
// deploySubAccountOverrideToContext sets subaccount as override to credentials
|
||||
// DeploySubAccountOverrideToContext sets subaccount as override to credentials
|
||||
// as a separate flag.
|
||||
func deploySubAccountOverrideToContext(ctx context.Context, subAccount string) context.Context {
|
||||
func DeploySubAccountOverrideToContext(ctx context.Context, subAccount string) context.Context {
|
||||
return context.WithValue(ctx, ContextSubAccountFlag, subAccount)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
|
||||
To Enable database logging support you must have an active migrated database by following the [database setup guide](../database/README.md)
|
||||
|
||||
##### Syntax Highlighting
|
||||
|
||||
To enable syntax highlighting for vscode download extension [graphman65/vscode-tengo](https://github.com/graphman65/vscode-tengo/) then add `".gct"` to vscode-tengo package.json [settings](https://github.com/graphman65/vscode-tengo/blob/master/package.json#L27) to enable highlighting of our files.
|
||||
|
||||
##### Configuration
|
||||
|
||||
The gctscript configuration struct is currently:
|
||||
|
||||
31
gctscript/examples/account.gct
Normal file
31
gctscript/examples/account.gct
Normal file
@@ -0,0 +1,31 @@
|
||||
global := import("global")
|
||||
exch := import("exchange")
|
||||
fmt := import("fmt")
|
||||
|
||||
load := func() {
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// It contains script ID and shortname of file as save details to default
|
||||
// script output directory.
|
||||
|
||||
// Set account func allows the setting of account details via script
|
||||
// which can then be passed into auth functions to specifically target
|
||||
// different subaccounts while trading or retrieving fund details.
|
||||
// Basic required implementation below:
|
||||
ctx = global.set_account(ctx, "api_key_str", "api_secret_str")
|
||||
|
||||
// Full implementation:
|
||||
// ctx = global.set_account(ctx, "api_key_str", "api_secret_str", "sub_account_str", "client_Id_str", "PEM_key_str", "OTP_Str")
|
||||
|
||||
// Set sub account func allows the setting of just the individual sub
|
||||
// account details while utilizing the configured config.json apikeys.
|
||||
// ctx = global.set_sub_account(ctx, "sub_account_str")
|
||||
|
||||
info := exch.accountinfo(ctx, "ftx", "spot")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
load()
|
||||
@@ -1,5 +1,6 @@
|
||||
exch := import("exchange")
|
||||
t := import("times")
|
||||
fmt := import("fmt")
|
||||
// Import all the indicators you want
|
||||
atr := import("indicator/atr")
|
||||
sma := import("indicator/sma")
|
||||
@@ -12,7 +13,12 @@ load := func() {
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
|
||||
// This fetches the ohlcv
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
|
||||
// construct ta values
|
||||
avgtr := atr.calculate(ohlcvData.candles, 14)
|
||||
@@ -22,7 +28,14 @@ load := func() {
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// It contains script ID and shortname of file as save details to default
|
||||
// script output directory.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
common.writeascsv(ctx, ohlcvData, avgtr, simma, expma)
|
||||
|
||||
// A custom filename can also be declared when using a string instead of the
|
||||
// context variable like below. This will continue to save in the output
|
||||
// folder of the scripts file and will look something like this
|
||||
// 'super_cool_filename-1658465844999067400.csv'.
|
||||
// common.writeascsv("super_cool_filename", ohlcvData, avgtr, simma, expma)
|
||||
}
|
||||
|
||||
load()
|
||||
@@ -4,8 +4,14 @@ fmt := import("fmt")
|
||||
exch := import("exchange")
|
||||
|
||||
load := func() {
|
||||
// retrieve account information from exchange and store in info variable
|
||||
info := exch.accountinfo("BTC Markets", "spot")
|
||||
// Retrieve account information from exchange and store in info variable
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
// for more details.
|
||||
info := exch.accountinfo(ctx, "BTC Markets", "spot")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
// print out info
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@ fmt := import("fmt")
|
||||
exch := import("exchange")
|
||||
|
||||
load := func() {
|
||||
info := exch.ordercancel("binance","13371337", "btc-usdt", "spot")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
info := exch.ordercancel(ctx, "binance","13371337", "btc-usdt", "spot")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ exch := import("exchange")
|
||||
|
||||
load := func() {
|
||||
info := exch.depositaddress("BTC Markets", "BTC", "")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,12 @@ t := import("times")
|
||||
|
||||
load := func() {
|
||||
start := t.add(t.now(), -t.hour*24)
|
||||
ohlcvData := exch.ohlcv("coinbasepro", "BTC-USD", "-", "SPOT", start, t.now(), "1h")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "coinbasepro", "BTC-USD", "-", "SPOT", start, t.now(), "1h")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(ohlcvData)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,12 @@ name := "run"
|
||||
timer := "5s"
|
||||
|
||||
load := func() {
|
||||
tx := exch.orderbook("btc markets", "btc-aud", "-", "spot")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
tx := exch.orderbook(ctx, "btc markets", "btc-aud", "-", "spot")
|
||||
if is_error(tx) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(tx)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ exch := import("exchange")
|
||||
|
||||
load := func() {
|
||||
info := exch.pairs("BTC Markets", false, "SPOT")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,12 @@ fmt := import("fmt")
|
||||
exch := import("exchange")
|
||||
|
||||
load := func() {
|
||||
info := exch.orderquery("binance", "4491600698", "BTC-USDT", "spot")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
info := exch.orderquery(ctx, "binance", "4491600698", "BTC-USDT", "spot")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,12 @@ fmt := import("fmt")
|
||||
exch := import("exchange")
|
||||
|
||||
load := func() {
|
||||
info := exch.ordersubmit("BTC Markets","BTC-AUD","-","LIMIT","SELL",1000000, 1,"", "spot")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
info := exch.ordersubmit(ctx, "BTC Markets","BTC-AUD","-","LIMIT","SELL",1000000, 1,"", "spot")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,12 @@ name := "run"
|
||||
timer := "5s"
|
||||
|
||||
load := func() {
|
||||
tx := exch.ticker("btc markets", "btc-aud", "-", "spot")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
tx := exch.ticker(ctx, "btc markets", "btc-aud", "-", "spot")
|
||||
if is_error(tx) {
|
||||
// handle error
|
||||
}
|
||||
fmt.println(tx)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,14 @@ load := func() {
|
||||
// 4: address tag
|
||||
// 5: amount
|
||||
// 6: fee amount
|
||||
// 7: trade password
|
||||
// 8: OTP
|
||||
// 7: description
|
||||
|
||||
info := exch.withdrawcrypto("BTC Markets","BTC", "1234562362", "1231", 1.0, 0.0, "","" )
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
info := exch.withdrawcrypto(ctx, "BTC Markets", "BTC", "1234562362", "1231", 1.0, 0.0, "")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
// print out info
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
@@ -16,8 +16,13 @@ load := func() {
|
||||
// 7: trade password
|
||||
// 8: OTP
|
||||
|
||||
// submit request to withdraw funds
|
||||
info := exch.withdrawfiat("BTC Markets", "AUD", "hello", 1, "-")
|
||||
// Submit request to withdraw funds
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
info := exch.withdrawfiat(ctx, "BTC Markets", "AUD", "hello", 1, "-")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
// print out info
|
||||
fmt.println(info)
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
fmt := import("fmt")
|
||||
|
||||
// 'timer' is a GCT key word that is captured at compilation and used to execute
|
||||
// this script task every defined duration.
|
||||
timer := "5s"
|
||||
|
||||
exit := func() {
|
||||
timer = 0
|
||||
timer = "0s" // This will reset the timer to zero and shutdown the script.
|
||||
}
|
||||
|
||||
load := func() {
|
||||
for x := 0 ; x < 20; x++ {
|
||||
fmt.printf("Hello %v", x)
|
||||
fmt.printf("Hello %v\n", x)
|
||||
}
|
||||
exit()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,14 @@ atr := import("indicator/atr")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17, 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
|
||||
ret := atr.calculate(ohlcvData.candles, 14)
|
||||
fmt.println(ret)
|
||||
|
||||
@@ -6,7 +6,14 @@ bbands := import("indicator/bbands")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
|
||||
ret := bbands.calculate("close", ohlcvData.candles, 20, 2.0, 2.0, "sma")
|
||||
fmt.println(ret)
|
||||
|
||||
@@ -6,8 +6,20 @@ cc := import("indicator/correlationcoefficient")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvDataBTC := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
ohlcvDataETH := exch.ohlcv("binance", "ETH-USDT", "-", "SPOT", start, end, "1d")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvDataBTC := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvDataBTC) {
|
||||
// handle error
|
||||
fmt.println(ohlcvDataBTC)
|
||||
return
|
||||
}
|
||||
ohlcvDataETH := exch.ohlcv(ctx, "binance", "ETH-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvDataETH) {
|
||||
// handle error
|
||||
fmt.println(ohlcvDataETH)
|
||||
return
|
||||
}
|
||||
ret := cc.calculate(ohlcvDataBTC.candles, ohlcvDataETH.candles, 20)
|
||||
fmt.println(ret)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,14 @@ ema := import("indicator/ema")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
ret := ema.calculate(ohlcvData.candles, 9)
|
||||
fmt.println(ret)
|
||||
|
||||
|
||||
@@ -6,8 +6,14 @@ macd := import("indicator/macd")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
ret := macd.calculate(ohlcvData.candles, 12, 26, 9)
|
||||
fmt.println(ret)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,14 @@ mfi := import("indicator/mfi")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
|
||||
ret := mfi.calculate(ohlcvData.candles, 14)
|
||||
fmt.println(ret)
|
||||
|
||||
@@ -6,7 +6,14 @@ obv := import("indicator/obv")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
|
||||
ret := obv.calculate(ohlcvData.candles)
|
||||
fmt.println(ret)
|
||||
|
||||
@@ -6,7 +6,14 @@ rsi := import("indicator/rsi")
|
||||
load := func() {
|
||||
start := t.date(2017, 8 , 17 , 0 , 0 , 0, 0)
|
||||
end := t.add_date(start, 0, 6 , 0)
|
||||
ohlcvData := exch.ohlcv("binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// To add debugging information to the request, see verbose.gct. To add account credentials, see account.gct
|
||||
ohlcvData := exch.ohlcv(ctx, "binance", "BTC-USDT", "-", "SPOT", start, end, "1d")
|
||||
if is_error(ohlcvData) {
|
||||
// handle error
|
||||
fmt.println(ohlcvData)
|
||||
return
|
||||
}
|
||||
|
||||
ret := rsi.calculate(ohlcvData.candles, 14)
|
||||
fmt.println(ret)
|
||||
|
||||
27
gctscript/examples/verbose.gct
Normal file
27
gctscript/examples/verbose.gct
Normal file
@@ -0,0 +1,27 @@
|
||||
global := import("global")
|
||||
exch := import("exchange")
|
||||
fmt := import("fmt")
|
||||
|
||||
load := func() {
|
||||
// 'ctx' is already defined when we construct our bytecode from file.
|
||||
// It contains script ID and shortname of file as save details to default
|
||||
// script output directory.
|
||||
|
||||
// Set verbosity func allows the setting of rest request verbosity to
|
||||
// specifically log out this scripts interaction with any http outbound
|
||||
// request for debugging purposes.
|
||||
ctx = global.set_verbose(ctx)
|
||||
|
||||
// Any verbose logs will be output according to logger settings defined in the config
|
||||
// NOTE: Get account info is cached and updated by another worker thread
|
||||
// therefore calling this script multiple times, if data has already been
|
||||
// fetched request verbosity will be limited.
|
||||
info := exch.accountinfo(ctx, "ftx", "spot")
|
||||
if is_error(info) {
|
||||
// handle error
|
||||
}
|
||||
|
||||
fmt.println(info)
|
||||
}
|
||||
|
||||
load()
|
||||
@@ -59,6 +59,26 @@ func WriteAsCSV(args ...objects.Object) (objects.Object, error) {
|
||||
case indicators.OHLCV:
|
||||
temp, err = convertOHLCV(args[i])
|
||||
front = true
|
||||
case "scriptContext":
|
||||
if target != "" {
|
||||
return nil, fmt.Errorf("filename already set, extra string %v cannot be processed", args[i])
|
||||
}
|
||||
scriptCtx, ok := objects.ToInterface(args[i]).(*Context)
|
||||
if !ok {
|
||||
return nil, common.GetAssertError("*gct.Context", args[i])
|
||||
}
|
||||
|
||||
scriptDetails, ok := scriptCtx.Value["script"]
|
||||
if !ok {
|
||||
return nil, errors.New("no script details")
|
||||
}
|
||||
|
||||
target, ok = objects.ToString(scriptDetails)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to convert incoming output to string")
|
||||
}
|
||||
|
||||
target = processTarget(target)
|
||||
case "string":
|
||||
if target != "" {
|
||||
return nil, fmt.Errorf("filename already set, extra string %v cannot be processed", args[i])
|
||||
@@ -73,26 +93,7 @@ func WriteAsCSV(args ...objects.Object) (objects.Object, error) {
|
||||
return nil, errors.New("script context details not specified")
|
||||
}
|
||||
|
||||
// Removes file transversal
|
||||
target = filepath.Base(target)
|
||||
|
||||
// checks to see if file is context defined, if not it will allow
|
||||
// a client defined filename and append a date, forces the use of
|
||||
// .csv file extension
|
||||
switch {
|
||||
case filepath.Ext(target) != ".csv" && strings.Contains(target, common.GctExt):
|
||||
target += ".csv"
|
||||
case filepath.Ext(target) == ".csv":
|
||||
s := strings.Split(target, ".")
|
||||
if len(s) == 2 {
|
||||
target = s[0] + "-" + strconv.FormatInt(time.Now().UnixNano(), 10) + ".csv"
|
||||
}
|
||||
default:
|
||||
target += "-" + strconv.FormatInt(time.Now().UnixNano(), 10) + ".csv"
|
||||
}
|
||||
|
||||
target = filepath.Join(OutputDir, target)
|
||||
|
||||
target = processTarget(target)
|
||||
default:
|
||||
err = fmt.Errorf("%s type is not handled", args[i].TypeName())
|
||||
}
|
||||
@@ -130,7 +131,7 @@ func WriteAsCSV(args ...objects.Object) (objects.Object, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof(log.GCTScriptMgr,
|
||||
log.Debugf(log.GCTScriptMgr,
|
||||
"CSV file successfully saved to: %s",
|
||||
target)
|
||||
return nil, nil
|
||||
@@ -484,3 +485,24 @@ func convertOHLCV(a objects.Object) ([][]string, error) {
|
||||
}
|
||||
return bucket, nil
|
||||
}
|
||||
|
||||
func processTarget(target string) string {
|
||||
// Removes file transversal
|
||||
target = filepath.Base(target)
|
||||
|
||||
// checks to see if file is context defined, if not it will allow
|
||||
// a client defined filename and append a date, forces the use of
|
||||
// .csv file extension
|
||||
switch {
|
||||
case filepath.Ext(target) != ".csv" && strings.Contains(target, common.GctExt):
|
||||
target += ".csv"
|
||||
case filepath.Ext(target) == ".csv":
|
||||
s := strings.Split(target, ".")
|
||||
if len(s) == 2 {
|
||||
target = s[0] + "-" + strconv.FormatInt(time.Now().UnixNano(), 10) + ".csv"
|
||||
}
|
||||
default:
|
||||
target += "-" + strconv.FormatInt(time.Now().UnixNano(), 10) + ".csv"
|
||||
}
|
||||
return filepath.Join(OutputDir, target)
|
||||
}
|
||||
|
||||
39
gctscript/modules/gct/errors.go
Normal file
39
gctscript/modules/gct/errors.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package gct
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
objects "github.com/d5/tengo/v2"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
)
|
||||
|
||||
const standardFormatting = "%s"
|
||||
|
||||
var (
|
||||
errFormatStringIsEmpty = errors.New("format string is empty")
|
||||
errNoArguments = errors.New("no arguments for error response")
|
||||
)
|
||||
|
||||
// errorResponsef is a helper function to apply error details to a return object
|
||||
// for better script side error handling
|
||||
func errorResponsef(format string, a ...interface{}) (objects.Object, error) {
|
||||
if format == "" {
|
||||
return nil, fmt.Errorf("cannot generate tengo error object %w", errFormatStringIsEmpty)
|
||||
}
|
||||
|
||||
if len(a) == 0 {
|
||||
return nil, fmt.Errorf("cannot generate tengo error object %w", errNoArguments)
|
||||
}
|
||||
|
||||
return &objects.Error{
|
||||
Value: &objects.String{Value: fmt.Sprintf(format, a...)},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func constructRuntimeError(argPosition int, funcName, expectedType string, unexpectedData interface{}) error {
|
||||
return fmt.Errorf("function [%s] argument position [%d] - %w",
|
||||
funcName,
|
||||
argPosition,
|
||||
common.GetAssertError(expectedType, unexpectedData))
|
||||
}
|
||||
38
gctscript/modules/gct/errors_test.go
Normal file
38
gctscript/modules/gct/errors_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package gct
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
)
|
||||
|
||||
func TestErrorResponse(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := errorResponsef("")
|
||||
if !errors.Is(err, errFormatStringIsEmpty) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errFormatStringIsEmpty)
|
||||
}
|
||||
|
||||
_, err = errorResponsef("--")
|
||||
if !errors.Is(err, errNoArguments) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoArguments)
|
||||
}
|
||||
|
||||
errResp, err := errorResponsef("error %s", "hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if errResp.String() != `error: "error hello"` {
|
||||
t.Fatalf("received: %v but expected: %v", errResp.String(), `error: "error hello"`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstructRuntimeError(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := constructRuntimeError(0, "", "", nil)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("receieved: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package gct
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -16,74 +15,93 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
const (
|
||||
orderbookFunc = "orderbook"
|
||||
tickerFunc = "ticker"
|
||||
exchangesFunc = "exchanges"
|
||||
pairsFunc = "pairs"
|
||||
accountInfoFunc = "accountinfo"
|
||||
depositAddressFunc = "depositaddress"
|
||||
orderQueryFunc = "orderquery"
|
||||
orderCancelFunc = "ordercancel"
|
||||
orderSubmitFunc = "ordersubmit"
|
||||
withdrawCryptoFunc = "withdrawcrypto"
|
||||
withdrawFiatFunc = "withdrawfiat"
|
||||
ohlcvFunc = "ohlcv"
|
||||
)
|
||||
|
||||
var exchangeModule = map[string]objects.Object{
|
||||
"orderbook": &objects.UserFunction{Name: "orderbook", Value: ExchangeOrderbook},
|
||||
"ticker": &objects.UserFunction{Name: "ticker", Value: ExchangeTicker},
|
||||
"exchanges": &objects.UserFunction{Name: "exchanges", Value: ExchangeExchanges},
|
||||
"pairs": &objects.UserFunction{Name: "pairs", Value: ExchangePairs},
|
||||
"accountinfo": &objects.UserFunction{Name: "accountinfo", Value: ExchangeAccountInfo},
|
||||
"depositaddress": &objects.UserFunction{Name: "depositaddress", Value: ExchangeDepositAddress},
|
||||
"orderquery": &objects.UserFunction{Name: "orderquery", Value: ExchangeOrderQuery},
|
||||
"ordercancel": &objects.UserFunction{Name: "ordercancel", Value: ExchangeOrderCancel},
|
||||
"ordersubmit": &objects.UserFunction{Name: "ordersubmit", Value: ExchangeOrderSubmit},
|
||||
"withdrawcrypto": &objects.UserFunction{Name: "withdrawcrypto", Value: ExchangeWithdrawCrypto},
|
||||
"withdrawfiat": &objects.UserFunction{Name: "withdrawfiat", Value: ExchangeWithdrawFiat},
|
||||
"ohlcv": &objects.UserFunction{Name: "ohlcv", Value: exchangeOHLCV},
|
||||
orderbookFunc: &objects.UserFunction{Name: orderbookFunc, Value: ExchangeOrderbook},
|
||||
tickerFunc: &objects.UserFunction{Name: tickerFunc, Value: ExchangeTicker},
|
||||
exchangesFunc: &objects.UserFunction{Name: exchangesFunc, Value: ExchangeExchanges},
|
||||
pairsFunc: &objects.UserFunction{Name: pairsFunc, Value: ExchangePairs},
|
||||
accountInfoFunc: &objects.UserFunction{Name: accountInfoFunc, Value: ExchangeAccountInfo},
|
||||
depositAddressFunc: &objects.UserFunction{Name: depositAddressFunc, Value: ExchangeDepositAddress},
|
||||
orderQueryFunc: &objects.UserFunction{Name: orderQueryFunc, Value: ExchangeOrderQuery},
|
||||
orderCancelFunc: &objects.UserFunction{Name: orderCancelFunc, Value: ExchangeOrderCancel},
|
||||
orderSubmitFunc: &objects.UserFunction{Name: orderSubmitFunc, Value: ExchangeOrderSubmit},
|
||||
withdrawCryptoFunc: &objects.UserFunction{Name: withdrawCryptoFunc, Value: ExchangeWithdrawCrypto},
|
||||
withdrawFiatFunc: &objects.UserFunction{Name: withdrawFiatFunc, Value: ExchangeWithdrawFiat},
|
||||
ohlcvFunc: &objects.UserFunction{Name: ohlcvFunc, Value: exchangeOHLCV},
|
||||
}
|
||||
|
||||
// ExchangeOrderbook returns orderbook for requested exchange & currencypair
|
||||
func ExchangeOrderbook(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 4 {
|
||||
if len(args) != 5 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, orderbookFunc, "*gct.Context", args[0])
|
||||
}
|
||||
currencyPair, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPair)
|
||||
return nil, constructRuntimeError(2, orderbookFunc, "string", args[1])
|
||||
}
|
||||
delimiter, ok := objects.ToString(args[2])
|
||||
currencyPair, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, delimiter)
|
||||
return nil, constructRuntimeError(3, orderbookFunc, "string", args[2])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[3])
|
||||
delimiter, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetTypeParam)
|
||||
return nil, constructRuntimeError(4, orderbookFunc, "string", args[3])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(5, orderbookFunc, "string", args[4])
|
||||
}
|
||||
|
||||
pair, err := currency.NewPairDelimiter(currencyPair, delimiter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
assetType, err := asset.New(assetTypeParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
ob, err := wrappers.GetWrapper().
|
||||
Orderbook(context.TODO(), exchangeName, pair, assetType)
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
ob, err := wrappers.GetWrapper().Orderbook(ctx, exchangeName, pair, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
var asks, bids objects.Array
|
||||
|
||||
asks := objects.Array{Value: make([]objects.Object, len(ob.Asks))}
|
||||
for x := range ob.Asks {
|
||||
temp := make(map[string]objects.Object, 2)
|
||||
temp["amount"] = &objects.Float{Value: ob.Asks[x].Amount}
|
||||
temp["price"] = &objects.Float{Value: ob.Asks[x].Price}
|
||||
asks.Value = append(asks.Value, &objects.Map{Value: temp})
|
||||
asks.Value[x] = &objects.Map{Value: temp}
|
||||
}
|
||||
|
||||
bids := objects.Array{Value: make([]objects.Object, len(ob.Bids))}
|
||||
for x := range ob.Bids {
|
||||
temp := make(map[string]objects.Object, 2)
|
||||
temp["amount"] = &objects.Float{Value: ob.Bids[x].Amount}
|
||||
temp["price"] = &objects.Float{Value: ob.Bids[x].Price}
|
||||
bids.Value = append(bids.Value, &objects.Map{Value: temp})
|
||||
bids.Value[x] = &objects.Map{Value: temp}
|
||||
}
|
||||
|
||||
data := make(map[string]objects.Object, 5)
|
||||
@@ -93,32 +111,35 @@ func ExchangeOrderbook(args ...objects.Object) (objects.Object, error) {
|
||||
data["bids"] = &bids
|
||||
data["asset"] = &objects.String{Value: ob.Asset.String()}
|
||||
|
||||
return &objects.Map{
|
||||
Value: data,
|
||||
}, nil
|
||||
return &objects.Map{Value: data}, nil
|
||||
}
|
||||
|
||||
// ExchangeTicker returns ticker data for requested exchange and currency pair
|
||||
func ExchangeTicker(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 4 {
|
||||
if len(args) != 5 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, tickerFunc, "*gct.Context", args[0])
|
||||
}
|
||||
currencyPair, ok := objects.ToString(args[1])
|
||||
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPair)
|
||||
return nil, constructRuntimeError(2, tickerFunc, "string", args[1])
|
||||
}
|
||||
delimiter, ok := objects.ToString(args[2])
|
||||
currencyPair, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, delimiter)
|
||||
return nil, constructRuntimeError(3, tickerFunc, "string", args[2])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[3])
|
||||
delimiter, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetTypeParam)
|
||||
return nil, constructRuntimeError(4, tickerFunc, "string", args[3])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(5, tickerFunc, "string", args[4])
|
||||
}
|
||||
|
||||
pair, err := currency.NewPairDelimiter(currencyPair, delimiter)
|
||||
@@ -128,13 +149,13 @@ func ExchangeTicker(args ...objects.Object) (objects.Object, error) {
|
||||
|
||||
assetType, err := asset.New(assetTypeParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
tx, err := wrappers.GetWrapper().
|
||||
Ticker(context.TODO(), exchangeName, pair, assetType)
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
tx, err := wrappers.GetWrapper().Ticker(ctx, exchangeName, pair, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
data := make(map[string]objects.Object, 14)
|
||||
@@ -166,13 +187,15 @@ func ExchangeExchanges(args ...objects.Object) (objects.Object, error) {
|
||||
|
||||
enabledOnly, ok := objects.ToBool(args[0])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, enabledOnly)
|
||||
return nil, constructRuntimeError(1, exchangesFunc, "bool", args[0])
|
||||
}
|
||||
rtnValue := wrappers.GetWrapper().Exchanges(enabledOnly)
|
||||
|
||||
r := objects.Array{}
|
||||
r := objects.Array{
|
||||
Value: make([]objects.Object, len(rtnValue)),
|
||||
}
|
||||
for x := range rtnValue {
|
||||
r.Value = append(r.Value, &objects.String{Value: rtnValue[x]})
|
||||
r.Value[x] = &objects.String{Value: rtnValue[x]}
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
@@ -186,56 +209,64 @@ func ExchangePairs(args ...objects.Object) (objects.Object, error) {
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, pairsFunc, "string", args[0])
|
||||
}
|
||||
enabledOnly, ok := objects.ToBool(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, enabledOnly)
|
||||
return nil, constructRuntimeError(2, pairsFunc, "bool", args[1])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetTypeParam)
|
||||
return nil, constructRuntimeError(3, pairsFunc, "string", args[2])
|
||||
}
|
||||
assetType, err := asset.New(assetTypeParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
rtnValue, err := wrappers.GetWrapper().Pairs(exchangeName, enabledOnly, assetType)
|
||||
pairs, err := wrappers.GetWrapper().Pairs(exchangeName, enabledOnly, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
r := objects.Array{}
|
||||
pairs := *(*[]currency.Pair)(rtnValue)
|
||||
for x := range pairs {
|
||||
r.Value = append(r.Value, &objects.String{Value: pairs[x].String()})
|
||||
r := objects.Array{
|
||||
Value: make([]objects.Object, len(*pairs)),
|
||||
}
|
||||
|
||||
for x := range *pairs {
|
||||
r.Value[x] = &objects.String{Value: (*pairs)[x].String()}
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// ExchangeAccountInfo returns account information for requested exchange
|
||||
func ExchangeAccountInfo(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
if len(args) != 3 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, accountInfoFunc, "*gct.Context", args[0])
|
||||
}
|
||||
assetString, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetString)
|
||||
return nil, constructRuntimeError(2, accountInfoFunc, "string", args[1])
|
||||
}
|
||||
assetString, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(3, accountInfoFunc, "string", args[2])
|
||||
}
|
||||
assetType, err := asset.New(assetString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
rtnValue, err := wrappers.GetWrapper().
|
||||
AccountInformation(context.TODO(), exchangeName, assetType)
|
||||
AccountInformation(ctx, exchangeName, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
var funds objects.Array
|
||||
@@ -252,62 +283,65 @@ func ExchangeAccountInfo(args ...objects.Object) (objects.Object, error) {
|
||||
data := make(map[string]objects.Object, 2)
|
||||
data["exchange"] = &objects.String{Value: rtnValue.Exchange}
|
||||
data["currencies"] = &funds
|
||||
|
||||
return &objects.Map{
|
||||
Value: data,
|
||||
}, nil
|
||||
return &objects.Map{Value: data}, nil
|
||||
}
|
||||
|
||||
// ExchangeOrderQuery query order on exchange
|
||||
func ExchangeOrderQuery(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) < 2 {
|
||||
if len(args) < 3 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, orderQueryFunc, "*gct.Context", args[0])
|
||||
}
|
||||
orderID, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderID)
|
||||
return nil, constructRuntimeError(2, orderQueryFunc, "string", args[1])
|
||||
}
|
||||
orderID, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(3, orderQueryFunc, "string", args[2])
|
||||
}
|
||||
|
||||
var pair currency.Pair
|
||||
assetTypeString := asset.Spot.String()
|
||||
|
||||
switch len(args) {
|
||||
case 4:
|
||||
assetTypeString, ok = objects.ToString(args[3])
|
||||
case 5:
|
||||
assetTypeString, ok = objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetTypeString)
|
||||
return nil, constructRuntimeError(5, orderQueryFunc, "string", args[4])
|
||||
}
|
||||
fallthrough
|
||||
case 3:
|
||||
currencyPairString, isOk := objects.ToString(args[2])
|
||||
case 4:
|
||||
currencyPairString, isOk := objects.ToString(args[3])
|
||||
if !isOk {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPairString)
|
||||
return nil, constructRuntimeError(4, orderQueryFunc, "string", args[3])
|
||||
}
|
||||
|
||||
var err error
|
||||
pair, err = currency.NewPairFromString(currencyPairString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPairString)
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
}
|
||||
|
||||
assetType, err := asset.New(assetTypeString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
orderDetails, err := wrappers.GetWrapper().
|
||||
QueryOrder(context.TODO(), exchangeName, orderID, pair, assetType)
|
||||
QueryOrder(ctx, exchangeName, orderID, pair, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
var tradeHistory objects.Array
|
||||
tradeHistory.Value = make([]objects.Object, len(orderDetails.Trades))
|
||||
for x := range orderDetails.Trades {
|
||||
temp := make(map[string]objects.Object, 7)
|
||||
temp["timestamp"] = &objects.Time{Value: orderDetails.Trades[x].Timestamp}
|
||||
@@ -317,7 +351,7 @@ func ExchangeOrderQuery(args ...objects.Object) (objects.Object, error) {
|
||||
temp["type"] = &objects.String{Value: orderDetails.Trades[x].Type.String()}
|
||||
temp["side"] = &objects.String{Value: orderDetails.Trades[x].Side.String()}
|
||||
temp["description"] = &objects.String{Value: orderDetails.Trades[x].Description}
|
||||
tradeHistory.Value = append(tradeHistory.Value, &objects.Map{Value: temp})
|
||||
tradeHistory.Value[x] = &objects.Map{Value: temp}
|
||||
}
|
||||
|
||||
data := make(map[string]objects.Object, 14)
|
||||
@@ -336,63 +370,65 @@ func ExchangeOrderQuery(args ...objects.Object) (objects.Object, error) {
|
||||
data["status"] = &objects.String{Value: orderDetails.Status.String()}
|
||||
data["trades"] = &tradeHistory
|
||||
|
||||
return &objects.Map{
|
||||
Value: data,
|
||||
}, nil
|
||||
return &objects.Map{Value: data}, nil
|
||||
}
|
||||
|
||||
// ExchangeOrderCancel cancels order on requested exchange
|
||||
func ExchangeOrderCancel(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) < 2 || len(args) > 4 {
|
||||
if len(args) < 3 || len(args) > 5 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, orderCancelFunc, "*gct.Context", args[0])
|
||||
}
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(2, orderCancelFunc, "string", args[1])
|
||||
}
|
||||
if exchangeName == "" {
|
||||
return nil, fmt.Errorf(ErrEmptyParameter, "exchange name")
|
||||
}
|
||||
var orderID string
|
||||
orderID, ok = objects.ToString(args[1])
|
||||
orderID, ok = objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderID)
|
||||
return nil, constructRuntimeError(3, orderCancelFunc, "string", args[2])
|
||||
}
|
||||
if orderID == "" {
|
||||
return nil, fmt.Errorf(ErrEmptyParameter, "orderID")
|
||||
}
|
||||
var err error
|
||||
var cp currency.Pair
|
||||
if len(args) > 2 {
|
||||
if len(args) > 3 {
|
||||
var currencyPair string
|
||||
currencyPair, ok = objects.ToString(args[2])
|
||||
currencyPair, ok = objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPair)
|
||||
return nil, constructRuntimeError(4, orderCancelFunc, "string", args[3])
|
||||
}
|
||||
cp, err = currency.NewPairFromString(currencyPair)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
}
|
||||
var a asset.Item
|
||||
if len(args) > 3 {
|
||||
if len(args) > 4 {
|
||||
var assetType string
|
||||
assetType, ok = objects.ToString(args[3])
|
||||
assetType, ok = objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetType)
|
||||
return nil, constructRuntimeError(5, orderCancelFunc, "string", args[4])
|
||||
}
|
||||
a, err = asset.New(assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
}
|
||||
|
||||
var isCancelled bool
|
||||
isCancelled, err = wrappers.GetWrapper().
|
||||
CancelOrder(context.TODO(), exchangeName, orderID, cp, a)
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
isCancelled, err := wrappers.GetWrapper().
|
||||
CancelOrder(ctx, exchangeName, orderID, cp, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
if isCancelled {
|
||||
@@ -403,63 +439,69 @@ func ExchangeOrderCancel(args ...objects.Object) (objects.Object, error) {
|
||||
|
||||
// ExchangeOrderSubmit submit order on exchange
|
||||
func ExchangeOrderSubmit(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 9 {
|
||||
if len(args) != 10 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, orderSubmitFunc, "*gct.Context", args[0])
|
||||
}
|
||||
currencyPair, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPair)
|
||||
return nil, constructRuntimeError(2, orderSubmitFunc, "string", args[1])
|
||||
}
|
||||
delimiter, ok := objects.ToString(args[2])
|
||||
currencyPair, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, delimiter)
|
||||
return nil, constructRuntimeError(3, orderSubmitFunc, "string", args[2])
|
||||
}
|
||||
delimiter, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(4, orderSubmitFunc, "string", args[3])
|
||||
}
|
||||
orderType, ok := objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(5, orderSubmitFunc, "string", args[4])
|
||||
}
|
||||
orderSide, ok := objects.ToString(args[5])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(6, orderSubmitFunc, "string", args[5])
|
||||
}
|
||||
orderPrice, ok := objects.ToFloat64(args[6])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(7, orderSubmitFunc, "float64", args[6])
|
||||
}
|
||||
orderAmount, ok := objects.ToFloat64(args[7])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(8, orderSubmitFunc, "float64", args[7])
|
||||
}
|
||||
orderClientID, ok := objects.ToString(args[8])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(9, orderSubmitFunc, "string", args[8])
|
||||
}
|
||||
assetType, ok := objects.ToString(args[9])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(10, orderSubmitFunc, "string", args[9])
|
||||
}
|
||||
|
||||
pair, err := currency.NewPairDelimiter(currencyPair, delimiter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderType, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderType)
|
||||
}
|
||||
orderSide, ok := objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderSide)
|
||||
}
|
||||
orderPrice, ok := objects.ToFloat64(args[5])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderPrice)
|
||||
}
|
||||
orderAmount, ok := objects.ToFloat64(args[6])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderAmount)
|
||||
}
|
||||
orderClientID, ok := objects.ToString(args[7])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderClientID)
|
||||
}
|
||||
assetType, ok := objects.ToString(args[8])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, orderClientID)
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
a, err := asset.New(assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
side, err := order.StringToOrderSide(orderSide)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
oType, err := order.StringToOrderType(orderType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
tempSubmit := &order.Submit{
|
||||
@@ -473,18 +515,17 @@ func ExchangeOrderSubmit(args ...objects.Object) (objects.Object, error) {
|
||||
Exchange: exchangeName,
|
||||
}
|
||||
|
||||
rtn, err := wrappers.GetWrapper().SubmitOrder(context.TODO(), tempSubmit)
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
rtn, err := wrappers.GetWrapper().SubmitOrder(ctx, tempSubmit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
data := make(map[string]objects.Object, 2)
|
||||
data["orderid"] = &objects.String{Value: rtn.OrderID}
|
||||
data["isorderplaced"] = objects.TrueValue
|
||||
|
||||
return &objects.Map{
|
||||
Value: data,
|
||||
}, nil
|
||||
return &objects.Map{Value: data}, nil
|
||||
}
|
||||
|
||||
// ExchangeDepositAddress returns deposit address (if supported by exchange)
|
||||
@@ -495,65 +536,67 @@ func ExchangeDepositAddress(args ...objects.Object) (objects.Object, error) {
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, depositAddressFunc, "string", args[0])
|
||||
}
|
||||
currencyCode, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyCode)
|
||||
return nil, constructRuntimeError(2, depositAddressFunc, "string", args[1])
|
||||
}
|
||||
chain, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, chain)
|
||||
return nil, constructRuntimeError(3, depositAddressFunc, "string", args[2])
|
||||
}
|
||||
|
||||
currCode := currency.NewCode(currencyCode)
|
||||
|
||||
rtn, err := wrappers.GetWrapper().DepositAddress(exchangeName, chain, currCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
data := make(map[string]objects.Object, 2)
|
||||
data["address"] = &objects.String{Value: rtn.Address}
|
||||
data["tag"] = &objects.String{Value: rtn.Tag}
|
||||
return &objects.Map{
|
||||
Value: data,
|
||||
}, nil
|
||||
return &objects.Map{Value: data}, nil
|
||||
}
|
||||
|
||||
// ExchangeWithdrawCrypto submit request to withdraw crypto assets
|
||||
func ExchangeWithdrawCrypto(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 7 {
|
||||
if len(args) != 8 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, withdrawCryptoFunc, "*gct.Context", args[0])
|
||||
}
|
||||
cur, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, cur)
|
||||
return nil, constructRuntimeError(2, withdrawCryptoFunc, "string", args[1])
|
||||
}
|
||||
address, ok := objects.ToString(args[2])
|
||||
cur, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, address)
|
||||
return nil, constructRuntimeError(3, withdrawCryptoFunc, "string", args[2])
|
||||
}
|
||||
addressTag, ok := objects.ToString(args[3])
|
||||
address, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, addressTag)
|
||||
return nil, constructRuntimeError(4, withdrawCryptoFunc, "string", args[3])
|
||||
}
|
||||
amount, ok := objects.ToFloat64(args[4])
|
||||
addressTag, ok := objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, amount)
|
||||
return nil, constructRuntimeError(5, withdrawCryptoFunc, "string", args[4])
|
||||
}
|
||||
feeAmount, ok := objects.ToFloat64(args[5])
|
||||
amount, ok := objects.ToFloat64(args[5])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, feeAmount)
|
||||
return nil, constructRuntimeError(6, withdrawCryptoFunc, "float64", args[5])
|
||||
}
|
||||
description, ok := objects.ToString(args[6])
|
||||
feeAmount, ok := objects.ToFloat64(args[6])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, description)
|
||||
return nil, constructRuntimeError(7, withdrawCryptoFunc, "float64", args[6])
|
||||
}
|
||||
description, ok := objects.ToString(args[7])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(8, withdrawCryptoFunc, "string", args[7])
|
||||
}
|
||||
|
||||
withdrawRequest := &withdraw.Request{
|
||||
@@ -568,10 +611,10 @@ func ExchangeWithdrawCrypto(args ...objects.Object) (objects.Object, error) {
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
rtn, err := wrappers.GetWrapper().
|
||||
WithdrawalCryptoFunds(context.TODO(), withdrawRequest)
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
rtn, err := wrappers.GetWrapper().WithdrawalCryptoFunds(ctx, withdrawRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
return &objects.String{Value: rtn}, nil
|
||||
@@ -579,29 +622,33 @@ func ExchangeWithdrawCrypto(args ...objects.Object) (objects.Object, error) {
|
||||
|
||||
// ExchangeWithdrawFiat submit request to withdraw fiat assets
|
||||
func ExchangeWithdrawFiat(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 5 {
|
||||
if len(args) != 6 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, withdrawFiatFunc, "*gct.Context", args[0])
|
||||
}
|
||||
cur, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, cur)
|
||||
return nil, constructRuntimeError(2, withdrawFiatFunc, "string", args[1])
|
||||
}
|
||||
description, ok := objects.ToString(args[2])
|
||||
cur, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, description)
|
||||
return nil, constructRuntimeError(3, withdrawFiatFunc, "string", args[2])
|
||||
}
|
||||
amount, ok := objects.ToFloat64(args[3])
|
||||
description, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, amount)
|
||||
return nil, constructRuntimeError(4, withdrawFiatFunc, "string", args[3])
|
||||
}
|
||||
bankAccountID, ok := objects.ToString(args[4])
|
||||
amount, ok := objects.ToFloat64(args[4])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, bankAccountID)
|
||||
return nil, constructRuntimeError(5, withdrawFiatFunc, "float64", args[4])
|
||||
}
|
||||
bankAccountID, ok := objects.ToString(args[5])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(6, withdrawFiatFunc, "string", args[5])
|
||||
}
|
||||
|
||||
withdrawRequest := &withdraw.Request{
|
||||
@@ -611,10 +658,11 @@ func ExchangeWithdrawFiat(args ...objects.Object) (objects.Object, error) {
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
rtn, err := wrappers.GetWrapper().
|
||||
WithdrawalFiatFunds(context.TODO(), bankAccountID, withdrawRequest)
|
||||
WithdrawalFiatFunds(ctx, bankAccountID, withdrawRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
return &objects.String{Value: rtn}, nil
|
||||
@@ -631,56 +679,61 @@ func (o *OHLCV) TypeName() string {
|
||||
}
|
||||
|
||||
func exchangeOHLCV(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 7 {
|
||||
if len(args) != 8 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
exchangeName, ok := objects.ToString(args[0])
|
||||
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, exchangeName)
|
||||
return nil, constructRuntimeError(1, ohlcvFunc, "*gct.Context", args[0])
|
||||
}
|
||||
currencyPair, ok := objects.ToString(args[1])
|
||||
exchangeName, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, currencyPair)
|
||||
return nil, constructRuntimeError(2, ohlcvFunc, "string", args[1])
|
||||
}
|
||||
delimiter, ok := objects.ToString(args[2])
|
||||
currencyPair, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, delimiter)
|
||||
return nil, constructRuntimeError(3, ohlcvFunc, "string", args[2])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[3])
|
||||
delimiter, ok := objects.ToString(args[3])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, assetTypeParam)
|
||||
return nil, constructRuntimeError(4, ohlcvFunc, "string", args[3])
|
||||
}
|
||||
assetTypeParam, ok := objects.ToString(args[4])
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(5, ohlcvFunc, "string", args[4])
|
||||
}
|
||||
|
||||
startTime, ok := objects.ToTime(args[4])
|
||||
startTime, ok := objects.ToTime(args[5])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, startTime)
|
||||
return nil, constructRuntimeError(6, ohlcvFunc, "string", args[5])
|
||||
}
|
||||
|
||||
endTime, ok := objects.ToTime(args[5])
|
||||
endTime, ok := objects.ToTime(args[6])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, endTime)
|
||||
return nil, constructRuntimeError(7, ohlcvFunc, "time.Time", args[6])
|
||||
}
|
||||
|
||||
intervalStr, ok := objects.ToString(args[6])
|
||||
intervalStr, ok := objects.ToString(args[7])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(ErrParameterConvertFailed, endTime)
|
||||
return nil, constructRuntimeError(8, ohlcvFunc, "string", args[7])
|
||||
}
|
||||
interval, err := parseInterval(intervalStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
pair, err := currency.NewPairDelimiter(currencyPair, delimiter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
assetType, err := asset.New(assetTypeParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
ctx := processScriptContext(scriptCtx)
|
||||
ret, err := wrappers.GetWrapper().
|
||||
OHLCV(context.TODO(),
|
||||
OHLCV(ctx,
|
||||
exchangeName,
|
||||
pair,
|
||||
assetType,
|
||||
@@ -688,21 +741,21 @@ func exchangeOHLCV(args ...objects.Object) (objects.Object, error) {
|
||||
endTime,
|
||||
kline.Interval(interval))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return errorResponsef(standardFormatting, err)
|
||||
}
|
||||
|
||||
var candles objects.Array
|
||||
candles := objects.Array{Value: make([]objects.Object, len(ret.Candles))}
|
||||
for x := range ret.Candles {
|
||||
candle := &objects.Array{}
|
||||
candle.Value = append(candle.Value, &objects.Int{Value: ret.Candles[x].Time.Unix()},
|
||||
&objects.Float{Value: ret.Candles[x].Open},
|
||||
&objects.Float{Value: ret.Candles[x].High},
|
||||
&objects.Float{Value: ret.Candles[x].Low},
|
||||
&objects.Float{Value: ret.Candles[x].Close},
|
||||
&objects.Float{Value: ret.Candles[x].Volume},
|
||||
)
|
||||
|
||||
candles.Value = append(candles.Value, candle)
|
||||
candles.Value[x] = &objects.Array{
|
||||
Value: []objects.Object{
|
||||
&objects.Int{Value: ret.Candles[x].Time.Unix()},
|
||||
&objects.Float{Value: ret.Candles[x].Open},
|
||||
&objects.Float{Value: ret.Candles[x].High},
|
||||
&objects.Float{Value: ret.Candles[x].Low},
|
||||
&objects.Float{Value: ret.Candles[x].Close},
|
||||
&objects.Float{Value: ret.Candles[x].Volume},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
retValue := make(map[string]objects.Object, 5)
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
package gct
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
objects "github.com/d5/tengo/v2"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
)
|
||||
|
||||
const (
|
||||
setVerboseFunc = "set_verbose"
|
||||
setAccountFunc = "set_account"
|
||||
setSubAccountFunc = "set_sub_account"
|
||||
)
|
||||
|
||||
var globalModules = map[string]objects.Object{
|
||||
setVerboseFunc: &objects.UserFunction{Name: setVerboseFunc, Value: setVerbose},
|
||||
setAccountFunc: &objects.UserFunction{Name: setAccountFunc, Value: setAccount},
|
||||
setSubAccountFunc: &objects.UserFunction{Name: setSubAccountFunc, Value: setSubAccount},
|
||||
}
|
||||
|
||||
// AllModuleNames returns a list of all default module names.
|
||||
func AllModuleNames() []string {
|
||||
names := make([]string, 0, len(Modules))
|
||||
@@ -8,3 +28,183 @@ func AllModuleNames() []string {
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// setVerbose specifically sets verbosity for http rest requests for this script
|
||||
// Params: scriptCTX
|
||||
func setVerbose(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
ctx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(1, setVerboseFunc, "*gct.Context", args[0])
|
||||
}
|
||||
if ctx.Value == nil {
|
||||
ctx.Value = make(map[string]objects.Object)
|
||||
}
|
||||
ctx.Value["verbose"] = objects.TrueValue
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// setAccount sets account details which overrides default credentials for
|
||||
// script account management, api key and secret are required.
|
||||
// Params: scriptCTX, apiKey, apiSecret, subAccount, clientID, PEMKey, OneTimePassword string
|
||||
func setAccount(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) < 3 || len(args) > 7 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
ctx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(1, setAccountFunc, "*gct.Context", args[0])
|
||||
}
|
||||
|
||||
apikey, ok := objects.ToInterface(args[1]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(2, setAccountFunc, "string", args[1])
|
||||
}
|
||||
|
||||
if ctx.Value == nil {
|
||||
ctx.Value = make(map[string]objects.Object)
|
||||
}
|
||||
|
||||
ctx.Value["apikey"] = &objects.String{Value: apikey}
|
||||
|
||||
apisecret, ok := objects.ToInterface(args[2]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(3, setAccountFunc, "string", args[2])
|
||||
}
|
||||
|
||||
ctx.Value["apisecret"] = &objects.String{Value: apisecret}
|
||||
|
||||
if len(args) > 3 {
|
||||
var subaccount string
|
||||
subaccount, ok = objects.ToInterface(args[3]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(4, setAccountFunc, "string", args[3])
|
||||
}
|
||||
|
||||
if subaccount != "" {
|
||||
ctx.Value["subaccount"] = &objects.String{Value: subaccount}
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) > 4 {
|
||||
var clientID string
|
||||
clientID, ok = objects.ToInterface(args[4]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(5, setAccountFunc, "string", args[4])
|
||||
}
|
||||
if clientID != "" {
|
||||
ctx.Value["clientid"] = &objects.String{Value: clientID}
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) > 5 {
|
||||
var pemKey string
|
||||
pemKey, ok = objects.ToInterface(args[5]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(6, setAccountFunc, "string", args[5])
|
||||
}
|
||||
if pemKey != "" {
|
||||
ctx.Value["pemkey"] = &objects.String{Value: pemKey}
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) > 5 {
|
||||
var oneTimePassword string
|
||||
oneTimePassword, ok = objects.ToInterface(args[6]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(7, setAccountFunc, "string", args[6])
|
||||
}
|
||||
if oneTimePassword != "" {
|
||||
ctx.Value["otp"] = &objects.String{Value: oneTimePassword}
|
||||
}
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// setSubAccount sets sub account details which overrides default credential
|
||||
// sub account but uses the same configured api keys.
|
||||
// Params: scriptCTX, subAccount string
|
||||
func setSubAccount(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
ctx, ok := objects.ToInterface(args[0]).(*Context)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(1, setSubAccountFunc, "*gct.Context", args[0])
|
||||
}
|
||||
|
||||
sub, ok := objects.ToInterface(args[1]).(string)
|
||||
if !ok {
|
||||
return nil, constructRuntimeError(2, setSubAccountFunc, "string", args[1])
|
||||
}
|
||||
|
||||
if ctx.Value == nil {
|
||||
ctx.Value = make(map[string]objects.Object)
|
||||
}
|
||||
|
||||
ctx.Value["subaccount"] = &objects.String{Value: sub}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func processScriptContext(scriptCtx *Context) context.Context {
|
||||
ctx := context.Background()
|
||||
if scriptCtx == nil || scriptCtx.Value == nil {
|
||||
return ctx
|
||||
}
|
||||
var object objects.Object
|
||||
if object = scriptCtx.Value["verbose"]; object != nil {
|
||||
ctx = request.WithVerbose(ctx)
|
||||
}
|
||||
|
||||
if object = scriptCtx.Value["apikey"]; object != nil {
|
||||
key, _ := objects.ToString(object)
|
||||
|
||||
var secret string
|
||||
if object = scriptCtx.Value["apisecret"]; object != nil {
|
||||
secret, _ = objects.ToString(object)
|
||||
}
|
||||
|
||||
var subAccount string
|
||||
if object = scriptCtx.Value["subaccount"]; object != nil {
|
||||
subAccount, _ = objects.ToString(object)
|
||||
}
|
||||
|
||||
var clientID string
|
||||
if object = scriptCtx.Value["clientid"]; object != nil {
|
||||
clientID, _ = objects.ToString(object)
|
||||
}
|
||||
|
||||
var pemKey string
|
||||
if object = scriptCtx.Value["pemkey"]; object != nil {
|
||||
pemKey, _ = objects.ToString(object)
|
||||
}
|
||||
|
||||
var otp string
|
||||
if object = scriptCtx.Value["otp"]; object != nil {
|
||||
otp, _ = objects.ToString(object)
|
||||
}
|
||||
|
||||
ctx = account.DeployCredentialsToContext(ctx, &account.Credentials{
|
||||
Key: key,
|
||||
Secret: secret,
|
||||
SubAccount: subAccount,
|
||||
ClientID: clientID,
|
||||
PEMKey: pemKey,
|
||||
OneTimePassword: otp,
|
||||
})
|
||||
} else if object = scriptCtx.Value["subaccount"]; object != nil {
|
||||
subAccount, _ := objects.ToString(object)
|
||||
ctx = account.DeploySubAccountOverrideToContext(ctx, subAccount)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
// TypeName returns the name of the custom type.
|
||||
func (c *Context) TypeName() string {
|
||||
return "scriptContext"
|
||||
}
|
||||
|
||||
@@ -8,12 +8,15 @@ import (
|
||||
"time"
|
||||
|
||||
objects "github.com/d5/tengo/v2"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/modules"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/wrappers/validator"
|
||||
)
|
||||
|
||||
var (
|
||||
ctx = &Context{}
|
||||
exch = &objects.String{
|
||||
Value: "BTC Markets",
|
||||
}
|
||||
@@ -48,7 +51,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func TestExchangeOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := ExchangeOrderbook(exch, currencyPair, delimiter, assetType)
|
||||
_, err := ExchangeOrderbook(ctx, exch, currencyPair, delimiter, assetType)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -66,7 +69,7 @@ func TestExchangeOrderbook(t *testing.T) {
|
||||
|
||||
func TestExchangeTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := ExchangeTicker(exch, currencyPair, delimiter, assetType)
|
||||
_, err := ExchangeTicker(ctx, exch, currencyPair, delimiter, assetType)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -133,12 +136,12 @@ func TestAccountInfo(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeAccountInfo(exch, assetType)
|
||||
_, err = ExchangeAccountInfo(ctx, exch, assetType)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeAccountInfo(exchError, assetType)
|
||||
_, err = ExchangeAccountInfo(ctx, exchError, assetType)
|
||||
if err != nil && !errors.Is(err, errTestFailed) {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -152,12 +155,12 @@ func TestExchangeOrderQuery(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderQuery(exch, orderID)
|
||||
_, err = ExchangeOrderQuery(ctx, exch, orderID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderQuery(exchError, orderID)
|
||||
_, err = ExchangeOrderQuery(ctx, exchError, orderID)
|
||||
if err != nil && !errors.Is(err, errTestFailed) {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -180,17 +183,17 @@ func TestExchangeOrderCancel(t *testing.T) {
|
||||
t.Error("expecting error")
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderCancel(exch, orderID)
|
||||
_, err = ExchangeOrderCancel(ctx, exch, orderID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderCancel(exch, orderID, currencyPair)
|
||||
_, err = ExchangeOrderCancel(ctx, exch, orderID, currencyPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderCancel(exch, orderID, currencyPair, assetType)
|
||||
_, err = ExchangeOrderCancel(ctx, exch, orderID, currencyPair, assetType)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -209,19 +212,19 @@ func TestExchangeOrderSubmit(t *testing.T) {
|
||||
orderAmount := &objects.Float{Value: 1}
|
||||
orderAsset := &objects.String{Value: asset.Spot.String()}
|
||||
|
||||
_, err = ExchangeOrderSubmit(exch, currencyPair, delimiter,
|
||||
_, err = ExchangeOrderSubmit(ctx, exch, currencyPair, delimiter,
|
||||
orderType, orderSide, orderPrice, orderAmount, orderID, orderAsset)
|
||||
if err != nil && !errors.Is(err, errTestFailed) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderSubmit(exch, currencyPair, delimiter,
|
||||
_, err = ExchangeOrderSubmit(ctx, exch, currencyPair, delimiter,
|
||||
orderType, orderSide, orderPrice, orderAmount, orderID, orderAsset)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = ExchangeOrderSubmit(objects.TrueValue, currencyPair, delimiter,
|
||||
_, err = ExchangeOrderSubmit(ctx, objects.TrueValue, currencyPair, delimiter,
|
||||
orderType, orderSide, orderPrice, orderAmount, orderID, orderAsset)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -269,7 +272,7 @@ func TestExchangeWithdrawCrypto(t *testing.T) {
|
||||
address := &objects.String{Value: "0xTHISISALEGITBTCADDRESSS"}
|
||||
amount := &objects.Float{Value: 1.0}
|
||||
|
||||
_, err = ExchangeWithdrawCrypto(exch, currCode, address, address, amount, amount, desc)
|
||||
_, err = ExchangeWithdrawCrypto(ctx, exch, currCode, address, address, amount, amount, desc)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -286,7 +289,7 @@ func TestExchangeWithdrawFiat(t *testing.T) {
|
||||
desc := &objects.String{Value: "Hello"}
|
||||
amount := &objects.Float{Value: 1.0}
|
||||
bankID := &objects.String{Value: "test-bank-01"}
|
||||
_, err = ExchangeWithdrawFiat(exch, currCode, desc, amount, bankID)
|
||||
_, err = ExchangeWithdrawFiat(ctx, exch, currCode, desc, amount, bankID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -333,3 +336,193 @@ func TestParseInterval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetVerbose(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := setVerbose()
|
||||
if !errors.Is(err, objects.ErrWrongNumArguments) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, objects.ErrWrongNumArguments)
|
||||
}
|
||||
|
||||
_, err = setVerbose(objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
resp, err := setVerbose(&Context{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
ctx, ok := objects.ToInterface(resp).(*Context)
|
||||
if !ok {
|
||||
t.Fatal("should be of type *Context")
|
||||
}
|
||||
|
||||
val := ctx.Value["verbose"]
|
||||
if val.String() != objects.TrueValue.String() {
|
||||
t.Fatal("should contain verbose string in map")
|
||||
}
|
||||
}
|
||||
|
||||
var dummyStr = &objects.String{Value: "xxxx"}
|
||||
|
||||
func TestSetAccount(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := setAccount()
|
||||
if !errors.Is(err, objects.ErrWrongNumArguments) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, objects.ErrWrongNumArguments)
|
||||
}
|
||||
|
||||
_, err = setAccount(objects.TrueValue, objects.TrueValue, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setAccount(&Context{}, objects.TrueValue, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setAccount(&Context{}, dummyStr, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setAccount(&Context{}, dummyStr, dummyStr, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setAccount(&Context{}, dummyStr, dummyStr, dummyStr, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setAccount(&Context{}, dummyStr, dummyStr, dummyStr, dummyStr, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setAccount(&Context{}, dummyStr, dummyStr, dummyStr, dummyStr, dummyStr, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
resp, err := setAccount(&Context{}, dummyStr, dummyStr, dummyStr, dummyStr, dummyStr, dummyStr)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
ctx, ok := objects.ToInterface(resp).(*Context)
|
||||
if !ok {
|
||||
t.Fatal("should be of type *Context")
|
||||
}
|
||||
|
||||
val := ctx.Value["apikey"]
|
||||
if val.String() != dummyStr.String() {
|
||||
t.Fatal("should contain apikey string in map")
|
||||
}
|
||||
val = ctx.Value["apisecret"]
|
||||
if val.String() != dummyStr.String() {
|
||||
t.Fatal("should contain apisecret string in map")
|
||||
}
|
||||
val = ctx.Value["subaccount"]
|
||||
if val.String() != dummyStr.String() {
|
||||
t.Fatal("should contain subaccount string in map")
|
||||
}
|
||||
val = ctx.Value["clientid"]
|
||||
if val.String() != dummyStr.String() {
|
||||
t.Fatal("should contain clientid string in map")
|
||||
}
|
||||
val = ctx.Value["pemkey"]
|
||||
if val.String() != dummyStr.String() {
|
||||
t.Fatal("should contain pemkey string in map")
|
||||
}
|
||||
val = ctx.Value["otp"]
|
||||
if val.String() != dummyStr.String() {
|
||||
t.Fatal("should contain otp string in map")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetSubAccount(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := setSubAccount()
|
||||
if !errors.Is(err, objects.ErrWrongNumArguments) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, objects.ErrWrongNumArguments)
|
||||
}
|
||||
|
||||
_, err = setSubAccount(objects.TrueValue, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
_, err = setSubAccount(&Context{}, objects.TrueValue)
|
||||
if !errors.Is(err, common.ErrTypeAssertFailure) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrTypeAssertFailure)
|
||||
}
|
||||
|
||||
subby, err := setSubAccount(&Context{}, dummyStr)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
ctxWSubAcc, ok := subby.(*Context)
|
||||
if !ok {
|
||||
t.Fatal("unexpected type returned")
|
||||
}
|
||||
|
||||
if ctxWSubAcc.Value["subaccount"].String() != dummyStr.String() {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", ctxWSubAcc.Value["subaccount"].String(), dummyStr.String())
|
||||
}
|
||||
|
||||
// Deploy override to actual context.Context type
|
||||
ctx := processScriptContext(ctxWSubAcc)
|
||||
if ctx == nil {
|
||||
t.Fatal("should not be nil")
|
||||
}
|
||||
|
||||
subaccount, ok := ctx.Value(account.ContextSubAccountFlag).(string)
|
||||
if !ok {
|
||||
t.Fatal("wrong type")
|
||||
}
|
||||
|
||||
if subaccount != dummyStr.String()[1:5] {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", subaccount, dummyStr.String()[1:5])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessScriptContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := processScriptContext(nil)
|
||||
if ctx == nil {
|
||||
t.Fatal("should not be nil")
|
||||
}
|
||||
|
||||
fromScript, err := setAccount(&Context{}, dummyStr, dummyStr, dummyStr, dummyStr, dummyStr, dummyStr)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
fromScript, err = setVerbose(fromScript)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
scriptCTX, ok := objects.ToInterface(fromScript).(*Context)
|
||||
if !ok {
|
||||
t.Fatal("should assert correctly")
|
||||
}
|
||||
|
||||
ctx = processScriptContext(scriptCTX)
|
||||
if ctx == nil {
|
||||
t.Fatal("should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestScriptCredentialTypeName(t *testing.T) {
|
||||
t.Parallel()
|
||||
if name := (&Context{}).TypeName(); name != "scriptContext" {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package gct
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/d5/tengo/v2"
|
||||
objects "github.com/d5/tengo/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -17,7 +17,13 @@ var errInvalidInterval = errors.New("invalid interval")
|
||||
var supportedDurations = []string{"1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "12h", "24h", "1d", "3d", "1w"}
|
||||
|
||||
// Modules map of all loadable modules
|
||||
var Modules = map[string]map[string]tengo.Object{
|
||||
var Modules = map[string]map[string]objects.Object{
|
||||
"exchange": exchangeModule,
|
||||
"common": commonModule,
|
||||
"global": globalModules,
|
||||
}
|
||||
|
||||
// Context defines a juncture for script context to go context awareness
|
||||
type Context struct {
|
||||
objects.Map
|
||||
}
|
||||
|
||||
@@ -52,10 +52,11 @@ func (g *GctScriptManager) ShutdownAll() (err error) {
|
||||
}
|
||||
|
||||
var shutdownErrors []error
|
||||
AllVMSync.Range(func(k, v interface{}) bool {
|
||||
AllVMSync.Range(func(_, v interface{}) bool {
|
||||
vm, ok := v.(*VM)
|
||||
if !ok {
|
||||
shutdownErrors = append(shutdownErrors, errors.New("unable to type assert VM"))
|
||||
return true
|
||||
}
|
||||
errShutdown := vm.Shutdown()
|
||||
if err != nil {
|
||||
@@ -73,7 +74,7 @@ func (g *GctScriptManager) ShutdownAll() (err error) {
|
||||
|
||||
// RemoveVM remove VM from list
|
||||
func (g *GctScriptManager) RemoveVM(id uuid.UUID) error {
|
||||
if _, f := AllVMSync.Load(id); !f {
|
||||
if _, ok := AllVMSync.Load(id); !ok {
|
||||
return fmt.Errorf(ErrNoVMFound, id.String())
|
||||
}
|
||||
|
||||
|
||||
@@ -33,17 +33,12 @@ func NewManager(config *Config) (*GctScriptManager, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config must be provided for script manager")
|
||||
}
|
||||
return &GctScriptManager{
|
||||
config: config,
|
||||
}, nil
|
||||
return &GctScriptManager{config: config}, nil
|
||||
}
|
||||
|
||||
// IsRunning returns if gctscript manager subsystem is started
|
||||
func (g *GctScriptManager) IsRunning() bool {
|
||||
if g == nil {
|
||||
return false
|
||||
}
|
||||
return atomic.LoadInt32(&g.started) == 1
|
||||
return g != nil && atomic.LoadInt32(&g.started) == 1
|
||||
}
|
||||
|
||||
// Start starts gctscript subsystem and creates shutdown channel
|
||||
@@ -54,12 +49,6 @@ func (g *GctScriptManager) Start(wg *sync.WaitGroup) (err error) {
|
||||
if !atomic.CompareAndSwapInt32(&g.started, 0, 1) {
|
||||
return fmt.Errorf("%s %s", caseName, ErrScriptFailedValidation)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
atomic.CompareAndSwapInt32(&g.started, 1, 0)
|
||||
}
|
||||
}()
|
||||
|
||||
g.shutdown = make(chan struct{})
|
||||
wg.Add(1)
|
||||
go g.run(wg)
|
||||
@@ -74,9 +63,7 @@ func (g *GctScriptManager) Stop() error {
|
||||
if atomic.LoadInt32(&g.started) == 0 {
|
||||
return fmt.Errorf("%s not running", caseName)
|
||||
}
|
||||
defer func() {
|
||||
atomic.CompareAndSwapInt32(&g.started, 1, 0)
|
||||
}()
|
||||
defer atomic.CompareAndSwapInt32(&g.started, 1, 0)
|
||||
|
||||
if err := g.ShutdownAll(); err != nil {
|
||||
return err
|
||||
@@ -90,9 +77,7 @@ func (g *GctScriptManager) run(wg *sync.WaitGroup) {
|
||||
|
||||
SetDefaultScriptOutput()
|
||||
g.autoLoad()
|
||||
defer func() {
|
||||
wg.Done()
|
||||
}()
|
||||
defer wg.Done()
|
||||
|
||||
<-g.shutdown
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
scriptevent "github.com/thrasher-corp/gocryptotrader/database/repository/script"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/modules/gct"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/modules/loader"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/wrappers/validator"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
@@ -33,10 +34,7 @@ func (g *GctScriptManager) NewVM() *VM {
|
||||
}
|
||||
newUUID, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
log.Error(log.GCTScriptMgr, Error{
|
||||
Action: "New: UUID",
|
||||
Cause: err,
|
||||
})
|
||||
log.Error(log.GCTScriptMgr, Error{Action: "New: UUID", Cause: err})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -82,18 +80,19 @@ func (vm *VM) Load(file string) error {
|
||||
|
||||
code, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return &Error{
|
||||
Action: "Load: ReadFile",
|
||||
Script: file,
|
||||
Cause: err,
|
||||
}
|
||||
return &Error{Action: "Load: ReadFile", Script: file, Cause: err}
|
||||
}
|
||||
|
||||
vm.File = file
|
||||
vm.Path = filepath.Dir(file)
|
||||
vm.Script = tengo.NewScript(code)
|
||||
scriptctx := vm.ShortName() + "-" + vm.ID.String()
|
||||
err = vm.Script.Add("ctx", scriptctx)
|
||||
|
||||
scriptCtx := &gct.Context{}
|
||||
scriptCtx.Value = map[string]tengo.Object{
|
||||
"script": &tengo.String{Value: vm.ShortName() + "-" + vm.ID.String()},
|
||||
}
|
||||
|
||||
err = vm.Script.Add("ctx", scriptCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -113,9 +112,8 @@ func (vm *VM) Load(file string) error {
|
||||
|
||||
// Compile compiles to byte code loaded copy of vm script
|
||||
func (vm *VM) Compile() (err error) {
|
||||
vm.Compiled = new(tengo.Compiled)
|
||||
vm.Compiled, err = vm.Script.Compile()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// RunCtx runs compiled byte code with context.Context support.
|
||||
@@ -133,13 +131,10 @@ func (vm *VM) RunCtx() (err error) {
|
||||
err = vm.Compiled.RunContext(ctx)
|
||||
if err != nil {
|
||||
vm.event(StatusFailure, TypeExecute)
|
||||
return Error{
|
||||
Action: "RunCtx",
|
||||
Cause: err,
|
||||
}
|
||||
return Error{Action: "RunCtx", Cause: err}
|
||||
}
|
||||
vm.event(StatusSuccess, TypeExecute)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// CompileAndRun Compile and Run script with support for task running
|
||||
@@ -176,21 +171,18 @@ func (vm *VM) CompileAndRun() {
|
||||
}
|
||||
return
|
||||
}
|
||||
if vm.T < time.Nanosecond {
|
||||
log.Error(log.GCTScriptMgr, "Repeat timer cannot be under 1 nano second")
|
||||
err = vm.Shutdown()
|
||||
if err != nil {
|
||||
log.Errorln(log.GCTScriptMgr, err)
|
||||
}
|
||||
if vm.T > 0 {
|
||||
vm.runner()
|
||||
return
|
||||
}
|
||||
vm.runner()
|
||||
} else {
|
||||
err = vm.Shutdown()
|
||||
if err != nil {
|
||||
log.Error(log.GCTScriptMgr, err)
|
||||
|
||||
if vm.T < 0 {
|
||||
log.Error(log.GCTScriptMgr, "Repeat timer cannot be under 1 nano second")
|
||||
}
|
||||
return
|
||||
}
|
||||
err = vm.Shutdown()
|
||||
if err != nil {
|
||||
log.Error(log.GCTScriptMgr, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,24 +239,23 @@ func (vm *VM) event(status, executionType string) {
|
||||
}
|
||||
|
||||
func (vm *VM) scriptData() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
w := zip.NewWriter(buf)
|
||||
|
||||
f, err := w.Create(vm.ShortName())
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
contents, err := vm.read()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
w := zip.NewWriter(buf)
|
||||
f, err := w.Create(vm.ShortName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = f.Write(contents)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
@@ -34,11 +34,7 @@ const (
|
||||
type vmscount int32
|
||||
|
||||
var (
|
||||
pool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(tengo.Script)
|
||||
},
|
||||
}
|
||||
pool = &sync.Pool{New: func() interface{} { return new(tengo.Script) }}
|
||||
// AllVMSync stores all current Virtual Machine instances
|
||||
AllVMSync = &sync.Map{}
|
||||
// VMSCount running total count of Virtual Machines
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
objects "github.com/d5/tengo/v2"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/engine"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/modules"
|
||||
"github.com/thrasher-corp/gocryptotrader/gctscript/modules/gct"
|
||||
@@ -102,6 +101,8 @@ var (
|
||||
Value: "1235",
|
||||
}
|
||||
|
||||
ctx = &gct.Context{}
|
||||
|
||||
tv = objects.TrueValue
|
||||
fv = objects.FalseValue
|
||||
errTestFailed = errors.New("test failed")
|
||||
@@ -109,12 +110,12 @@ var (
|
||||
|
||||
func TestExchangeOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := gct.ExchangeOrderbook(exch, currencyPair, delimiter, assetType)
|
||||
_, err := gct.ExchangeOrderbook(ctx, exch, currencyPair, delimiter, assetType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = gct.ExchangeOrderbook(exchError, currencyPair, delimiter, assetType)
|
||||
_, err = gct.ExchangeOrderbook(ctx, exchError, currencyPair, delimiter, assetType)
|
||||
if err != nil && errors.Is(err, errTestFailed) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -127,12 +128,12 @@ func TestExchangeOrderbook(t *testing.T) {
|
||||
|
||||
func TestExchangeTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := gct.ExchangeTicker(exch, currencyPair, delimiter, assetType)
|
||||
_, err := gct.ExchangeTicker(ctx, exch, currencyPair, delimiter, assetType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = gct.ExchangeTicker(exchError, currencyPair, delimiter, assetType)
|
||||
_, err = gct.ExchangeTicker(ctx, exchError, currencyPair, delimiter, assetType)
|
||||
if err != nil && errors.Is(err, errTestFailed) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -190,9 +191,14 @@ func TestAccountInfo(t *testing.T) {
|
||||
if !errors.Is(err, objects.ErrWrongNumArguments) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = gct.ExchangeAccountInfo(exch, assetType)
|
||||
if !errors.Is(err, exchange.ErrAuthenticationSupportNotEnabled) {
|
||||
t.Errorf("received: %v but expected: %v", err, exchange.ErrAuthenticationSupportNotEnabled)
|
||||
obj, err := gct.ExchangeAccountInfo(ctx, exch, assetType)
|
||||
if err != nil {
|
||||
t.Fatalf("received: %v but expected: %v", err, nil)
|
||||
}
|
||||
rString, _ := objects.ToString(obj)
|
||||
if rString != `error: "Bitstamp REST or Websocket authentication support is not enabled"` {
|
||||
t.Errorf("received: %v but expected: %v",
|
||||
rString, `error: "Bitstamp REST or Websocket authentication support is not enabled"`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +210,7 @@ func TestExchangeOrderQuery(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = gct.ExchangeOrderQuery(exch, orderID)
|
||||
_, err = gct.ExchangeOrderQuery(ctx, exch, orderID)
|
||||
if err != nil && err != common.ErrNotYetImplemented {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -216,7 +222,7 @@ func TestExchangeOrderCancel(t *testing.T) {
|
||||
if !errors.Is(err, objects.ErrWrongNumArguments) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = gct.ExchangeOrderCancel(exch, orderID, currencyPair, assetType)
|
||||
_, err = gct.ExchangeOrderCancel(ctx, exch, orderID, currencyPair, assetType)
|
||||
if err != nil && err != common.ErrNotYetImplemented {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -235,10 +241,25 @@ func TestExchangeOrderSubmit(t *testing.T) {
|
||||
orderAmount := &objects.Float{Value: 1}
|
||||
orderAsset := &objects.String{Value: asset.Spot.String()}
|
||||
|
||||
_, err = gct.ExchangeOrderSubmit(exch, currencyPair, delimiter,
|
||||
orderType, orderSide, orderPrice, orderAmount, orderID, orderAsset)
|
||||
if !errors.Is(err, exchange.ErrAuthenticationSupportNotEnabled) {
|
||||
t.Errorf("received: %v but expected: %v", err, exchange.ErrAuthenticationSupportNotEnabled)
|
||||
obj, err := gct.ExchangeOrderSubmit(ctx,
|
||||
exch,
|
||||
currencyPair,
|
||||
delimiter,
|
||||
orderType,
|
||||
orderSide,
|
||||
orderPrice,
|
||||
orderAmount,
|
||||
orderID,
|
||||
orderAsset)
|
||||
if err != nil {
|
||||
t.Fatalf("received: %v but expected: %v", err, nil)
|
||||
}
|
||||
|
||||
rString, _ := objects.ToString(obj)
|
||||
if rString != `error: "Bitstamp REST or Websocket authentication support is not enabled"` {
|
||||
t.Errorf("received: [%v] but expected: %v",
|
||||
rString,
|
||||
`error: "Bitstamp REST or Websocket authentication support is not enabled"`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +299,14 @@ func TestExchangeWithdrawCrypto(t *testing.T) {
|
||||
address := &objects.String{Value: "0xTHISISALEGITBTCADDRESSS"}
|
||||
amount := &objects.Float{Value: 1.0}
|
||||
|
||||
_, err = gct.ExchangeWithdrawCrypto(exch, currCode, address, address, amount, amount, desc)
|
||||
_, err = gct.ExchangeWithdrawCrypto(ctx,
|
||||
exch,
|
||||
currCode,
|
||||
address,
|
||||
address,
|
||||
amount,
|
||||
amount,
|
||||
desc)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -295,7 +323,7 @@ func TestExchangeWithdrawFiat(t *testing.T) {
|
||||
amount := &objects.Float{Value: 1.0}
|
||||
desc := &objects.String{Value: "2"}
|
||||
bankID := &objects.String{Value: "3!"}
|
||||
_, err = gct.ExchangeWithdrawFiat(exch, currCode, desc, amount, bankID)
|
||||
_, err = gct.ExchangeWithdrawFiat(ctx, exch, currCode, desc, amount, bankID)
|
||||
if err != nil && err.Error() != "exchange Bitstamp bank details not found for TEST" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
1
go.mod
1
go.mod
@@ -31,6 +31,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/friendsofgo/errors v0.9.2 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -28,7 +28,6 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8=
|
||||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
@@ -42,7 +41,6 @@ cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTB
|
||||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||
cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc=
|
||||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
|
||||
Reference in New Issue
Block a user