mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-24 15:10:19 +00:00
* public endpoints methods added * Completing mapping REST endpoints * Binanceus Wrapper methods -Partially * BinaWra functions with test funs; Not Completed * Finalizing wrapper methods & test * Finalizing wrapper methods & test * Fix & Complete wrapper functions * Adding Stream Datas * WS Test functions * CI: Fix golangci-lint linter issues * CI: Fix reverting unnessesary changes and type conversion issues * CI: Fix reverting unnessesary changes and type conversion issues * CI: Fix comment, method use, error handling, and code handling issues * build(deps): bump github.com/urfave/cli/v2 from 2.4.0 to 2.4.8 (#932) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.4.0 to 2.4.8. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.4.0...v2.4.8) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump google.golang.org/grpc from 1.45.0 to 1.46.0 (#931) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.45.0 to 1.46.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.45.0...v1.46.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * asset: bitmask type optimisation (#922) * asset: basic optim. bitmask * glorious: nits * currency: forgot parralel in testttttt * ticker/orderbook: test fixes * engine/rpcserver: fix and expand tests * test: use `T.TempDir` to create temporary test directory (#934) * test: use `T.TempDir` to create temporary test directory This commit replaces `ioutil.TempDir` with `t.TempDir` in tests. The directory created by `t.TempDir` is automatically removed when the test and all its subtests complete. Prior to this commit, temporary directory created using `ioutil.TempDir` needs to be removed manually by calling `os.RemoveAll`, which is omitted in some tests. The error handling boilerplate e.g. defer func() { if err := os.RemoveAll(dir); err != nil { t.Fatal(err) } } is also tedious, but `t.TempDir` handles this for us nicely. Reference: https://pkg.go.dev/testing#T.TempDir Signed-off-by: Eng Zer Jun <engzerjun@gmail.com> * test: fix TestEncryptTwiceReusesSaltButNewCipher on Windows Signed-off-by: Eng Zer Jun <engzerjun@gmail.com> * test: fix TestCheckConnection on Windows Signed-off-by: Eng Zer Jun <engzerjun@gmail.com> * test: fix TestRPCServer_GetTicker_LastUpdatedNanos on Windows Signed-off-by: Eng Zer Jun <engzerjun@gmail.com> * test: cleanup TestGenerateReport Signed-off-by: Eng Zer Jun <engzerjun@gmail.com> * account: storage, processing and method on balances update (#916) * account: update account storage, retrieval and implement alert functionality when a currency change occurs. * account: Add cancel channel * account: remove old code * account: don't embed mutex * Update exchanges/account/account.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/account/account.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/account/account.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * account: addr nits * account: Pull out test into indiv. * account: Add test for update method * account: add no change to test * Update exchanges/account/account.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * account/portfolio: differentiate between asset type segregation and default to spot holdings. * glorious: nits * thrasher: nit * ticker: fix spelling * Update engine/portfolio_manager.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * thrasher: nits Co-authored-by: Scott <gloriousCode@users.noreply.github.com> Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * build(deps): bump github.com/urfave/cli/v2 from 2.4.8 to 2.5.1 (#936) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.4.8 to 2.5.1. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.4.8...v2.5.1) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * orderbook/buffer: data integrity and resubscription pass (#910) * orderbook/buffer: data integrity and resubscription pass * btcmarkets: REMOVE THAT LIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIINE!!!!!!!!!!!!!!!!! * buffer: reinstate publish, refaactor, invalidate more and comments * buffer/orderbook: improve update and snapshot performance. Move Update type to orderbook package to util. pointer through entire function calls. (cleanup). Change action string to uint8 for easier comparison. Add parsing helper. Update current test benchmark comments. * dispatch: change publish func to variadic id param * dispatch: remove sender receiver wait time as this adds overhead and complexity. update tests. * dispatch: don't create pointers for every job container * rpcserver: fix assertion issues with data publishing change * linter: fixes * glorious: nits addr * depth: change validation handling to incorporate and store err * linter: fix more issues * dispatch: fix race * travis: update before fetching * depth: wrap and return wrapped error in invalidate call and fix tests * btcmarkets: fix commenting * workflow: check * workflow: check * orderbook: check error * buffer/depth: return invalidation error and fix tests * gctcli: display errors on orderbook streams * buffer: remove unused types * orderbook/bitmex: shift function to bitmex * orderbook: Add specific comments to unexported functions that don't have locking require locking. * orderbook: restrict published data functionality to orderbook.Outbound interface * common: add assertion failure helper for error * dispatch: remove atomics, add mutex protection, remove add/remove worker, redo main tests * dispatch: export function * engine: revert and change sub logger to manager * engine: remove old test * dispatch: add common variable ;) * btcmarket: don't overflow int in tests on 32bit systems * ci: force 1.17.7 usage for go * Revert "ci: force 1.17.7 usage for go" This reverts commit af2f95563bf218cf2b9f36a9fcf3258e2c6a2d91. * golangci: bump version add and remove linter items * Revert "golangci: bump version add and remove linter items" This reverts commit 3c98bffc9d030e39faca0387ea40c151df2ab06b. * dispatch: remove unsused mutex from mux * order: slight optimizations * nits: glorious * dispatch: fix regression on uuid generation and input inline with master * linter: fix * linter: fix * glorious: nit - rm slice segration * account: fix test after merge * coinbasepro: revert change * account: close channel instead of needing a receiver, push alert in routine to prepare for waiter. Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> * exchange/wrapper: add GetServerTime() for exchange analytics (#938) * exchange/wrapper: add GetServerTime() for exchange analytics * binance: fix linter issue * glorious: nits * glorious: nits rides again * thrasher: nits implement huobi * thrasher: nits add to exchange_wrapper_issues cmd * order: slight optimizations (#917) * order: slight optimizations * orders: add benchmarks, small optimize and change order side to uin8 for comparitive optimizations. * orders: continue to convert string type -> uint * orders/backtester: interim move type to orders package, later can expand or deprecate. * orders: handle errors * orders: optimize filters and remove error returns when its clearly not needed * orders: remove log call * backtester: zero value check * orders/futures: zero value -> flag * linter: fix * linter: more fixes * linters: rides again * glorious: nits * common: Add zero value unix check for time values; also addresses glorious nits * glorious scott: nits Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> * btcm: add order execution limit wrapper support (#941) * btcm: add in order execution limit fetching * btcm/test: add t.Parrrrrralllleeellllllllll * btcm/wrapper: add update on startup * glorious: nits * thrasher: nit add status field * build(deps): bump github.com/urfave/cli/v2 from 2.5.1 to 2.6.0 (#944) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.5.1 to 2.6.0. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.5.1...v2.6.0) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * proto/lint: Add protobuf GitHub action and linter (#943) * Buf upgrades * Buf format and basic endpoint fixes * gRPC linter fixes * Amend buf.yaml linter exceptions * Update README * Freshly generated gRPC code after depends update * Nitterinos * ordermanager: fix test error introduced in #917 (#942) * ordermanager: fix residual test issue from #917 and reduce some racey action * glorious: nits; also removed functions that weren't being used and were unexported * rm: pew * linter: fix issues * glourious: nits * credentials: fix test issue with racey racey horse basey * engine: Add websocket data handler register function (#935) * engine: Add websocket interceptor register function * Update engine/engine.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update engine/websocketroutine_manager_types.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * engine/websock: switch to data handler function register and range over handlers to still include default gct handling * engine/websocket: change name * glorious: nits * linter: fix * glorious: nits Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * btcm: add modify order functionality, change return to pointer (#940) * btcm: add modify order functionality, change return to pointer * glorious: nits * glorious: nits * btcm: Adjust function name * thrasher: nits * thrasher: nits cont... * request: adds WithVerbose function to package to add verbosity to request context (#950) * request: adds WithVerbose function to package to add verbosity to request context * request: add t.Parr.... * thrasher: nits * build(deps): bump google.golang.org/grpc from 1.46.0 to 1.46.2 (#951) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.46.0 to 1.46.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.46.0...v1.46.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * exchange: expose GetCredentials() and split GetAuthenticatedAPISupport() (#954) * exchange/wrapper: expose GetCredentials func to IBotInterface * exchanges: split up GetAuthenticatedAPISupport into specific function calls, organize IBotExchange functionality getter functions * interface: change name - RPCSercer: rm GetBase func call. * glorious: nits (fix panic) Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> * CI: merge fixes * CI: fixing github generated lint issues * orders: Add method for creating cancel struct from order details (#947) * orders: Add method for creating cancel struct from order details * orders: remove uneeded fields * glorious: nit * grpc: add shutdown call for external management (#957) * grpc: add shutdown call for external management * go mod: tidy * glorious: suggestion * Update engine/engine.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update engine/rpcserver.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update main.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update engine/rpcserver.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * build(deps): bump github.com/lib/pq from 1.10.5 to 1.10.6 (#960) Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.5 to 1.10.6. - [Release notes](https://github.com/lib/pq/releases) - [Commits](https://github.com/lib/pq/compare/v1.10.5...v1.10.6) --- updated-dependencies: - dependency-name: github.com/lib/pq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/urfave/cli/v2 from 2.6.0 to 2.8.0 (#958) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.6.0 to 2.8.0. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.6.0...v2.8.0) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/grpc-ecosystem/grpc-gateway/v2 (#963) Bumps [github.com/grpc-ecosystem/grpc-gateway/v2](https://github.com/grpc-ecosystem/grpc-gateway) from 2.10.0 to 2.10.2. - [Release notes](https://github.com/grpc-ecosystem/grpc-gateway/releases) - [Changelog](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/.goreleaser.yml) - [Commits](https://github.com/grpc-ecosystem/grpc-gateway/compare/v2.10.0...v2.10.2) --- updated-dependencies: - dependency-name: github.com/grpc-ecosystem/grpc-gateway/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * orders: adds method to retrieve snapshot of order execution limit values (#946) * orders: add method to Limit to retrieve order execution limit snapshots * currency/btcmarkets: add error and update field name to standard * linter: fix * limts: don't return pointer * limit: Add notes * glorious: nits * linter: fix * limit: reinstate nil check * exchanges: change field names to be more consistent (@thrasher-) suggestion Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> * orders: Add derive modify struct method from order.Detail (#948) * orders: Add derive modify struct method to order.Detail and then subsequent method to derive and standardize response details * exchanges: call modify method in wrappers * linter: fixes * engine/wsroutineman: remove print summary * glorious: nits, removed modifyOrder functionality for Bithumb. There are not docs to support this. * Update exchanges/order/orders.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * build(deps): bump github.com/spf13/viper from 1.11.0 to 1.12.0 (#965) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.11.0 to 1.12.0. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.11.0...v1.12.0) --- updated-dependencies: - dependency-name: github.com/spf13/viper dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/urfave/cli/v2 from 2.8.0 to 2.8.1 (#964) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.8.0 to 2.8.1. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.8.0...v2.8.1) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * orders: Add methods to derive SubmitResponse and Detail types (#955) * orders: deprecate SubmitResponse return and change to *order.Detail construct detail from order.Submit struct * orders: add coverage, fix tests * coinut: rm test for checking * orders: revert change for return and change field ID to a more explicit name OrderID * orders: Add method to see if the order was placed * order: change field name in Cancel type to be more explicit * orders: standardize field -> OrderID * backtester: populate change * orders: add test * gctscript: fix field name * linter: fix issues * linter: more fixes * linter: forever * exchanges_tests: populate order.Submit field exchange name * Update exchanges/order/order_types.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/order/orders.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * glorious: nits * thrasher: nits Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * build(deps): bump bufbuild/buf-setup-action from 1.4.0 to 1.5.0 (#973) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.4.0...v1.5.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump google.golang.org/grpc from 1.46.2 to 1.47.0 (#972) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.46.2 to 1.47.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.46.2...v1.47.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/grpc-ecosystem/grpc-gateway/v2 (#971) Bumps [github.com/grpc-ecosystem/grpc-gateway/v2](https://github.com/grpc-ecosystem/grpc-gateway) from 2.10.2 to 2.10.3. - [Release notes](https://github.com/grpc-ecosystem/grpc-gateway/releases) - [Changelog](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/.goreleaser.yml) - [Commits](https://github.com/grpc-ecosystem/grpc-gateway/compare/v2.10.2...v2.10.3) --- updated-dependencies: - dependency-name: github.com/grpc-ecosystem/grpc-gateway/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/d5/tengo/v2 from 2.10.1 to 2.11.2 (#975) Bumps [github.com/d5/tengo/v2](https://github.com/d5/tengo) from 2.10.1 to 2.11.2. - [Release notes](https://github.com/d5/tengo/releases) - [Changelog](https://github.com/d5/tengo/blob/master/.goreleaser.yml) - [Commits](https://github.com/d5/tengo/compare/v2.10.1...v2.11.2) --- updated-dependencies: - dependency-name: github.com/d5/tengo/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/urfave/cli/v2 from 2.8.1 to 2.10.1 (#979) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.8.1 to 2.10.1. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.8.1...v2.10.1) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/d5/tengo/v2 from 2.11.2 to 2.12.0 (#978) Bumps [github.com/d5/tengo/v2](https://github.com/d5/tengo) from 2.11.2 to 2.12.0. - [Release notes](https://github.com/d5/tengo/releases) - [Changelog](https://github.com/d5/tengo/blob/master/.goreleaser.yml) - [Commits](https://github.com/d5/tengo/compare/v2.11.2...v2.12.0) --- updated-dependencies: - dependency-name: github.com/d5/tengo/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * CI: adding WS and REST tests, and minor fixes * CI: fixes on available asset and related minor issues * CI: fixes on endpoint function, test functions, and types * CI: updating templates and slight fixes * CI: updating slight fixes on tests and withdraws Request model * build(deps): bump styfle/cancel-workflow-action from 0.9.1 to 0.10.0 (#985) Bumps [styfle/cancel-workflow-action](https://github.com/styfle/cancel-workflow-action) from 0.9.1 to 0.10.0. - [Release notes](https://github.com/styfle/cancel-workflow-action/releases) - [Commits](https://github.com/styfle/cancel-workflow-action/compare/0.9.1...0.10.0) --- updated-dependencies: - dependency-name: styfle/cancel-workflow-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump bufbuild/buf-setup-action from 1.5.0 to 1.6.0 (#984) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * backtester: Futures handling & FTX Cash and Carry example strategy (#930) * implements futures functions and GRPC functions on new branch * lint and test fixes * Fix uneven split pnl. Adds collateral weight test. docs. New clear func * Test protection if someone has zero collateral * Uses string instead of double for accuracy * Fixes old code panic * context, match, docs * Addresses Shazniterinos, var names, expanded tests * Returns subaccount name, provides USD values when offlinecalc * Fixes oopsie * Fixes cool bug which allowed made up subaccount results * Subaccount override on FTX, subaccount results for collateral * Strenghten collateral account info checks. Improve FTX test * English is my first language * Fixes oopsies * Adds some conceptual futures order details to track PNL * Initial design of future order processing in the backtester * Introduces futures concept for collateral and spot/futures config diffs * Fixes most tests * Simple designs for collateral funding pair concept * Expands interface use so much it hurts * Implements more collateral interfaces * Adds liquidation, adds strategy, struggles with Binance * Attempts at getting FTX to work * Adds calculatePNL as a wrapper function and adds an `IsFutures` asset check * Successfully loads backtester with collateral currency * Fails to really get much going for supporting futures * Merges master changes * Fleshes out how FTX processes collateral * Further FTX collateral workings * hooks up more ftx collateral and pnl calculations * more funcs to flesh out handling * Adds more links, just can't fit the pieces together :( * Greatly expands futures order processing * Fleshes out position tracker to also handle asset and exchange +testing * RM linkedOrderID. rn positioncontroller, unexport * Successfully tracks futures order positions * Fails to calculate PNL * Calculates pnl from orders accurately with exception to flipping orders * Calculates PNL from orders * Adds another controller layer to make it ez from orderstore * Backtester now compiles. Adds test coverage * labels things add scaling collateral test * Calculates pnl in line with fees * Mostly accurate PNL, with exception to appending with diff prices * Adds locks, adds rpc function * grpc implementations * Gracefully handles rpc function * beautiful tests! * rejiggles tests to polish * Finishes FTX testing, adds comments * Exposes collateral calculations to rpc * Adds commands and testing for rpcserver.go functions * Increase testing and fix up backtester code * Returns cool changes to original branch * end of day fixes * Fixing some tests * Fixing tests 🎉 * Fixes all the tests * Splits the backtester setup and running into different files * Merge, minor fixes * Messing with some strategy updates * Failed understanding at collateral usage * Begins the creation of cash and carry strategy * Adds underlying pair, adds filldependentevent for futures * Completes fill prerequsite event implementation. Can't short though * Some bug fixes * investigating funds * CAN NOW CREATE A SHORT ORDER * Minor change in short size * Fixes for unrealised PNL & collateral rendering * Fixes lint and tests * Adds some verbosity * Updates to pnl calc * Tracks pnl for short orders, minor update to strategy * Close and open event based on conditions * Adds pnl data for currency statistics * Working through PNL calculation automatically. Now panics * Adds tracking, is blocked from design * Work to flesh out closing a position * vain attempts at tracking zeroing out bugs * woww, super fun new subloggers 🎉 * Begins attempt at automatically handling contracts and collateral based on direction * Merge master + fixes * Investigating issues with pnl and holdings * Minor pnl fixes * Fixes future position sizing, needs contract sizing * Can render pnl results, focussing on funding statistics * tracking candles for futures, but why not btc * Improves funding statistics * Colours and stats * Fixes collateral and snapshot bugs * Completes test * Fixes totals bug * Fix double buy, expand stats, fixes usd totals, introduce interface * Begins report formatting and calculations * Appends pnl to receiving curr. Fixes map[time]. accurate USD * Improves report output rendering * PNL stats in report. New tests for futures * Fixes existing tests before adding new coverage * Test coverage * Completes portfolio coverage * Increase coverage exchange, portfolio. fix size bug. NEW CHART * WHAT IS GOING ON WITH PNL * Fixes PNL calculation. Adds ability to skip om futures tracking * minor commit before merge * Adds basic liquidation to backtester * Changes liquidation to order based * Liquidationnnnnn * Further fleshes out liquidations * Completes liquidations in a honorable manner. Adds AppendReasonf * Beginnings of spot futures gap chart. Needs to link currencies to render difference * Removes fake liquidation. Adds cool new chart * Fixes somet tests,allows for zero fee value v nil distinction,New tests * Some annoying test fixes that took too long * portfolio coverage * holding coverage, privatisation funding * Testwork * boring tests * engine coverage * More backtesting coverage * Funding, strategy, report test coverage * Completes coverage of report package * Documentation, fixes some assumptions on asset errors * Changes before master merge * Lint and Tests * defaults to non-coloured rendering * Chart rendering * Fixes surprise non-local-lints * Niterinos to the extremeos * Fixes merge problems * The linter splintered across the glinting plinths * Many nits addressed. Now sells spot position on final candle * Adds forgotten coverage * Adds ability to size futures contracts to match spot positions. * fixes order sell sizing * Adds tests to sizing. Fixes charting issue * clint splintered the linters with flint * Improves stats, stat rendering * minifix * Fixes tests and fee bug * Merge fixeroos * Microfixes * Updates orderPNL on first Correctly utilises fees. Adds committed funds * New base funcs. New order summary * Fun test updates * Fix logo colouring * Fixes niteroonies * Fix report * BAD COMMIT * Fixes funding issues.Updates default fee rates.Combines cashcarry case * doc regen * Now returns err * Fixes sizing bug issue introduced in PR * Fixes fun fee/total US value bug * Fix chart bug. Show log charts with disclaimer * sellside fee * fixes fee and slippage view * Fixed slippage price issue * Fixes calculation and removes rendering * Fixes stats and some rendering * Merge fix * Fixes merge issues * go mod tidy, lint updates * New linter attempt * Version bump in appveyor and makefile * Regex filename, config fixes, template h2 fixes * Removes bad stats. * neatens config builder. Moves filename generator * Fixes issue where linter wants to fix my spelling * Fixes pointers and starts * build(deps): bump github.com/urfave/cli/v2 from 2.10.1 to 2.10.3 (#982) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.10.1 to 2.10.3. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.10.1...v2.10.3) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * alert: Add optimizations (#939) * alert: Add optimizations * alert: add basic benchmarks * alert: fix linter issue * documentation: change to text/template as html/template escapes to protect against code injection. Add readme.md for alert. * README: Add package name * alert: link up with engine settings * request: isVerbose refactor * Update exchanges/alert/alert_test.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/alert/alert.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * glorious: fun police * documentation: regen Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * technical_analysis: TWAP & VWAP + TA methods to candles and link to existing RPC server for GCTCLI prototyping (#970) * kline: add weighted price helpers for candles * twap/vwap: basic implementation and hook to rpc for protype * ta: cont implementation. (WIP) * kline: Add tests * kline: add helpers * ta: full impl. * kline: remove support for macd and add in correlation-coefficient handling * rpc: change naming convention * linter: fix * protolinter: fix * linter: ++ * kline: reinstate macd handling after adding in check * glorious: nits * gctcl: linter * Update exchanges/kline/weighted_price.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * glorious: nits v2.0 * kline: fix test * huobi-tests: shift from next quarter to this weeks contracts as they were erroring out in tests. * btcmarkets: update supported kline intervals * zb: fix test * rpcserver: fix bug and tests Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * build(deps): bump github.com/urfave/cli/v2 from 2.10.3 to 2.11.0 (#993) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.10.3 to 2.11.0. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.10.3...v2.11.0) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * FTX: Margin lending/borrow rate history (#981) * Adds lending rates/borrows to FTX and the command * Movements, renames, rpc test * Fleshing out rpc response * Allows rpcserver to calculate offline (but not gctcli). Expands tests * rn structs. add exchange_wrapper_issues support * Adds a nice yearly rate * Surprise yearly borrow rate! * Rn+Mv to margin package. Fixes some serious whoopsies * Adds average lend/borrow rates instead of sum * rm oopsie whoopsie * This is what the linter was having an issue with * re-gen * lintl * niteroos * build(deps): bump google.golang.org/grpc from 1.47.0 to 1.48.0 (#995) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.47.0 to 1.48.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.47.0...v1.48.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * account: segregate holdings by credentials for future multi-key management (#956) * 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 Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * CI: fixing linter issue and conflicts * CI: fixing ratelimit and other slight issues * build(deps): bump github.com/grpc-ecosystem/grpc-gateway/v2 (#998) Bumps [github.com/grpc-ecosystem/grpc-gateway/v2](https://github.com/grpc-ecosystem/grpc-gateway) from 2.10.3 to 2.11.0. - [Release notes](https://github.com/grpc-ecosystem/grpc-gateway/releases) - [Changelog](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/.goreleaser.yml) - [Commits](https://github.com/grpc-ecosystem/grpc-gateway/compare/v2.10.3...v2.11.0) --- updated-dependencies: - dependency-name: github.com/grpc-ecosystem/grpc-gateway/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/d5/tengo/v2 from 2.12.0 to 2.12.1 (#997) Bumps [github.com/d5/tengo/v2](https://github.com/d5/tengo) from 2.12.0 to 2.12.1. - [Release notes](https://github.com/d5/tengo/releases) - [Changelog](https://github.com/d5/tengo/blob/master/.goreleaser.yml) - [Commits](https://github.com/d5/tengo/compare/v2.12.0...v2.12.1) --- updated-dependencies: - dependency-name: github.com/d5/tengo/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/urfave/cli/v2 from 2.11.0 to 2.11.1 (#996) Bumps [github.com/urfave/cli/v2](https://github.com/urfave/cli) from 2.11.0 to 2.11.1. - [Release notes](https://github.com/urfave/cli/releases) - [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/urfave/cli/compare/v2.11.0...v2.11.1) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * CI: fixing type and other slight issues * Cleanup after merge * Endpoints rate limit update Signed-off-by: Eng Zer Jun <engzerjun@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ryan O'Hara-Reid <oharareid.ryan@gmail.com> Co-authored-by: Eng Zer Jun <engzerjun@gmail.com> Co-authored-by: Scott <gloriousCode@users.noreply.github.com> Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
2003 lines
68 KiB
Go
2003 lines
68 KiB
Go
package binanceus
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"net/http"
|
||
"net/url"
|
||
"sort"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/thrasher-corp/gocryptotrader/common"
|
||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||
"github.com/thrasher-corp/gocryptotrader/log"
|
||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||
)
|
||
|
||
// Binanceus is the overarching type across this package
|
||
type Binanceus struct {
|
||
validLimits []int64
|
||
exchange.Base
|
||
obm *orderbookManager
|
||
}
|
||
|
||
const (
|
||
// General Data Endpoints
|
||
serverTime = "/api/v3/time"
|
||
systemStatus = "/sapi/v1/system/status"
|
||
|
||
// Public endpoints
|
||
exchangeInfo = "/api/v3/exchangeInfo"
|
||
recentTrades = "/api/v3/trades"
|
||
aggregatedTrades = "/api/v3/aggTrades"
|
||
orderBookDepth = "/api/v3/depth"
|
||
candleStick = "/api/v3/klines"
|
||
tickerPrice = "/api/v3/ticker/price"
|
||
averagePrice = "/api/v3/avgPrice"
|
||
bestPrice = "/api/v3/ticker/bookTicker"
|
||
priceChange = "/api/v3/ticker/24hr"
|
||
historicalTrades = "/api/v3/historicalTrades"
|
||
|
||
// Withdraw API endpoints
|
||
tradingStatus = "/sapi/v3/apiTradingStatus"
|
||
tradeFee = "/wapi/v3/tradeFee.html"
|
||
|
||
// Subaccounts
|
||
subaccountsInformation = "/sapi/v3/sub-account/list"
|
||
subaccountTransferHistory = "/sapi/v3/sub-account/transfer/history"
|
||
subaccountTransfer = "/sapi/v3/sub-account/transfer"
|
||
subaccountAssets = "/sapi/v3/sub-account/assets"
|
||
|
||
// Account Endpoint
|
||
accountInfo = "/api/v3/account"
|
||
accountStatus = "/sapi/v3/accountStatus"
|
||
accountEnableCryptoWithdrawalEndpoint = "/sapi/v1/account/quickEnableWithdrawal"
|
||
accountDisableCryptoWithdrawalEndpoint = "/sapi/v1/account/quickDisableWithdrawal"
|
||
masterAccounts = "/sapi/v1/sub-account/spotSummary"
|
||
subAccountStatusList = "/sapi/v1/sub-account/status"
|
||
usersSpotAssetsSnapshot = "/sapi/v1/accountSnapshot"
|
||
|
||
// Trade Order Endpoints
|
||
orderRateLimit = "/api/v3/rateLimit/order"
|
||
testCreateNeworder = "/api/v3/order/test" // Method: POST
|
||
orderRequest = "/api/v3/order" // Used in Create {Method: POST}, Cancel {DELETE}, and get{GET} OrderRequest
|
||
openOrders = "/api/v3/openOrders"
|
||
myTrades = "/api/v3/myTrades"
|
||
|
||
// One-Cancels-the-Other Orders (OCO Orders)
|
||
ocoOrder = "/api/v3/order/oco"
|
||
ocoOrderList = "/api/v3/orderList"
|
||
ocoAllOrderList = "/api/v3/allOrderList"
|
||
ocoOpenOrders = "/api/v3/openOrderList"
|
||
|
||
// OTC Endpoints
|
||
// Over-The-Counter Endpoints
|
||
otcSelectors = "/sapi/v1/otc/coinPairs"
|
||
otcQuotes = "/sapi/v1/otc/quotes"
|
||
otcTradeOrder = "/sapi/v1/otc/orders"
|
||
otcTradeOrders = "/sapi/v1/otc/orders/"
|
||
ocbsTradeOrders = "/sapi/v1/ocbs/orders"
|
||
|
||
// Wallet endpoints
|
||
assetDistributionHistory = "/sapi/v1/asset/assetDistributionHistory"
|
||
assetFeeAndWalletStatus = "/sapi/v1/capital/config/getall"
|
||
applyWithdrawal = "/sapi/v1/capital/withdraw/apply"
|
||
withdrawalHistory = "/sapi/v1/capital/withdraw/history"
|
||
withdrawFiat = "/sapi/v1/fiatpayment/apply/withdraw"
|
||
fiatWithdrawalHistory = "/sapi/v1/fiatpayment/query/withdraw/history"
|
||
fiatDepositHistory = "/sapi/v1/fiatpayment/query/deposit/history"
|
||
depositAddress = "/sapi/v1/capital/deposit/address"
|
||
depositHistory = "/sapi/v1/capital/deposit/hisrec"
|
||
subAccountDepositAddress = "/sapi/v1/capital/sub-account/deposit/address"
|
||
subAccountDepositHistory = "/sapi/v1/capital/sub-account/deposit/history"
|
||
|
||
// Referral Reward Endpoints
|
||
referralRewardHistory = "/sapi/v1/marketing/referral/reward/history"
|
||
|
||
// Web socket related route
|
||
userAccountStream = "/api/v3/userDataStream"
|
||
|
||
// Other Consts
|
||
defaultRecvWindow = 5 * time.Second
|
||
binanceUSAPITimeLayout = "2006-01-02 15:04:05"
|
||
|
||
// recvWindowSize5000
|
||
recvWindowSize5000 = 5000
|
||
)
|
||
|
||
var (
|
||
recvWindowSize5000String = strconv.Itoa(recvWindowSize5000)
|
||
)
|
||
|
||
// This is a list of error Messages to be returned by binanceus endpoint methods.
|
||
var (
|
||
errNotValidEmailAddress = errors.New("invalid email address")
|
||
errUnacceptableSenderEmail = errors.New("senders address email is missing")
|
||
errUnacceptableReceiverEmail = errors.New("receiver address email is missing")
|
||
errInvalidAssetValue = errors.New("invalid asset ")
|
||
errInvalidAssetAmount = errors.New("invalid asset amount")
|
||
errIncompleteArguments = errors.New("missing required argument")
|
||
errStartTimeOrFromIDNotSet = errors.New("please set StartTime or FromId, but not both")
|
||
errIncorrectLimitValues = errors.New("incorrect limit values - valid values are 5, 10, 20, 50, 100, 500, 1000")
|
||
errUnableToTypeAssertResponseData = errors.New("unable to type assert responseData")
|
||
errUnableToTypeAssertInvalidData = errors.New("unable to type assert individualData")
|
||
errUnexpectedKlineDataLength = errors.New("unexpected kline data length")
|
||
errUnableToTypeAssertTradeCount = errors.New("unable to type assert trade count")
|
||
errMissingRequiredArgumentCoin = errors.New("missing required argument,coin")
|
||
errMissingRequiredArgumentNetwork = errors.New("missing required argument,network")
|
||
errAmountValueMustBeGreaterThan0 = errors.New("amount must be greater than 0")
|
||
errMissingPaymentAccountInfo = errors.New("error: missing payment account")
|
||
errUnixMilliSecTypeAssertion = errors.New("error while asserting unix time integer")
|
||
errMissingRequiredParameterAddress = errors.New("missing required parameter \"address\"")
|
||
errMissingCurrencySymbol = errors.New("missing currency symbol")
|
||
errEitherOrderIDOrClientOrderIDIsRequired = errors.New("either order id or client order id is required")
|
||
errMissingRequestAmount = errors.New("missing required value \"requestAmount\"")
|
||
errMissingRequestCoin = errors.New("missing required value \"requestCoin\" name")
|
||
errMissingToCoinName = errors.New("missing required value \"toCoin\" name")
|
||
errMissingFromCoinName = errors.New("missing required value \"fromCoin\" name")
|
||
errMissingQuoteID = errors.New("missing quote id")
|
||
errMissingSubAccountEmail = errors.New("missing sub-account email address")
|
||
errMissingCurrencyCoin = errors.New("missing currency coin")
|
||
errInvalidUserBusinessType = errors.New("only 0: referrer and 1: referee are allowed")
|
||
errMissingPageNumber = errors.New("missing page number")
|
||
errInvalidRowNumber = errors.New("invalid row number")
|
||
)
|
||
|
||
// SetValues sets the default valid values
|
||
func (bi *Binanceus) SetValues() {
|
||
bi.validLimits = []int64{5, 10, 20, 50, 100, 500, 1000, 5000}
|
||
}
|
||
|
||
// General Data Endpoints
|
||
|
||
// GetServerTime this endpoint returns the exchange server time.
|
||
func (bi *Binanceus) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) {
|
||
var response ServerTime
|
||
return response.Timestamp,
|
||
bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
serverTime, spotDefaultRate,
|
||
&response)
|
||
}
|
||
|
||
// GetSystemStatus endpoint to fetch whether the system status is normal or under maintenance.
|
||
func (bi *Binanceus) GetSystemStatus(ctx context.Context) (int, error) {
|
||
resp := struct {
|
||
Status int `json:"status"`
|
||
}{}
|
||
return resp.Status, bi.SendAuthHTTPRequest(
|
||
ctx, exchange.RestSpotSupplementary,
|
||
http.MethodGet, systemStatus,
|
||
nil, spotDefaultRate, &resp)
|
||
}
|
||
|
||
// GetExchangeInfo to get the current exchange trading rules and trading pair information.
|
||
func (bi *Binanceus) GetExchangeInfo(ctx context.Context) (ExchangeInfo, error) {
|
||
var respo ExchangeInfo
|
||
return respo, bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
exchangeInfo, spotExchangeInfo, &respo)
|
||
}
|
||
|
||
// GetMostRecentTrades to get older trades. maximum limit in the RecentTradeRequestParams is 1,000 trades.
|
||
func (bi *Binanceus) GetMostRecentTrades(ctx context.Context, rtr RecentTradeRequestParams) ([]RecentTrade, error) {
|
||
params := url.Values{}
|
||
symbol, err := bi.FormatSymbol(rtr.Symbol, asset.Spot)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
params.Set("symbol", symbol)
|
||
params.Set("limit", strconv.FormatInt(rtr.Limit, 10))
|
||
path := common.EncodeURLValues(recentTrades, params)
|
||
var resp []RecentTrade
|
||
return resp, bi.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, path, spotDefaultRate, &resp)
|
||
}
|
||
|
||
// GetHistoricalTrades returns historical trade activity
|
||
// symbol: string of currency pair
|
||
// limit: Optional. Default 500; max 1000.
|
||
func (bi *Binanceus) GetHistoricalTrades(ctx context.Context, hist HistoricalTradeParams) ([]HistoricalTrade, error) {
|
||
var resp []HistoricalTrade
|
||
params := url.Values{}
|
||
params.Set("symbol", hist.Symbol)
|
||
params.Set("limit", strconv.FormatInt(hist.Limit, 10))
|
||
if hist.FromID > 0 {
|
||
params.Set("fromId", strconv.FormatUint(hist.FromID, 10))
|
||
}
|
||
path := common.EncodeURLValues(historicalTrades, params)
|
||
return resp, bi.SendAPIKeyHTTPRequest(ctx, exchange.RestSpotSupplementary, path, spotHistoricalTradesRate, &resp)
|
||
}
|
||
|
||
// GetAggregateTrades to get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same price will have the quantity aggregated.
|
||
func (bi *Binanceus) GetAggregateTrades(ctx context.Context, agg *AggregatedTradeRequestParams) ([]AggregatedTrade, error) {
|
||
params := url.Values{}
|
||
symbol, err := bi.FormatSymbol(agg.Symbol, asset.Spot)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
params.Set("symbol", symbol)
|
||
needBatch := false
|
||
if agg.Limit > 0 {
|
||
if agg.Limit > 1000 {
|
||
needBatch = true
|
||
} else {
|
||
params.Set("limit", strconv.Itoa(agg.Limit))
|
||
}
|
||
}
|
||
if agg.FromID != 0 {
|
||
params.Set("fromId", strconv.FormatInt(agg.FromID, 10))
|
||
}
|
||
startTime := time.UnixMilli(int64(agg.StartTime))
|
||
endTime := time.UnixMilli(int64(agg.EndTime))
|
||
|
||
if (endTime.UnixNano() - startTime.UnixNano()) >= int64(time.Hour) {
|
||
endTime = startTime.Add(time.Minute * 59)
|
||
}
|
||
|
||
if !startTime.IsZero() && startTime.Unix() != 0 {
|
||
params.Set("startTime", strconv.Itoa(int(agg.StartTime)))
|
||
}
|
||
if !endTime.IsZero() && endTime.Unix() != 0 {
|
||
params.Set("endTime", strconv.Itoa(int(agg.EndTime)))
|
||
}
|
||
needBatch = needBatch || (!startTime.IsZero() && !endTime.IsZero() && endTime.Sub(startTime) > time.Hour)
|
||
if needBatch {
|
||
// fromId xor start time must be set
|
||
canBatch := agg.FromID == 0 != startTime.IsZero()
|
||
if canBatch {
|
||
return bi.batchAggregateTrades(ctx, agg, params)
|
||
}
|
||
// Can't handle this request locally or remotely
|
||
// We would receive {"code":-1128,"msg":"Combination of optional parameters invalid."}
|
||
return nil, errStartTimeOrFromIDNotSet
|
||
}
|
||
var resp []AggregatedTrade
|
||
path := common.EncodeURLValues(aggregatedTrades, params)
|
||
return resp, bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, path, spotDefaultRate, &resp)
|
||
}
|
||
|
||
// batchAggregateTrades fetches trades in multiple requests <-- copied and amended from the binance
|
||
// first phase, hourly requests until the first trade (or end time) is reached
|
||
// second phase, limit requests from previous trade until end time (or limit) is reached
|
||
func (bi *Binanceus) batchAggregateTrades(ctx context.Context, arg *AggregatedTradeRequestParams, params url.Values) ([]AggregatedTrade, error) {
|
||
var resp []AggregatedTrade
|
||
// prepare first request with only first hour and max limit
|
||
if arg.Limit == 0 || arg.Limit > 1000 {
|
||
// Extend from the default of 500
|
||
params.Set("limit", "1000")
|
||
}
|
||
startTime := time.UnixMilli(int64(arg.StartTime))
|
||
endTime := time.UnixMilli(int64(arg.EndTime))
|
||
var fromID int64
|
||
if arg.FromID > 0 {
|
||
fromID = arg.FromID
|
||
} else {
|
||
// Only 10 seconds is used to prevent limit of 1000 being reached in the first request,
|
||
// cutting off trades for high activity pairs
|
||
increment := time.Second * 10
|
||
for len(resp) == 0 {
|
||
startTime = startTime.Add(increment)
|
||
if !endTime.IsZero() && !startTime.Before(endTime) {
|
||
// All requests returned empty
|
||
return nil, nil
|
||
}
|
||
params.Set("startTime", strconv.Itoa(int(startTime.UnixMilli())))
|
||
params.Set("endTime", strconv.Itoa(int(startTime.Add(increment).UnixMilli())))
|
||
path := common.EncodeURLValues(aggregatedTrades, params)
|
||
err := bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, path, spotDefaultRate, &resp)
|
||
if err != nil {
|
||
log.Warn(log.ExchangeSys, err.Error())
|
||
return resp, err
|
||
}
|
||
}
|
||
fromID = resp[len(resp)-1].ATradeID
|
||
}
|
||
|
||
// other requests follow from the last aggregate trade id and have no time window
|
||
params.Del("startTime")
|
||
params.Del("endTime")
|
||
// while we haven't reached the limit
|
||
for ; arg.Limit == 0 || len(resp) < arg.Limit; fromID = resp[len(resp)-1].ATradeID {
|
||
// Keep requesting new data after last retrieved trade
|
||
params.Set("fromId", strconv.FormatInt(fromID, 10))
|
||
path := common.EncodeURLValues(aggregatedTrades, params)
|
||
var additionalTrades []AggregatedTrade
|
||
err := bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
path,
|
||
spotDefaultRate,
|
||
&additionalTrades)
|
||
if err != nil {
|
||
return resp, err
|
||
}
|
||
lastIndex := len(additionalTrades)
|
||
if !endTime.IsZero() && endTime.Unix() != 0 {
|
||
// get index for truncating to end time
|
||
lastIndex = sort.Search(len(additionalTrades), func(i int) bool {
|
||
return endTime.Before(additionalTrades[i].TimeStamp)
|
||
})
|
||
}
|
||
// don't include the first as the request was inclusive from last ATradeID
|
||
resp = append(resp, additionalTrades[1:lastIndex]...)
|
||
// If only the starting trade is returned or if we received trades after end time
|
||
if len(additionalTrades) == 1 || lastIndex < len(additionalTrades) {
|
||
break
|
||
}
|
||
}
|
||
// Truncate if necessary
|
||
if arg.Limit > 0 && len(resp) > arg.Limit {
|
||
resp = resp[:arg.Limit]
|
||
}
|
||
return resp, nil
|
||
}
|
||
|
||
// GetOrderBookDepth to get the order book depth. Please note the limits in the table below.
|
||
func (bi *Binanceus) GetOrderBookDepth(ctx context.Context, arg *OrderBookDataRequestParams) (*OrderBook, error) {
|
||
if err := bi.CheckLimit(arg.Limit); err != nil {
|
||
return nil, err
|
||
}
|
||
params := url.Values{}
|
||
symbol, err := bi.FormatSymbol(arg.Symbol, asset.Spot)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
params.Set("symbol", symbol)
|
||
params.Set("limit", fmt.Sprintf("%d", arg.Limit))
|
||
var resp OrderBookData
|
||
if err := bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
common.EncodeURLValues(orderBookDepth, params),
|
||
orderbookLimit(arg.Limit), &resp); err != nil {
|
||
return nil, err
|
||
}
|
||
orderbook := OrderBook{
|
||
Bids: make([]OrderbookItem, len(resp.Bids)),
|
||
Asks: make([]OrderbookItem, len(resp.Asks)),
|
||
LastUpdateID: resp.LastUpdateID,
|
||
}
|
||
for x := range resp.Bids {
|
||
price, err := strconv.ParseFloat(resp.Bids[x][0], 64)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
amount, err := strconv.ParseFloat(resp.Bids[x][1], 64)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
orderbook.Bids[x] = OrderbookItem{
|
||
Price: price,
|
||
Quantity: amount,
|
||
}
|
||
}
|
||
for x := range resp.Asks {
|
||
price, err := strconv.ParseFloat(resp.Asks[x][0], 64)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
amount, err := strconv.ParseFloat(resp.Asks[x][1], 64)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
orderbook.Asks[x] = OrderbookItem{
|
||
Price: price,
|
||
Quantity: amount,
|
||
}
|
||
}
|
||
return &orderbook, nil
|
||
}
|
||
|
||
// CheckLimit checks value against a variable list
|
||
func (bi *Binanceus) CheckLimit(limit int64) error {
|
||
for x := range bi.validLimits {
|
||
if bi.validLimits[x] == limit {
|
||
return nil
|
||
}
|
||
}
|
||
return errIncorrectLimitValues
|
||
}
|
||
|
||
// GetIntervalEnum allowed interval params by Binanceus
|
||
func (bi *Binanceus) GetIntervalEnum(interval kline.Interval) string {
|
||
switch interval {
|
||
case kline.OneMin:
|
||
return "1m"
|
||
case kline.ThreeMin:
|
||
return "3m"
|
||
case kline.FiveMin:
|
||
return "5m"
|
||
case kline.FifteenMin:
|
||
return "15m"
|
||
case kline.ThirtyMin:
|
||
return "30m"
|
||
case kline.OneHour:
|
||
return "1h"
|
||
case kline.TwoHour:
|
||
return "2h"
|
||
case kline.FourHour:
|
||
return "4h"
|
||
case kline.SixHour:
|
||
return "6h"
|
||
case kline.EightHour:
|
||
return "8h"
|
||
case kline.TwelveHour:
|
||
return "12h"
|
||
case kline.OneDay:
|
||
return "1d"
|
||
case kline.ThreeDay:
|
||
return "3d"
|
||
case kline.OneWeek:
|
||
return "1w"
|
||
case kline.OneMonth:
|
||
return "1M"
|
||
default:
|
||
return "notfound"
|
||
}
|
||
}
|
||
|
||
// GetSpotKline to get Kline/candlestick bars for a token symbol. Klines are uniquely identified by their open time.
|
||
func (bi *Binanceus) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([]CandleStick, error) {
|
||
symbol, err := bi.FormatSymbol(arg.Symbol, asset.Spot)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
params := url.Values{}
|
||
params.Set("symbol", symbol)
|
||
params.Set("interval", arg.Interval)
|
||
if arg.Limit != 0 {
|
||
params.Set("limit", strconv.FormatInt(arg.Limit, 10))
|
||
}
|
||
if !arg.StartTime.IsZero() && arg.StartTime.Unix() != 0 {
|
||
params.Set("startTime", strconv.FormatInt((arg.StartTime).UnixMilli(), 10))
|
||
}
|
||
if !arg.EndTime.IsZero() && arg.EndTime.Unix() != 0 {
|
||
params.Set("endTime", strconv.FormatInt((arg.EndTime).UnixMilli(), 10))
|
||
}
|
||
path := common.EncodeURLValues(candleStick, params)
|
||
var resp interface{}
|
||
err = bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
path,
|
||
spotDefaultRate,
|
||
&resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
responseData, ok := resp.([]interface{})
|
||
if !ok {
|
||
return nil, errUnableToTypeAssertResponseData
|
||
}
|
||
|
||
klineData := make([]CandleStick, len(responseData))
|
||
for x := range responseData {
|
||
individualData, ok := responseData[x].([]interface{})
|
||
if !ok {
|
||
return nil, errUnableToTypeAssertInvalidData
|
||
}
|
||
if len(individualData) != 12 {
|
||
return nil, errUnexpectedKlineDataLength
|
||
}
|
||
var candle CandleStick
|
||
val, ok := individualData[0].(float64)
|
||
if !ok {
|
||
return nil, errUnixMilliSecTypeAssertion
|
||
}
|
||
candle.OpenTime = time.UnixMilli(int64(val))
|
||
if candle.Open, err = convert.FloatFromString(individualData[1]); err != nil {
|
||
return nil, err
|
||
}
|
||
if candle.High, err = convert.FloatFromString(individualData[2]); err != nil {
|
||
return nil, err
|
||
}
|
||
if candle.Low, err = convert.FloatFromString(individualData[3]); err != nil {
|
||
return nil, err
|
||
}
|
||
if candle.Close, err = convert.FloatFromString(individualData[4]); err != nil {
|
||
return nil, err
|
||
}
|
||
if candle.Volume, err = convert.FloatFromString(individualData[5]); err != nil {
|
||
return nil, err
|
||
}
|
||
val, ok = individualData[6].(float64)
|
||
if !ok {
|
||
return nil, errUnixMilliSecTypeAssertion
|
||
}
|
||
candle.CloseTime = time.UnixMilli(int64(val))
|
||
if candle.QuoteAssetVolume, err = convert.FloatFromString(individualData[7]); err != nil {
|
||
return nil, err
|
||
}
|
||
if candle.TradeCount, ok = individualData[8].(float64); !ok {
|
||
return nil, errUnableToTypeAssertTradeCount
|
||
}
|
||
if candle.TakerBuyAssetVolume, err = convert.FloatFromString(individualData[9]); err != nil {
|
||
return nil, err
|
||
}
|
||
if candle.TakerBuyQuoteAssetVolume, err = convert.FloatFromString(individualData[10]); err != nil {
|
||
return nil, err
|
||
}
|
||
klineData[x] = candle
|
||
}
|
||
return klineData, nil
|
||
}
|
||
|
||
// GetSinglePriceData to get the latest price for a token symbol or symbols.
|
||
func (bi *Binanceus) GetSinglePriceData(ctx context.Context, symbol currency.Pair) (SymbolPrice, error) {
|
||
var res SymbolPrice
|
||
params := url.Values{}
|
||
symbolValue, err := bi.FormatSymbol(symbol, asset.Spot)
|
||
if err != nil {
|
||
return res, err
|
||
}
|
||
params.Set("symbol", symbolValue)
|
||
path := common.EncodeURLValues(tickerPrice, params)
|
||
return res, bi.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, path, spotDefaultRate, &res)
|
||
}
|
||
|
||
// GetPriceDatas to get the latest price for symbols.
|
||
func (bi *Binanceus) GetPriceDatas(ctx context.Context) (SymbolPrices, error) {
|
||
var res SymbolPrices
|
||
return res, bi.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, tickerPrice, spotSymbolPriceAllRate, &res)
|
||
}
|
||
|
||
// GetAveragePrice returns current average price for a symbol.
|
||
//
|
||
// symbol: string of currency pair
|
||
func (bi *Binanceus) GetAveragePrice(ctx context.Context, symbol currency.Pair) (AveragePrice, error) {
|
||
resp := AveragePrice{}
|
||
params := url.Values{}
|
||
symbolValue, err := bi.FormatSymbol(symbol, asset.Spot)
|
||
if err != nil {
|
||
return resp, err
|
||
}
|
||
params.Set("symbol", symbolValue)
|
||
|
||
path := common.EncodeURLValues(averagePrice, params)
|
||
|
||
return resp, bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, path, spotDefaultRate, &resp)
|
||
}
|
||
|
||
// GetBestPrice returns the latest best price for symbol
|
||
// symbol: string of currency pair
|
||
func (bi *Binanceus) GetBestPrice(ctx context.Context, symbol currency.Pair) (BestPrice, error) {
|
||
resp := BestPrice{}
|
||
params := url.Values{}
|
||
rateLimit := spotOrderbookTickerAllRate
|
||
if !symbol.IsEmpty() {
|
||
rateLimit = spotDefaultRate
|
||
symbolValue, err := bi.FormatSymbol(symbol, asset.Spot)
|
||
if err != nil {
|
||
return resp, err
|
||
}
|
||
params.Set("symbol", symbolValue)
|
||
}
|
||
path := common.EncodeURLValues(bestPrice, params)
|
||
|
||
return resp,
|
||
bi.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, path, rateLimit, &resp)
|
||
}
|
||
|
||
// GetPriceChangeStats returns price change statistics for the last 24 hours
|
||
// symbol: string of currency pair
|
||
func (bi *Binanceus) GetPriceChangeStats(ctx context.Context, symbol currency.Pair) (PriceChangeStats, error) {
|
||
resp := PriceChangeStats{}
|
||
params := url.Values{}
|
||
rateLimit := spotPriceChangeAllRate
|
||
if !symbol.IsEmpty() {
|
||
rateLimit = spotDefaultRate
|
||
symbolValue, err := bi.FormatSymbol(symbol, asset.Spot)
|
||
if err != nil {
|
||
return resp, err
|
||
}
|
||
params.Set("symbol", symbolValue)
|
||
}
|
||
path := common.EncodeURLValues(priceChange, params)
|
||
|
||
return resp, bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, path, rateLimit, &resp)
|
||
}
|
||
|
||
// GetTickers returns the ticker data for the last 24 hrs
|
||
func (bi *Binanceus) GetTickers(ctx context.Context) ([]PriceChangeStats, error) {
|
||
var resp []PriceChangeStats
|
||
return resp, bi.SendHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, priceChange, spotPriceChangeAllRate, &resp)
|
||
}
|
||
|
||
// GetAccount returns binance user accounts
|
||
func (bi *Binanceus) GetAccount(ctx context.Context) (*Account, error) {
|
||
type response struct {
|
||
Response
|
||
Account
|
||
}
|
||
var resp response
|
||
params := url.Values{}
|
||
if err := bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, accountInfo,
|
||
params, spotAccountInformationRate,
|
||
&resp); err != nil {
|
||
return &resp.Account, err
|
||
}
|
||
|
||
if resp.Code != 0 {
|
||
return &resp.Account, errors.New(resp.Msg)
|
||
}
|
||
|
||
return &resp.Account, nil
|
||
}
|
||
|
||
// GetUserAccountStatus to fetch account status detail.
|
||
func (bi *Binanceus) GetUserAccountStatus(ctx context.Context, recvWindow uint) (*AccountStatusResponse, error) {
|
||
var resp AccountStatusResponse
|
||
params := url.Values{}
|
||
timestamp := time.Now().UnixMilli()
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
if recvWindow > 0 && recvWindow < 60000 {
|
||
if recvWindow < 2000 {
|
||
recvWindow += 1500
|
||
}
|
||
params.Set("recvWindow", strconv.Itoa(int(recvWindow)))
|
||
}
|
||
|
||
return &resp,
|
||
bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
accountStatus,
|
||
params,
|
||
spotDefaultRate,
|
||
&resp)
|
||
}
|
||
|
||
// GetUserAPITradingStatus to fetch account API trading status details.
|
||
func (bi *Binanceus) GetUserAPITradingStatus(ctx context.Context, recvWindow uint) (*TradeStatus, error) {
|
||
type response struct {
|
||
Success bool `json:"success"`
|
||
TC TradeStatus `json:"status"`
|
||
}
|
||
var resp response
|
||
params := url.Values{}
|
||
timestamp := time.Now().UnixMilli()
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
if recvWindow > 0 && recvWindow < 2000 {
|
||
recvWindow += 1500
|
||
}
|
||
params.Set("recvWindow", strconv.Itoa(int(recvWindow)))
|
||
return &resp.TC,
|
||
bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
tradingStatus,
|
||
params,
|
||
spotDefaultRate,
|
||
&resp)
|
||
}
|
||
|
||
// GetFee to fetch trading fees.
|
||
func (bi *Binanceus) GetFee(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||
var fee float64
|
||
switch feeBuilder.FeeType {
|
||
case exchange.CryptocurrencyTradeFee:
|
||
multiplier, er := bi.getMultiplier(ctx, feeBuilder.IsMaker, feeBuilder)
|
||
if er != nil {
|
||
return 0, er
|
||
}
|
||
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, multiplier)
|
||
case exchange.CryptocurrencyWithdrawalFee:
|
||
wallet, er := bi.GetAssetFeesAndWalletStatus(ctx)
|
||
if er != nil {
|
||
return fee, er
|
||
}
|
||
for x := range wallet {
|
||
for y := range wallet[x].NetworkList {
|
||
if wallet[x].NetworkList[y].IsDefault {
|
||
return wallet[x].NetworkList[y].WithdrawFee, nil
|
||
}
|
||
}
|
||
}
|
||
case exchange.OfflineTradeFee:
|
||
fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
|
||
}
|
||
if fee < 0 {
|
||
fee = 0
|
||
}
|
||
return fee, nil
|
||
}
|
||
|
||
// getMultiplier retrieves account based taker/maker fees
|
||
func (bi *Binanceus) getMultiplier(ctx context.Context, isMaker bool, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||
symbol, er := bi.FormatSymbol(feeBuilder.Pair, asset.Spot)
|
||
if er != nil {
|
||
return 0, er
|
||
}
|
||
trades, er := bi.GetTradeFee(ctx, 0, symbol)
|
||
if er != nil {
|
||
return 0, er
|
||
}
|
||
for x := range trades.TradeFee {
|
||
if trades.TradeFee[x].Symbol == symbol {
|
||
if isMaker {
|
||
return trades.TradeFee[x].Maker, nil
|
||
}
|
||
return trades.TradeFee[x].Taker, nil
|
||
}
|
||
}
|
||
return 0, nil
|
||
}
|
||
|
||
// getOfflineTradeFee calculates the worst case-scenario trading fee
|
||
func getOfflineTradeFee(price, amount float64) float64 {
|
||
return 0.001 * price * amount
|
||
}
|
||
|
||
// calculateTradingFee returns the fee for trading any currency on Binanceus
|
||
func calculateTradingFee(purchasePrice, amount, multiplier float64) float64 {
|
||
return (multiplier / 100) * purchasePrice * amount
|
||
}
|
||
|
||
// GetTradeFee to fetch trading fees.
|
||
func (bi *Binanceus) GetTradeFee(ctx context.Context, recvWindow uint, symbol string) (TradeFeeList, error) {
|
||
timestamp := time.Now().UnixMilli()
|
||
params := url.Values{}
|
||
var resp TradeFeeList
|
||
params.Set("timestamp", strconv.FormatInt(timestamp, 10))
|
||
if recvWindow > 0 {
|
||
if recvWindow < 2000 {
|
||
recvWindow += 3000
|
||
} else if recvWindow > 60000 {
|
||
recvWindow = recvWindowSize5000
|
||
}
|
||
params.Set("recvWindow", strconv.Itoa(int(recvWindow)))
|
||
}
|
||
if symbol != "" {
|
||
params.Set("symbol", symbol)
|
||
}
|
||
return resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
tradeFee,
|
||
params,
|
||
spotDefaultRate,
|
||
&resp)
|
||
}
|
||
|
||
// GetAssetDistributionHistory this endpoint to query
|
||
// asset distribution records, including for staking, referrals and airdrops etc.
|
||
// INPUTS:
|
||
// asset: string , startTime & endTime unix time in Milli seconds, recvWindow(duration in milli seconds > 2000 to < 6000)
|
||
func (bi *Binanceus) GetAssetDistributionHistory(ctx context.Context, asset string, startTime, endTime uint64, recvWindow uint) (*AssetDistributionHistories, error) {
|
||
params := url.Values{}
|
||
timestamp := time.Now().UnixMilli()
|
||
var resp AssetDistributionHistories
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
if startTime > 0 && time.UnixMilli(int64(startTime)).Before(time.Now()) {
|
||
params.Set("startTime", strconv.Itoa(int(startTime)))
|
||
}
|
||
if startTime > 0 {
|
||
params.Set("endTime", strconv.Itoa(int(endTime)))
|
||
}
|
||
if recvWindow > 0 && recvWindow < 60000 {
|
||
if recvWindow < 2000 {
|
||
recvWindow += 2000
|
||
} else if recvWindow > 6000 {
|
||
recvWindow = recvWindowSize5000
|
||
}
|
||
params.Set("recvWindow", strconv.Itoa(int(recvWindow)))
|
||
}
|
||
|
||
if asset != "" {
|
||
params.Set("asset", asset)
|
||
}
|
||
return &resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, assetDistributionHistory,
|
||
params,
|
||
spotDefaultRate, &resp)
|
||
}
|
||
|
||
// QuickEnableCryptoWithdrawal use this endpoint to enable crypto withdrawals.
|
||
func (bi *Binanceus) QuickEnableCryptoWithdrawal(ctx context.Context) error {
|
||
params := url.Values{}
|
||
response := struct {
|
||
Data interface{}
|
||
}{}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
return bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodPost,
|
||
accountEnableCryptoWithdrawalEndpoint, params, spotDefaultRate, &(response.Data))
|
||
}
|
||
|
||
// QuickDisableCryptoWithdrawal use this endpoint to disable crypto withdrawals.
|
||
func (bi *Binanceus) QuickDisableCryptoWithdrawal(ctx context.Context) error {
|
||
params := url.Values{}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
return bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodPost,
|
||
accountDisableCryptoWithdrawalEndpoint, params, spotDefaultRate, nil)
|
||
}
|
||
|
||
// GetUsersSpotAssetSnapshot retrieves a snapshot of list of assets in the account.
|
||
func (bi *Binanceus) GetUsersSpotAssetSnapshot(ctx context.Context, startTime, endTime time.Time, limit, offset uint) (*SpotAssetsSnapshotResponse, error) {
|
||
params := url.Values{}
|
||
params.Set("type", "SPOT")
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
if !(startTime.IsZero() && startTime.Unix() <= 0) && startTime.Before(time.Now()) {
|
||
params.Set("startTime", strconv.FormatInt(startTime.UnixMilli(), 10))
|
||
}
|
||
if !(endTime.IsZero() && endTime.Unix() <= 0) && endTime.After(time.Now()) {
|
||
if (params.Get("startTime") != "" && endTime.After(startTime)) || params.Get("startTime") == "" {
|
||
params.Set("endTime", strconv.FormatInt(endTime.UnixMilli(), 10))
|
||
}
|
||
}
|
||
if limit > 0 {
|
||
params.Set("limit", strconv.Itoa(int(limit)))
|
||
}
|
||
if offset > 0 {
|
||
params.Set("offset", strconv.Itoa(int(offset)))
|
||
}
|
||
var resp SpotAssetsSnapshotResponse
|
||
return &resp, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodGet, usersSpotAssetsSnapshot,
|
||
params, spotDefaultRate, &resp)
|
||
}
|
||
|
||
// GetSubaccountInformation to fetch your sub-account list.
|
||
func (bi *Binanceus) GetSubaccountInformation(ctx context.Context, page, limit uint, status, email string) ([]SubAccount, error) {
|
||
params := url.Values{}
|
||
type response struct {
|
||
Success bool `json:"success"`
|
||
Subaccounts []SubAccount `json:"subAccounts"`
|
||
}
|
||
var resp response
|
||
|
||
if email != "" {
|
||
params.Set("email", email)
|
||
}
|
||
if status != "" && (status == "enabled" || status == "disabled") {
|
||
params.Set("status", status)
|
||
}
|
||
if page != 0 {
|
||
params.Set("page", strconv.Itoa(int(page)))
|
||
}
|
||
if limit != 0 {
|
||
params.Set("limit", strconv.Itoa(int(limit)))
|
||
}
|
||
timestamp := time.Now().UnixMilli()
|
||
params.Set("timestamp", strconv.FormatInt(timestamp, 10))
|
||
return resp.Subaccounts, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
subaccountsInformation,
|
||
params,
|
||
spotDefaultRate,
|
||
resp)
|
||
}
|
||
|
||
// GetSubaccountTransferHistory to fetch sub-account asset transfer history.
|
||
func (bi *Binanceus) GetSubaccountTransferHistory(ctx context.Context,
|
||
email string,
|
||
startTime uint64,
|
||
endTime uint64,
|
||
page, limit int) ([]TransferHistory, error) {
|
||
timestamp := time.Now().UnixMilli()
|
||
params := url.Values{}
|
||
type response struct {
|
||
Success bool `json:"success"`
|
||
Transfers []TransferHistory `json:"transfers"`
|
||
}
|
||
var resp response
|
||
if !common.MatchesEmailPattern(email) {
|
||
return nil, errNotValidEmailAddress
|
||
}
|
||
params.Set("email", email)
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
if page != 0 {
|
||
params.Set("page", strconv.Itoa(page))
|
||
}
|
||
if limit != 0 {
|
||
params.Set("limit", strconv.Itoa(limit))
|
||
}
|
||
startTimeT := time.UnixMilli(int64(startTime))
|
||
endTimeT := time.UnixMilli(int64(endTime))
|
||
|
||
hundredDayBefore := time.Now()
|
||
hundredDayBefore.Sub(time.UnixMilli(int64((time.Hour * 24 * 10) / time.Millisecond)))
|
||
if !(startTimeT.Before(hundredDayBefore)) || !startTimeT.After(time.Now()) {
|
||
params.Set("startTime", strconv.Itoa(int(startTime)))
|
||
}
|
||
if !(endTimeT.Before(hundredDayBefore)) || !endTimeT.After(time.Now()) {
|
||
params.Set("startTime", strconv.Itoa(int(endTime)))
|
||
}
|
||
return resp.Transfers, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
subaccountTransferHistory,
|
||
params,
|
||
spotDefaultRate,
|
||
resp)
|
||
}
|
||
|
||
// ExecuteSubAccountTransfer to execute sub-account asset transfers.
|
||
func (bi *Binanceus) ExecuteSubAccountTransfer(ctx context.Context, arg *SubAccountTransferRequestParams) (*SubAccountTransferResponse, error) {
|
||
params := url.Values{}
|
||
var response SubAccountTransferResponse
|
||
if !common.MatchesEmailPattern(arg.FromEmail) {
|
||
return nil, errUnacceptableSenderEmail
|
||
}
|
||
if !common.MatchesEmailPattern(arg.ToEmail) {
|
||
return nil, errUnacceptableReceiverEmail
|
||
}
|
||
if len(arg.Asset) <= 2 {
|
||
return nil, errInvalidAssetValue
|
||
}
|
||
if arg.Amount <= 0.0 {
|
||
return nil, errInvalidAssetAmount
|
||
}
|
||
params.Set("fromEmail", arg.FromEmail)
|
||
params.Set("toEmail", arg.ToEmail)
|
||
params.Set("asset", arg.Asset)
|
||
params.Set("amount", strconv.FormatFloat(arg.Amount, 'f', 0, 64))
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
return &response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodPost, subaccountTransfer, params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// GetSubaccountAssets to fetch sub-account assets.
|
||
func (bi *Binanceus) GetSubaccountAssets(ctx context.Context, email string) (*SubAccountAssets, error) {
|
||
var resp SubAccountAssets
|
||
if !common.MatchesEmailPattern(email) {
|
||
return nil, errNotValidEmailAddress
|
||
}
|
||
params := url.Values{}
|
||
timestamp := time.Now().UnixMilli()
|
||
params.Set("timestamp", fmt.Sprintf("%d", timestamp))
|
||
params.Set("email", email)
|
||
//
|
||
return &resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, http.MethodGet,
|
||
subaccountAssets, params,
|
||
spotDefaultRate,
|
||
&resp)
|
||
}
|
||
|
||
// GetMasterAccountTotalUSDValue this endpoint to get the total value of assets in the master account in USD.
|
||
func (bi *Binanceus) GetMasterAccountTotalUSDValue(ctx context.Context, email string, page, size int) (*SpotUSDMasterAccounts, error) {
|
||
var response SpotUSDMasterAccounts
|
||
params := url.Values{}
|
||
if email != "" {
|
||
params.Set("email", email)
|
||
}
|
||
if page > 0 {
|
||
params.Set("page", strconv.Itoa(page))
|
||
}
|
||
if size > 0 {
|
||
params.Set("size", strconv.Itoa(size))
|
||
}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
return &response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodGet, masterAccounts, params,
|
||
spotDefaultRate, &response)
|
||
}
|
||
|
||
// GetSubaccountStatusList this endpoint retrieves a status list of sub-accounts.
|
||
func (bi *Binanceus) GetSubaccountStatusList(ctx context.Context, email string) ([]SubAccountStatus, error) {
|
||
params := url.Values{}
|
||
if !common.MatchesEmailPattern(email) {
|
||
return nil, errMissingSubAccountEmail
|
||
}
|
||
params.Set("email", email)
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
var response []SubAccountStatus
|
||
return response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodGet, subAccountStatusList, params,
|
||
spotDefaultRate, &response)
|
||
}
|
||
|
||
// Trade Order Endpoints
|
||
|
||
// GetOrderRateLimits get the current trade order count rate limits for all time intervals.
|
||
// INPUTS: recvWindow <= 60000
|
||
func (bi *Binanceus) GetOrderRateLimits(ctx context.Context, recvWindow uint) ([]OrderRateLimit, error) {
|
||
params := url.Values{}
|
||
timestamp := time.Now().UnixMilli()
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
if recvWindow > 1000 && recvWindow < 60000 {
|
||
params.Set("recvWindow", strconv.Itoa(int(recvWindow)))
|
||
} else {
|
||
params.Set("recvWindow", strconv.Itoa(30000))
|
||
}
|
||
var resp []OrderRateLimit
|
||
return resp, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet, orderRateLimit, params, spotOrderRateLimitRate, &resp)
|
||
}
|
||
|
||
// NewOrder sends a new order to Binanceus
|
||
func (bi *Binanceus) NewOrder(ctx context.Context, o *NewOrderRequest) (NewOrderResponse, error) {
|
||
var resp NewOrderResponse
|
||
if err := bi.newOrder(ctx, orderRequest, o, &resp); err != nil {
|
||
return resp, err
|
||
}
|
||
if resp.Code != 0 {
|
||
return resp, errors.New(resp.Msg)
|
||
}
|
||
return resp, nil
|
||
}
|
||
|
||
// NewOrderTest sends a new test order to Binanceus
|
||
// to test new order creation and signature/recvWindow long. The endpoint creates and validates a new order but does not send it into the matching engine.
|
||
func (bi *Binanceus) NewOrderTest(ctx context.Context, o *NewOrderRequest) (*NewOrderResponse, error) {
|
||
var resp NewOrderResponse
|
||
return &resp, bi.newOrder(ctx, testCreateNeworder, o, &resp)
|
||
}
|
||
|
||
// newOrder this endpoint is used by both new order and NewOrderTest passing their route and order information to send new order.
|
||
func (bi *Binanceus) newOrder(ctx context.Context, api string, o *NewOrderRequest, resp *NewOrderResponse) error {
|
||
params := url.Values{}
|
||
symbol, err := bi.FormatSymbol(o.Symbol, asset.Spot)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
params.Set("symbol", symbol)
|
||
params.Set("side", o.Side)
|
||
params.Set("type", string(o.TradeType))
|
||
if o.QuoteOrderQty > 0 {
|
||
params.Set("quoteOrderQty", strconv.FormatFloat(o.QuoteOrderQty, 'f', -1, 64))
|
||
} else {
|
||
params.Set("quantity", strconv.FormatFloat(o.Quantity, 'f', -1, 64))
|
||
}
|
||
if o.TradeType == BinanceRequestParamsOrderLimit {
|
||
params.Set("price", strconv.FormatFloat(o.Price, 'f', -1, 64))
|
||
}
|
||
if o.TimeInForce != "" {
|
||
params.Set("timeInForce", string(o.TimeInForce))
|
||
}
|
||
if o.NewClientOrderID != "" {
|
||
params.Set("newClientOrderId", o.NewClientOrderID)
|
||
}
|
||
if o.StopPrice != 0 {
|
||
params.Set("stopPrice", strconv.FormatFloat(o.StopPrice, 'f', -1, 64))
|
||
}
|
||
if o.IcebergQty != 0 {
|
||
params.Set("icebergQty", strconv.FormatFloat(o.IcebergQty, 'f', -1, 64))
|
||
}
|
||
if o.NewOrderRespType != "" {
|
||
params.Set("newOrderRespType", o.NewOrderRespType)
|
||
}
|
||
return bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodPost, api, params,
|
||
spotOrderRate, resp)
|
||
}
|
||
|
||
// GetOrder to check a trade order's status.
|
||
func (bi *Binanceus) GetOrder(ctx context.Context, arg *OrderRequestParams) (*Order, error) {
|
||
var resp Order
|
||
params := url.Values{}
|
||
if arg.Symbol == "" {
|
||
return nil, errIncompleteArguments
|
||
}
|
||
params.Set("symbol", strings.ToUpper(arg.Symbol))
|
||
if arg.OrderID > 0 {
|
||
params.Set("orderId", strconv.Itoa(int(arg.OrderID)))
|
||
}
|
||
timestamp := time.Now().UnixMilli()
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
if arg.OrigClientOrderID != "" {
|
||
params.Set("origClientOrderId", arg.OrigClientOrderID)
|
||
}
|
||
if arg.recvWindow > 200 && arg.recvWindow <= 6000 {
|
||
params.Set("recvWindow", strconv.Itoa(int(arg.recvWindow)))
|
||
}
|
||
return &resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, orderRequest,
|
||
params, spotOrderQueryRate,
|
||
&resp)
|
||
}
|
||
|
||
// GetAllOpenOrders to get all open trade orders on a token symbol. Do not access this without a token symbol as this would return all pair data.
|
||
func (bi *Binanceus) GetAllOpenOrders(ctx context.Context, symbol string) ([]Order, error) {
|
||
var response []Order
|
||
params := url.Values{}
|
||
|
||
timestamp := time.Now().UnixMilli()
|
||
if symbol != "" {
|
||
params.Set("symbol", symbol)
|
||
}
|
||
params.Set("timestamp", strconv.Itoa(int(timestamp)))
|
||
params.Set("recvWindow", recvWindowSize5000String)
|
||
var rateLimit request.EndpointLimit
|
||
if symbol != "" {
|
||
rateLimit = spotOpenOrdersSpecificRate
|
||
} else {
|
||
rateLimit = spotOpenOrdersAllRate
|
||
}
|
||
return response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, http.MethodGet,
|
||
openOrders, params,
|
||
rateLimit, &response)
|
||
}
|
||
|
||
// CancelExistingOrder to cancel an active trade order.
|
||
func (bi *Binanceus) CancelExistingOrder(ctx context.Context, arg *CancelOrderRequestParams) (*Order, error) {
|
||
params := url.Values{}
|
||
var response Order
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
symbolValue, err := bi.FormatSymbol(arg.Symbol, asset.Spot)
|
||
if err != nil || symbolValue == "" {
|
||
return nil, errMissingCurrencySymbol
|
||
}
|
||
params.Set("symbol", symbolValue)
|
||
if arg.OrderID == "" && arg.ClientSuppliedOrderID == "" {
|
||
return nil, errEitherOrderIDOrClientOrderIDIsRequired
|
||
}
|
||
if arg.ClientSuppliedOrderID != "" {
|
||
params.Set("origClientOrderId", arg.ClientSuppliedOrderID)
|
||
} else {
|
||
params.Set("orderId", arg.OrderID)
|
||
}
|
||
params.Set("recvWindow", recvWindowSize5000String)
|
||
return &response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodDelete, orderRequest,
|
||
params, spotOrderRate, &response)
|
||
}
|
||
|
||
// CancelOpenOrdersForSymbol request to cancel an open orders.
|
||
func (bi *Binanceus) CancelOpenOrdersForSymbol(ctx context.Context, symbol string) ([]Order, error) {
|
||
params := url.Values{}
|
||
if symbol == "" || len(symbol) < 4 {
|
||
return nil, errMissingCurrencySymbol
|
||
}
|
||
params.Set("symbol", symbol)
|
||
params.Set("timestamp", strconv.Itoa(int(time.Now().UnixMilli())))
|
||
params.Set("recvWindow", "5000")
|
||
var response []Order
|
||
return response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodDelete, openOrders,
|
||
params, spotOrderRate, response)
|
||
}
|
||
|
||
// GetTrades to get trade data for a specific account and token symbol.
|
||
func (bi *Binanceus) GetTrades(ctx context.Context, arg *GetTradesParams) ([]Trade, error) {
|
||
var resp []Trade
|
||
params := url.Values{}
|
||
if arg.Symbol == "" || len(arg.Symbol) <= 2 {
|
||
return nil, errIncompleteArguments
|
||
}
|
||
params.Set("symbol", arg.Symbol)
|
||
params.Set("timestamp", strconv.Itoa(int(time.Now().UnixMilli())))
|
||
if arg.RecvWindow > 3000 {
|
||
params.Set("recvWindow", strconv.Itoa(int(arg.RecvWindow)))
|
||
}
|
||
if arg.StartTime != nil {
|
||
params.Set("startTime", strconv.Itoa(int(arg.StartTime.UnixMilli())))
|
||
}
|
||
if arg.EndTime != nil {
|
||
params.Set("endTime", strconv.Itoa(int(arg.EndTime.UnixMilli())))
|
||
}
|
||
if arg.FromID > 0 {
|
||
params.Set("fromId", strconv.Itoa(int(arg.FromID)))
|
||
}
|
||
if arg.Limit > 0 && arg.Limit < 1000 {
|
||
params.Set("limit", fmt.Sprint(arg.Limit))
|
||
} else if arg.Limit > 1000 {
|
||
params.Set("limit", strconv.Itoa(1000))
|
||
}
|
||
return resp, bi.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, myTrades, params, spotTradesQueryRate, &resp)
|
||
}
|
||
|
||
// OCO Orders
|
||
|
||
// CreateNewOCOOrder o place a new OCO(one-cancels-the-other) order.
|
||
func (bi *Binanceus) CreateNewOCOOrder(ctx context.Context, arg *OCOOrderInputParams) (*OCOFullOrderResponse, error) {
|
||
params := url.Values{}
|
||
if arg == nil || arg.Symbol == "" || len(arg.Symbol) <= 2 || arg.Quantity == 0 || arg.Side == "" || arg.Price == 0 || arg.StopPrice == 0 {
|
||
return nil, errIncompleteArguments
|
||
}
|
||
params.Set("symbol", arg.Symbol)
|
||
params.Set("quantity", strconv.FormatFloat(arg.Quantity, 'f', 5, 64))
|
||
params.Set("side", arg.Side)
|
||
params.Set("price", strconv.FormatFloat(arg.Price, 'f', 5, 64))
|
||
params.Set("stopPrice", strconv.FormatFloat(arg.StopPrice, 'f', 5, 64))
|
||
if arg.ListClientOrderID != "" {
|
||
params.Set("listClientOrderId", arg.ListClientOrderID)
|
||
}
|
||
if arg.LimitClientOrderID != "" {
|
||
params.Set("limitClientOrderId", arg.LimitClientOrderID)
|
||
}
|
||
if arg.LimitIcebergQty > 0 {
|
||
params.Set("limitIcebergQty", strconv.FormatFloat(arg.LimitIcebergQty, 'f', 5, 64))
|
||
}
|
||
if arg.StopClientOrderID != "" {
|
||
params.Set("stopClientOrderId", arg.StopClientOrderID)
|
||
}
|
||
if arg.StopLimitPrice > 0.0 {
|
||
params.Set("stopLimitPrice", strconv.FormatFloat(arg.StopLimitPrice, 'f', 5, 64))
|
||
}
|
||
if arg.StopIcebergQty > 0.0 {
|
||
params.Set("stopIcebergQty", strconv.FormatFloat(arg.StopIcebergQty, 'f', 5, 64))
|
||
}
|
||
if arg.StopLimitTimeInForce != "" {
|
||
params.Set("stopLimitTimeInForce", arg.StopLimitTimeInForce)
|
||
}
|
||
if arg.NewOrderRespType != "" {
|
||
params.Set("newOrderRespType", arg.NewOrderRespType)
|
||
}
|
||
if arg.RecvWindow > 200 {
|
||
params.Set("recvWindow", strconv.Itoa(int(arg.RecvWindow)))
|
||
} else {
|
||
params.Set("recvWindow", "6000")
|
||
}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
var response OCOFullOrderResponse
|
||
return &response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodPost, ocoOrder, params,
|
||
spotOrderRate, &response)
|
||
}
|
||
|
||
// GetOCOOrder to retrieve a specific OCO order based on provided optional parameters.
|
||
func (bi *Binanceus) GetOCOOrder(ctx context.Context, arg *GetOCOOrderRequestParams) (*OCOOrderResponse, error) {
|
||
params := url.Values{}
|
||
params.Set("timestamp", fmt.Sprint(time.Now().UnixMilli()))
|
||
switch {
|
||
case arg.OrderListID != "":
|
||
params.Set("orderListId", arg.OrderListID)
|
||
case arg.OrigClientOrderID != "":
|
||
params.Set("origClientOrderId", arg.OrigClientOrderID)
|
||
default:
|
||
return nil, errIncompleteArguments
|
||
}
|
||
params.Set("recvWindow", "60000")
|
||
var response OCOOrderResponse
|
||
return &response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet, ocoOrderList, params, spotSingleOCOOrderRate, &response)
|
||
}
|
||
|
||
// GetAllOCOOrder to retrieve all OCO orders based on provided optional parameters. Please note the maximum limit is 1,000 orders.
|
||
func (bi *Binanceus) GetAllOCOOrder(ctx context.Context, arg *OCOOrdersRequestParams) ([]OCOOrderResponse, error) {
|
||
params := url.Values{}
|
||
params.Set("timestamp", fmt.Sprint(time.Now().UnixMilli()))
|
||
var response []OCOOrderResponse
|
||
if arg.FromID > 0 {
|
||
params.Set("fromId", fmt.Sprint(arg.FromID))
|
||
} else {
|
||
if arg.StartTime.Unix() > 0 && arg.StartTime.Before(arg.EndTime) {
|
||
params.Set("startTime", fmt.Sprint(arg.StartTime.UnixMilli()))
|
||
params.Set("endTime", fmt.Sprint(arg.EndTime.UnixMilli()))
|
||
} else if arg.StartTime.Unix() > 0 {
|
||
params.Set("startTime", fmt.Sprint(arg.StartTime.UnixMilli()))
|
||
}
|
||
}
|
||
if arg.Limit > 0 {
|
||
params.Set("limit", fmt.Sprint(arg.Limit))
|
||
}
|
||
if arg.RecvWindow > 0 {
|
||
params.Set("recvWindow", fmt.Sprint(arg.RecvWindow))
|
||
}
|
||
return response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodGet, ocoAllOrderList,
|
||
params, spotAllOCOOrdersRate,
|
||
&response)
|
||
}
|
||
|
||
// GetOpenOCOOrders to query open OCO orders.
|
||
func (bi *Binanceus) GetOpenOCOOrders(ctx context.Context, recvWindow uint) ([]OCOOrderResponse, error) {
|
||
params := url.Values{}
|
||
params.Set("timestamp", fmt.Sprint(time.Now().UnixMilli()))
|
||
if recvWindow > 0 {
|
||
params.Set("recvWindow", fmt.Sprint(recvWindow))
|
||
} else {
|
||
params.Set("recvWindow", "30000")
|
||
}
|
||
var response []OCOOrderResponse
|
||
return response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet,
|
||
ocoOpenOrders, params,
|
||
spotOpenOrdersSpecificRate, &response)
|
||
}
|
||
|
||
// CancelOCOOrder to cancel an entire order list.
|
||
func (bi *Binanceus) CancelOCOOrder(ctx context.Context, arg *OCOOrdersDeleteRequestParams) (*OCOFullOrderResponse, error) {
|
||
var response OCOFullOrderResponse
|
||
params := url.Values{}
|
||
params.Set("timestamp", fmt.Sprint(time.Now().UnixMilli()))
|
||
switch {
|
||
case arg.OrderListID > 0:
|
||
params.Set("orderListId", strconv.Itoa(int(arg.OrderListID)))
|
||
case arg.ListClientOrderID != "":
|
||
params.Set("listClientOrderId", arg.ListClientOrderID)
|
||
default:
|
||
return nil, errIncompleteArguments
|
||
}
|
||
if arg.RecvWindow > 0 {
|
||
params.Set("recvWindow", fmt.Sprint(arg.RecvWindow))
|
||
}
|
||
return &response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodGet, ocoOrderList,
|
||
params, spotOrderRate, &response)
|
||
}
|
||
|
||
// OTC end points
|
||
|
||
// GetSupportedCoinPairs to get a list of supported coin pairs for convert.
|
||
// returns list of CoinPairInfo
|
||
func (bi *Binanceus) GetSupportedCoinPairs(ctx context.Context, symbol currency.Pair) ([]CoinPairInfo, error) {
|
||
params := url.Values{}
|
||
if !symbol.IsEmpty() {
|
||
params.Set("fromCoin", symbol.Base.String())
|
||
params.Set("toCoin", symbol.Quote.String())
|
||
}
|
||
var resp []CoinPairInfo
|
||
return resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, http.MethodGet, otcSelectors,
|
||
params, spotDefaultRate, &resp)
|
||
}
|
||
|
||
// RequestForQuote endpoint to request a quote for a from-to coin pair.
|
||
func (bi *Binanceus) RequestForQuote(ctx context.Context, arg *RequestQuoteParams) (*Quote, error) {
|
||
params := url.Values{}
|
||
var resp Quote
|
||
if arg.FromCoin == "" {
|
||
return nil, errMissingFromCoinName
|
||
}
|
||
if arg.ToCoin == "" {
|
||
return nil, errMissingToCoinName
|
||
}
|
||
if arg.RequestCoin == "" {
|
||
return nil, errMissingRequestCoin
|
||
}
|
||
if arg.RequestAmount <= 0 {
|
||
return nil, errMissingRequestAmount
|
||
}
|
||
params.Set("fromCoin", arg.FromCoin)
|
||
params.Set("toCoin", arg.ToCoin)
|
||
params.Set("requestAmount", strconv.FormatFloat(arg.RequestAmount, 'f', 0, 64))
|
||
params.Set("requestCoin", arg.RequestCoin)
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
return &resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpot,
|
||
http.MethodPost, otcQuotes, params,
|
||
spotDefaultRate, &resp)
|
||
}
|
||
|
||
// PlaceOTCTradeOrder to place an order using an acquired quote.
|
||
// returns OTCTradeOrderResponse response containing the OrderID,OrderStatus, and CreateTime information of an order.
|
||
func (bi *Binanceus) PlaceOTCTradeOrder(ctx context.Context, quoteID string) (*OTCTradeOrderResponse, error) {
|
||
params := url.Values{}
|
||
if strings.Trim(quoteID, " ") == "" {
|
||
return nil, errMissingQuoteID
|
||
}
|
||
params.Set("quoteId", quoteID)
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
var response OTCTradeOrderResponse
|
||
return &response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpot, http.MethodPost,
|
||
otcTradeOrder, params,
|
||
spotOrderRate, &response)
|
||
}
|
||
|
||
// GetOTCTradeOrder returns a single OTC Trade Order instance.
|
||
func (bi *Binanceus) GetOTCTradeOrder(ctx context.Context, orderID uint64) (*OTCTradeOrder, error) {
|
||
var response OTCTradeOrder
|
||
params := url.Values{}
|
||
if orderID <= 0 {
|
||
return nil, errIncompleteArguments
|
||
}
|
||
orderIDStr := strconv.FormatUint(orderID, 10)
|
||
params.Set("orderId", orderIDStr)
|
||
params.Set("timestamp", fmt.Sprint(time.Now().UnixMilli()))
|
||
path := otcTradeOrders + orderIDStr
|
||
return &response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
path, params,
|
||
spotOrderRate, response)
|
||
}
|
||
|
||
// GetAllOTCTradeOrders returns list of OTC Trade Orders
|
||
func (bi *Binanceus) GetAllOTCTradeOrders(ctx context.Context, arg *OTCTradeOrderRequestParams) ([]OTCTradeOrder, error) {
|
||
params := url.Values{}
|
||
if arg.OrderID != "" {
|
||
params.Set("orderId", arg.OrderID)
|
||
}
|
||
if arg.FromCoin != "" {
|
||
params.Set("fromCoin", arg.FromCoin)
|
||
}
|
||
if !(arg.StartTime.IsZero()) {
|
||
params.Set("startTime", strconv.FormatInt(arg.StartTime.UnixMilli(), 10))
|
||
}
|
||
if !(arg.EndTime.IsZero()) {
|
||
params.Set("endTime", strconv.FormatInt(arg.EndTime.UnixMilli(), 10))
|
||
}
|
||
if arg.ToCoin != "" {
|
||
params.Set("toCoin", arg.ToCoin)
|
||
}
|
||
if arg.Limit > 0 {
|
||
params.Set("limit", strconv.Itoa(int(arg.Limit)))
|
||
}
|
||
var response []OTCTradeOrder
|
||
return response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, otcTradeOrder,
|
||
params, spotOrderRate, &response)
|
||
}
|
||
|
||
// GetAllOCBSTradeOrders use this endpoint to query all OCBS orders by condition.
|
||
func (bi *Binanceus) GetAllOCBSTradeOrders(ctx context.Context, arg OCBSOrderRequestParams) (*OCBSTradeOrdersResponse, error) {
|
||
var resp OCBSTradeOrdersResponse
|
||
params := url.Values{}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
if arg.OrderID != "" {
|
||
params.Set("orderId", arg.OrderID)
|
||
}
|
||
if !arg.StartTime.IsZero() {
|
||
params.Set("startTime", strconv.FormatInt(arg.StartTime.UnixMilli(), 10))
|
||
}
|
||
if !arg.EndTime.IsZero() {
|
||
params.Set("endTime", strconv.FormatInt(arg.StartTime.UnixMilli(), 10))
|
||
}
|
||
if arg.Limit > 0 && arg.Limit < 100 {
|
||
params.Set("limit", strconv.Itoa(int(arg.Limit)))
|
||
}
|
||
return &resp, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, ocbsTradeOrders,
|
||
params, spotOrderRate, &resp)
|
||
}
|
||
|
||
// Wallet End points
|
||
|
||
// GetAssetFeesAndWalletStatus to fetch the details of all crypto assets, including fees, withdrawal limits and network status.
|
||
// returns the asset wallet detail as a list.
|
||
func (bi *Binanceus) GetAssetFeesAndWalletStatus(ctx context.Context) (AssetWalletList, error) {
|
||
params := url.Values{}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
var response AssetWalletList
|
||
return response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, assetFeeAndWalletStatus,
|
||
params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// WithdrawCrypto method to withdraw crypto
|
||
func (bi *Binanceus) WithdrawCrypto(ctx context.Context, arg *withdraw.Request) (string, error) {
|
||
params := url.Values{}
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
if arg.Currency.String() == "" {
|
||
return "", errMissingRequiredArgumentCoin
|
||
}
|
||
params.Set("coin", arg.Currency.String())
|
||
if arg.Crypto.Chain == "" {
|
||
return "", errMissingRequiredArgumentNetwork
|
||
}
|
||
params.Set("network", arg.Crypto.Chain)
|
||
if arg.ClientOrderID != "" {
|
||
params.Set("withdrawOrderId", arg.ClientOrderID)
|
||
}
|
||
if arg.Crypto.Address == "" {
|
||
return "", errMissingRequiredParameterAddress
|
||
}
|
||
params.Set("address", arg.Crypto.Address)
|
||
if arg.Crypto.AddressTag != "" {
|
||
params.Set("addressTag", arg.Crypto.AddressTag)
|
||
}
|
||
if arg.Amount <= 0 {
|
||
return "", errAmountValueMustBeGreaterThan0
|
||
}
|
||
params.Set("amount", strconv.FormatFloat(arg.Amount, 'f', 0, 64))
|
||
var response WithdrawalResponse
|
||
var er = bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodPost, applyWithdrawal,
|
||
params, spotDefaultRate, &response)
|
||
if er != nil {
|
||
return "", er
|
||
}
|
||
return response.ID, er
|
||
}
|
||
|
||
// WithdrawalHistory gets the status of recent withdrawals
|
||
// status `param` used as string to prevent default value 0 (for int) interpreting as EmailSent status
|
||
func (bi *Binanceus) WithdrawalHistory(ctx context.Context, c currency.Code, status string, startTime, endTime time.Time, offset, limit int) ([]WithdrawStatusResponse, error) {
|
||
params := url.Values{}
|
||
if !c.IsEmpty() {
|
||
params.Set("coin", c.String())
|
||
}
|
||
if status != "" {
|
||
i, err := strconv.Atoi(status)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("wrong param (status): %s. Error: %v", status, err)
|
||
}
|
||
switch i {
|
||
case EmailSent, Cancelled, AwaitingApproval, Rejected, Processing, Failure, Completed:
|
||
default:
|
||
return nil, fmt.Errorf("wrong param (status): %s", status)
|
||
}
|
||
params.Set("status", status)
|
||
}
|
||
if !startTime.IsZero() && startTime.Unix() != 0 {
|
||
params.Set("startTime", strconv.FormatInt(startTime.UTC().Unix(), 10))
|
||
}
|
||
if !endTime.IsZero() && endTime.Unix() != 0 {
|
||
params.Set("endTime", strconv.FormatInt(endTime.UTC().Unix(), 10))
|
||
}
|
||
if offset != 0 {
|
||
params.Set("offset", strconv.Itoa(offset))
|
||
}
|
||
if limit != 0 {
|
||
params.Set("limit", strconv.Itoa(limit))
|
||
}
|
||
var withdrawStatus []WithdrawStatusResponse
|
||
if err := bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
withdrawalHistory,
|
||
params,
|
||
spotDefaultRate,
|
||
&withdrawStatus); err != nil {
|
||
return nil, err
|
||
}
|
||
return withdrawStatus, nil
|
||
}
|
||
|
||
// FiatWithdrawalHistory to fetch your fiat (USD) withdrawal history.
|
||
// returns FiatAssetHistory containing list of fiat asset records.
|
||
func (bi *Binanceus) FiatWithdrawalHistory(ctx context.Context, arg *FiatWithdrawalRequestParams) (FiatAssetsHistory, error) {
|
||
var response FiatAssetsHistory
|
||
params := url.Values{}
|
||
if !(arg.EndTime.IsZero()) && !(arg.EndTime.Before(time.Now())) {
|
||
params.Set("endTime", strconv.Itoa(int(arg.EndTime.UnixMilli())))
|
||
}
|
||
if !arg.StartTime.IsZero() && !(arg.StartTime.After(time.Now())) {
|
||
params.Set("startTime", strconv.Itoa(int(arg.StartTime.UnixMilli())))
|
||
}
|
||
if arg.FiatCurrency != "" {
|
||
params.Set("fiatCurrency", arg.FiatCurrency)
|
||
}
|
||
if arg.Offset > 0 {
|
||
params.Set("offset", strconv.FormatInt(arg.Offset, 10))
|
||
}
|
||
if arg.PaymentChannel != "" {
|
||
params.Set("paymentChannel", arg.PaymentChannel)
|
||
}
|
||
if arg.PaymentMethod != "" {
|
||
params.Set("paymentMethod", arg.PaymentMethod)
|
||
}
|
||
params.Set("timestamp", strconv.Itoa(int(time.Now().UnixMilli())))
|
||
return response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet, fiatWithdrawalHistory,
|
||
params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// WithdrawFiat to submit a USD withdraw request via Silvergate Exchange Network (SEN).
|
||
// returns the Order ID as string
|
||
func (bi *Binanceus) WithdrawFiat(ctx context.Context, arg *WithdrawFiatRequestParams) (string, error) {
|
||
params := url.Values{}
|
||
timestamp := strconv.Itoa(int(time.Now().UnixMilli()))
|
||
if arg == nil {
|
||
return "", errIncompleteArguments
|
||
}
|
||
params.Set("timestamp", timestamp)
|
||
if arg.PaymentChannel != "" {
|
||
params.Set("paymentChannel", arg.PaymentChannel)
|
||
}
|
||
if arg.PaymentMethod != "" {
|
||
params.Set("paymentMethod", arg.PaymentMethod)
|
||
}
|
||
if arg.PaymentAccount == "" {
|
||
return "", errMissingPaymentAccountInfo
|
||
}
|
||
if arg.FiatCurrency != "" {
|
||
params.Set("fiatCurrency", arg.FiatCurrency)
|
||
}
|
||
if arg.Amount <= 0 {
|
||
return "", errAmountValueMustBeGreaterThan0
|
||
}
|
||
type response struct {
|
||
OrderID string `json:"orderId"`
|
||
}
|
||
var resp response
|
||
return resp.OrderID, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary,
|
||
http.MethodPost, withdrawFiat,
|
||
params, spotDefaultRate, &resp,
|
||
)
|
||
}
|
||
|
||
/*
|
||
Deposits
|
||
Get Crypto Deposit Address
|
||
*/
|
||
|
||
// GetDepositAddressForCurrency retrieves the wallet address for a given currency
|
||
func (bi *Binanceus) GetDepositAddressForCurrency(ctx context.Context, currency, chain string) (*DepositAddress, error) {
|
||
params := url.Values{}
|
||
if currency == "" {
|
||
return nil, errMissingRequiredArgumentCoin
|
||
}
|
||
params.Set("coin", currency)
|
||
if chain != "" {
|
||
params.Set("network", chain)
|
||
}
|
||
params.Set("recvWindow", "10000")
|
||
var d DepositAddress
|
||
return &d,
|
||
bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet, depositAddress, params, spotDefaultRate, &d)
|
||
}
|
||
|
||
// DepositHistory returns the deposit history based on the supplied params
|
||
// status `param` used as string to prevent default value 0 (for int) interpreting as EmailSent status
|
||
func (bi *Binanceus) DepositHistory(ctx context.Context, c currency.Code, status uint8, startTime, endTime time.Time, offset, limit int) ([]DepositHistory, error) {
|
||
var response []DepositHistory
|
||
params := url.Values{}
|
||
if !c.IsEmpty() {
|
||
params.Set("coin", c.String())
|
||
}
|
||
|
||
if status > 0 {
|
||
switch status {
|
||
case 0 /*Pending*/, 1 /*Success*/, 6 /*Credited but cannot withdraw*/ :
|
||
params.Set("status", strconv.Itoa(int(status)))
|
||
default:
|
||
return nil, fmt.Errorf("wrong param (status) 0 Pending, 1 success, 6 credited but cannot withdraw are allowed: %d ", status)
|
||
}
|
||
}
|
||
if !startTime.IsZero() && startTime.Unix() != 0 {
|
||
params.Set("startTime", strconv.FormatInt(startTime.UTC().Unix(), 10))
|
||
}
|
||
|
||
if !endTime.IsZero() && endTime.Unix() != 0 {
|
||
params.Set("endTime", strconv.FormatInt(endTime.UTC().Unix(), 10))
|
||
}
|
||
|
||
if offset != 0 {
|
||
params.Set("offset", strconv.Itoa(offset))
|
||
}
|
||
|
||
if limit != 0 {
|
||
params.Set("limit", strconv.Itoa(limit))
|
||
}
|
||
|
||
if err := bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary,
|
||
http.MethodGet,
|
||
depositHistory,
|
||
params,
|
||
spotDefaultRate,
|
||
&response); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return response, nil
|
||
}
|
||
|
||
// FiatDepositHistory fetch your fiat (USD) deposit history as Fiat Assets History
|
||
func (bi *Binanceus) FiatDepositHistory(ctx context.Context, arg *FiatWithdrawalRequestParams) (FiatAssetsHistory, error) {
|
||
params := url.Values{}
|
||
if !(arg.EndTime.IsZero()) && !(arg.EndTime.Before(time.Now())) {
|
||
params.Set("endTime", fmt.Sprint(arg.EndTime.UnixMilli()))
|
||
}
|
||
if !(arg.StartTime.IsZero()) && !(arg.StartTime.After(time.Now())) {
|
||
params.Set("startTime", fmt.Sprint(arg.StartTime.UnixMilli()))
|
||
}
|
||
if arg.FiatCurrency != "" {
|
||
params.Set("fiatCurrency", arg.FiatCurrency)
|
||
}
|
||
if arg.Offset > 0 {
|
||
params.Set("offset", fmt.Sprint(arg.Offset))
|
||
}
|
||
if arg.PaymentChannel != "" {
|
||
params.Set("paymentChannel", arg.PaymentChannel)
|
||
}
|
||
if arg.PaymentMethod != "" {
|
||
params.Set("paymentMethod", arg.PaymentMethod)
|
||
}
|
||
params.Set("timestamp", fmt.Sprint(time.Now().UnixMilli()))
|
||
var response FiatAssetsHistory
|
||
return response, bi.SendAuthHTTPRequest(ctx,
|
||
exchange.RestSpotSupplementary, http.MethodGet,
|
||
fiatDepositHistory, params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// GetSubAccountDepositAddress retrieves sub-account’s deposit address.
|
||
func (bi *Binanceus) GetSubAccountDepositAddress(ctx context.Context, arg SubAccountDepositAddressRequestParams) (*SubAccountDepositAddress, error) {
|
||
params := url.Values{}
|
||
if !common.MatchesEmailPattern(arg.Email) {
|
||
return nil, errMissingSubAccountEmail
|
||
} else if arg.Coin.String() == "" {
|
||
return nil, errMissingCurrencyCoin
|
||
}
|
||
params.Set("email", arg.Email)
|
||
params.Set("coin", arg.Coin.String())
|
||
var response SubAccountDepositAddress
|
||
return &response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet,
|
||
subAccountDepositAddress, params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// GetSubAccountDepositHistory retrieves sub-account deposit history.
|
||
func (bi *Binanceus) GetSubAccountDepositHistory(ctx context.Context, email string, coin currency.Code,
|
||
status int, startTime, endTime time.Time, limit, offset int) ([]SubAccountDepositItem, error) {
|
||
params := url.Values{}
|
||
if !common.MatchesEmailPattern(email) {
|
||
return nil, errMissingSubAccountEmail
|
||
}
|
||
params.Set("email", email)
|
||
if coin.String() != "" {
|
||
params.Set("coin", coin.String())
|
||
}
|
||
if status == 0 || status == 6 || status == 1 {
|
||
params.Set("status", strconv.Itoa(status))
|
||
}
|
||
if !startTime.IsZero() && startTime.Unix() != 0 && startTime.Before(time.Now()) {
|
||
params.Set("startTime", strconv.FormatInt(startTime.UnixMilli(), 10))
|
||
}
|
||
if !endTime.IsZero() && endTime.Unix() != 0 && endTime.Before(time.Now()) {
|
||
params.Set("endTime", strconv.FormatInt(endTime.UnixMilli(), 10))
|
||
}
|
||
if limit > 0 {
|
||
params.Set("limit", strconv.Itoa(limit))
|
||
}
|
||
if offset > 0 {
|
||
params.Set("offset", strconv.Itoa(offset))
|
||
}
|
||
var response []SubAccountDepositItem
|
||
return response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet,
|
||
subAccountDepositHistory, params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// Referral Endpoints
|
||
|
||
// GetReferralRewardHistory retrieves the user’s referral reward history.
|
||
func (bi *Binanceus) GetReferralRewardHistory(ctx context.Context, userBusinessType, page, rows int) (*ReferralRewardHistoryResponse, error) {
|
||
params := url.Values{}
|
||
switch {
|
||
case !(userBusinessType == 0 || userBusinessType == 1):
|
||
return nil, errInvalidUserBusinessType
|
||
case page == 0:
|
||
return nil, errMissingPageNumber
|
||
case rows < 1 || rows > 200:
|
||
return nil, errInvalidRowNumber
|
||
}
|
||
params.Set("userBizType", strconv.Itoa(userBusinessType))
|
||
params.Set("page", strconv.Itoa(page))
|
||
params.Set("rows", strconv.Itoa(rows))
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
var response ReferralRewardHistoryResponse
|
||
return &response, bi.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet, referralRewardHistory, params, spotDefaultRate, &response)
|
||
}
|
||
|
||
// SendHTTPRequest sends an unauthenticated request
|
||
func (bi *Binanceus) SendHTTPRequest(ctx context.Context, ePath exchange.URL, path string, f request.EndpointLimit, result interface{}) error {
|
||
endpointPath, err := bi.API.Endpoints.GetURL(ePath)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
item := &request.Item{
|
||
Method: http.MethodGet,
|
||
Path: endpointPath + path,
|
||
Result: result,
|
||
Verbose: bi.Verbose,
|
||
HTTPDebugging: bi.HTTPDebugging,
|
||
HTTPRecording: bi.HTTPRecording,
|
||
}
|
||
return bi.SendPayload(ctx, f, func() (*request.Item, error) {
|
||
return item, nil
|
||
})
|
||
}
|
||
|
||
// SendAPIKeyHTTPRequest is a special API request where the api key is
|
||
// appended to the headers without a secret
|
||
func (bi *Binanceus) SendAPIKeyHTTPRequest(ctx context.Context, ePath exchange.URL, path string, f request.EndpointLimit, result interface{}) error {
|
||
endpointPath, err := bi.API.Endpoints.GetURL(ePath)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
creds, err := bi.GetCredentials(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
headers := make(map[string]string)
|
||
headers["X-MBX-APIKEY"] = creds.Key
|
||
item := &request.Item{
|
||
Method: http.MethodGet,
|
||
Path: endpointPath + path,
|
||
Headers: headers,
|
||
Result: result,
|
||
Verbose: bi.Verbose,
|
||
HTTPDebugging: bi.HTTPDebugging,
|
||
HTTPRecording: bi.HTTPRecording}
|
||
|
||
return bi.SendPayload(ctx, f, func() (*request.Item, error) {
|
||
return item, nil
|
||
})
|
||
}
|
||
|
||
// SendAuthHTTPRequest sends an authenticated HTTP request
|
||
func (bi *Binanceus) SendAuthHTTPRequest(ctx context.Context, ePath exchange.URL, method, path string, params url.Values, f request.EndpointLimit, result interface{}) error {
|
||
creds, err := bi.GetCredentials(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
endpointPath, err := bi.API.Endpoints.GetURL(ePath)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if params == nil {
|
||
params = url.Values{}
|
||
}
|
||
if params.Get("recvWindow") == "" {
|
||
params.Set("recvWindow", strconv.FormatInt(defaultRecvWindow.Milliseconds(), 10))
|
||
}
|
||
interim := json.RawMessage{}
|
||
err = bi.SendPayload(ctx, f, func() (*request.Item, error) {
|
||
fullPath := endpointPath + path
|
||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||
signature := params.Encode()
|
||
var hmacSigned []byte
|
||
hmacSigned, err = crypto.GetHMAC(crypto.HashSHA256,
|
||
[]byte(signature),
|
||
[]byte(creds.Secret))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
hmacSignedStr := crypto.HexEncodeToString(hmacSigned)
|
||
headers := make(map[string]string)
|
||
headers["X-MBX-APIKEY"] = creds.Key
|
||
fullPath = common.EncodeURLValues(fullPath, params)
|
||
fullPath += "&signature=" + hmacSignedStr
|
||
return &request.Item{
|
||
Method: method,
|
||
Path: fullPath,
|
||
Headers: headers,
|
||
Result: &interim,
|
||
AuthRequest: true,
|
||
Verbose: bi.Verbose,
|
||
HTTPDebugging: bi.HTTPDebugging,
|
||
HTTPRecording: bi.HTTPRecording}, nil
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
errCap := struct {
|
||
Success bool `json:"success"`
|
||
Message string `json:"msg"`
|
||
Code int64 `json:"code"`
|
||
}{}
|
||
if err := json.Unmarshal(interim, &errCap); err == nil {
|
||
if !errCap.Success && errCap.Message != "" && errCap.Code != 200 {
|
||
return errors.New(errCap.Message)
|
||
}
|
||
}
|
||
return json.Unmarshal(interim, result)
|
||
}
|
||
|
||
// ----- Web socket related methods
|
||
|
||
// GetWsAuthStreamKey this method 'Creates User Data Stream' will retrieve a key to use for authorised WS streaming
|
||
// Same as that of Binance
|
||
// Start a new user data stream. The stream will close after 60 minutes unless a keepalive is sent.
|
||
// If the account has an active listenKey,
|
||
// that listenKey will be returned and its validity will be extended for 60 minutes.
|
||
func (bi *Binanceus) GetWsAuthStreamKey(ctx context.Context) (string, error) {
|
||
endpointPath, err := bi.API.Endpoints.GetURL(exchange.RestSpotSupplementary)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
creds, err := bi.GetCredentials(ctx)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
var resp UserAccountStream
|
||
headers := make(map[string]string)
|
||
headers["X-MBX-APIKEY"] = creds.Key
|
||
item := &request.Item{
|
||
Method: http.MethodPost,
|
||
Path: endpointPath + userAccountStream,
|
||
Headers: headers,
|
||
Result: &resp,
|
||
AuthRequest: true,
|
||
Verbose: bi.Verbose,
|
||
HTTPDebugging: bi.HTTPDebugging,
|
||
HTTPRecording: bi.HTTPRecording,
|
||
}
|
||
|
||
err = bi.SendPayload(ctx, spotDefaultRate, func() (*request.Item, error) {
|
||
return item, nil
|
||
})
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return resp.ListenKey, nil
|
||
}
|
||
|
||
// MaintainWsAuthStreamKey will Extend User Data Stream
|
||
// Similar functionality to the same method of Binance.
|
||
// Keepalive a user data stream to prevent a time out.
|
||
// User data streams will close after 60 minutes.
|
||
// It's recommended to send a ping about every 30 minutes.
|
||
func (bi *Binanceus) MaintainWsAuthStreamKey(ctx context.Context) error {
|
||
endpointPath, err := bi.API.Endpoints.GetURL(exchange.RestSpotSupplementary)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if listenKey == "" {
|
||
listenKey, err = bi.GetWsAuthStreamKey(ctx)
|
||
return err
|
||
}
|
||
|
||
creds, err := bi.GetCredentials(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
path := endpointPath + userAccountStream
|
||
params := url.Values{}
|
||
params.Set("listenKey", listenKey)
|
||
path = common.EncodeURLValues(path, params)
|
||
headers := make(map[string]string)
|
||
headers["X-MBX-APIKEY"] = creds.Key
|
||
item := &request.Item{
|
||
Method: http.MethodPut,
|
||
Path: path,
|
||
Headers: headers,
|
||
AuthRequest: true,
|
||
Verbose: bi.Verbose,
|
||
HTTPDebugging: bi.HTTPDebugging,
|
||
HTTPRecording: bi.HTTPRecording,
|
||
}
|
||
|
||
return bi.SendPayload(ctx, spotDefaultRate, func() (*request.Item, error) {
|
||
return item, nil
|
||
})
|
||
}
|
||
|
||
// CloseUserDataStream Close out a user data stream.
|
||
func (bi *Binanceus) CloseUserDataStream(ctx context.Context) error {
|
||
endpointPath, err := bi.API.Endpoints.GetURL(exchange.RestSpotSupplementary)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if listenKey == "" {
|
||
listenKey, err = bi.GetWsAuthStreamKey(ctx)
|
||
return err
|
||
}
|
||
|
||
creds, err := bi.GetCredentials(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
path := endpointPath + userAccountStream
|
||
params := url.Values{}
|
||
params.Set("listenKey", listenKey)
|
||
path = common.EncodeURLValues(path, params)
|
||
headers := make(map[string]string)
|
||
headers["X-MBX-APIKEY"] = creds.Key
|
||
item := &request.Item{
|
||
Method: http.MethodDelete,
|
||
Path: path,
|
||
Headers: headers,
|
||
AuthRequest: true,
|
||
Verbose: bi.Verbose,
|
||
HTTPDebugging: bi.HTTPDebugging,
|
||
HTTPRecording: bi.HTTPRecording,
|
||
}
|
||
|
||
return bi.SendPayload(ctx, spotDefaultRate, func() (*request.Item, error) {
|
||
return item, nil
|
||
})
|
||
}
|