mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
exchanges: Add OKX support (#1005)
* public endpoints methods added * Completing mapping REST endpoints * Binanceus Wrapper methods -Partially * Binanceus Wrapper methods -Partially * BinaWra functions with test funs; Not Completed * Finalizing wrapper methods & test * Fix & Complete wrapper functions * Finalizing wrapper methods & test * 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 * Adding Public endpoints and tests * Adding Market and Public Endpoints * Adding Public endoints * Public Trading Endpoints & Authenticated Trade order methods * Adding Authenticated Methods and Tests * Adding algo and Funding Authenticated endpoints * Adding funding trading endpoints and correspondint tests * adding authenticated endpoints * Completing Block Trading endpoints and added subaccount endpoints * Completing sub account and grid Trading endpoints * Adding Rate Limit and missing endpoints * Wrapper and Websocket handlers * Fixing Websocket Test and Push Data Handler Issues * Fixing Websocket Test and Push Data Handler Issues * Fixing linter issues, package dependency, and other slight tempos * Fixing linter and slight tempos * Update on test functions, and Rest and Websocket Endpoint handlers * Remove okex, adding comments, and slight fixes on endpoints. * Fixing linter issues and adding comments * Slight code changes, updating documentation, and n and linter issues * Fix context and configuration endpoint issues * slight fixes on config and test files * adding some missing test and fix linter issues * fix linter issue * Slight fixes on code structure, shorthand exp,and ot and other * Fix slight linter issue * Slight code fixes and fixing linter issues * fixing linter iissues * fixing linter iissues * slight linter issue fix * slight linter issue fix * Fix on models, type convert funcs and endpoints * Adding Error messages map and update of models * Fix on error message string and linter issues * Fix slight linter issue * Fix slight linter issue * Fixing type converts, models, and linter issues * Adding Ws fixes * Slight fix on websocket and other issues * Adding slight websocket fixes * Remove 'books5' channel default subscription * Small changes on default subscription and checksum * Fix slight websocket tempos * Fix Wrapper function tempost and linter issues * Resolving slight naming and other issues * Resolve slight pointer issues * resolve slight linter issues * Resolve config files issue * Update websocket and wrapper funcs with test and docs * fixs on websocket multiplexer, types, and other slight issues * fix slight linter issues * slight update on web-socket orderbook and tickers * fix slight issues and websocket runtime errors * Slight unit test fix and assing simple semaphore * FIx race issue * Update on authenticated endpoints * Fix wsSetupRun check in websocket 'setupWsAuth' func * Update wsSetupRun check in websocket 'setupWsAuth' func * Slight update on websocket handling * Fix some race conditions * fix slight tempos * fix authenticated test issues * Update on conditional statements * slight update on unit test * fix unit test tempos * Fix slight tempos * Change check map from struct valued to bool valued * slight fix trial * Slight unit test update * Fix websocket timeout error * Updating websocket subscription endpoints, and unit tests * update unit tests * Slight issue on wrapper method 'GetActiveOrders' * Overall code update * Addressing missing review comments * Fix unit test tempo and linter issue * Monor fix * Slight update * Slight unit test fix * Slight fixes * Slight fixes * Fixing on missing review comments * Adding WS Fixes * slight fix * Monor fix on unit test * Minor convert issue * Minor change on WS * Monor logic fix * Fix code structure and logic issues * Fixing small typos * fix slight data format issue * Update on trade and order wrapper methods * Adding slight update * fix on order detail * Slight update on FetchTradablePairs wrapper method * Slight update on wrapper * Update on deserialization and other slight issues * Final update * Resolve missing review comments * Slight update on config and unit test * minor fix on GetDepositAddress param * Minor fix
This commit is contained in:
@@ -15,6 +15,7 @@ MadCozBadd | https://github.com/MadCozBadd
|
||||
vadimzhukck | https://github.com/vadimzhukck
|
||||
140am | https://github.com/140am
|
||||
marcofranssen | https://github.com/marcofranssen
|
||||
geseq | https://github.com/geseq
|
||||
dackroyd | https://github.com/dackroyd
|
||||
cranktakular | https://github.com/cranktakular
|
||||
khcchiu | https://github.com/khcchiu
|
||||
|
||||
11
README.md
11
README.md
@@ -43,7 +43,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| Lbank | Yes | No | NA |
|
||||
| LocalBitcoins | Yes | NA | NA |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
| Okx | Yes | Yes | NA |
|
||||
| Poloniex | Yes | Yes | NA |
|
||||
| Yobit | Yes | NA | NA |
|
||||
| ZB.COM | Yes | Yes | NA |
|
||||
@@ -145,10 +145,10 @@ Binaries will be published once the codebase reaches a stable condition.
|
||||
|
||||
|User|Contribution Amount|
|
||||
|--|--|
|
||||
| [thrasher-](https://github.com/thrasher-) | 667 |
|
||||
| [shazbert](https://github.com/shazbert) | 260 |
|
||||
| [gloriousCode](https://github.com/gloriousCode) | 199 |
|
||||
| [dependabot[bot]](https://github.com/apps/dependabot) | 99 |
|
||||
| [thrasher-](https://github.com/thrasher-) | 670 |
|
||||
| [shazbert](https://github.com/shazbert) | 268 |
|
||||
| [gloriousCode](https://github.com/gloriousCode) | 202 |
|
||||
| [dependabot[bot]](https://github.com/apps/dependabot) | 130 |
|
||||
| [dependabot-preview[bot]](https://github.com/apps/dependabot-preview) | 88 |
|
||||
| [xtda](https://github.com/xtda) | 47 |
|
||||
| [lrascao](https://github.com/lrascao) | 27 |
|
||||
@@ -160,6 +160,7 @@ Binaries will be published once the codebase reaches a stable condition.
|
||||
| [vadimzhukck](https://github.com/vadimzhukck) | 10 |
|
||||
| [140am](https://github.com/140am) | 8 |
|
||||
| [marcofranssen](https://github.com/marcofranssen) | 8 |
|
||||
| [geseq](https://github.com/geseq) | 7 |
|
||||
| [dackroyd](https://github.com/dackroyd) | 5 |
|
||||
| [cranktakular](https://github.com/cranktakular) | 5 |
|
||||
| [khcchiu](https://github.com/khcchiu) | 5 |
|
||||
|
||||
@@ -34,7 +34,6 @@ const (
|
||||
htmlScrape = "HTML String Check"
|
||||
pathBinance = "https://binance-docs.github.io/apidocs/spot/en/#change-log"
|
||||
pathOkCoin = "https://www.okcoin.com/docs/en/#change-change"
|
||||
pathOkex = "https://www.okex.com/docs/en/#change-change"
|
||||
pathFTX = "https://github.com/ftexchange/ftx"
|
||||
pathBTSE = "https://www.btse.com/apiexplorer/spot/#btse-spot-api"
|
||||
pathBitfinex = "https://docs.bitfinex.com/docs/changelog"
|
||||
@@ -494,7 +493,7 @@ func checkChangeLog(htmlData *HTMLScrapingData) (string, error) {
|
||||
dataStrings, err = htmlScrapeYobit(htmlData)
|
||||
case pathLocalBitcoins:
|
||||
dataStrings, err = htmlScrapeLocalBitcoins(htmlData)
|
||||
case pathOkCoin, pathOkex:
|
||||
case pathOkCoin:
|
||||
dataStrings, err = htmlScrapeOk(htmlData)
|
||||
default:
|
||||
dataStrings, err = htmlScrapeDefault(htmlData)
|
||||
@@ -801,7 +800,7 @@ func htmlScrapeBTCMarkets(htmlData *HTMLScrapingData) ([]string, error) {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// htmlScrapeOk gets the check string for Okex
|
||||
// htmlScrapeOk gets the check string for Okx
|
||||
func htmlScrapeOk(htmlData *HTMLScrapingData) ([]string, error) {
|
||||
var resp []string
|
||||
temp, err := sendHTTPGetRequest(htmlData.Path, nil)
|
||||
|
||||
@@ -403,7 +403,7 @@ func TestHTMLScrapeOk(t *testing.T) {
|
||||
Val: "./#change-change",
|
||||
TokenDataEnd: "./#change-",
|
||||
RegExp: `./#change-\d{8}`,
|
||||
Path: "https://www.okex.com/docs/en/"}
|
||||
Path: "https://www.okx.com/docs/en/"}
|
||||
if _, err := htmlScrapeOk(&data); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -358,22 +358,6 @@
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Okex",
|
||||
"CheckType": "HTML String Check",
|
||||
"Data": {
|
||||
"HTMLData": {
|
||||
"TokenData": "a",
|
||||
"Key": "href",
|
||||
"Val": "./#change-change",
|
||||
"TokenDataEnd": "./#change-",
|
||||
"RegExp": "./#change-\\d{8}",
|
||||
"CheckString": "20200331",
|
||||
"Path": "https://www.okex.com/docs/en/#change-change"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Gemini",
|
||||
"CheckType": "HTML String Check",
|
||||
|
||||
@@ -358,22 +358,6 @@
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Okex",
|
||||
"CheckType": "HTML String Check",
|
||||
"Data": {
|
||||
"HTMLData": {
|
||||
"TokenData": "a",
|
||||
"Key": "href",
|
||||
"Val": "./#change-change",
|
||||
"TokenDataEnd": "./#change-",
|
||||
"RegExp": "./#change-\\d{8}",
|
||||
"CheckString": "20200331",
|
||||
"Path": "https://www.okex.com/docs/en/#change-change"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Gemini",
|
||||
"CheckType": "HTML String Check",
|
||||
|
||||
@@ -287,6 +287,11 @@ func main() {
|
||||
URL: "https://github.com/lozdog245",
|
||||
Contributions: 2,
|
||||
},
|
||||
{
|
||||
Login: "if1live",
|
||||
URL: "https://github.com/if1live",
|
||||
Contributions: 2,
|
||||
},
|
||||
}...)
|
||||
|
||||
if verbose {
|
||||
|
||||
@@ -66,7 +66,7 @@ _b in this context is an `IBotExchange` implemented struct_
|
||||
| Lbank | Yes | No | Yes |
|
||||
| LocalBitcoins | Yes | NA | No |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
| Okx | Yes | Yes | Yes |
|
||||
| Poloniex | Yes | Yes | Yes |
|
||||
| Yobit | Yes | NA | No |
|
||||
| ZB.COM | Yes | Yes | No |
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
{{define "exchanges okex" -}}
|
||||
{{define "exchanges okx" -}}
|
||||
{{template "header" .}}
|
||||
## OKex Exchange
|
||||
## Okx Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST Support
|
||||
+ Websocket Support
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
[Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
|
||||
+ Individual package example below:
|
||||
|
||||
@@ -27,10 +28,10 @@ below:
|
||||
|
||||
main.go
|
||||
```go
|
||||
var o exchange.IBotExchange
|
||||
var ok exchange.IBotExchange
|
||||
|
||||
for i := range bot.Exchanges {
|
||||
if bot.Exchanges[i].GetName() == "OKex" {
|
||||
if bot.Exchanges[i].GetName() == "Okx" {
|
||||
y = bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
@@ -38,22 +39,22 @@ for i := range bot.Exchanges {
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := o.FetchTicker()
|
||||
tick, err := ok.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := o.FetchOrderbook()
|
||||
ob, err := ok.FetchOrderbook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
|
||||
// Private calls - wrapper functions - make sure your APIKEY, APISECRET, and API_CLIENT_ID are
|
||||
// set and AuthenticatedAPISupport is set to true
|
||||
|
||||
// Fetches current account information
|
||||
accountInfo, err := o.GetAccountInfo()
|
||||
accountInfo, err := ok.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
@@ -65,13 +66,26 @@ if err != nil {
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := o.GetSpotTicker()
|
||||
ticker, err := ok.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := o.GetSpotMarketDepth()
|
||||
ob, err := ok.GetOrderBook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches historic trade data within the timeframe provided
|
||||
tradeDatas, err := ok.GetHistoricTrades(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
|
||||
// Returns an estimate of fee based on the type of transaction
|
||||
fee, err := ok.GetFeeByType(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
@@ -79,20 +93,28 @@ if err != nil {
|
||||
// Private calls - make sure your APIKEY and APISECRET are set and
|
||||
// AuthenticatedAPISupport is set to true
|
||||
|
||||
// GetContractPosition returns contract positioning
|
||||
accountInfo, err := o.GetContractPosition(...)
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
orderID, err := ok.SubmitOrder(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := o.PlaceContractOrders(...)
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to market conversion
|
||||
updatedOrder, err := ok.ModifyOrder(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### How to do Websocket public/private calls
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
{{template "contributions"}}
|
||||
{{template "donations" .}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -44,7 +44,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| Lbank | Yes | No | NA |
|
||||
| LocalBitcoins | Yes | NA | NA |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
| Okx | Yes | Yes | NA |
|
||||
| Poloniex | Yes | Yes | NA |
|
||||
| Yobit | Yes | NA | NA |
|
||||
| ZB.COM | Yes | Yes | NA |
|
||||
|
||||
@@ -151,7 +151,7 @@ func main() {
|
||||
}
|
||||
|
||||
func parseCLFlags() {
|
||||
flag.StringVar(&exchangesToUseOverride, "exchanges", "", "a + delimited list of exchange names to run tests against eg -exchanges=bitfinex+okex")
|
||||
flag.StringVar(&exchangesToUseOverride, "exchanges", "", "a + delimited list of exchange names to run tests against eg -exchanges=bitfinex+okx")
|
||||
flag.StringVar(&exchangesToExcludeOverride, "excluded-exchanges", "", "a + delimited list of exchange names to ignore when they're being temperamental eg -exchangesToExlude=lbank")
|
||||
flag.StringVar(&assetTypeOverride, "asset", "", "the asset type to run tests against (where applicable)")
|
||||
flag.StringVar(¤cyPairOverride, "currency", "", "the currency to run tests against (where applicable)")
|
||||
|
||||
@@ -147,11 +147,11 @@
|
||||
"clientID": "ClientID",
|
||||
"otpSecret": "-"
|
||||
},
|
||||
"okex": {
|
||||
"key": "Key",
|
||||
"secret": "Secret",
|
||||
"clientID": "ClientID",
|
||||
"otpSecret": "-"
|
||||
"okx": {
|
||||
"key": "Key",
|
||||
"secret": "Secret",
|
||||
"clientID": "ClientID",
|
||||
"otpSecret": "-"
|
||||
},
|
||||
"poloniex": {
|
||||
"key": "Key",
|
||||
|
||||
@@ -2,9 +2,11 @@ package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -32,6 +34,13 @@ const (
|
||||
defaultTimeout = time.Second * 15
|
||||
)
|
||||
|
||||
// Strings representing the full lower, upper case English character alphabet and base-10 numbers for generating a random string.
|
||||
const (
|
||||
SmallLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||
CapitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
NumberCharacters = "0123456789"
|
||||
)
|
||||
|
||||
var (
|
||||
// emailRX represents email address matching pattern
|
||||
emailRX = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
||||
@@ -470,6 +479,30 @@ func StartEndTimeCheck(start, end time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateRandomString generates a random string provided a length and list of Character types { SmallLetters, CapitalLetters, NumberCharacters}.
|
||||
// if no characters are provided, the function uses a NumberCharacters(string of numeric characters).
|
||||
func GenerateRandomString(length uint, characters ...string) (string, error) {
|
||||
if length == 0 {
|
||||
return "", errors.New("invalid length, length must be non-zero positive integer")
|
||||
}
|
||||
b := make([]byte, length)
|
||||
chars := strings.Replace(strings.Join(characters, ""), " ", "", -1)
|
||||
if chars == "" && len(characters) != 0 {
|
||||
return "", errors.New("invalid characters, character must not be empty")
|
||||
} else if chars == "" {
|
||||
chars = NumberCharacters
|
||||
}
|
||||
for i := range b {
|
||||
nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(chars))))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
n := nBig.Int64()
|
||||
b[i] = chars[n]
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// GetAssertError returns additional information for when an assertion failure
|
||||
// occurs.
|
||||
func GetAssertError(required string, received interface{}) error {
|
||||
|
||||
@@ -721,3 +721,34 @@ func TestMatchesEmailPattern(t *testing.T) {
|
||||
t.Error("MatchesEmailPattern() unexpected test validation result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateRandomString(t *testing.T) {
|
||||
t.Parallel()
|
||||
sample, err := GenerateRandomString(5, NumberCharacters)
|
||||
if err != nil {
|
||||
t.Errorf("GenerateRandomString() %v", err)
|
||||
}
|
||||
value, err := strconv.Atoi(sample)
|
||||
if len(sample) != 5 || err != nil || value < 0 {
|
||||
t.Error("GenerateRandomString() unexpected test validation result")
|
||||
}
|
||||
sample, err = GenerateRandomString(5)
|
||||
if err != nil {
|
||||
t.Errorf("GenerateRandomString() %v", err)
|
||||
}
|
||||
values, err := strconv.ParseInt(sample, 10, 64)
|
||||
if len(sample) != 5 || err != nil || values < 0 {
|
||||
t.Error("GenerateRandomString() unexpected test validation result")
|
||||
}
|
||||
_, err = GenerateRandomString(1, "")
|
||||
if err == nil {
|
||||
t.Errorf("GenerateRandomString() expecting %s, but found %v", "invalid characters, character must not be empty", err)
|
||||
}
|
||||
sample, err = GenerateRandomString(0, "")
|
||||
if err != nil && !strings.Contains(err.Error(), "invalid length") {
|
||||
t.Errorf("GenerateRandomString() %v", err)
|
||||
}
|
||||
if sample != "" {
|
||||
t.Error("GenerateRandomString() unexpected test validation result")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,7 +1289,7 @@ func TestGetPrimaryForexProvider(t *testing.T) {
|
||||
|
||||
func TestUpdateExchangeConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
ok := "OKEX"
|
||||
ok := "Okx"
|
||||
cfg := &Config{
|
||||
Exchanges: []Exchange{
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -139,3 +139,8 @@ func (p Pair) Other(c Code) (Code, error) {
|
||||
}
|
||||
return EMPTYCODE, ErrCurrencyCodeEmpty
|
||||
}
|
||||
|
||||
// IsPopulated returns true if the currency pair have both non-empty values for base and quote.
|
||||
func (p Pair) IsPopulated() bool {
|
||||
return !p.Base.IsEmpty() && !p.Quote.IsEmpty()
|
||||
}
|
||||
|
||||
@@ -927,3 +927,18 @@ func TestOther(t *testing.T) {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPopulated(t *testing.T) {
|
||||
if receiver := NewPair(BTC, USDT).IsPopulated(); !receiver {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
if receiver := NewPair(BTC, NewCode("USD-1245")).IsPopulated(); !receiver {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
if receiver := NewPair(BTC, EMPTYCODE).IsPopulated(); receiver {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
if receiver := NewPair(EMPTYCODE, EMPTYCODE).IsPopulated(); receiver {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ Yes means supported, No means not yet implemented and NA means protocol unsuppor
|
||||
| Lbank | Yes | No | NA |
|
||||
| LocalBitcoins | Yes | NA | NA |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
| Okx | Yes | Yes | NA |
|
||||
| Poloniex | Yes | Yes | NA |
|
||||
| Yobit | Yes | NA | NA |
|
||||
| ZB.COM | Yes | Yes | NA |
|
||||
@@ -249,7 +249,7 @@ var Exchanges = []string{
|
||||
"lbank",
|
||||
"localbitcoins",
|
||||
"okcoin international",
|
||||
"okex",
|
||||
"okx",
|
||||
"poloniex",
|
||||
"yobit",
|
||||
"zb",
|
||||
|
||||
@@ -67,7 +67,7 @@ $ ./gctcli withdrawcryptofunds --exchange=ftx --currency=USDT --address=TJU9piX2
|
||||
| Lbank | No | No | |
|
||||
| LocalBitcoins | No | No | Supports BTC only |
|
||||
| OKCoin International | No | No | Requires API update to version 5 |
|
||||
| OKEX | No | No | Same as above |
|
||||
| Okx | Yes | Yes | |
|
||||
| Poloniex | Yes | Yes | |
|
||||
| Yobit | No | No | |
|
||||
| ZB.COM | Yes | No | Addresses must be created via their website first |
|
||||
|
||||
@@ -88,8 +88,8 @@ A helper tool [cmd/dbseed](../cmd/dbseed/README.md) has been created for assisti
|
||||
| Kraken | Y |
|
||||
| lBank | Y |
|
||||
| Localbitcoins | |
|
||||
| Okcoin | Y |
|
||||
| Okex | Y |
|
||||
| Okcoin | Y |
|
||||
| Okx | Y |
|
||||
| Poloniex | Y |
|
||||
| Yobit | |
|
||||
| ZB | Y |
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/lbank"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/localbitcoins"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okcoin"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okex"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okx"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/poloniex"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/yobit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/zb"
|
||||
@@ -195,8 +195,8 @@ func (m *ExchangeManager) NewExchangeByName(name string) (exchange.IBotExchange,
|
||||
exch = new(localbitcoins.LocalBitcoins)
|
||||
case "okcoin international":
|
||||
exch = new(okcoin.OKCoin)
|
||||
case "okex":
|
||||
exch = new(okex.OKEX)
|
||||
case "okx":
|
||||
exch = new(okx.Okx)
|
||||
case "poloniex":
|
||||
exch = new(poloniex.Poloniex)
|
||||
case "yobit":
|
||||
|
||||
@@ -82,7 +82,7 @@ func TestExchangeManagerRemoveExchange(t *testing.T) {
|
||||
|
||||
func TestNewExchangeByName(t *testing.T) {
|
||||
m := SetupExchangeManager()
|
||||
exchanges := []string{"binanceus", "binance", "bitfinex", "bitflyer", "bithumb", "bitmex", "bitstamp", "bittrex", "btc markets", "btse", "bybit", "coinut", "exmo", "coinbasepro", "ftx", "gateio", "gemini", "hitbtc", "huobi", "itbit", "kraken", "lbank", "localbitcoins", "okcoin international", "okex", "poloniex", "yobit", "zb", "fake"}
|
||||
exchanges := []string{"binanceus", "binance", "bitfinex", "bitflyer", "bithumb", "bitmex", "bitstamp", "bittrex", "btc markets", "btse", "bybit", "coinut", "exmo", "coinbasepro", "ftx", "gateio", "gemini", "hitbtc", "huobi", "itbit", "kraken", "lbank", "localbitcoins", "okcoin international", "okx", "poloniex", "yobit", "zb", "fake"}
|
||||
for i := range exchanges {
|
||||
exch, err := m.NewExchangeByName(exchanges[i])
|
||||
if err != nil && exchanges[i] != "fake" {
|
||||
|
||||
@@ -13,7 +13,7 @@ var (
|
||||
)
|
||||
|
||||
// Item stores the asset type
|
||||
type Item uint16
|
||||
type Item uint32
|
||||
|
||||
// Items stores a list of assets types
|
||||
type Items []Item
|
||||
@@ -34,9 +34,10 @@ const (
|
||||
CoinMarginedFutures
|
||||
USDTMarginedFutures
|
||||
USDCMarginedFutures
|
||||
Option
|
||||
|
||||
futuresFlag = PerpetualContract | PerpetualSwap | Futures | UpsideProfitContract | DownsideProfitContract | CoinMarginedFutures | USDTMarginedFutures | USDCMarginedFutures
|
||||
supportedFlag = Spot | Margin | MarginFunding | Index | Binary | PerpetualContract | PerpetualSwap | Futures | UpsideProfitContract | DownsideProfitContract | CoinMarginedFutures | USDTMarginedFutures | USDCMarginedFutures
|
||||
supportedFlag = Spot | Margin | MarginFunding | Index | Binary | PerpetualContract | PerpetualSwap | Futures | UpsideProfitContract | DownsideProfitContract | CoinMarginedFutures | USDTMarginedFutures | USDCMarginedFutures | Option
|
||||
|
||||
spot = "spot"
|
||||
margin = "margin"
|
||||
@@ -51,10 +52,11 @@ const (
|
||||
coinMarginedFutures = "coinmarginedfutures"
|
||||
usdtMarginedFutures = "usdtmarginedfutures"
|
||||
usdcMarginedFutures = "usdcmarginedfutures"
|
||||
option = "option"
|
||||
)
|
||||
|
||||
var (
|
||||
supportedList = Items{Spot, Margin, MarginFunding, Index, Binary, PerpetualContract, PerpetualSwap, Futures, UpsideProfitContract, DownsideProfitContract, CoinMarginedFutures, USDTMarginedFutures, USDCMarginedFutures}
|
||||
supportedList = Items{Spot, Margin, MarginFunding, Index, Binary, PerpetualContract, PerpetualSwap, Futures, UpsideProfitContract, DownsideProfitContract, CoinMarginedFutures, USDTMarginedFutures, USDCMarginedFutures, Option}
|
||||
)
|
||||
|
||||
// Supported returns a list of supported asset types
|
||||
@@ -91,6 +93,8 @@ func (a Item) String() string {
|
||||
return usdtMarginedFutures
|
||||
case USDCMarginedFutures:
|
||||
return usdcMarginedFutures
|
||||
case Option:
|
||||
return option
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -186,6 +190,8 @@ func New(input string) (Item, error) {
|
||||
return USDTMarginedFutures, nil
|
||||
case usdcMarginedFutures:
|
||||
return USDCMarginedFutures, nil
|
||||
case option:
|
||||
return Option, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("%w '%v', only supports %s",
|
||||
ErrNotSupported,
|
||||
|
||||
@@ -25,12 +25,15 @@ const (
|
||||
EightHour = 8 * OneHour
|
||||
TwelveHour = 12 * OneHour
|
||||
OneDay = 24 * OneHour
|
||||
TwoDay = 2 * OneDay
|
||||
ThreeDay = 3 * OneDay
|
||||
SevenDay = 7 * OneDay
|
||||
FifteenDay = 15 * OneDay
|
||||
OneWeek = 7 * OneDay
|
||||
TwoWeek = 2 * OneWeek
|
||||
OneMonth = 31 * OneDay
|
||||
ThreeMonth = 3 * OneMonth
|
||||
SixMonth = 6 * OneMonth
|
||||
OneYear = 365 * OneDay
|
||||
)
|
||||
|
||||
|
||||
@@ -789,7 +789,7 @@ func TestSendWsMessages(t *testing.T) {
|
||||
response := <-o.Websocket.DataHandler
|
||||
if err, ok = response.(error); ok && err != nil {
|
||||
if !strings.Contains(err.Error(), subscriptions[0].Channel) {
|
||||
t.Error("Expecting OKEX error - 30040 message: Channel badChannel doesn't exist")
|
||||
t.Error("Expecting OKCoin error - 30040 message: Channel badChannel doesn't exist")
|
||||
}
|
||||
}
|
||||
err = o.WsLogin(context.Background())
|
||||
|
||||
@@ -45,7 +45,7 @@ func (o *OKCoin) GetDefaultConfig() (*config.Exchange, error) {
|
||||
return exchCfg, nil
|
||||
}
|
||||
|
||||
// SetDefaults method assignes the default values for OKEX
|
||||
// SetDefaults method assignes the default values for OKCoin
|
||||
func (o *OKCoin) SetDefaults() {
|
||||
o.SetErrorDefaults()
|
||||
o.SetCheckVarDefaults()
|
||||
@@ -169,7 +169,7 @@ func (o *OKCoin) Start(wg *sync.WaitGroup) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run implements the OKEX wrapper
|
||||
// Run implements the OKCoin wrapper
|
||||
func (o *OKCoin) Run() {
|
||||
if o.Verbose {
|
||||
log.Debugf(log.ExchangeSys,
|
||||
|
||||
@@ -1,588 +0,0 @@
|
||||
package okex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
okExRateInterval = time.Second
|
||||
okExRequestRate = 6
|
||||
okExAPIPath = "api/"
|
||||
okExAPIURL = "https://www.okex.com/" + okExAPIPath
|
||||
okExAPIVersion = "/v3/"
|
||||
okExExchangeName = "OKEX"
|
||||
// OkExWebsocketURL WebsocketURL
|
||||
OkExWebsocketURL = "wss://real.okex.com:8443/ws/v3"
|
||||
// API subsections
|
||||
okGroupSpotSubsection = "spot"
|
||||
okGroupFuturesSubsection = "futures"
|
||||
okGroupSwapSubsection = "swap"
|
||||
okGroupETTSubsection = "ett"
|
||||
okGroupMarginSubsection = "margin"
|
||||
// Futures based endpoints
|
||||
okGroupFuturePosition = "position"
|
||||
okGroupFutureLeverage = "leverage"
|
||||
okGroupFutureOrder = "order"
|
||||
okGroupFutureHolds = "holds"
|
||||
okGroupIndices = "index"
|
||||
okGroupRate = "rate"
|
||||
okGroupEsimtatedPrice = "estimated_price"
|
||||
okGroupOpenInterest = "open_interest"
|
||||
// Perpetual swap based endpoints
|
||||
okGroupSettings = "settings"
|
||||
okGroupDepth = "depth"
|
||||
okGroupFundingTime = "funding_time"
|
||||
okGroupHistoricalFundingRate = "historical_funding_rate"
|
||||
okGroupSwapInstruments = "instruments"
|
||||
// ETT endpoints
|
||||
okGroupConstituents = "constituents"
|
||||
okGroupDefinePrice = "define-price"
|
||||
okGroupPerpSwapRates = "instruments/%s/historical_funding_rate?"
|
||||
okGroupPerpTickers = "instruments/ticker"
|
||||
okGroupMarginPairData = "accounts/%s/availability"
|
||||
okGroupMarginPairsData = "accounts/availability"
|
||||
okGroupInstruments = "instruments"
|
||||
)
|
||||
|
||||
// OKEX bases all account, spot and margin methods off okgroup implementation
|
||||
type OKEX struct {
|
||||
okgroup.OKGroup
|
||||
}
|
||||
|
||||
// GetSwapMarkets gets perpetual swap markets
|
||||
func (o *OKEX) GetSwapMarkets(ctx context.Context) ([]okgroup.SwapInstrumentsData, error) {
|
||||
var resp []okgroup.SwapInstrumentsData
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection,
|
||||
okGroupSwapInstruments,
|
||||
nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapInstruments gets perpetual swap instruments data
|
||||
func (o *OKEX) GetSwapInstruments(ctx context.Context) ([]okgroup.PerpSwapInstrumentData, error) {
|
||||
var resp []okgroup.PerpSwapInstrumentData
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection,
|
||||
okGroupInstruments,
|
||||
nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetAllMarginRates gets interest rates for all margin currencies on OKEX
|
||||
func (o *OKEX) GetAllMarginRates(ctx context.Context) ([]okgroup.MarginCurrencyData, error) {
|
||||
var resp []okgroup.MarginCurrencyData
|
||||
var result []map[string]interface{}
|
||||
var tempResp okgroup.MarginCurrencyData
|
||||
tempResp.Data = make(map[string]okgroup.MarginData)
|
||||
err := o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
||||
okGroupMarginSubsection,
|
||||
okGroupMarginPairsData,
|
||||
nil,
|
||||
&result,
|
||||
true)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
for i := range result {
|
||||
for k, v := range result[i] {
|
||||
if strings.Contains(k, "currency:") {
|
||||
var byteData []byte
|
||||
var marginData okgroup.MarginData
|
||||
currencyString := strings.Replace(k, "currency:", "", 1)
|
||||
byteData, err = json.Marshal(v)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
err = json.Unmarshal(byteData, &marginData)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
tempResp.Data[currencyString] = marginData
|
||||
}
|
||||
var strData string
|
||||
var ok bool
|
||||
strData, ok = result[i]["instrument_id"].(string)
|
||||
if !ok {
|
||||
return resp, errors.New("type conversion failed for instrument_id")
|
||||
}
|
||||
tempResp.InstrumentID = strData
|
||||
strData, ok = result[i]["product_id"].(string)
|
||||
if !ok {
|
||||
return resp, errors.New("type conversion failed for product_id")
|
||||
}
|
||||
tempResp.ProductID = strData
|
||||
resp = append(resp, tempResp)
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetMarginRates gets interest rates for margin currencies
|
||||
func (o *OKEX) GetMarginRates(ctx context.Context, instrumentID currency.Pair) (okgroup.MarginCurrencyData, error) {
|
||||
var resp okgroup.MarginCurrencyData
|
||||
resp.Data = make(map[string]okgroup.MarginData)
|
||||
var result []map[string]interface{}
|
||||
err := o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
||||
okGroupMarginSubsection,
|
||||
fmt.Sprintf(okGroupMarginPairData, instrumentID),
|
||||
nil,
|
||||
&result,
|
||||
true)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
for i := range result {
|
||||
for k, v := range result[i] {
|
||||
var byteData []byte
|
||||
var marginData okgroup.MarginData
|
||||
byteData, err = json.Marshal(v)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
if strings.Contains(k, instrumentID.Base.String()) {
|
||||
err = json.Unmarshal(byteData, &marginData)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Data[instrumentID.Base.String()] = marginData
|
||||
} else if strings.Contains(k, instrumentID.Quote.String()) {
|
||||
err = json.Unmarshal(byteData, &marginData)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Data[instrumentID.Quote.String()] = marginData
|
||||
}
|
||||
}
|
||||
var strData string
|
||||
var ok bool
|
||||
strData, ok = result[i]["instrument_id"].(string)
|
||||
if !ok {
|
||||
return resp, errors.New("type conversion failed for instrument_id")
|
||||
}
|
||||
resp.InstrumentID = strData
|
||||
strData, ok = result[i]["product_id"].(string)
|
||||
if !ok {
|
||||
return resp, errors.New("type conversion failed for product_id")
|
||||
}
|
||||
resp.ProductID = strData
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetSpotMarkets gets perpetual swap markets' data
|
||||
func (o *OKEX) GetSpotMarkets(ctx context.Context) ([]okgroup.TradingPairData, error) {
|
||||
var resp []okgroup.TradingPairData
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSpotSubsection, okGroupInstruments, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFundingRate gets funding rate of a given currency
|
||||
func (o *OKEX) GetFundingRate(ctx context.Context, marketName, limit string) ([]okgroup.PerpSwapFundingRates, error) {
|
||||
params := url.Values{}
|
||||
params.Set("limit", limit)
|
||||
var resp []okgroup.PerpSwapFundingRates
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection,
|
||||
fmt.Sprintf(okGroupPerpSwapRates, marketName)+params.Encode(),
|
||||
nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetPerpSwapMarkets gets perpetual swap markets' data
|
||||
func (o *OKEX) GetPerpSwapMarkets(ctx context.Context) ([]okgroup.TickerData, error) {
|
||||
var resp []okgroup.TickerData
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection,
|
||||
okGroupPerpTickers,
|
||||
nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesPostions Get the information of all holding positions in futures trading.
|
||||
// Due to high energy consumption, you are advised to capture data with the "Futures Account of a Currency" API instead.
|
||||
func (o *OKEX) GetFuturesPostions(ctx context.Context) (resp okgroup.GetFuturesPositionsResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, okGroupFuturePosition, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesPostionsForCurrency Get the information of holding positions of a contract.
|
||||
func (o *OKEX) GetFuturesPostionsForCurrency(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesPositionsForCurrencyResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", instrumentID, okGroupFuturePosition)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesAccountOfAllCurrencies Get the futures account info of all token.
|
||||
// Due to high energy consumption, you are advised to capture data with the "Futures Account of a Currency" API instead.
|
||||
func (o *OKEX) GetFuturesAccountOfAllCurrencies(ctx context.Context) (resp okgroup.FuturesAccountForAllCurrenciesResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, okgroup.OKGroupAccounts, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesAccountOfACurrency Get the futures account info of a token.
|
||||
func (o *OKEX) GetFuturesAccountOfACurrency(ctx context.Context, instrumentID string) (resp okgroup.FuturesCurrencyData, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupAccounts, instrumentID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesLeverage Get the leverage of the futures account
|
||||
func (o *OKEX) GetFuturesLeverage(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesLeverageResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, instrumentID, okGroupFutureLeverage)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// SetFuturesLeverage Adjusting the leverage for futures account。
|
||||
// Cross margin request requirements: {"leverage":"10"}
|
||||
// Fixed margin request requirements: {"instrument_id":"BTC-USD-180213","direction":"long","leverage":"10"}
|
||||
func (o *OKEX) SetFuturesLeverage(ctx context.Context, request okgroup.SetFuturesLeverageRequest) (resp okgroup.SetFuturesLeverageResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, request.Currency, okGroupFutureLeverage)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupFuturesSubsection, requestURL, request, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesBillDetails Shows the account’s historical coin in flow and out flow.
|
||||
// All paginated requests return the latest information (newest) as the first page sorted by newest (in chronological time) first.
|
||||
func (o *OKEX) GetFuturesBillDetails(ctx context.Context, request okgroup.GetSpotBillDetailsForCurrencyRequest) (resp []okgroup.GetSpotBillDetailsForCurrencyResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupAccounts, request.Currency, okgroup.OKGroupLedger, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// PlaceFuturesOrder OKEx futures trading only supports limit orders.
|
||||
// You can place an order only if you have enough funds. Once your order is placed, the amount will be put on hold in the order lifecycle.
|
||||
// The assets and amount on hold depends on the order's specific type and parameters.
|
||||
func (o *OKEX) PlaceFuturesOrder(ctx context.Context, request okgroup.PlaceFuturesOrderRequest) (resp okgroup.PlaceFuturesOrderResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupFuturesSubsection, okGroupFutureOrder, request, &resp, true)
|
||||
}
|
||||
|
||||
// PlaceFuturesOrderBatch Batch contract placing order operation.
|
||||
func (o *OKEX) PlaceFuturesOrderBatch(ctx context.Context, request okgroup.PlaceFuturesOrderBatchRequest) (resp okgroup.PlaceFuturesOrderBatchResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupFuturesSubsection, okgroup.OKGroupOrders, request, &resp, true)
|
||||
}
|
||||
|
||||
// CancelFuturesOrder Cancelling an unfilled order.
|
||||
func (o *OKEX) CancelFuturesOrder(ctx context.Context, request okgroup.CancelFuturesOrderRequest) (resp okgroup.CancelFuturesOrderResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupCancelOrder, request.InstrumentID, request.OrderID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupFuturesSubsection, requestURL, request, &resp, true)
|
||||
}
|
||||
|
||||
// CancelFuturesOrderBatch With best effort, cancel all open orders.
|
||||
func (o *OKEX) CancelFuturesOrderBatch(ctx context.Context, request okgroup.CancelMultipleSpotOrdersRequest) (resp okgroup.CancelMultipleSpotOrdersResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupCancelBatchOrders, request.InstrumentID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupFuturesSubsection, requestURL, request, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesOrderList List your orders. Cursor pagination is used.
|
||||
// All paginated requests return the latest information (newest) as the first page sorted by newest (in chronological time) first.
|
||||
func (o *OKEX) GetFuturesOrderList(ctx context.Context, request okgroup.GetFuturesOrdersListRequest) (resp okgroup.GetFuturesOrderListResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v%v", okgroup.OKGroupOrders, request.InstrumentID, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesOrderDetails Get order details by order ID.
|
||||
func (o *OKEX) GetFuturesOrderDetails(ctx context.Context, request okgroup.GetFuturesOrderDetailsRequest) (resp okgroup.GetFuturesOrderDetailsResponseData, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupOrders, request.InstrumentID, request.OrderID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesTransactionDetails Get details of the recent filled orders. Cursor pagination is used.
|
||||
// All paginated requests return the latest information (newest) as the first page sorted by newest (in chronological time) first.
|
||||
func (o *OKEX) GetFuturesTransactionDetails(ctx context.Context, request okgroup.GetFuturesTransactionDetailsRequest) (resp []okgroup.GetFuturesTransactionDetailsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v%v", okgroup.OKGroupGetSpotTransactionDetails, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesContractInformation Get market data. This endpoint provides the snapshots of market data and can be used without verifications.
|
||||
func (o *OKEX) GetFuturesContractInformation(ctx context.Context) (resp []okgroup.GetFuturesContractInformationResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, okgroup.OKGroupInstruments, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetAllFuturesTokenInfo Get the last traded price, best bid/ask price, 24 hour trading volume and more info of all contracts.
|
||||
func (o *OKEX) GetAllFuturesTokenInfo(ctx context.Context) (resp []okgroup.GetFuturesTokenInfoResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupInstruments, okgroup.OKGroupTicker)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesTokenInfoForCurrency Get the last traded price, best bid/ask price, 24 hour trading volume and more info of a contract.
|
||||
func (o *OKEX) GetFuturesTokenInfoForCurrency(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesTokenInfoResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okgroup.OKGroupTicker)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesFilledOrder Get the recent 300 transactions of all contracts. Pagination is not supported here.
|
||||
// The whole book will be returned for one request. Websocket is recommended here.
|
||||
func (o *OKEX) GetFuturesFilledOrder(ctx context.Context, request okgroup.GetFuturesFilledOrderRequest) (resp []okgroup.GetFuturesFilledOrdersResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okgroup.OKGroupTrades, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesHoldAmount Get the number of futures with hold.
|
||||
func (o *OKEX) GetFuturesHoldAmount(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesHoldAmountResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, instrumentID, okGroupFutureHolds)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetFuturesIndices Get Indices of tokens. This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesIndices(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesIndicesResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupIndices)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesExchangeRates Get the fiat exchange rates. This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesExchangeRates(ctx context.Context) (resp okgroup.GetFuturesExchangeRatesResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, okGroupRate, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesEstimatedDeliveryPrice the estimated delivery price. It is available 3 hours before delivery.
|
||||
// This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesEstimatedDeliveryPrice(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesEstimatedDeliveryPriceResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupEsimtatedPrice)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesOpenInterests Get the open interest of a contract. This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesOpenInterests(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesOpenInterestsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupOpenInterest)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesCurrentPriceLimit The maximum buying price and the minimum selling price of the contract.
|
||||
// This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesCurrentPriceLimit(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesCurrentPriceLimitResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okgroup.OKGroupPriceLimit)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesCurrentMarkPrice The maximum buying price and the minimum selling price of the contract.
|
||||
// This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesCurrentMarkPrice(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesCurrentMarkPriceResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okgroup.OKGroupMarkPrice)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesForceLiquidatedOrders Get force liquidated orders. This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesForceLiquidatedOrders(ctx context.Context, request okgroup.GetFuturesForceLiquidatedOrdersRequest) (resp []okgroup.GetFuturesForceLiquidatedOrdersResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okgroup.OKGroupLiquidation, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetFuturesTagPrice Get the tag price. This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetFuturesTagPrice(ctx context.Context, instrumentID string) (resp okgroup.GetFuturesTagPriceResponse, _ error) {
|
||||
// OKEX documentation is missing for this endpoint. Guessing "tag_price" for the URL results in 404
|
||||
return okgroup.GetFuturesTagPriceResponse{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetSwapPostions Get the information of all holding positions in swap trading.
|
||||
// Due to high energy consumption, you are advised to capture data with the "Swap Account of a Currency" API instead.
|
||||
func (o *OKEX) GetSwapPostions(ctx context.Context) (resp []okgroup.GetSwapPostionsResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, okGroupFuturePosition, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapPostionsForContract Get the information of holding positions of a contract.
|
||||
func (o *OKEX) GetSwapPostionsForContract(ctx context.Context, instrumentID string) (resp okgroup.GetSwapPostionsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", instrumentID, okGroupFuturePosition)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapAccountOfAllCurrency Get the perpetual swap account info of a token.
|
||||
// Margin ratio set as 10,000 when users have no open position.
|
||||
func (o *OKEX) GetSwapAccountOfAllCurrency(ctx context.Context) (resp okgroup.GetSwapAccountOfAllCurrencyResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, okgroup.OKGroupAccounts, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapAccountSettingsOfAContract Get leverage level and margin mode of a contract.
|
||||
func (o *OKEX) GetSwapAccountSettingsOfAContract(ctx context.Context, instrumentID string) (resp okgroup.GetSwapAccountSettingsOfAContractResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, instrumentID, okGroupSettings)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// SetSwapLeverageLevelOfAContract Setting the leverage level of a contract
|
||||
// TODO this returns invalid parameters, but matches spec. Unsure how to fix
|
||||
func (o *OKEX) SetSwapLeverageLevelOfAContract(ctx context.Context, request okgroup.SetSwapLeverageLevelOfAContractRequest) (resp okgroup.SetSwapLeverageLevelOfAContractResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, request.InstrumentID, okGroupFutureLeverage)
|
||||
request.InstrumentID = ""
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupSwapSubsection, requestURL, request, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapBillDetails Shows the account’s historical coin in flow and out flow.
|
||||
// All paginated requests return the latest information (newest) as the first page sorted by newest (in chronological time) first.
|
||||
func (o *OKEX) GetSwapBillDetails(ctx context.Context, request okgroup.GetSpotBillDetailsForCurrencyRequest) (resp []okgroup.GetSwapBillDetailsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupAccounts, request.Currency, okgroup.OKGroupLedger, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// PlaceSwapOrder OKEx perpetual swap trading only supports limit orders,USD as quote currency for orders.
|
||||
// You can place an order only if you have enough funds. Once your order is placed, the amount will be put on hold in the order lifecycle.
|
||||
// The assets and amount on hold depends on the order's specific type and parameters.
|
||||
func (o *OKEX) PlaceSwapOrder(ctx context.Context, request okgroup.PlaceSwapOrderRequest) (resp okgroup.PlaceSwapOrderResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupSwapSubsection, okGroupFutureOrder, request, &resp, true)
|
||||
}
|
||||
|
||||
// PlaceMultipleSwapOrders Batch contract placing order operation.
|
||||
func (o *OKEX) PlaceMultipleSwapOrders(ctx context.Context, request okgroup.PlaceMultipleSwapOrdersRequest) (resp okgroup.PlaceMultipleSwapOrdersResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupSwapSubsection, okgroup.OKGroupOrders, request, &resp, true)
|
||||
}
|
||||
|
||||
// CancelSwapOrder Cancelling an unfilled order
|
||||
func (o *OKEX) CancelSwapOrder(ctx context.Context, request okgroup.CancelSwapOrderRequest) (resp okgroup.CancelSwapOrderResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupCancelOrder, request.InstrumentID, request.OrderID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// CancelMultipleSwapOrders With best effort, cancel all open orders.
|
||||
func (o *OKEX) CancelMultipleSwapOrders(ctx context.Context, request okgroup.CancelMultipleSwapOrdersRequest) (resp okgroup.CancelMultipleSwapOrdersResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupCancelBatchOrders, request.InstrumentID)
|
||||
request.InstrumentID = ""
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupSwapSubsection, requestURL, request, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapOrderList List your orders. Cursor pagination is used.
|
||||
// All paginated requests return the latest information (newest) as the first page sorted by newest (in chronological time) first.
|
||||
func (o *OKEX) GetSwapOrderList(ctx context.Context, request okgroup.GetSwapOrderListRequest) (resp okgroup.GetSwapOrderListResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v%v", okgroup.OKGroupOrders, request.InstrumentID, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapOrderDetails Get order details by order ID.
|
||||
func (o *OKEX) GetSwapOrderDetails(ctx context.Context, request okgroup.GetSwapOrderDetailsRequest) (resp okgroup.GetSwapOrderListResponseData, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupOrders, request.InstrumentID, request.OrderID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapTransactionDetails Get details of the recent filled orders
|
||||
func (o *OKEX) GetSwapTransactionDetails(ctx context.Context, request okgroup.GetSwapTransactionDetailsRequest) (resp []okgroup.GetSwapTransactionDetailsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v%v", okgroup.OKGroupGetSpotTransactionDetails, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapContractInformation Get market data.
|
||||
func (o *OKEX) GetSwapContractInformation(ctx context.Context) (resp []okgroup.GetSwapContractInformationResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, okgroup.OKGroupInstruments, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetAllSwapTokensInformation Get the last traded price, best bid/ask price, 24 hour trading volume and more info of all contracts.
|
||||
func (o *OKEX) GetAllSwapTokensInformation(ctx context.Context) (resp []okgroup.GetAllSwapTokensInformationResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupInstruments, okgroup.OKGroupTicker)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapTokensInformationForCurrency Get the last traded price, best bid/ask price, 24 hour trading volume and more info of all contracts.
|
||||
func (o *OKEX) GetSwapTokensInformationForCurrency(ctx context.Context, instrumentID string) (resp okgroup.GetAllSwapTokensInformationResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okgroup.OKGroupTicker)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapFilledOrdersData Get details of the recent filled orders
|
||||
func (o *OKEX) GetSwapFilledOrdersData(ctx context.Context, request *okgroup.GetSwapFilledOrdersDataRequest) (resp []okgroup.GetSwapFilledOrdersDataResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okgroup.OKGroupTrades, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapIndices Get Indices of tokens.
|
||||
func (o *OKEX) GetSwapIndices(ctx context.Context, instrumentID string) (resp okgroup.GetSwapIndecesResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupIndices)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapExchangeRates Get the fiat exchange rates.
|
||||
func (o *OKEX) GetSwapExchangeRates(ctx context.Context) (resp okgroup.GetSwapExchangeRatesResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, okGroupRate, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapOpenInterest Get the open interest of a contract.
|
||||
func (o *OKEX) GetSwapOpenInterest(ctx context.Context, instrumentID string) (resp okgroup.GetSwapExchangeRatesResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupOpenInterest)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapCurrentPriceLimits Get the open interest of a contract.
|
||||
func (o *OKEX) GetSwapCurrentPriceLimits(ctx context.Context, instrumentID string) (resp okgroup.GetSwapCurrentPriceLimitsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okgroup.OKGroupPriceLimit)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapForceLiquidatedOrders Get force liquidated orders.
|
||||
func (o *OKEX) GetSwapForceLiquidatedOrders(ctx context.Context, request okgroup.GetSwapForceLiquidatedOrdersRequest) (resp []okgroup.GetSwapForceLiquidatedOrdersResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okgroup.OKGroupLiquidation, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapOnHoldAmountForOpenOrders Get On Hold Amount for Open Orders.
|
||||
func (o *OKEX) GetSwapOnHoldAmountForOpenOrders(ctx context.Context, instrumentID string) (resp okgroup.GetSwapOnHoldAmountForOpenOrdersResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, instrumentID, okGroupFutureHolds)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetSwapNextSettlementTime Get the time of next settlement.
|
||||
func (o *OKEX) GetSwapNextSettlementTime(ctx context.Context, instrumentID string) (resp okgroup.GetSwapNextSettlementTimeResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupFundingTime)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapMarkPrice Get the time of next settlement.
|
||||
func (o *OKEX) GetSwapMarkPrice(ctx context.Context, instrumentID string) (resp okgroup.GetSwapMarkPriceResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okgroup.OKGroupMarkPrice)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetSwapFundingRateHistory Get Funding Rate History.
|
||||
func (o *OKEX) GetSwapFundingRateHistory(ctx context.Context, request okgroup.GetSwapFundingRateHistoryRequest) (resp []okgroup.GetSwapFundingRateHistoryResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okGroupHistoricalFundingRate, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetETT List the assets in ETT account. Get information such as balance, amount on hold/ available.
|
||||
func (o *OKEX) GetETT(ctx context.Context) (resp []okgroup.GetETTResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, okgroup.OKGroupAccounts, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetETTAccountInformationForCurrency Getting the balance, amount available/on hold of a token in ETT account.
|
||||
func (o *OKEX) GetETTAccountInformationForCurrency(ctx context.Context, currency string) (resp okgroup.GetETTResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupAccounts, currency)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetETTBillsDetails Bills details. All paginated requests return the latest information (newest)
|
||||
// as the first page sorted by newest (in chronological time) first
|
||||
func (o *OKEX) GetETTBillsDetails(ctx context.Context, currency string) (resp []okgroup.GetETTBillsDetailsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, currency, okgroup.OKGroupLedger)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// PlaceETTOrder You can place subscription or redemption orders under ETT trading.
|
||||
// You can place an order only if you have enough funds. Once your order is placed,
|
||||
// the amount will be put on hold in the order lifecycle.
|
||||
// The assets and amount on hold depends on the order's specific type and parameters.
|
||||
func (o *OKEX) PlaceETTOrder(ctx context.Context, request *okgroup.PlaceETTOrderRequest) (resp okgroup.PlaceETTOrderResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupETTSubsection, okgroup.OKGroupOrders, nil, &resp, true)
|
||||
}
|
||||
|
||||
// CancelETTOrder Cancel an unfilled order.
|
||||
func (o *OKEX) CancelETTOrder(ctx context.Context, orderID string) (resp okgroup.PlaceETTOrderResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupOrders, orderID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete, okGroupETTSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetETTOrderList List your orders. Cursor pagination is used. All paginated requests return the latest information
|
||||
// (newest) as the first page sorted by newest (in chronological time) first.
|
||||
func (o *OKEX) GetETTOrderList(ctx context.Context, request okgroup.GetETTOrderListRequest) (resp []okgroup.GetETTOrderListResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v%v", okgroup.OKGroupOrders, okgroup.FormatParameters(request))
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetETTOrderDetails Get order details by order ID.
|
||||
func (o *OKEX) GetETTOrderDetails(ctx context.Context, orderID string) (resp okgroup.GetETTOrderListResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupOrders, orderID)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// GetETTConstituents Get ETT Constituents.This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetETTConstituents(ctx context.Context, ett string) (resp okgroup.GetETTConstituentsResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okGroupConstituents, ett)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
|
||||
// GetETTSettlementPriceHistory Get ETT settlement price history. This is a public endpoint, no identity verification is needed.
|
||||
func (o *OKEX) GetETTSettlementPriceHistory(ctx context.Context, ett string) (resp []okgroup.GetETTSettlementPriceHistoryResponse, _ error) {
|
||||
requestURL := fmt.Sprintf("%v/%v", okGroupDefinePrice, ett)
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupETTSubsection, requestURL, nil, &resp, false)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,676 +0,0 @@
|
||||
package okex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okgroup"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
)
|
||||
|
||||
// GetDefaultConfig returns a default exchange config
|
||||
func (o *OKEX) GetDefaultConfig() (*config.Exchange, error) {
|
||||
o.SetDefaults()
|
||||
exchCfg := new(config.Exchange)
|
||||
exchCfg.Name = o.Name
|
||||
exchCfg.HTTPTimeout = exchange.DefaultHTTPTimeout
|
||||
exchCfg.BaseCurrencies = o.BaseCurrencies
|
||||
|
||||
err := o.SetupDefaults(exchCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.Features.Supports.RESTCapabilities.AutoPairUpdates {
|
||||
err = o.UpdateTradablePairs(context.TODO(), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return exchCfg, nil
|
||||
}
|
||||
|
||||
// SetDefaults method assignes the default values for OKEX
|
||||
func (o *OKEX) SetDefaults() {
|
||||
o.SetErrorDefaults()
|
||||
o.SetCheckVarDefaults()
|
||||
o.Name = okExExchangeName
|
||||
o.Enabled = true
|
||||
o.Verbose = true
|
||||
o.API.CredentialsValidator.RequiresKey = true
|
||||
o.API.CredentialsValidator.RequiresSecret = true
|
||||
o.API.CredentialsValidator.RequiresClientID = true
|
||||
|
||||
// Same format used for perpetual swap and futures
|
||||
futures := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.UnderscoreDelimiter,
|
||||
},
|
||||
}
|
||||
|
||||
swap := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.UnderscoreDelimiter,
|
||||
},
|
||||
}
|
||||
|
||||
err := o.StoreAssetPairFormat(asset.PerpetualSwap, swap)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
err = o.StoreAssetPairFormat(asset.Futures, futures)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
index := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
},
|
||||
}
|
||||
|
||||
spot := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.DashDelimiter,
|
||||
},
|
||||
}
|
||||
|
||||
err = o.StoreAssetPairFormat(asset.Spot, spot)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
err = o.StoreAssetPairFormat(asset.Index, index)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
o.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerBatching: true,
|
||||
TickerFetching: true,
|
||||
KlineFetching: true,
|
||||
TradeFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
AccountInfo: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrder: true,
|
||||
CancelOrders: true,
|
||||
SubmitOrder: true,
|
||||
SubmitOrders: true,
|
||||
DepositHistory: true,
|
||||
WithdrawalHistory: true,
|
||||
UserTradeHistory: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
TradeFee: true,
|
||||
CryptoWithdrawalFee: true,
|
||||
},
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
TradeFetching: true,
|
||||
KlineFetching: true,
|
||||
OrderbookFetching: true,
|
||||
Subscribe: true,
|
||||
Unsubscribe: true,
|
||||
AuthenticatedEndpoints: true,
|
||||
MessageCorrelation: true,
|
||||
GetOrders: true,
|
||||
GetOrder: true,
|
||||
AccountBalance: true,
|
||||
},
|
||||
WithdrawPermissions: exchange.AutoWithdrawCrypto |
|
||||
exchange.NoFiatWithdrawals,
|
||||
Kline: kline.ExchangeCapabilitiesSupported{
|
||||
DateRanges: true,
|
||||
Intervals: true,
|
||||
},
|
||||
},
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: map[string]bool{
|
||||
kline.OneMin.Word(): true,
|
||||
kline.ThreeMin.Word(): true,
|
||||
kline.FiveMin.Word(): true,
|
||||
kline.FifteenMin.Word(): true,
|
||||
kline.ThirtyMin.Word(): true,
|
||||
kline.OneHour.Word(): true,
|
||||
kline.TwoHour.Word(): true,
|
||||
kline.FourHour.Word(): true,
|
||||
kline.SixHour.Word(): true,
|
||||
kline.TwelveHour.Word(): true,
|
||||
kline.OneDay.Word(): true,
|
||||
kline.ThreeDay.Word(): true,
|
||||
kline.OneWeek.Word(): true,
|
||||
},
|
||||
ResultLimit: 1440,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
o.Requester, err = request.New(o.Name,
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout),
|
||||
// TODO: Specify each individual endpoint rate limits as per docs
|
||||
request.WithLimiter(request.NewBasicRateLimit(okExRateInterval, okExRequestRate)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
o.API.Endpoints = o.NewEndpoints()
|
||||
err = o.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
exchange.RestSpot: okExAPIURL,
|
||||
exchange.WebsocketSpot: OkExWebsocketURL,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
o.Websocket = stream.New()
|
||||
o.APIVersion = okExAPIVersion
|
||||
o.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
o.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
o.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
|
||||
}
|
||||
|
||||
// Start starts the OKGroup go routine
|
||||
func (o *OKEX) Start(wg *sync.WaitGroup) error {
|
||||
if wg == nil {
|
||||
return fmt.Errorf("%T %w", wg, common.ErrNilPointer)
|
||||
}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
o.Run()
|
||||
wg.Done()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run implements the OKEX wrapper
|
||||
func (o *OKEX) Run() {
|
||||
if o.Verbose {
|
||||
wsEndpoint, err := o.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
if err != nil {
|
||||
log.Error(log.ExchangeSys, err)
|
||||
}
|
||||
log.Debugf(log.ExchangeSys,
|
||||
"%s Websocket: %s. (url: %s).\n",
|
||||
o.Name,
|
||||
common.IsEnabled(o.Websocket.IsEnabled()),
|
||||
wsEndpoint)
|
||||
}
|
||||
|
||||
format, err := o.GetPairFormat(asset.Spot, false)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to update tradable pairs. Err: %s",
|
||||
o.Name,
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
forceUpdate := false
|
||||
if !o.BypassConfigFormatUpgrades {
|
||||
var enabled, avail currency.Pairs
|
||||
enabled, err = o.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to update tradable pairs. Err: %s",
|
||||
o.Name,
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
avail, err = o.GetAvailablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to update tradable pairs. Err: %s",
|
||||
o.Name,
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
|
||||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
|
||||
forceUpdate = true
|
||||
var p currency.Pairs
|
||||
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
|
||||
format.Delimiter +
|
||||
currency.USDT.String()})
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to update currencies.\n",
|
||||
o.Name)
|
||||
} else {
|
||||
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, o.Name, asset.Spot, p)
|
||||
|
||||
err = o.UpdatePairs(p, asset.Spot, true, forceUpdate)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to update currencies.\n",
|
||||
o.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !o.GetEnabledFeatures().AutoPairUpdates && !forceUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
err = o.UpdateTradablePairs(context.TODO(), forceUpdate)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to update tradable pairs. Err: %s",
|
||||
o.Name,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (o *OKEX) FetchTradablePairs(ctx context.Context, i asset.Item) ([]string, error) {
|
||||
var pairs []string
|
||||
|
||||
format, err := o.GetPairFormat(i, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch i {
|
||||
case asset.Spot:
|
||||
prods, err := o.GetSpotTokenPairDetails(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for x := range prods {
|
||||
pairs = append(pairs,
|
||||
currency.NewPairWithDelimiter(prods[x].BaseCurrency,
|
||||
prods[x].QuoteCurrency,
|
||||
format.Delimiter).String())
|
||||
}
|
||||
return pairs, nil
|
||||
case asset.Futures:
|
||||
prods, err := o.GetFuturesContractInformation(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for x := range prods {
|
||||
p := strings.Split(prods[x].InstrumentID, currency.DashDelimiter)
|
||||
pairs = append(pairs, p[0]+currency.DashDelimiter+p[1]+format.Delimiter+p[2])
|
||||
}
|
||||
return pairs, nil
|
||||
|
||||
case asset.PerpetualSwap:
|
||||
prods, err := o.GetSwapContractInformation(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for x := range prods {
|
||||
pairs = append(pairs,
|
||||
prods[x].UnderlyingIndex+
|
||||
currency.DashDelimiter+
|
||||
prods[x].QuoteCurrency+
|
||||
format.Delimiter+
|
||||
"SWAP")
|
||||
}
|
||||
return pairs, nil
|
||||
case asset.Index:
|
||||
// This is updated in futures index
|
||||
return nil, errors.New("index updated in futures")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%s invalid asset type", o.Name)
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func (o *OKEX) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error {
|
||||
assets := o.CurrencyPairs.GetAssetTypes(false)
|
||||
for x := range assets {
|
||||
if assets[x] == asset.Index {
|
||||
// Update from futures
|
||||
continue
|
||||
}
|
||||
|
||||
pairs, err := o.FetchTradablePairs(ctx, assets[x])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if assets[x] == asset.Futures {
|
||||
var indexPairs []string
|
||||
var futuresContracts []string
|
||||
for i := range pairs {
|
||||
item := strings.Split(pairs[i], currency.UnderscoreDelimiter)[0]
|
||||
futuresContracts = append(futuresContracts, pairs[i])
|
||||
if common.StringDataContains(indexPairs, item) {
|
||||
continue
|
||||
}
|
||||
indexPairs = append(indexPairs, item)
|
||||
}
|
||||
var indexPair currency.Pairs
|
||||
indexPair, err = currency.NewPairsFromStrings(indexPairs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = o.UpdatePairs(indexPair, asset.Index, false, forceUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var futurePairs currency.Pairs
|
||||
for i := range futuresContracts {
|
||||
var c currency.Pair
|
||||
c, err = currency.NewPairDelimiter(futuresContracts[i], currency.UnderscoreDelimiter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
futurePairs = append(futurePairs, c)
|
||||
}
|
||||
|
||||
err = o.UpdatePairs(futurePairs, asset.Futures, false, forceUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
p, err := currency.NewPairsFromStrings(pairs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = o.UpdatePairs(p, assets[x], false, forceUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTickers updates the ticker for all currency pairs of a given asset type
|
||||
func (o *OKEX) UpdateTickers(ctx context.Context, a asset.Item) error {
|
||||
switch a {
|
||||
case asset.Spot:
|
||||
resp, err := o.GetSpotAllTokenPairsInformation(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enabled, err := o.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for j := range resp {
|
||||
if !enabled.Contains(resp[j].InstrumentID, true) {
|
||||
continue
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: resp[j].Last,
|
||||
High: resp[j].High24h,
|
||||
Low: resp[j].Low24h,
|
||||
Bid: resp[j].BestBid,
|
||||
Ask: resp[j].BestAsk,
|
||||
Volume: resp[j].BaseVolume24h,
|
||||
QuoteVolume: resp[j].QuoteVolume24h,
|
||||
Open: resp[j].Open24h,
|
||||
Pair: resp[j].InstrumentID,
|
||||
LastUpdated: resp[j].Timestamp,
|
||||
ExchangeName: o.Name,
|
||||
AssetType: a})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
case asset.PerpetualSwap:
|
||||
resp, err := o.GetAllSwapTokensInformation(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enabled, err := o.GetEnabledPairs(asset.PerpetualSwap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for j := range resp {
|
||||
p := strings.Split(resp[j].InstrumentID, currency.DashDelimiter)
|
||||
nC := currency.NewPairWithDelimiter(p[0]+currency.DashDelimiter+p[1],
|
||||
p[2],
|
||||
currency.UnderscoreDelimiter)
|
||||
if !enabled.Contains(nC, true) {
|
||||
continue
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: resp[j].Last,
|
||||
High: resp[j].High24H,
|
||||
Low: resp[j].Low24H,
|
||||
Bid: resp[j].BestBid,
|
||||
Ask: resp[j].BestAsk,
|
||||
Volume: resp[j].Volume24H,
|
||||
Pair: nC,
|
||||
LastUpdated: resp[j].Timestamp,
|
||||
ExchangeName: o.Name,
|
||||
AssetType: a})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
case asset.Futures:
|
||||
resp, err := o.GetAllFuturesTokenInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enabled, err := o.GetEnabledPairs(asset.Futures)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for j := range resp {
|
||||
p := strings.Split(resp[j].InstrumentID, currency.DashDelimiter)
|
||||
nC := currency.NewPairWithDelimiter(p[0]+currency.DashDelimiter+p[1],
|
||||
p[2],
|
||||
currency.UnderscoreDelimiter)
|
||||
if !enabled.Contains(nC, true) {
|
||||
continue
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: resp[j].Last,
|
||||
High: resp[j].High24h,
|
||||
Low: resp[j].Low24h,
|
||||
Bid: resp[j].BestBid,
|
||||
Ask: resp[j].BestAsk,
|
||||
Volume: resp[j].Volume24h,
|
||||
Pair: nC,
|
||||
LastUpdated: resp[j].Timestamp,
|
||||
ExchangeName: o.Name,
|
||||
AssetType: a})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (o *OKEX) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
|
||||
if err := o.UpdateTickers(ctx, a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ticker.GetTicker(o.Name, p, a)
|
||||
}
|
||||
|
||||
// FetchTicker returns the ticker for a currency pair
|
||||
func (o *OKEX) FetchTicker(ctx context.Context, p currency.Pair, assetType asset.Item) (tickerData *ticker.Price, err error) {
|
||||
if assetType == asset.Index {
|
||||
return tickerData, errors.New("ticker fetching not supported for index")
|
||||
}
|
||||
fPair, err := o.FormatExchangeCurrency(p, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tickerData, err = ticker.GetTicker(o.Name, fPair, assetType)
|
||||
if err != nil {
|
||||
return o.UpdateTicker(ctx, fPair, assetType)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetRecentTrades returns recent trade data
|
||||
func (o *OKEX) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
|
||||
var err error
|
||||
p, err = o.FormatExchangeCurrency(p, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp []trade.Data
|
||||
var side order.Side
|
||||
switch assetType {
|
||||
case asset.Spot:
|
||||
var tradeData []okgroup.GetSpotFilledOrdersInformationResponse
|
||||
tradeData, err = o.GetSpotFilledOrdersInformation(ctx,
|
||||
okgroup.GetSpotFilledOrdersInformationRequest{
|
||||
InstrumentID: p.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range tradeData {
|
||||
side, err = order.StringToOrderSide(tradeData[i].Side)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, trade.Data{
|
||||
Exchange: o.Name,
|
||||
TID: tradeData[i].TradeID,
|
||||
CurrencyPair: p,
|
||||
Side: side,
|
||||
AssetType: assetType,
|
||||
Price: tradeData[i].Price,
|
||||
Amount: tradeData[i].Size,
|
||||
Timestamp: tradeData[i].Timestamp,
|
||||
})
|
||||
}
|
||||
case asset.Futures:
|
||||
var tradeData []okgroup.GetFuturesFilledOrdersResponse
|
||||
tradeData, err = o.GetFuturesFilledOrder(ctx,
|
||||
okgroup.GetFuturesFilledOrderRequest{
|
||||
InstrumentID: p.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range tradeData {
|
||||
side, err = order.StringToOrderSide(tradeData[i].Side)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, trade.Data{
|
||||
Exchange: o.Name,
|
||||
TID: tradeData[i].TradeID,
|
||||
CurrencyPair: p,
|
||||
Side: side,
|
||||
AssetType: assetType,
|
||||
Price: tradeData[i].Price,
|
||||
Amount: tradeData[i].Qty,
|
||||
Timestamp: tradeData[i].Timestamp,
|
||||
})
|
||||
}
|
||||
case asset.PerpetualSwap:
|
||||
var tradeData []okgroup.GetSwapFilledOrdersDataResponse
|
||||
tradeData, err = o.GetSwapFilledOrdersData(ctx,
|
||||
&okgroup.GetSwapFilledOrdersDataRequest{
|
||||
InstrumentID: p.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range tradeData {
|
||||
side, err = order.StringToOrderSide(tradeData[i].Side)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, trade.Data{
|
||||
Exchange: o.Name,
|
||||
TID: tradeData[i].TradeID,
|
||||
CurrencyPair: p,
|
||||
Side: side,
|
||||
AssetType: assetType,
|
||||
Price: tradeData[i].Price,
|
||||
Amount: tradeData[i].Size,
|
||||
Timestamp: tradeData[i].Timestamp,
|
||||
})
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("%s asset type %v unsupported", o.Name, assetType)
|
||||
}
|
||||
|
||||
err = o.AddTradesToBuffer(resp...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Sort(trade.ByDate(resp))
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// CancelBatchOrders cancels an orders by their corresponding ID numbers
|
||||
func (o *OKEX) CancelBatchOrders(_ context.Context, _ []order.Cancel) (order.CancelBatchResponse, error) {
|
||||
return order.CancelBatchResponse{}, common.ErrNotYetImplemented
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
# GoCryptoTrader package Okex
|
||||
# GoCryptoTrader package Okgroup
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/okex)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/okgroup)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This okex package is part of the GoCryptoTrader codebase.
|
||||
This OKCoin package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
@@ -18,7 +18,7 @@ You can track ideas, planned features and what's in progress on this Trello boar
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
|
||||
|
||||
## OKex Exchange
|
||||
## OKCoin Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
@@ -48,8 +48,8 @@ main.go
|
||||
var o exchange.IBotExchange
|
||||
|
||||
for i := range Bot.Exchanges {
|
||||
if Bot.Exchanges[i].GetName() == "OKex" {
|
||||
y = Bot.Exchanges[i]
|
||||
if Bot.Exchanges[i].GetName() == "OKCoin" {
|
||||
o = Bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ const (
|
||||
okGroupGetRepayment = "repayment"
|
||||
)
|
||||
|
||||
// OKGroup is the overaching type across the all of OKEx's exchange methods
|
||||
// OKGroup is the overaching type across the all of OKCoin's exchange methods
|
||||
type OKGroup struct {
|
||||
exchange.Base
|
||||
ExchangeName string
|
||||
// Spot and contract market error codes as per https://www.okex.com/rest_request.html
|
||||
// Spot and contract market error codes
|
||||
ErrorCodes map[string]error
|
||||
// Stores for corresponding variable checks
|
||||
ContractTypes []string
|
||||
@@ -121,7 +121,7 @@ func (o *OKGroup) TransferAccountFunds(ctx context.Context, request TransferAcco
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupAccountSubsection, okGroupFundsTransfer, request, &resp, true)
|
||||
}
|
||||
|
||||
// AccountWithdraw withdrawal of tokens to OKCoin International, other OKEx accounts or other addresses.
|
||||
// AccountWithdraw withdrawal of tokens to OKCoin International or other addresses.
|
||||
func (o *OKGroup) AccountWithdraw(ctx context.Context, request AccountWithdrawRequest) (resp AccountWithdrawResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupAccountSubsection, okGroupWithdraw, request, &resp, true)
|
||||
}
|
||||
@@ -435,8 +435,7 @@ func (o *OKGroup) RepayMarginLoan(ctx context.Context, request RepayMarginLoanRe
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupMarginTradingSubsection, requestURL, request, &resp, true)
|
||||
}
|
||||
|
||||
// PlaceMarginOrder OKEx API only supports limit and market orders (more orders will become available in the future).
|
||||
// You can place an order only if you have enough funds. Once your order is placed, the amount will be put on hold.
|
||||
// PlaceMarginOrder You can place an order only if you have enough funds. Once your order is placed, the amount will be put on hold.
|
||||
func (o *OKGroup) PlaceMarginOrder(ctx context.Context, request *PlaceOrderRequest) (resp PlaceOrderResponse, _ error) {
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, okGroupMarginTradingSubsection, OKGroupOrders, request, &resp, true)
|
||||
}
|
||||
@@ -529,7 +528,7 @@ func (o *OKGroup) GetMarginTransactionDetails(ctx context.Context, request GetSp
|
||||
return resp, o.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, okGroupMarginTradingSubsection, requestURL, nil, &resp, true)
|
||||
}
|
||||
|
||||
// FormatParameters Formats URL parameters, useful for optional parameters due to OKEX signature check
|
||||
// FormatParameters Formats URL parameters, useful for optional parameters due to OKCoin signature check
|
||||
func FormatParameters(request interface{}) (parameters string) {
|
||||
v, err := query.Values(request)
|
||||
if err != nil {
|
||||
|
||||
@@ -143,8 +143,8 @@ type TransferAccountFundsResponse struct {
|
||||
type AccountWithdrawRequest struct {
|
||||
Amount float64 `json:"amount"` // [required] withdrawal amount
|
||||
Currency string `json:"currency"` // [required] token
|
||||
Destination int64 `json:"destination"` // [required] withdrawal address(2:OKCoin International 3:OKEx 4:others)
|
||||
Fee float64 `json:"fee"` // [required] Network transaction fee≥0. Withdrawals to OKCoin or OKEx are fee-free, please set as 0. Withdrawal to external digital asset address requires network transaction fee.
|
||||
Destination int64 `json:"destination"` // [required] withdrawal address(2:OKCoin International 3:others)
|
||||
Fee float64 `json:"fee"` // [required] Network transaction fee≥0. Withdrawals to OKCoin are fee-free, please set as 0. Withdrawal to external digital asset address requires network transaction fee.
|
||||
ToAddress string `json:"to_address"` // [required] verified digital asset address, email or mobile number,some digital asset address format is address+tag , eg: "ARDOR-7JF3-8F2E-QUWZ-CAN7F:123456"
|
||||
TradePwd string `json:"trade_pwd"` // [required] fund password
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
)
|
||||
|
||||
// Note: GoCryptoTrader wrapper funcs currently only support SPOT trades.
|
||||
// Therefore this OKGroup_Wrapper can be shared between OKEX and OKCoin.
|
||||
// Therefore this OKGroup_Wrapper can be shared between OKCoin and OKCoin.
|
||||
// When circumstances change, wrapper funcs can be split appropriately
|
||||
|
||||
var errNoAccountDepositAddress = errors.New("no account deposit address")
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# GoCryptoTrader package Okex
|
||||
# GoCryptoTrader package Okx
|
||||
|
||||
<img src="/common/gctlogo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/okex)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/okx)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This okex package is part of the GoCryptoTrader codebase.
|
||||
This okx package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
@@ -18,15 +18,16 @@ You can track ideas, planned features and what's in progress on this Trello boar
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk)
|
||||
|
||||
## OKex Exchange
|
||||
## Okx Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST Support
|
||||
+ Websocket Support
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
[Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
|
||||
+ Individual package example below:
|
||||
|
||||
@@ -45,10 +46,10 @@ below:
|
||||
|
||||
main.go
|
||||
```go
|
||||
var o exchange.IBotExchange
|
||||
var ok exchange.IBotExchange
|
||||
|
||||
for i := range bot.Exchanges {
|
||||
if bot.Exchanges[i].GetName() == "OKex" {
|
||||
if bot.Exchanges[i].GetName() == "Okx" {
|
||||
y = bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
@@ -56,22 +57,22 @@ for i := range bot.Exchanges {
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := o.FetchTicker()
|
||||
tick, err := ok.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := o.FetchOrderbook()
|
||||
ob, err := ok.FetchOrderbook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
|
||||
// Private calls - wrapper functions - make sure your APIKEY, APISECRET, and API_CLIENT_ID are
|
||||
// set and AuthenticatedAPISupport is set to true
|
||||
|
||||
// Fetches current account information
|
||||
accountInfo, err := o.GetAccountInfo()
|
||||
accountInfo, err := ok.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
@@ -83,13 +84,26 @@ if err != nil {
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := o.GetSpotTicker()
|
||||
ticker, err := ok.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := o.GetSpotMarketDepth()
|
||||
ob, err := ok.GetOrderBook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches historic trade data within the timeframe provided
|
||||
tradeDatas, err := ok.GetHistoricTrades(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
|
||||
// Returns an estimate of fee based on the type of transaction
|
||||
fee, err := ok.GetFeeByType(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
@@ -97,17 +111,25 @@ if err != nil {
|
||||
// Private calls - make sure your APIKEY and APISECRET are set and
|
||||
// AuthenticatedAPISupport is set to true
|
||||
|
||||
// GetContractPosition returns contract positioning
|
||||
accountInfo, err := o.GetContractPosition(...)
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
orderID, err := ok.SubmitOrder(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := o.PlaceContractOrders(...)
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to market conversion
|
||||
updatedOrder, err := ok.ModifyOrder(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### How to do Websocket public/private calls
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
4319
exchanges/okx/okx.go
Normal file
4319
exchanges/okx/okx.go
Normal file
File diff suppressed because it is too large
Load Diff
524
exchanges/okx/okx_err_codes.go
Normal file
524
exchanges/okx/okx_err_codes.go
Normal file
@@ -0,0 +1,524 @@
|
||||
package okx
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrorCodes and their corresponding error messages
|
||||
var (
|
||||
ErrorCodes = map[string]error{
|
||||
"60001": errors.New("\"OK_ACCESS_KEY\" can not be empty"),
|
||||
"60002": errors.New("\"OK_ACCESS_SIGN\" can not be empty"),
|
||||
"60003": errors.New("\"OK_ACCESS_PASSPHRASE\" can not be empty"),
|
||||
"60004": errors.New("invalid OK_ACCESS_TIMESTAMP"),
|
||||
"60005": errors.New("invalid OK_ACCESS_KEY"),
|
||||
"60006": errors.New("timestamp request expired"),
|
||||
"60007": errors.New("invalid sign"),
|
||||
"60008": errors.New("public websocket services do not support subscribing to private channels"),
|
||||
"60009": errors.New("login failed"),
|
||||
"60011": errors.New("please log in"),
|
||||
"60012": errors.New("illegal request"),
|
||||
"60013": errors.New("invalid args"),
|
||||
"60014": errors.New("requests too frequent"),
|
||||
"60015": errors.New("connection closed as there was no data transmission in the last 30 seconds"),
|
||||
"60016": errors.New("buffer is full, cannot write data"),
|
||||
"60017": errors.New("invalid url path"),
|
||||
"60018": errors.New("the {0} {1} {2} {3} {4} does not exist"),
|
||||
"60019": errors.New("invalid op {op}"),
|
||||
"60020": errors.New("apikey subscription amount exceeds the limit {0}"),
|
||||
"60021": errors.New("this operation does not support multiple accounts login"),
|
||||
"60022": errors.New("bulk login partially succeeded"),
|
||||
"60023": errors.New("bulk login requests too frequent"),
|
||||
"60024": errors.New("wrong passphrase"),
|
||||
"60025": errors.New("token subscription amount exceeds the limit {0}"),
|
||||
"60026": errors.New("batch login by apikey and token simultaneously is not supported"),
|
||||
"60027": errors.New("parameter {0} can not be empty"),
|
||||
"60028": errors.New("private websocket services do not support subscribing to public channels"),
|
||||
"60029": errors.New("only users who're VIP5 and above can subscribe to books-l2-tbt order book channels"),
|
||||
"60030": errors.New("only users who're VIP4 and above can subscribe to books50-l2-tbt order book channels"),
|
||||
"63999": errors.New("internal system error"),
|
||||
"70000": errors.New("rFQ does not exist"),
|
||||
"70001": errors.New("quote does not exist"),
|
||||
"70002": errors.New("block trade does not exist"),
|
||||
"70003": errors.New("public block trade does not exist"),
|
||||
"70004": errors.New("invalid instrument {0}"),
|
||||
"70005": errors.New("the number of legs in RFQ cannot exceed maximum value"),
|
||||
"70006": errors.New("does not meet the minimum asset requirement"),
|
||||
"70007": errors.New("underlying index {0} does not exist under instType {1}"),
|
||||
"70008": errors.New("operation failed under MMP status, the frozen window is {0} seconds"),
|
||||
"70009": errors.New("data must have at least 1 valid element"),
|
||||
"70011": errors.New("duplicate setting for instType {0}"),
|
||||
"70100": errors.New("duplicate instruments in legs array"),
|
||||
"70101": errors.New("duplicate clRfqId"),
|
||||
"70102": errors.New("no counterparties specified"),
|
||||
"70103": errors.New("invalid counterparty"),
|
||||
"70105": errors.New("the total value should be greater than the min notional value {0}"),
|
||||
"70106": errors.New("the trading amount does not meet the min tradable amount requirement"),
|
||||
"70107": errors.New("the number of counterparties cannot exceed maximum value"),
|
||||
"70109": errors.New("counterparties for selected instruments are currently unavailable"),
|
||||
"70200": errors.New("the RFQ with {0} status cannot be canceled"),
|
||||
"70203": errors.New("cancellation failed as rfq count exceeds the limit {0}"),
|
||||
"70207": errors.New("cancellation failed as you do not have any active RFQs"),
|
||||
"70208": errors.New("cancellation failed as service is unavailable now, please try again later"),
|
||||
"70301": errors.New("duplicate clQuoteId"),
|
||||
"70303": errors.New("the RFQ with {0} status cannot be quoted"),
|
||||
"70304": errors.New("price should be an integer multiple of the tick size"),
|
||||
"70305": errors.New("bid price cannot be higher than offer price"),
|
||||
"70306": errors.New("the legs of quote do not match the legs of {0}"),
|
||||
"70307": errors.New("size should be in integral multiples of the lot size"),
|
||||
"70308": errors.New("quote to your own RFQ is not allowed"),
|
||||
"70309": errors.New("quote to the same RFQ with the same side is not allowed"),
|
||||
"70310": errors.New("quoted price of instId {0} cannot exceed your preset price limit"),
|
||||
"70400": errors.New("the quote with {0} status cannot be canceled"),
|
||||
"70408": errors.New("cancellation failed as quote count exceeds the limit {0}"),
|
||||
"70409": errors.New("cancellation failed as you do not have any active quotes"),
|
||||
"70501": errors.New("RFQ {0} is not quoted by {1}"),
|
||||
"70502": errors.New("the legs do not match the legs of {0}"),
|
||||
"70503": errors.New("the legs of execution do not match the legs of {0}"),
|
||||
"70504": errors.New("execution failed as the RFQ status is {0}"),
|
||||
"70505": errors.New("execution failed as the quote status is {0}"),
|
||||
"70511": errors.New("execution is being processed"),
|
||||
"56000": errors.New("block trade does not exist"),
|
||||
"56001": errors.New("the number of multi-legs cannot exceed {0}"),
|
||||
"56002": errors.New("the number of multi-legs does not match with the verified one"),
|
||||
"56003": errors.New("duplicated clBlockTdId"),
|
||||
"56004": errors.New("trade with yourself is not allowed"),
|
||||
"56005": errors.New("\"clBlockTdId\" should be the same as the verified one"),
|
||||
"56006": errors.New("the role should be different from the verified one"),
|
||||
"56007": errors.New("leg no.{0} does not match with the verified one"),
|
||||
"56008": errors.New("duplicate instruments in legs array"),
|
||||
"59000": errors.New("your settings failed as you have positions or open orders"),
|
||||
"59001": errors.New("switching unavailable as you have borrowings"),
|
||||
"59004": errors.New("only IDs with the same instrument type are supported"),
|
||||
"59005": errors.New("when users transfer the margin by themselves in isolated mode, the value of the asset allocated to the position for the first time must be greater than 10,000 USDT"),
|
||||
"59100": errors.New("you have open positions. please cancel all open positions before changing the leverage"),
|
||||
"59101": errors.New("you have pending orders with isolated positions. please cancel all the pending isolated margin orders and adjust the leverage"),
|
||||
"59102": errors.New("leverage exceeds the maximum leverage. please adjust the leverage"),
|
||||
"59103": errors.New("leverage is too low and no sufficient margin in your account. please adjust the leverage"),
|
||||
"59104": errors.New("the leverage is too high. the borrowed position has exceeded the maximum position of this leverage. please adjust the leverage"),
|
||||
"59105": errors.New("leverage can not be less than {0}. please adjust the leverage"),
|
||||
"59106": errors.New("the max available margin corresponding to your order tier please adjust your margin and place a new order"),
|
||||
"59107": errors.New("you have pending cross margin orders under the service, please modify the leverage after canceling all pending cross margin orders"),
|
||||
"59108": errors.New("low leverage and insufficient margin, please adjust the leverage"),
|
||||
"59109": errors.New("account equity less than the required margin amount after adjustment. please adjust the leverage "),
|
||||
"59110": errors.New("the instrument type corresponding to this {0} does not support the tgtCcy parameter"),
|
||||
"59111": errors.New("you cannot query the leverage of cross derivatives positions under a PM account"),
|
||||
"59112": errors.New("you have isolated/cross pending orders. please cancel them before adjusting your leverage"),
|
||||
"59200": errors.New("insufficient account balance"),
|
||||
"59201": errors.New("negative account balance"),
|
||||
"59300": errors.New("margin call failed. position does not exist"),
|
||||
"59301": errors.New("margin adjustment failed for exceeding the max limit"),
|
||||
"59302": errors.New("you have pending close orders, please modify the margin after canceling the orders"),
|
||||
"59303": errors.New("insufficient available margin, add margin or reduce the borrowing amount"),
|
||||
"59304": errors.New("insufficient equity for borrowing, keep enough funds to pay interest for at least one day"),
|
||||
"59305": errors.New("use VIP loan first to set the VIP loan priority"),
|
||||
"59306": errors.New("your borrowing amount exceeds the max limit"),
|
||||
"59307": errors.New("you are not eligible for VIP loans"),
|
||||
"59308": errors.New("unable to repay VIP loan due to insufficient borrow limit"),
|
||||
"59309": errors.New("unable to repay an amount that exceeds the borrowed amount"),
|
||||
"59310": errors.New("your account does not support VIP loan"),
|
||||
"59311": errors.New("unable to set up as there is VIP loan"),
|
||||
"59312": errors.New("{currency} does not support VIP loans"),
|
||||
"59401": errors.New("holdings already reached the limit"),
|
||||
"59402": errors.New("none of the passed instId is in live state, please check them separately"),
|
||||
"59500": errors.New("only the APIKey of the main account has permission"),
|
||||
"59501": errors.New("only 50 APIKeys can be created per account"),
|
||||
"59502": errors.New("note name cannot be duplicate with the currently created APIKey note name"),
|
||||
"59503": errors.New("each APIKey can bind up to 20 IP addresses"),
|
||||
"59504": errors.New("the sub account does not support the withdrawal function"),
|
||||
"59505": errors.New("the passphrase format is incorrect"),
|
||||
"59506": errors.New("apikey does not exist"),
|
||||
"59507": errors.New("the two accounts involved in a transfer must be two different sub accounts under the same parent account"),
|
||||
"59508": errors.New("the sub account of {0} is suspended"),
|
||||
"59509": errors.New("account does not have permission to reset MMP status"),
|
||||
"59510": errors.New("sub-account does not exist"),
|
||||
"59512": errors.New("unable to set up this permission for ND brokers sub accounts. by default, all ND sub accounts can transfer funds out"),
|
||||
"59601": errors.New("this sub-account name already exists, try another name"),
|
||||
"59602": errors.New("number of API keys exceeds the limit"),
|
||||
"59603": errors.New("number of sub accounts exceeds the limit"),
|
||||
"59604": errors.New("only the main account APIkey can access this API"),
|
||||
"59605": errors.New("this API key does not exist in your sub-account, try another API key"),
|
||||
"59606": errors.New("transfer funds to your main account before deleting your sub-account"),
|
||||
"59608": errors.New("only the broker account has permission to operate this API"),
|
||||
"59609": errors.New("broker already exists"),
|
||||
"59610": errors.New("broker does not exist"),
|
||||
"59611": errors.New("broker unverified"),
|
||||
"59612": errors.New("cannot convert time format"),
|
||||
"59613": errors.New("there is currently no escrow relationship established with the sub account"),
|
||||
"59614": errors.New("managed sub account do not support this operation"),
|
||||
"59615": errors.New("the time interval between the begin date and end date cannot exceed 180 days"),
|
||||
"59616": errors.New("begin date cannot be greater than end date"),
|
||||
"59617": errors.New("sub-account created. failed to set up account level"),
|
||||
"59618": errors.New("failed to create sub-account"),
|
||||
"58000": errors.New("account type {0} does not supported when getting the sub-account balance"),
|
||||
"58001": errors.New("incorrect trade password"),
|
||||
"58002": errors.New("please activate savings account first"),
|
||||
"58003": errors.New("currency type is not supported by savings account"),
|
||||
"58004": errors.New("account blocked (transfer & withdrawal endpoint: either end of the account does not authorize the transfer)"),
|
||||
"58005": errors.New("the purchase/redeemed amount must be no greater than {0}"),
|
||||
"58006": errors.New("service unavailable for token {0}"),
|
||||
"58007": errors.New("abnormal assets interface. please try again later"),
|
||||
"58008": errors.New("you do not have assets in this currency"),
|
||||
"58009": errors.New("currency pair do not exist"),
|
||||
"58010": errors.New("the chain {0} is not supported"),
|
||||
"58011": errors.New("sorry, we are unable to provide services to unverified users in {Region} due to local laws and regulations. please verify your account in order to use the services"),
|
||||
"58012": errors.New("sorry, you can't transfer assets to this recipient as OKX are unable to provide services to unverified users in {region} due to local laws and regulations"),
|
||||
"58100": errors.New("the trading product triggers risk control, and the platform has suspended the fund transfer-out function with related users. please wait patiently"),
|
||||
"58101": errors.New("transfer suspended (transfer endpoint: either end of the account does not authorize the transfer)"),
|
||||
"58102": errors.New("too frequent transfer (transfer too frequently)"),
|
||||
"58104": errors.New("since your P2P transaction is abnormal, you are restricted from making fund transfers. please contact customer support to remove the restriction"),
|
||||
"58105": errors.New(`since your P2P transaction is abnormal, you are restricted from making fund transfers. please transfer funds on our website or app to complete identity verification`),
|
||||
"58106": errors.New("please enable the account for spot contract"),
|
||||
"58107": errors.New("please enable the account for futures contract"),
|
||||
"58108": errors.New("please enable the account for option contract"),
|
||||
"58109": errors.New("please enable the account for swap contract"),
|
||||
"58110": errors.New("the contract triggers risk control, and the platform has suspended the fund transfer function of it. please wait patiently"),
|
||||
"58111": errors.New("funds transfer unavailable as the perpetual contract is charging the funding fee. please try again later"),
|
||||
"58112": errors.New("your fund transfer failed. please try again later"),
|
||||
"58114": errors.New("transfer amount must be more than 0"),
|
||||
"58115": errors.New("sub-account does not exist"),
|
||||
"58116": errors.New("transfer amount exceeds the limit"),
|
||||
"58117": errors.New("account assets are abnormal, please deal with negative assets before transferring"),
|
||||
"58119": errors.New("{0} sub-account has no permission to transfer out, please set first"),
|
||||
"58120": errors.New("the transfer service is temporarily unavailable, please try again later"),
|
||||
"58121": errors.New("this transfer will result in a high-risk level of your position, which may lead to forced liquidation. You need to re-adjust the transfer amount to make sure the position is at a safe level before proceeding with the transfer"),
|
||||
"58122": errors.New("a portion of your spot is being used for delta offset between positions. if the transfer amount exceeds the available amount, it may affect current spot-derivatives risk offset structure, which will result in an increased maintenance margin requirement (MMR) rate. please be aware of your risk level"),
|
||||
"58123": errors.New("parameter from can not equal to parameter to"),
|
||||
"58200": errors.New("withdrawal from {0} to {1} is unavailable for this currency"),
|
||||
"58201": errors.New("withdrawal amount exceeds the daily limit"),
|
||||
"58202": errors.New("the minimum withdrawal amount for NEO is 1, and the amount must be an integer"),
|
||||
"58203": errors.New("please add a withdrawal address"),
|
||||
"58204": errors.New("withdrawal suspended"),
|
||||
"58205": errors.New("withdrawal amount exceeds the upper limit"),
|
||||
"58206": errors.New("withdrawal amount is lower than the lower limit"),
|
||||
"58207": errors.New("withdrawal address is not in the verification-free whitelist"),
|
||||
"58208": errors.New("withdrawal failed. please link your email"),
|
||||
"58209": errors.New("sub-accounts cannot be deposits or withdrawals"),
|
||||
"58210": errors.New("withdrawal fee exceeds the upper limit"),
|
||||
"58211": errors.New("withdrawal fee is lower than the lower limit (withdrawal endpoint: incorrect fee)"),
|
||||
"58212": errors.New("withdrawal fee should be {0} of the withdrawal amount"),
|
||||
"58214": errors.New("withdrawals suspended due to {chainName} maintenance"),
|
||||
"58215": errors.New("withdrawal ID does not exist"),
|
||||
"58216": errors.New("operation not allowed"),
|
||||
"58217": errors.New("you cannot withdraw your asset at the moment due to a risk detected in your withdrawal address, contact customer support for details"),
|
||||
"58218": errors.New("your saved withdrawal account has expired"),
|
||||
"58220": errors.New("the withdrawal order is already canceled"),
|
||||
"58221": errors.New("missing label of withdrawal address"),
|
||||
"58222": errors.New("illegal withdrawal address"),
|
||||
"58224": errors.New("this type of crypto does not support on-chain withdrawing to OKX addresses. please withdraw through internal transfers"),
|
||||
"58225": errors.New("sorry, you can't transfer assets to this recipient as OKX are unable to provide services to unverified users in {region} due to local laws and regulations"),
|
||||
"58300": errors.New("deposit-address count exceeds the limit"),
|
||||
"58301": errors.New("deposit-address not exist"),
|
||||
"58302": errors.New("deposit-address needs tag"),
|
||||
"58303": errors.New("deposit for the chain {0} is closed now"),
|
||||
"58304": errors.New("failed to create invoice"),
|
||||
"58350": errors.New("insufficient balance"),
|
||||
"58351": errors.New("invoice expired"),
|
||||
"58352": errors.New("invalid invoice"),
|
||||
"58353": errors.New("deposit amount must be within limits"),
|
||||
"58354": errors.New("you have reached the limit of 10000 invoices per day"),
|
||||
"58355": errors.New("permission denied. please contact your account manager"),
|
||||
"58356": errors.New("the accounts of the same node do not support the lightning network deposit or withdrawal"),
|
||||
"58357": errors.New("{0} is not allowed to create a deposit address"),
|
||||
"58358": errors.New("fromCcy should not be the same as toCcy"),
|
||||
"58370": errors.New("the daily usage of small assets convert exceeds the limit"),
|
||||
"58371": errors.New("small assets exceed the maximum limit"),
|
||||
"58372": errors.New("insufficient small assets"),
|
||||
"55000": errors.New("cannot be transferred out within 30 minutes after delivery"),
|
||||
"54000": errors.New("margin transactions unavailable"),
|
||||
"54001": errors.New("only multi-currency margin account can be set to borrow coins automatically"),
|
||||
"52900": errors.New("general Invalid request"),
|
||||
"52901": errors.New("invalid base asset"),
|
||||
"52902": errors.New("invalid quote asset"),
|
||||
"52903": errors.New("invalid quote amount"),
|
||||
"52904": errors.New("invalid quote side"),
|
||||
"52905": errors.New("invalid quote price"),
|
||||
"52907": errors.New("order not found"),
|
||||
"52908": errors.New("invalid order ID"),
|
||||
"52909": errors.New("duplicated client order Id"),
|
||||
"52910": errors.New("service unavailable, please try again later"),
|
||||
"52911": errors.New("RFQ service unavailable, please try again later"),
|
||||
"52912": errors.New("server timeout"),
|
||||
"52913": errors.New("trade rejected"),
|
||||
"52915": errors.New("cannot quote due to large amounts of RFQ and insufficient liquidity, please try again later"),
|
||||
"52916": errors.New("insufficient balance in funding account"),
|
||||
"52917": errors.New("RFQ quantity cannot be less than the lower limit"),
|
||||
"52918": errors.New("insufficient balance in funding account"),
|
||||
"52919": errors.New("parameter {param} of convert trading is inconsistent with the quotation"),
|
||||
"52920": errors.New("quantity of convert trading cannot exceed the quotation quantity"),
|
||||
"52921": errors.New("quote traded, please ask for quote again"),
|
||||
"52922": errors.New("quote expired, please ask for quote again"),
|
||||
"52923": errors.New("service unavailable, please try again later"),
|
||||
"51720": errors.New("redeem error"),
|
||||
"51721": errors.New("cancel redeem error"),
|
||||
"51722": errors.New("redeem already complete"),
|
||||
"51723": errors.New("early redemption is not supported"),
|
||||
"51724": errors.New("redemption is currently not supported"),
|
||||
"51725": errors.New("cancellation is currently not supported"),
|
||||
"51726": errors.New("cancellation of subscriptions/redemptions is not supported"),
|
||||
"51727": errors.New("the subscription quantity is below the minimum requirement"),
|
||||
"51728": errors.New("the subscription quantity is above the maximum limit"),
|
||||
"51729": errors.New("this project has not reached the redemption date"),
|
||||
"51730": errors.New("sold out"),
|
||||
"52000": errors.New("no market data found"),
|
||||
"51000": errors.New("parameter {0} error"),
|
||||
"51001": errors.New("instrument ID does not exist"),
|
||||
"51002": errors.New("instrument ID does not match underlying index"),
|
||||
"51003": errors.New("either client order ID or order ID is required"),
|
||||
"51004": errors.New("order amount exceeds current tier limit, please lower the leverage"),
|
||||
"51005": errors.New("order amount exceeds the limit"),
|
||||
"51006": errors.New("order price is not within the price limit (max buy price: {0} min sell price: {1})"),
|
||||
"51007": errors.New("order placement failed. order amount should be at least 1 contract (showing up when placing an order with less than 1 contract)"),
|
||||
"51008": errors.New("delegate failed. Insufficient {0} balance in account"),
|
||||
"51009": errors.New("order placement function is blocked by the platform"),
|
||||
"51010": errors.New("operation is not supported under the current account mode"),
|
||||
"51011": errors.New("duplicated order ID"),
|
||||
"51012": errors.New("token does not exist"),
|
||||
"51014": errors.New("index does not exist"),
|
||||
"51015": errors.New("instrument ID does not match instrument type"),
|
||||
"51016": errors.New("duplicated client order ID"),
|
||||
"51017": errors.New("borrow amount exceeds the limit"),
|
||||
"51018": errors.New("user with option account can not hold net short positions"),
|
||||
"51019": errors.New("no net long positions can be held under cross margin mode in options"),
|
||||
"51020": errors.New("order amount should be greater than the min available amount"),
|
||||
"51021": errors.New("contract to be listed"),
|
||||
"51022": errors.New("contract suspended"),
|
||||
"51023": errors.New("position does not exist"),
|
||||
"51024": errors.New("trading account is blocked"),
|
||||
"51025": errors.New("order count exceeds the limit"),
|
||||
"51026": errors.New("instrument type does not match underlying index"),
|
||||
"51027": errors.New("contract expired"),
|
||||
"51028": errors.New("contract under delivery"),
|
||||
"51029": errors.New("contract is being settled"),
|
||||
"51030": errors.New("funding fee is being settled"),
|
||||
"51031": errors.New("this order price is not within the closing price range"),
|
||||
"51032": errors.New("closing all positions at market price"),
|
||||
"51033": errors.New("the total amount per order for this pair has reached the upper limit"),
|
||||
"51037": errors.New("the current account risk status only supports you to place IOC orders that can reduce the risk of your account"),
|
||||
"51038": errors.New("there is already an IOC order under the current risk module that reduces the risk of the account"),
|
||||
"51039": errors.New("leverage cannot be adjusted for the cross positions of futures and perpetual swap under the PM account"),
|
||||
"51040": errors.New("cannot adjust margins for long isolated options positions"),
|
||||
"51041": errors.New("portfolio margin account only supports net mode"),
|
||||
"51044": errors.New("the order type {0}, {1} is not allowed to set stop loss and take profit"),
|
||||
"51046": errors.New("the take profit trigger price should be higher than the order price"),
|
||||
"51047": errors.New("the stop loss trigger price should be lower than the order price"),
|
||||
"51048": errors.New("the take profit trigger price should be lower than the order price"),
|
||||
"51049": errors.New("the stop loss trigger price should be higher than the order price"),
|
||||
"51050": errors.New("the take profit trigger price should be higher than the best ask price"),
|
||||
"51051": errors.New("the stop loss trigger price should be lower than the best ask price"),
|
||||
"51052": errors.New("the take profit trigger price should be lower than the best bid price"),
|
||||
"51053": errors.New("the stop loss trigger price should be higher than the best bid price"),
|
||||
"51054": errors.New("getting information timed out, please try again later"),
|
||||
"51055": errors.New("futures grid is not available in portfolio margin mode"),
|
||||
"51056": errors.New("action not allowed"),
|
||||
"51057": errors.New("futures grid is not available in simple trading mode"),
|
||||
"51058": errors.New("no position"),
|
||||
"51059": errors.New("strategy for the current state does not support this operation"),
|
||||
"51101": errors.New("entered amount exceeds the max pending order amount per transaction"),
|
||||
"51102": errors.New("entered amount exceeds the max pending count"),
|
||||
"51103": errors.New("entered amount exceeds the max pending order count of the underlying asset"),
|
||||
"51104": errors.New("entered amount exceeds the max pending order amount of the underlying asset"),
|
||||
"51105": errors.New("entered amount exceeds the max order amount of the contract"),
|
||||
"51106": errors.New("entered amount exceeds the max order amount of the underlying asset"),
|
||||
"51107": errors.New("entered amount exceeds the max holding amount"),
|
||||
"51108": errors.New("positions exceed the limit for closing out with the market price"),
|
||||
"51109": errors.New("no available offer"),
|
||||
"51110": errors.New("you can only place a limit order after call auction has started"),
|
||||
"51111": errors.New("maximum {0} orders can be placed in bulk"),
|
||||
"51112": errors.New("close order size exceeds your available size"),
|
||||
"51113": errors.New("market-price liquidation requests too frequent"),
|
||||
"51115": errors.New("cancel all pending close-orders before liquidation"),
|
||||
"51116": errors.New("order price or trigger price exceeds {0}"),
|
||||
"51117": errors.New("pending close-orders count exceeds limit"),
|
||||
"51120": errors.New("order quantity is less than {0}, please try again"),
|
||||
"51121": errors.New("order count should be the integer multiples of the lot size"),
|
||||
"51122": errors.New("order price should be higher than the min price {0}"),
|
||||
"51124": errors.New("you can only place limit orders during call auction"),
|
||||
"51125": errors.New("currently there are reduce + reverse position pending orders in margin trading. please cancel all reduce + reverse position pending orders and continue"),
|
||||
"51126": errors.New("currently there are reduce only pending orders in margin trading. please cancel all reduce only pending orders and continue"),
|
||||
"51127": errors.New("available balance is 0"),
|
||||
"51128": errors.New("multi-currency margin account can not do cross-margin trading"),
|
||||
"51129": errors.New("the value of the position and buy order has reached the position limit, and no further buying is allowed"),
|
||||
"51130": errors.New("fixed margin currency error"),
|
||||
"51131": errors.New("insufficient balance"),
|
||||
"51132": errors.New("your position amount is negative and less than the minimum trading amount"),
|
||||
"51133": errors.New("reduce-only feature is unavailable for the spot transactions by multi-currency margin account"),
|
||||
"51134": errors.New("closing failed. please check your holdings and pending orders"),
|
||||
"51135": errors.New("your closing price has triggered the limit price, and the max buy price is {0}"),
|
||||
"51136": errors.New("your closing price has triggered the limit price, and the min sell price is {0}"),
|
||||
"51137": errors.New("your opening price has triggered the limit price, and the max buy price is {0}"),
|
||||
"51138": errors.New("your opening price has triggered the limit price, and the min sell price is {0}"),
|
||||
"51139": errors.New("reduce-only feature is unavailable for the spot transactions by simple account"),
|
||||
"51145": errors.New("when users transfer the margin by themselves in isolated mode, it’s not supported to place orders in advance"),
|
||||
"51147": errors.New("the total value of assets in your trading account needs to be greater than 50,000 USD to trade options"),
|
||||
"51148": errors.New("reduceOnly cannot increase the position quantity"),
|
||||
"51149": errors.New("order timed out, please try again later"),
|
||||
"51150": errors.New("the precision of the number of trades or the price exceeds the limit"),
|
||||
"51201": errors.New("value of per market order cannot exceed 1,000,000 USDT"),
|
||||
"51202": errors.New("market - order amount exceeds the max amount"),
|
||||
"51203": errors.New("order amount exceeds the limit {0}"),
|
||||
"51204": errors.New("the price for the limit order can not be empty"),
|
||||
"51205": errors.New("reduce-only is not available"),
|
||||
"51206": errors.New("please cancel the reduce only order before placing the current {0} order to avoid opening a reverse position"),
|
||||
"51250": errors.New("algo order price is out of the available range"),
|
||||
"51251": errors.New("algo order type error (when user place an iceberg order)"),
|
||||
"51252": errors.New("algo order price is out of the available range"),
|
||||
"51253": errors.New("average amount exceeds the limit of per iceberg order"),
|
||||
"51254": errors.New("iceberg average amount error (when user place an iceberg order)"),
|
||||
"51255": errors.New("limit of per iceberg order: total amount/1000 < x <= total amount"),
|
||||
"51256": errors.New("iceberg order price variance error"),
|
||||
"51257": errors.New("trail order callback rate error"),
|
||||
"51258": errors.New("trail - order placement failed. the trigger price of a sell order should be higher than the last transaction price"),
|
||||
"51259": errors.New("trail - order placement failed. the trigger price of a buy order should be lower than the last transaction price"),
|
||||
"51260": errors.New("maximum {0} pending trail - orders can be held at the same time"),
|
||||
"51261": errors.New("each user can hold up to {0} pending stop - orders at the same time"),
|
||||
"51262": errors.New("maximum {0} pending iceberg orders can be held at the same time"),
|
||||
"51263": errors.New("maximum {0} pending time-weighted orders can be held at the same time"),
|
||||
"51264": errors.New("average amount exceeds the limit of per time-weighted order"),
|
||||
"51265": errors.New("time-weighted order limit error"),
|
||||
"51267": errors.New("time-weighted order strategy initiative rate error"),
|
||||
"51268": errors.New("time-weighted order strategy initiative range error"),
|
||||
"51269": errors.New("time-weighted order interval error, the interval should be {0}<= x<={1}"),
|
||||
"51270": errors.New("the limit of time-weighted order price variance is 0 < x <= 1%"),
|
||||
"51271": errors.New("sweep ratio should be 0 < x <= 100%"),
|
||||
"51272": errors.New("price variance should be 0 < x <= 1%"),
|
||||
"51273": errors.New("total amount should be more than {0}"),
|
||||
"51274": errors.New("total quantity of time-weighted order must be larger than single order limit"),
|
||||
"51275": errors.New("the amount of single stop-market order can not exceed the upper limit"),
|
||||
"51276": errors.New("stop - market orders cannot specify a price"),
|
||||
"51277": errors.New("TP trigger price can not be higher than the last price"),
|
||||
"51278": errors.New("SL trigger price can not be lower than the last price"),
|
||||
"51279": errors.New("TP trigger price can not be lower than the last price"),
|
||||
"51280": errors.New("SL trigger price can not be higher than the last price"),
|
||||
"51281": errors.New("trigger not support the tgtCcy parameter"),
|
||||
"51282": errors.New("the range of price variance is {0}~{1}"),
|
||||
"51283": errors.New("the range of time interval is {0}~{1}"),
|
||||
"51284": errors.New("the range of average amount is {0}~{1}"),
|
||||
"51285": errors.New("the range of total amount is {0}~{1}"),
|
||||
"51286": errors.New("the total amount should not be less than {0}"),
|
||||
"51287": errors.New("contract not supported"),
|
||||
"51288": errors.New("we are stopping the bot. please do not click it multiple times"),
|
||||
"51289": errors.New("bot configuration does not exist. please try again later"),
|
||||
"51290": errors.New("the bot engine is being upgraded. please try again later"),
|
||||
"51291": errors.New("this bot does not exist or has been stopped"),
|
||||
"51292": errors.New("this bot type does not exist"),
|
||||
"51293": errors.New("this bot does not exist"),
|
||||
"51294": errors.New("this bot cannot be created temporarily. please try again later"),
|
||||
"51295": errors.New("portfolio margin account does not support ordType {0} in trading bot mode"),
|
||||
"51298": errors.New("trigger orders are not available in the net mode of futures and perpetual swaps"),
|
||||
"51299": errors.New("order did not go through. you can hold maximum {0} orders of this type"),
|
||||
"51300": errors.New("TP trigger price can not be higher than the mark price"),
|
||||
"51302": errors.New("SL trigger price can not be lower than the mark price"),
|
||||
"51303": errors.New("TP trigger price can not be lower than the mark price"),
|
||||
"51304": errors.New("SL trigger price can not be higher than the mark price"),
|
||||
"51305": errors.New("TP trigger price can not be higher than the index price"),
|
||||
"51306": errors.New("SL trigger price can not be lower than the index price"),
|
||||
"51307": errors.New("TP trigger price can not be lower than the index price"),
|
||||
"51308": errors.New("SL trigger price can not be higher than the index price"),
|
||||
"51309": errors.New("cannot create trading bot during call auction"),
|
||||
"51310": errors.New("when users transfer the margin by themselves in isolated mode, strategic orders with ordType iceberg and twap will not be supported"),
|
||||
"51311": errors.New("failed to place trailing stop order. callback rate should be within {0}<x<={1}"),
|
||||
"51312": errors.New("failed to place trailing stop order. order amount should be within {0}<x<={1}"),
|
||||
"51313": errors.New("manual transfer in isolated mode does not support bot trading"),
|
||||
"51317": errors.New("trigger orders are not available by margin"),
|
||||
"51340": errors.New("used margin must be greater than {0}{1}"),
|
||||
"51341": errors.New("position closing not allowed"),
|
||||
"51342": errors.New("closing order already exists.please try again later"),
|
||||
"51343": errors.New("TP price must be less than the lower price"),
|
||||
"51344": errors.New("SL price must be greater than the upper price"),
|
||||
"51345": errors.New("policy type is not grid policy"),
|
||||
"51346": errors.New("the highest price cannot be lower than the lowest price"),
|
||||
"51347": errors.New("no profit available"),
|
||||
"51348": errors.New("stop price should be less than the lowest price in the range"),
|
||||
"51349": errors.New("stop profit price should be greater than the highest price in the range"),
|
||||
"51350": errors.New("no recommended parameters"),
|
||||
"51351": errors.New("single income must be greater than 0"),
|
||||
"51370": errors.New("the range of lever is {0}~{1}"),
|
||||
"51400": errors.New("cancellation failed as the order does not exist"),
|
||||
"51401": errors.New("cancellation failed as the order is already canceled"),
|
||||
"51402": errors.New("cancellation failed as the order is already completed"),
|
||||
"51403": errors.New("cancellation failed as the order type does not support cancellation"),
|
||||
"51404": errors.New("order cancellation unavailable during the second phase of call auction"),
|
||||
"51405": errors.New("cancellation failed as you do not have any pending orders"),
|
||||
"51406": errors.New("canceled - order count exceeds the limit {0}"),
|
||||
"51407": errors.New("either order ID or client order ID is required"),
|
||||
"51408": errors.New("pair ID or name does not match the order info"),
|
||||
"51409": errors.New("either pair ID or pair name ID is required"),
|
||||
"51410": errors.New("cancellation failed as the order is already under cancelling status"),
|
||||
"51411": errors.New("account does not have permission for mass cancellation"),
|
||||
"51412": errors.New("the order has been triggered and cannot be cancelled"),
|
||||
"51413": errors.New("cancellation failed as the order type is not supported by endpoint"),
|
||||
"51415": errors.New("unable to place order. spot trading only supports using the last price as trigger price. please select \"Last\" and try again"),
|
||||
"51500": errors.New("either order price or amount is required"),
|
||||
"51501": errors.New("maximum {0} orders can be modified"),
|
||||
"51502": errors.New("order modification failed for insufficient margin"),
|
||||
"51503": errors.New("order modification failed as the order does not exist"),
|
||||
"51506": errors.New("order modification unavailable for the order type"),
|
||||
"51508": errors.New("orders are not allowed to be modified during the call auction"),
|
||||
"51509": errors.New("modification failed as the order has been canceled"),
|
||||
"51510": errors.New("modification failed as the order has been completed"),
|
||||
"51511": errors.New("operation failed as the order price did not meet the requirement for post only"),
|
||||
"51512": errors.New("failed to amend bulk orders. you cannot add duplicate batch orders in your portfolio margin account"),
|
||||
"51513": errors.New("number of modification requests that are currently in progress for an order cannot exceed 3"),
|
||||
"51600": errors.New("status not found"),
|
||||
"51601": errors.New("order status and order ID cannot exist at the same time"),
|
||||
"51602": errors.New("either order status or order ID is required"),
|
||||
"51603": errors.New("order does not exist"),
|
||||
"51607": errors.New("the file is generating"),
|
||||
"50100": errors.New("API frozen, please contact customer service"),
|
||||
"50101": errors.New("APIKey does not match current environment"),
|
||||
"50102": errors.New("timestamp request expired"),
|
||||
"50103": errors.New("request header \"OK_ACCESS_KEY\" can not be empty"),
|
||||
"50104": errors.New("request header \"OK_ACCESS_PASSPHRASE\" can not be empty"),
|
||||
"50105": errors.New("request header \"OK_ACCESS_PASSPHRASE\" incorrect"),
|
||||
"50106": errors.New("request header \"OK_ACCESS_SIGN\" can not be empty"),
|
||||
"50107": errors.New("request header \"OK_ACCESS_TIMESTAMP\" can not be empty"),
|
||||
"50108": errors.New("exchange ID does not exist"),
|
||||
"50109": errors.New("exchange domain does not exist"),
|
||||
"50110": errors.New("your IP {0} is not in linking trusted IP addresses.(You can add your IP in linking trusted IP addresses)"),
|
||||
"50111": errors.New("invalid OK_ACCESS_KEY"),
|
||||
"50112": errors.New("invalid OK_ACCESS_TIMESTAMP"),
|
||||
"50113": errors.New("invalid signature"),
|
||||
"50114": errors.New("invalid authorization"),
|
||||
"50115": errors.New("invalid request method"),
|
||||
"1": errors.New("operation failed"),
|
||||
"2": errors.New("bulk operation partially succeeded"),
|
||||
"50000": errors.New("body can not be empty"),
|
||||
"50001": errors.New("service temporarily unavailable, please try again later"),
|
||||
"50002": errors.New("json data format error"),
|
||||
"50004": errors.New("endpoint request timeout (does not mean that the request was successful or failed, please check the request result)"),
|
||||
"50005": errors.New("API is offline or unavailable"),
|
||||
"50006": errors.New("invalid Content_Type, please use \"application/json\" format"),
|
||||
"50007": errors.New("account blocked"),
|
||||
"50008": errors.New("user does not exist"),
|
||||
"50009": errors.New("account is suspended due to ongoing liquidation"),
|
||||
"50010": errors.New("user ID can not be empty"),
|
||||
"50011": errors.New("requests too frequent"),
|
||||
"50012": errors.New("account status invalid"),
|
||||
"50013": errors.New("system is busy, please try again later"),
|
||||
"50014": errors.New("parameter {0} can not be empty"),
|
||||
"50015": errors.New("either parameter {0} or {1} is required"),
|
||||
"50016": errors.New("parameter {0} does not match parameter {1}"),
|
||||
"50017": errors.New("the position is frozen due to ADL. operation restricted"),
|
||||
"50018": errors.New("currency {0} is frozen due to ADL. operation restricted"),
|
||||
"50019": errors.New("the account is frozen due to ADL. operation restricted"),
|
||||
"50020": errors.New("the position is frozen due to liquidation. operation restricted"),
|
||||
"50021": errors.New("currency {0} is frozen due to liquidation. operation restricted"),
|
||||
"50022": errors.New("the account is frozen due to liquidation. operation restricted"),
|
||||
"50023": errors.New("funding fee frozen. operation restricted"),
|
||||
"50024": errors.New("parameter {0} and {1} can not exist at the same time"),
|
||||
"50025": errors.New("parameter {0} count exceeds the limit {1}"),
|
||||
"50026": errors.New("system error, please try again later"),
|
||||
"50027": errors.New("the account is restricted from trading"),
|
||||
"50028": errors.New("unable to take the order, please reach out to support center for details"),
|
||||
"50029": errors.New(`this instrument ({0}) is unavailable at present due to risk management. please contact customer service for help`),
|
||||
"50030": errors.New("no permission to use this API"),
|
||||
"50031": errors.New("amount cannot exceed 100"),
|
||||
"50032": errors.New("this asset is blocked, allow its trading and try again"),
|
||||
"50033": errors.New("this instrument is blocked, allow its trading and try again"),
|
||||
"50034": errors.New("you are not currently on the whitelist, please contact customer service"),
|
||||
"50035": errors.New("this endpoint requires that APIKey must be bound to IP"),
|
||||
"50036": errors.New("invalid expTime"),
|
||||
"50037": errors.New("order expired"),
|
||||
"50038": errors.New("this feature is temporarily unavailable in demo trading"),
|
||||
"50039": errors.New("the before parameter is not available for implementing timestamp pagination"),
|
||||
}
|
||||
)
|
||||
3176
exchanges/okx/okx_test.go
Normal file
3176
exchanges/okx/okx_test.go
Normal file
File diff suppressed because one or more lines are too long
742
exchanges/okx/okx_type_convert.go
Normal file
742
exchanges/okx/okx_type_convert.go
Normal file
@@ -0,0 +1,742 @@
|
||||
package okx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
)
|
||||
|
||||
type okxNumericalValue float64
|
||||
|
||||
// UnmarshalJSON is custom type json unmarshaller for okxNumericalValue
|
||||
func (a *okxNumericalValue) UnmarshalJSON(data []byte) error {
|
||||
var num string
|
||||
err := json.Unmarshal(data, &num)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if num == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := strconv.ParseFloat(num, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*a = okxNumericalValue(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Float64 returns a float64 value for okxNumericalValue
|
||||
func (a *okxNumericalValue) Float64() float64 { return float64(*a) }
|
||||
|
||||
type okxUnixMilliTime int64
|
||||
|
||||
// UnmarshalJSON deserializes byte data to okxunixMilliTime instance.
|
||||
func (a *okxUnixMilliTime) UnmarshalJSON(data []byte) error {
|
||||
var num string
|
||||
err := json.Unmarshal(data, &num)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if num == "" {
|
||||
return nil
|
||||
}
|
||||
value, err := strconv.ParseInt(num, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*a = okxUnixMilliTime(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Time returns the time instance from unix value of integer.
|
||||
func (a *okxUnixMilliTime) Time() time.Time {
|
||||
return time.UnixMilli(int64(*a))
|
||||
}
|
||||
|
||||
// numbersOnlyRegexp for checking the value is numerics only
|
||||
var numbersOnlyRegexp = regexp.MustCompile(`^\d*$`)
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *Instrument) UnmarshalJSON(data []byte) error {
|
||||
type Alias Instrument
|
||||
chil := &struct {
|
||||
*Alias
|
||||
ListTime string `json:"listTime"`
|
||||
ExpTime string `json:"expTime"`
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if numbersOnlyRegexp.MatchString(chil.ListTime) {
|
||||
var val int
|
||||
if val, err = strconv.Atoi(chil.ListTime); err == nil {
|
||||
a.ListTime = time.UnixMilli(int64(val))
|
||||
}
|
||||
}
|
||||
if numbersOnlyRegexp.MatchString(chil.ExpTime) {
|
||||
var val int
|
||||
if val, err = strconv.Atoi(chil.ExpTime); err == nil {
|
||||
a.ExpTime = time.UnixMilli(int64(val))
|
||||
}
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON decoder for OpenInterestResponse instance.
|
||||
func (a *OpenInterest) UnmarshalJSON(data []byte) error {
|
||||
type Alias OpenInterest
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{Alias: (*Alias)(a)}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *FundingRateResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias FundingRateResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
FundingRate string `json:"fundingRate"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *LimitPriceResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias LimitPriceResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Timestamp int64 `json:"ts,string"`
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes the account and position response.
|
||||
func (a *TickerResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias TickerResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *OptionMarketDataResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias OptionMarketDataResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, asset item, and timestamp information.
|
||||
func (a *DeliveryEstimatedPrice) UnmarshalJSON(data []byte) error {
|
||||
type Alias DeliveryEstimatedPrice
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON custom Unmarshaler to convert the Instrument type string to an asset.Item instance.
|
||||
func (a *LiquidationOrder) UnmarshalJSON(data []byte) error {
|
||||
type Alias LiquidationOrder
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals the timestamp for mark price data
|
||||
func (a *MarkPrice) UnmarshalJSON(data []byte) error {
|
||||
type Alias MarkPrice
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if chil.InstrumentType == "" {
|
||||
a.InstrumentType = asset.Empty
|
||||
} else if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *OrderDetail) UnmarshalJSON(data []byte) error {
|
||||
type Alias OrderDetail
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Side string `json:"side"`
|
||||
UpdateTime int64 `json:"uTime,string"`
|
||||
CreationTime int64 `json:"cTime,string"`
|
||||
InstrumentType string `json:"instType"`
|
||||
FillTime string `json:"fillTime"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
a.UpdateTime = time.UnixMilli(chil.UpdateTime)
|
||||
a.CreationTime = time.UnixMilli(chil.CreationTime)
|
||||
a.Side, err = order.StringToOrderSide(chil.Side)
|
||||
if chil.FillTime == "" {
|
||||
a.FillTime = time.Time{}
|
||||
} else {
|
||||
var value int64
|
||||
value, err = strconv.ParseInt(chil.FillTime, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.FillTime = time.UnixMilli(value)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *PendingOrderItem) UnmarshalJSON(data []byte) error {
|
||||
type Alias PendingOrderItem
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Side string `json:"side"`
|
||||
UpdateTime string `json:"uTime"`
|
||||
CreationTime string `json:"cTime"`
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uTime, err := strconv.ParseInt(chil.UpdateTime, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cTime, err := strconv.ParseInt(chil.CreationTime, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Side, err = order.StringToOrderSide(chil.Side)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
a.CreationTime = time.UnixMilli(cTime)
|
||||
a.UpdateTime = time.UnixMilli(uTime)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *TransactionDetail) UnmarshalJSON(data []byte) error {
|
||||
type Alias TransactionDetail
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *AlgoOrderResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias AlgoOrderResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *PositionData) UnmarshalJSON(data []byte) error {
|
||||
type Alias PositionData
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *AccountPosition) UnmarshalJSON(data []byte) error {
|
||||
type Alias AccountPosition
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserialises the JSON info, asset item instance, and including the timestamp
|
||||
func (a *AccountPositionHistory) UnmarshalJSON(data []byte) error {
|
||||
type Alias AccountPositionHistory
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *BillsDetailResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias BillsDetailResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *TradeFeeRate) UnmarshalJSON(data []byte) error {
|
||||
type Alias TradeFeeRate
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *PositionBuilderData) UnmarshalJSON(data []byte) error {
|
||||
type Alias PositionBuilderData
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *RfqTradeResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias RfqTradeResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
CreationTime int64 `json:"cTime,string"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
a.CreationTime = time.UnixMilli(chil.CreationTime)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *BlockTicker) UnmarshalJSON(data []byte) error {
|
||||
type Alias BlockTicker
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Timestamp int64 `json:"ts,string"`
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *BlockTrade) UnmarshalJSON(data []byte) error {
|
||||
type Alias BlockTrade
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Side string `json:"side"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case strings.EqualFold(chil.Side, "buy"):
|
||||
a.Side = order.Buy
|
||||
case strings.EqualFold(chil.Side, "sell"):
|
||||
a.Side = order.Sell
|
||||
default:
|
||||
a.Side = order.UnknownSide
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *UnitConvertResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias UnitConvertResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
ConvertType int `json:"type,string"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
switch chil.ConvertType {
|
||||
case 1:
|
||||
a.ConvertType = 1
|
||||
case 2:
|
||||
a.ConvertType = 2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *GridAlgoSuborder) UnmarshalJSON(data []byte) error {
|
||||
type Alias GridAlgoSuborder
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *GridAlgoOrderResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias GridAlgoOrderResponse
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *AlgoOrderPosition) UnmarshalJSON(data []byte) error {
|
||||
type Alias AlgoOrderPosition
|
||||
chil := &struct {
|
||||
*Alias
|
||||
InstrumentType string `json:"instType"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chil.InstrumentType = strings.ToUpper(chil.InstrumentType)
|
||||
if a.InstrumentType, err = GetAssetTypeFromInstrumentType(chil.InstrumentType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *QuoteLeg) UnmarshalJSON(data []byte) error {
|
||||
type Alias QuoteLeg
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Side string `json:"side"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
chil.Side = strings.ToLower(chil.Side)
|
||||
if chil.Side == "buy" {
|
||||
a.Side = order.Buy
|
||||
} else {
|
||||
a.Side = order.Sell
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON serialized QuoteLeg instance into bytes
|
||||
func (a *QuoteLeg) MarshalJSON() ([]byte, error) {
|
||||
type Alias QuoteLeg
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Side string `json:"side"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if a.Side == order.Buy {
|
||||
chil.Side = "buy"
|
||||
} else {
|
||||
chil.Side = "sell"
|
||||
}
|
||||
return json.Marshal(chil)
|
||||
}
|
||||
|
||||
// MarshalJSON serialized CreateQuoteParams instance into bytes
|
||||
func (a *CreateQuoteParams) MarshalJSON() ([]byte, error) {
|
||||
type Alias CreateQuoteParams
|
||||
chil := &struct {
|
||||
*Alias
|
||||
QuoteSide string `json:"quoteSide"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if a.QuoteSide == order.Buy {
|
||||
chil.QuoteSide = "buy"
|
||||
} else {
|
||||
chil.QuoteSide = "sell"
|
||||
}
|
||||
return json.Marshal(chil)
|
||||
}
|
||||
|
||||
// MarshalJSON serializes the WebsocketLoginData object
|
||||
func (a *WebsocketLoginData) MarshalJSON() ([]byte, error) {
|
||||
type Alias WebsocketLoginData
|
||||
return json.Marshal(struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
*Alias
|
||||
}{
|
||||
Timestamp: a.Timestamp.UTC().Unix(),
|
||||
Alias: (*Alias)(a),
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *WebsocketLoginData) UnmarshalJSON(data []byte) error {
|
||||
type Alias WebsocketLoginData
|
||||
chil := &struct {
|
||||
*Alias
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
if err := json.Unmarshal(data, chil); err != nil {
|
||||
return err
|
||||
}
|
||||
a.Timestamp = time.UnixMilli(chil.Timestamp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes JSON, and timestamp information.
|
||||
func (a *CurrencyOneClickRepay) UnmarshalJSON(data []byte) error {
|
||||
type Alias CurrencyOneClickRepay
|
||||
chil := &struct {
|
||||
*Alias
|
||||
UpdateTime int64 `json:"uTime,string"`
|
||||
FillToSize string `json:"fillToSz"`
|
||||
FillFromSize string `json:"fillFromSz"`
|
||||
}{
|
||||
Alias: (*Alias)(a),
|
||||
}
|
||||
err := json.Unmarshal(data, chil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.UpdateTime = time.Unix(chil.UpdateTime, 0)
|
||||
return nil
|
||||
}
|
||||
3169
exchanges/okx/okx_types.go
Normal file
3169
exchanges/okx/okx_types.go
Normal file
File diff suppressed because it is too large
Load Diff
2031
exchanges/okx/okx_websocket.go
Normal file
2031
exchanges/okx/okx_websocket.go
Normal file
File diff suppressed because it is too large
Load Diff
1471
exchanges/okx/okx_wrapper.go
Normal file
1471
exchanges/okx/okx_wrapper.go
Normal file
File diff suppressed because it is too large
Load Diff
1034
exchanges/okx/ratelimit.go
Normal file
1034
exchanges/okx/ratelimit.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -286,7 +286,7 @@ const (
|
||||
)
|
||||
|
||||
// Type enforces a standard for order types across the code base
|
||||
type Type uint16
|
||||
type Type uint32
|
||||
|
||||
// Defined package order types
|
||||
const (
|
||||
@@ -306,6 +306,7 @@ const (
|
||||
AnyType
|
||||
Liquidation
|
||||
Trigger
|
||||
OptimalLimitIOC
|
||||
)
|
||||
|
||||
// Side enforces a standard for order sides across the code base
|
||||
|
||||
@@ -611,6 +611,8 @@ func (t Type) String() string {
|
||||
return "LIQUIDATION"
|
||||
case Trigger:
|
||||
return "TRIGGER"
|
||||
case OptimalLimitIOC:
|
||||
return "OPTIMAL_LIMIT_IOC"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
@@ -1008,6 +1010,8 @@ func StringToOrderType(oType string) (Type, error) {
|
||||
return AnyType, nil
|
||||
case Trigger.String():
|
||||
return Trigger, nil
|
||||
case OptimalLimitIOC.String():
|
||||
return OptimalLimitIOC, nil
|
||||
default:
|
||||
return UnknownType, fmt.Errorf("'%v' %w", oType, errUnrecognisedOrderType)
|
||||
}
|
||||
@@ -1022,7 +1026,7 @@ func StringToOrderStatus(status string) (Status, error) {
|
||||
return AnyStatus, nil
|
||||
case New.String(), "PLACED", "ACCEPTED":
|
||||
return New, nil
|
||||
case Active.String(), "STATUS_ACTIVE":
|
||||
case Active.String(), "STATUS_ACTIVE", "LIVE":
|
||||
return Active, nil
|
||||
case PartiallyFilled.String(), "PARTIALLY MATCHED", "PARTIALLY FILLED":
|
||||
return PartiallyFilled, nil
|
||||
|
||||
@@ -16,7 +16,7 @@ const (
|
||||
WebsocketResponseExtendedTimeout = (15 * time.Second)
|
||||
// WebsocketChannelOverrideCapacity used in websocket testing
|
||||
// Defines channel capacity as defaults size can block tests
|
||||
WebsocketChannelOverrideCapacity = 75
|
||||
WebsocketChannelOverrideCapacity = 500
|
||||
|
||||
MockTesting = "Mock testing framework in use for %s exchange on REST endpoints only"
|
||||
LiveTesting = "Mock testing bypassed; live testing of REST endpoints in use for %s exchange"
|
||||
@@ -38,7 +38,7 @@ func GetWebsocketStructChannelOverride() chan struct{} {
|
||||
func NewTestWebsocket() *stream.Websocket {
|
||||
return &stream.Websocket{
|
||||
Init: true,
|
||||
DataHandler: make(chan interface{}, 75),
|
||||
DataHandler: make(chan interface{}, WebsocketChannelOverrideCapacity),
|
||||
ToRoutine: make(chan interface{}, 1000),
|
||||
TrafficAlert: make(chan struct{}),
|
||||
ReadMessageErrors: make(chan error),
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
testExchange = "OKEX"
|
||||
testExchange = "Okx"
|
||||
)
|
||||
|
||||
func TestLenByPrice(t *testing.T) {
|
||||
|
||||
@@ -870,7 +870,6 @@ func (w *Websocket) UnsubscribeChannels(channels []ChannelSubscription) error {
|
||||
w.exchangeName)
|
||||
}
|
||||
w.subscriptionMutex.Lock()
|
||||
defer w.subscriptionMutex.Unlock()
|
||||
|
||||
channels:
|
||||
for x := range channels {
|
||||
@@ -879,10 +878,12 @@ channels:
|
||||
continue channels
|
||||
}
|
||||
}
|
||||
w.subscriptionMutex.Unlock()
|
||||
return fmt.Errorf("%s websocket: subscription not found in list: %+v",
|
||||
w.exchangeName,
|
||||
channels[x])
|
||||
}
|
||||
w.subscriptionMutex.Unlock()
|
||||
return w.Unsubscriber(channels)
|
||||
}
|
||||
|
||||
@@ -902,16 +903,17 @@ func (w *Websocket) SubscribeToChannels(channels []ChannelSubscription) error {
|
||||
w.exchangeName)
|
||||
}
|
||||
w.subscriptionMutex.Lock()
|
||||
defer w.subscriptionMutex.Unlock()
|
||||
for x := range channels {
|
||||
for y := range w.subscriptions {
|
||||
if channels[x].Equal(&w.subscriptions[y]) {
|
||||
w.subscriptionMutex.Unlock()
|
||||
return fmt.Errorf("%s websocket: %v already subscribed",
|
||||
w.exchangeName,
|
||||
channels[x])
|
||||
}
|
||||
}
|
||||
}
|
||||
w.subscriptionMutex.Unlock()
|
||||
if err := w.Subscriber(channels); err != nil {
|
||||
return fmt.Errorf("%v %w: %v", w.exchangeName, ErrSubscriptionFailure, err)
|
||||
}
|
||||
@@ -921,12 +923,16 @@ func (w *Websocket) SubscribeToChannels(channels []ChannelSubscription) error {
|
||||
// AddSuccessfulSubscriptions adds subscriptions to the subscription lists that
|
||||
// has been successfully subscribed
|
||||
func (w *Websocket) AddSuccessfulSubscriptions(channels ...ChannelSubscription) {
|
||||
w.subscriptionMutex.Lock()
|
||||
w.subscriptions = append(w.subscriptions, channels...)
|
||||
w.subscriptionMutex.Unlock()
|
||||
}
|
||||
|
||||
// RemoveSuccessfulUnsubscriptions removes subscriptions from the subscription
|
||||
// list that has been successfulling unsubscribed
|
||||
func (w *Websocket) RemoveSuccessfulUnsubscriptions(channels ...ChannelSubscription) {
|
||||
w.subscriptionMutex.Lock()
|
||||
defer w.subscriptionMutex.Unlock()
|
||||
for x := range channels {
|
||||
for y := range w.subscriptions {
|
||||
if channels[x].Equal(&w.subscriptions[y]) {
|
||||
|
||||
@@ -38,7 +38,7 @@ var Exchanges = []string{
|
||||
"lbank",
|
||||
"localbitcoins",
|
||||
"okcoin international",
|
||||
"okex",
|
||||
"okx",
|
||||
"poloniex",
|
||||
"yobit",
|
||||
"zb",
|
||||
|
||||
@@ -84,7 +84,7 @@ _b in this context is an `IBotExchange` implemented struct_
|
||||
| Lbank | Yes | No | Yes |
|
||||
| LocalBitcoins | Yes | NA | No |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
| Okx | Yes | Yes | Yes |
|
||||
| Poloniex | Yes | Yes | Yes |
|
||||
| Yobit | Yes | NA | No |
|
||||
| ZB.COM | Yes | Yes | No |
|
||||
|
||||
@@ -191,7 +191,7 @@ func (z *ZB) Setup(exch *config.Exchange) error {
|
||||
})
|
||||
}
|
||||
|
||||
// Start starts the OKEX go routine
|
||||
// Start starts the ZB go routine
|
||||
func (z *ZB) Start(wg *sync.WaitGroup) error {
|
||||
if wg == nil {
|
||||
return fmt.Errorf("%T %w", wg, common.ErrNilPointer)
|
||||
@@ -204,7 +204,7 @@ func (z *ZB) Start(wg *sync.WaitGroup) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run implements the OKEX wrapper
|
||||
// Run implements the ZB wrapper
|
||||
func (z *ZB) Run() {
|
||||
if z.Verbose {
|
||||
z.PrintEnabledPairs()
|
||||
|
||||
@@ -152,10 +152,10 @@ func TestExchangeAddressExists(t *testing.T) {
|
||||
func TestAddExchangeAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
newBase := Base{}
|
||||
newBase.AddExchangeAddress("OKEX", currency.BTC, 100)
|
||||
newBase.AddExchangeAddress("OKEX", currency.BTC, 200)
|
||||
newBase.AddExchangeAddress("Okx", currency.BTC, 100)
|
||||
newBase.AddExchangeAddress("Okx", currency.BTC, 200)
|
||||
|
||||
if !newBase.ExchangeAddressExists("OKEX", currency.BTC) {
|
||||
if !newBase.ExchangeAddressExists("Okx", currency.BTC) {
|
||||
t.Error("address doesn't exist")
|
||||
}
|
||||
}
|
||||
@@ -369,13 +369,13 @@ func TestUpdatePortfolio(t *testing.T) {
|
||||
func TestGetPortfolioByExchange(t *testing.T) {
|
||||
t.Parallel()
|
||||
newBase := Base{}
|
||||
newBase.AddExchangeAddress("OKEX", currency.LTC, 0.07)
|
||||
newBase.AddExchangeAddress("Okx", currency.LTC, 0.07)
|
||||
newBase.AddExchangeAddress("Bitfinex", currency.LTC, 0.05)
|
||||
err := newBase.AddAddress("someaddress", "LTC", currency.NewCode(PersonalAddress), 0.03)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
value := newBase.GetPortfolioByExchange("OKEX")
|
||||
value := newBase.GetPortfolioByExchange("Okx")
|
||||
result, ok := value[currency.LTC]
|
||||
if !ok {
|
||||
t.Error("missing portfolio entry")
|
||||
@@ -399,7 +399,7 @@ func TestGetPortfolioByExchange(t *testing.T) {
|
||||
func TestGetExchangePortfolio(t *testing.T) {
|
||||
t.Parallel()
|
||||
newBase := Base{}
|
||||
err := newBase.AddAddress("OKEX", ExchangeAddress, currency.LTC, 0.03)
|
||||
err := newBase.AddAddress("Okx", ExchangeAddress, currency.LTC, 0.03)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -481,7 +481,7 @@ func TestGetPortfolioSummary(t *testing.T) {
|
||||
// Exchange holdings
|
||||
newBase.AddExchangeAddress("Bitfinex", currency.LTC, 20)
|
||||
newBase.AddExchangeAddress("Bitfinex", currency.BTC, 100)
|
||||
newBase.AddExchangeAddress("OKEX", currency.ETH, 42)
|
||||
newBase.AddExchangeAddress("Okx", currency.ETH, 42)
|
||||
|
||||
value := newBase.GetPortfolioSummary()
|
||||
|
||||
|
||||
228
testdata/configtest.json
vendored
228
testdata/configtest.json
vendored
File diff suppressed because one or more lines are too long
2
testdata/exchangelist.csv
vendored
2
testdata/exchangelist.csv
vendored
@@ -21,7 +21,7 @@ kraken,
|
||||
lbank,
|
||||
localbitcoins,
|
||||
okcoin international,
|
||||
okex,
|
||||
okx,
|
||||
poloniex,
|
||||
yobit,
|
||||
zb,
|
||||
|
Reference in New Issue
Block a user