exchanges: Update OKCoin V5 exchange support (#1206)

* starting public endpoints

* Adding public endpoints

* added public spot market endpoints

* websocket subscriptions updates

* websocket push data handlers completing

* linter fix

* Added funding private endpoints

* Adding authenticated account endpoints

* Added fiat and OTC-RFQ authenticated endpoints

* trading authenticated endpoints

* completing trade endpoints and add public wrapper endpoints

* Authenticated wrapper functions and corresponding unit test

* Adding authenticated websocket endpoint and fixing wrapper functions

* Documentation and exchange websocket update

* update websocket orderbook checksum handling

* linter issues fix and unit test update

* remove invalid orderbook endpoint and unit test

* Documentation, handlers, and model types update

* minot fix

* Minor fixes

* Updating unit tests and added missing endpoints

* Add missing credential check

* Minor unit test fixes

* fix minor linter issue

* add snaphot test unit test

* Fix on update checksum and documentation update

* update exchange, add UpdateOrderExecutionLimits, and update documentation

* Minor fix on tickers fetching

* Minor websocket fix and smaill unit tests

* Minor websocket and naming fixes

* uncomment default channels

* Fix type and unit test issues

* websocket channels and data handling update

* Update Advanced-Algo websocket handling and minor fixes

* documentation and minor code fixes

* Fix name changes

* documentation contribution update

* intervalToString method update

* fix exchange_wrapper_standard tests

* Fix minor issues based on exchange_wrapper_standards_test

* Fix wrapper extended candlestick check

* websocket orders fetching error check method update

* Exchange name check and change

* docs: Add missing contributors

---------

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Samuael A
2023-08-21 23:44:39 +00:00
committed by GitHub
parent a440fab4f3
commit 9c83231696
37 changed files with 7469 additions and 4559 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
wrapperconfig.json
config.json
config.dat
node_modules

View File

@@ -7,6 +7,7 @@ dependabot[bot] | https://github.com/apps/dependabot
dependabot-preview[bot] | https://github.com/apps/dependabot-preview
xtda | https://github.com/xtda
lrascao | https://github.com/lrascao
gbjk | https://github.com/gbjk
Rots | https://github.com/Rots
vazha | https://github.com/vazha
ydm | https://github.com/ydm
@@ -16,24 +17,25 @@ vadimzhukck | https://github.com/vadimzhukck
140am | https://github.com/140am
marcofranssen | https://github.com/marcofranssen
geseq | https://github.com/geseq
Beadko | https://github.com/Beadko
TaltaM | https://github.com/TaltaM
dackroyd | https://github.com/dackroyd
cranktakular | https://github.com/cranktakular
khcchiu | https://github.com/khcchiu
samuael | https://github.com/samuael
woshidama323 | https://github.com/woshidama323
yangrq1018 | https://github.com/yangrq1018
TaltaM | https://github.com/TaltaM
samuael | https://github.com/samuael
crackcomm | https://github.com/crackcomm
azhang | https://github.com/azhang
andreygrehov | https://github.com/andreygrehov
bretep | https://github.com/bretep
Christian-Achilli | https://github.com/Christian-Achilli
MarkDzulko | https://github.com/MarkDzulko
gam-phon | https://github.com/gam-phon
cornelk | https://github.com/cornelk
gam-phon | https://github.com/gam-phon
herenow | https://github.com/herenow
if1live | https://github.com/if1live
lozdog245 | https://github.com/lozdog245
MarkDzulko | https://github.com/MarkDzulko
mshogin | https://github.com/mshogin
soxipy | https://github.com/soxipy
tk42 | https://github.com/tk42

View File

@@ -40,7 +40,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| ItBit | Yes | NA | No |
| Kraken | Yes | Yes | NA |
| Lbank | Yes | No | NA |
| OKCoin International | Yes | Yes | No |
| Okcoin | Yes | Yes | No |
| Okx | Yes | Yes | NA |
| Poloniex | Yes | Yes | NA |
| Yobit | Yes | NA | NA |
@@ -143,13 +143,14 @@ Binaries will be published once the codebase reaches a stable condition.
|User|Contribution Amount|
|--|--|
| [thrasher-](https://github.com/thrasher-) | 675 |
| [shazbert](https://github.com/shazbert) | 273 |
| [gloriousCode](https://github.com/gloriousCode) | 208 |
| [dependabot[bot]](https://github.com/apps/dependabot) | 157 |
| [thrasher-](https://github.com/thrasher-) | 682 |
| [shazbert](https://github.com/shazbert) | 299 |
| [gloriousCode](https://github.com/gloriousCode) | 217 |
| [dependabot[bot]](https://github.com/apps/dependabot) | 202 |
| [dependabot-preview[bot]](https://github.com/apps/dependabot-preview) | 88 |
| [xtda](https://github.com/xtda) | 47 |
| [lrascao](https://github.com/lrascao) | 27 |
| [gbjk](https://github.com/gbjk) | 26 |
| [Rots](https://github.com/Rots) | 15 |
| [vazha](https://github.com/vazha) | 15 |
| [ydm](https://github.com/ydm) | 15 |
@@ -159,24 +160,25 @@ Binaries will be published once the codebase reaches a stable condition.
| [140am](https://github.com/140am) | 8 |
| [marcofranssen](https://github.com/marcofranssen) | 8 |
| [geseq](https://github.com/geseq) | 8 |
| [Beadko](https://github.com/Beadko) | 6 |
| [TaltaM](https://github.com/TaltaM) | 6 |
| [dackroyd](https://github.com/dackroyd) | 5 |
| [cranktakular](https://github.com/cranktakular) | 5 |
| [khcchiu](https://github.com/khcchiu) | 5 |
| [samuael](https://github.com/samuael) | 5 |
| [woshidama323](https://github.com/woshidama323) | 3 |
| [yangrq1018](https://github.com/yangrq1018) | 3 |
| [TaltaM](https://github.com/TaltaM) | 3 |
| [samuael](https://github.com/samuael) | 3 |
| [crackcomm](https://github.com/crackcomm) | 3 |
| [azhang](https://github.com/azhang) | 2 |
| [andreygrehov](https://github.com/andreygrehov) | 2 |
| [bretep](https://github.com/bretep) | 2 |
| [Christian-Achilli](https://github.com/Christian-Achilli) | 2 |
| [MarkDzulko](https://github.com/MarkDzulko) | 2 |
| [gam-phon](https://github.com/gam-phon) | 2 |
| [cornelk](https://github.com/cornelk) | 2 |
| [gam-phon](https://github.com/gam-phon) | 2 |
| [herenow](https://github.com/herenow) | 2 |
| [if1live](https://github.com/if1live) | 2 |
| [lozdog245](https://github.com/lozdog245) | 2 |
| [MarkDzulko](https://github.com/MarkDzulko) | 2 |
| [mshogin](https://github.com/mshogin) | 2 |
| [soxipy](https://github.com/soxipy) | 2 |
| [tk42](https://github.com/tk42) | 2 |

View File

@@ -64,7 +64,7 @@ const (
createCard = "UpdatesCard"
createChecklist = "UpdatesChecklist"
btcMarkets = "BTC Markets"
okcoin = "OkCoin International"
okcoin = "Okcoin"
)
var (

View File

@@ -328,7 +328,7 @@
"Disabled": false
},
{
"Name": "OkCoin International",
"Name": "Okcoin",
"CheckType": "HTML String Check",
"Data": {
"HTMLData": {

View File

@@ -328,7 +328,7 @@
"Disabled": false
},
{
"Name": "OkCoin International",
"Name": "Okcoin",
"CheckType": "HTML String Check",
"Data": {
"HTMLData": {

View File

@@ -178,6 +178,11 @@ func main() {
URL: "https://github.com/cornelk",
Contributions: 2,
},
{
Login: "gam-phon",
URL: "https://github.com/gam-phon",
Contributions: 2,
},
{
Login: "herenow",
URL: "https://github.com/herenow",
@@ -193,6 +198,11 @@ func main() {
URL: "https://github.com/lozdog245",
Contributions: 2,
},
{
Login: "MarkDzulko",
URL: "https://github.com/MarkDzulko",
Contributions: 2,
},
{
Login: "mshogin",
URL: "https://github.com/mshogin",

View File

@@ -63,7 +63,7 @@ _b in this context is an `IBotExchange` implemented struct_
| ItBit | Yes | NA | No |
| Kraken | Yes | Yes | No |
| Lbank | Yes | No | Yes |
| OKCoin International | Yes | Yes | No |
| Okcoin | Yes | Yes | Yes |
| Okx | Yes | Yes | Yes |
| Poloniex | Yes | Yes | Yes |
| Yobit | Yes | NA | No |

View File

@@ -1,6 +1,6 @@
{{define "exchanges okcoin" -}}
{{template "header" .}}
## OKCoin Exchange
## Okcoin Exchange
### Current Features
@@ -31,8 +31,8 @@ main.go
var o exchange.IBotExchange
for i := range bot.Exchanges {
if bot.Exchanges[i].GetName() == "OKCoin" {
y = bot.Exchanges[i]
if bot.Exchanges[i].GetName() == "Okcoin" {
o = bot.Exchanges[i]
}
}

View File

@@ -41,7 +41,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| ItBit | Yes | NA | No |
| Kraken | Yes | Yes | NA |
| Lbank | Yes | No | NA |
| OKCoin International | Yes | Yes | No |
| Okcoin | Yes | Yes | No |
| Okx | Yes | Yes | NA |
| Poloniex | Yes | Yes | NA |
| Yobit | Yes | NA | NA |

View File

@@ -521,10 +521,9 @@ var blockedCIExchanges = []string{
var unsupportedExchangeNames = []string{
"testexch",
"alphapoint",
"bitflyer", // Bitflyer has many "ErrNotYetImplemented, which is true, but not what we care to test for here
"bittrex", // the api is about to expire in March, and we haven't updated it yet
"itbit", // itbit has no way of retrieving pair data
"okcoin international", // TODO add support for v5 and remove this entry
"bitflyer", // Bitflyer has many "ErrNotYetImplemented, which is true, but not what we care to test for here
"bittrex", // the api is about to expire in March, and we haven't updated it yet
"itbit", // itbit has no way of retrieving pair data
}
// cryptoChainPerExchange holds the deposit address chain per exchange

View File

@@ -802,6 +802,8 @@ func (c *Config) CheckExchangeConfigValues() error {
for i := range c.Exchanges {
if strings.EqualFold(c.Exchanges[i].Name, "GDAX") {
c.Exchanges[i].Name = "CoinbasePro"
} else if strings.EqualFold(c.Exchanges[i].Name, "OKCOIN International") {
c.Exchanges[i].Name = "Okcoin"
}
// Check to see if the old API storage format is used

View File

@@ -1343,6 +1343,15 @@ func TestCheckExchangeConfigValues(t *testing.T) {
t.Error("exchange name should have been updated from GDAX to CoinbasePRo")
}
cfg.Exchanges[0].Name = "OKCOIN International"
err = cfg.CheckExchangeConfigValues()
if err != nil {
t.Error(err)
}
if cfg.Exchanges[0].Name != "Okcoin" {
t.Error("exchange name should have been updated from 'OKCOIN International' to 'Okcoin'")
}
// Test API settings migration
sptr := func(s string) *string { return &s }
int64ptr := func(i int64) *int64 { return &i }

View File

@@ -2055,7 +2055,7 @@
]
},
{
"name": "OKCOIN International",
"name": "Okcoin",
"enabled": true,
"verbose": false,
"httpTimeout": 15000000000,
@@ -2075,8 +2075,7 @@
},
"useGlobalFormat": true,
"assetTypes": [
"spot",
"margin"
"spot"
],
"pairs": {
"spot": {

View File

@@ -148,6 +148,7 @@ var (
GXS = NewCode("GXS")
DROP = NewCode("DROP")
MANA = NewCode("MANA")
APE = NewCode("APE")
PAY = NewCode("PAY")
MCO = NewCode("MCO")
THETA = NewCode("THETA")
@@ -986,6 +987,8 @@ var (
INCP = NewCode("INCP")
IN = NewCode("IN")
INC = NewCode("INC")
OneINCH = NewCode("1INCH")
FLR = NewCode("FLR")
IMS = NewCode("IMS")
IFLT = NewCode("IFLT")
INFX = NewCode("INFX")
@@ -1592,6 +1595,7 @@ var (
BWP = NewCode("BWP")
BGN = NewCode("BGN")
BRL = NewCode("BRL")
BRWL = NewCode("BRWL")
BND = NewCode("BND")
KHR = NewCode("KHR")
KYD = NewCode("KYD")
@@ -1675,6 +1679,7 @@ var (
YFI = NewCode("YFI")
BAL = NewCode("BAL")
UMA = NewCode("UMA")
KDA = NewCode("KDA")
SNX = NewCode("SNX")
CRV = NewCode("CRV")
OXT = NewCode("OXT")
@@ -1837,6 +1842,7 @@ var (
IQN = NewCode("IQN")
MNC = NewCode("MNC")
ONE = NewCode("ONE")
USTC = NewCode("USTC")
PRQ = NewCode("PRQ")
ROOBEE = NewCode("ROOBEE")
TONCOIN = NewCode("TONCOIN")
@@ -2220,6 +2226,7 @@ var (
NBOT = NewCode("NBOT")
BEAM = NewCode("BEAM")
MINA = NewCode("MINA")
LUNC = NewCode("LUNC")
ABBC = NewCode("ABBC")
FIC = NewCode("FIC")
STOX = NewCode("STOX")
@@ -2930,6 +2937,7 @@ var (
DON = NewCode("DON")
JUV = NewCode("JUV")
PHA = NewCode("PHA")
SPELL = NewCode("SPELL")
QISWAP = NewCode("QISWAP")
SUNOLD = NewCode("SUNOLD")
ETHBEAR = NewCode("ETHBEAR")

View File

@@ -216,7 +216,7 @@ Yes means supported, No means not yet implemented and NA means protocol unsuppor
| ItBit | Yes | NA | No |
| Kraken | Yes | Yes | NA |
| Lbank | Yes | No | NA |
| OKCoin International | Yes | Yes | No |
| Okcoin | Yes | Yes | No |
| Okx | Yes | Yes | NA |
| Poloniex | Yes | Yes | NA |
| Yobit | Yes | NA | NA |
@@ -246,7 +246,7 @@ var Exchanges = []string{
"itbit",
"kraken",
"lbank",
"okcoin international",
"okcoin",
"okx",
"poloniex",
"yobit",

View File

@@ -64,7 +64,7 @@ $ ./gctcli withdrawcryptofunds --exchange=binance --currency=USDT --address=TJU9
| ItBit | No | No | |
| Kraken | Yes | Yes | Front-end and API don't match total available transfer chains |
| Lbank | No | No | |
| OKCoin International | No | No | Requires API update to version 5 |
| Okcoin | Yes | Yes | |
| Okx | Yes | Yes | |
| Poloniex | Yes | Yes | |
| Yobit | No | No | |

View File

@@ -355,8 +355,7 @@ func TestSettingsPrint(t *testing.T) {
}
var unsupportedDefaultConfigExchanges = []string{
"okcoin international", // due to unsupported API
"itbit", // due to unsupported API
"itbit", // due to unsupported API
}
func TestGetDefaultConfigurations(t *testing.T) {

View File

@@ -198,8 +198,8 @@ func (m *ExchangeManager) NewExchangeByName(name string) (exchange.IBotExchange,
exch = new(kraken.Kraken)
case "lbank":
exch = new(lbank.Lbank)
case "okcoin international":
exch = new(okcoin.OKCoin)
case "okcoin":
exch = new(okcoin.Okcoin)
case "okx":
exch = new(okx.Okx)
case "poloniex":

View File

@@ -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://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk)
## OKCoin Exchange
## Okcoin Exchange
### Current Features
@@ -49,8 +49,8 @@ main.go
var o exchange.IBotExchange
for i := range bot.Exchanges {
if bot.Exchanges[i].GetName() == "OKCoin" {
y = bot.Exchanges[i]
if bot.Exchanges[i].GetName() == "Okcoin" {
o = bot.Exchanges[i]
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
package okcoin
import (
"encoding/json"
"fmt"
"strconv"
"time"
)
type okcoinTime time.Time
// UnmarshalJSON deserializes timestamp information to time.Time
func (o *okcoinTime) UnmarshalJSON(data []byte) error {
var timeMilliSecond interface{}
err := json.Unmarshal(data, &timeMilliSecond)
if err != nil {
return err
}
var timestamp int64
switch value := timeMilliSecond.(type) {
case string:
if value == "" {
*o = okcoinTime(time.Time{}) // in case timestamp information is empty string("") reset okcoinTime to zero.
return nil
}
timestamp, err = strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
case int64:
timestamp = value
case float64:
timestamp = int64(value)
case float32:
timestamp = int64(value)
default:
return fmt.Errorf("cannot unmarshal %T into okcoinTime", value)
}
if timestamp > 9999999999 {
*o = okcoinTime(time.UnixMilli(timestamp))
} else {
*o = okcoinTime(time.Unix(timestamp, 0))
}
return nil
}
// Time returns a time.Time instance from okcoinMilliSec instance
func (o *okcoinTime) Time() time.Time {
return time.Time(*o)
}
type okcoinNumber float64
// UnmarshalJSON a custom JSON deserialization function for numeric values to okcoinNumber instance.
func (a *okcoinNumber) UnmarshalJSON(data []byte) error {
var value interface{}
err := json.Unmarshal(data, &value)
if err != nil {
return err
}
switch val := value.(type) {
case string:
if val == "" {
*a = okcoinNumber(0)
return nil
}
floatValue, err := strconv.ParseFloat(val, 64)
if err != nil {
return err
}
*a = okcoinNumber(floatValue)
case float64:
*a = okcoinNumber(val)
case int64:
*a = okcoinNumber(val)
case int32:
*a = okcoinNumber(int64(val))
}
return nil
}
// Float64 returns a float64 value from okcoinNumber instance.
func (a okcoinNumber) Float64() float64 { return float64(a) }
// Int64 returns a int64 value from okcoinNumber instance.
func (a okcoinNumber) Int64() int64 { return int64(a) }
// String returns string wrapped float64 value from okcoinNumber instance.
func (a okcoinNumber) String() string { return strconv.FormatFloat(float64(a), 'f', -1, 64) }

View File

@@ -0,0 +1,465 @@
package okcoin
import "errors"
// SetErrorDefaults sets the full error default list
func (o *Okcoin) SetErrorDefaults() {
o.ErrorCodes = map[string]error{
"1": errors.New(`operation failed`),
"2": errors.New(`bulk operation partially succeeded`),
"50000": errors.New(`body cannot 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 cannot be empty`),
"50011": errors.New(`requests too frequent`),
"50012": errors.New(`account status invalid`),
"50013": errors.New(`system is busy, please try again later`),
"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`),
"50030": errors.New(`no permission to use this API`),
"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`),
"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`),
"50041": errors.New(`you are not currently on the whitelist, please contact customer service`),
"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" cannot be empty`),
"50104": errors.New(`request header "OK-ACCESS-PASSPHRASE" cannot be empty`),
"50105": errors.New(`request header "OK-ACCESS-PASSPHRASE" incorrect`),
"50106": errors.New(`request header "OK-ACCESS-SIGN" cannot be empty`),
"50107": errors.New(`request header "OK-ACCESS-TIMESTAMP" cannot be empty`),
"50108": errors.New(`exchange ID does not exist`),
"50109": errors.New(`exchange domain does not exist`),
"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`),
"51001": errors.New(`instrument ID does not exist`),
"51003": errors.New(`either client order ID or order ID is required`),
"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})`),
"51008": errors.New(`order failed. insufficient account balance, and the adjusted equity in USD is less than IMR`),
"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`),
"51020": errors.New(`order amount should be greater than the min available amount`),
"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`),
"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`),
"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`),
"51056": errors.New(`action not allowed`),
"51058": errors.New(`no available position for this algo order`),
"51059": errors.New(`strategy for the current state does not support this operation`),
"51101": errors.New(`entered amount exceeds the max pending order amount (Cont) per transaction`),
"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 (Cont) of the underlying asset`),
"51106": errors.New(`entered amount exceeds the max order amount (Cont) of the underlying asset`),
"51107": errors.New(`entered amount exceeds the max holding amount (Cont)`),
"51109": errors.New(`no available offer`),
"51110": errors.New(`you can only place a limit order after call auction has started`),
"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`),
"51117": errors.New(`pending close-orders count exceeds limit`),
"51121": errors.New(`order count should be the integer multiples of the lot size`),
"51124": errors.New(`you can only place limit orders during call auction`),
"51127": errors.New(`available balance is 0`),
"51129": errors.New(`the value of the position and buy order has reached the position limit, and no further buying is allowed`),
"51131": errors.New(`insufficient balance`),
"51132": errors.New(`your position amount is negative and less than the minimum trading amount`),
"51134": errors.New(`closing position failed. Please check your holdings and pending orders`),
"51139": errors.New(`reduce-only feature is unavailable for the spot transactions by simple account`),
"51143": errors.New(`there is no valid quotation in the market, and the order cannot be filled in USDT mode, please try to switch to currency mode`),
"51148": errors.New(`reduce-only 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`),
"51204": errors.New(`the price for the limit order cannot be empty`),
"51205": errors.New(`reduce-only is not available`),
"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 amount 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`),
"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`),
"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%`),
"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 cannot exceed the upper limit`),
"51276": errors.New(`stop - Market orders cannot specify a price`),
"51277": errors.New(`tp trigger price cannot be higher than the last price`),
"51278": errors.New(`sl trigger price cannot be lower than the last price`),
"51279": errors.New(`tp trigger price cannot be lower than the last price`),
"51280": errors.New(`sl trigger price cannot be higher than the last price`),
"51281": errors.New(`trigger not support the tgtCcy parameter`),
"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`),
"51300": errors.New(`tp trigger price cannot be higher than the mark price`),
"51302": errors.New(`sl trigger price cannot be lower than the mark price`),
"51303": errors.New(`tp trigger price cannot be lower than the mark price`),
"51304": errors.New(`sl trigger price cannot be higher than the mark price`),
"51305": errors.New(`tp trigger price cannot be higher than the index price`),
"51306": errors.New(`sl trigger price cannot be lower than the index price`),
"51307": errors.New(`tp trigger price cannot be lower than the index price`),
"51308": errors.New(`sl trigger price cannot be higher than the index price`),
"51309": errors.New(`cannot create trading bot during call auction`),
"51313": errors.New(`manual transfer in isolated mode does not support bot trading`),
"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 loss price should be less than the lower 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`),
"51400": errors.New(`cancelation failed as the order does not exist`),
"51401": errors.New(`cancelation failed as the order is already canceled`),
"51402": errors.New(`cancelation failed as the order is already completed`),
"51403": errors.New(`cancelation failed as the order type does not support cancelation`),
"51404": errors.New(`order cancellation unavailable during the second phase of call auction`),
"51405": errors.New(`cancelation failed as you do not have any pending orders`),
"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(`cancelation pending. duplicate order rejected`),
"51411": errors.New(`account does not have permission for mass cancelation`),
"51412": errors.New(`the order has been triggered and cannot be canceled`),
"51413": errors.New(`cancelation 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`),
"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 orders in batches. you cannot have duplicate orders in the same amend-batch-orders request`),
"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`),
"52000": errors.New(`no market data found`),
"54000": errors.New(`margin trading is not supported`),
"58002": errors.New(`please activate Savings Account first`),
"58003": errors.New(`currency type is not supported by Savings Account`),
"58004": errors.New(`account blocked`),
"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`),
"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`),
"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`),
"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`),
"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`),
"58123": errors.New(`parameter from cannot equal to parameter to`),
"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 less 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)`),
"58213": errors.New(`please set a trading password before withdrawing`),
"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(`temporarily unable to process withdrawal address`),
"58224": errors.New(`this type of coin does not support on-chain withdrawals. please use internal transfers`),
"58300": errors.New(`deposit-address count exceeds the limit`),
"58301": errors.New(`deposit-address not exist`),
"58302": errors.New(`deposit-address needs tag`),
"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 10,000 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`),
"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`),
"59000": errors.New(`your settings failed as you have positions or open orders`),
"59002": errors.New(`sub-account settings failed as it has positions, open orders, or trading bots`),
"59004": errors.New(`only ids with the same instrument type are supported`),
"59200": errors.New(`insufficient account balance`),
"59201": errors.New(`negative account balance`),
"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`),
"59510": errors.New(`sub-account does not exist`),
"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`),
"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`),
}
}
var websocketErrorCodes = map[string]string{
"1": "Operation failed.",
"2": "Bulk operation partially succeeded.",
"50000": "Body cannot be empty.",
"50001": "Service temporarily unavailable, please try again later.",
"50002": "Json data format error.",
"50004": "Endpoint request timeout (does not mean that the request was successful or failed, please check the request result).",
"50005": "API is offline or unavailable.",
"50006": "Invalid Content_Type, please use 'application/json' format.",
"50007": "Account blocked.",
"50008": "User does not exist.",
"50009": "Account is suspended due to ongoing liquidation.",
"50010": "User ID cannot be empty.",
"50011": "Requests too frequent.",
"50012": "Account status invalid.",
"50013": "System is busy, please try again later.",
"50026": "System error, please try again later.",
"50027": "The account is restricted from trading.",
"50028": "Unable to take the order, please reach out to support center for details.",
"50030": "No permission to use this API",
"50032": "This asset is blocked, allow its trading and try again",
"50033": "This instrument is blocked, allow its trading and try again",
"50035": "This endpoint requires that APIKey must be bound to IP",
"50036": "Invalid expTime",
"50037": "Order expired",
"50038": "This feature is temporarily unavailable in demo trading",
"50039": "The before parameter is not available for implementing timestamp pagination",
"50041": "You are not currently on the whitelist, please contact customer service",
"50100": `API frozen, please contact customer service`,
"50101": `APIKey does not match current environment`,
"50102": `Timestamp request expired`,
"50103": `Request header "OK-ACCESS-KEY" cannot be empty`,
"50104": `Request header "OK-ACCESS-PASSPHRASE" cannot be empty`,
"50105": `Request header "OK-ACCESS-PASSPHRASE" incorrect`,
"50106": `Request header "OK-ACCESS-SIGN" cannot be empty`,
"50107": `Request header "OK-ACCESS-TIMESTAMP" cannot be empty`,
"50108": `Exchange ID does not exist`,
"50109": `Exchange domain does not exist`,
"50111": `Invalid OK-ACCESS-KEY`,
"50112": `Invalid OK-ACCESS-TIMESTAMP`,
"50113": `Invalid signature`,
"50114": `Invalid authorization`,
"50115": `Invalid request method`,
"51001": `Instrument ID does not exist`,
"51003": `Either client order ID or order ID is required`,
"51005": `Order amount exceeds the limit`,
"51009": `Order placement function is blocked by the platform`,
"51010": `Operation is not supported under the current account mode`,
"51011": `Duplicated order ID`,
"51012": `Token does not exist`,
"51014": `Index does not exist`,
"51015": `Instrument ID does not match instrument type`,
"51016": `Duplicated client order ID`,
"51020": `Order amount should be greater than the min available amount`,
"51023": `Position does not exist`,
"51024": `Trading account is blocked`,
"51025": `Order count exceeds the limit`,
"51026": `Instrument type does not match underlying index`,
"51030": `Funding fee is being settled`,
"51031": `This order price is not within the closing price range`,
"51032": `Closing all positions at market price`,
"51033": `The total amount per order for this pair has reached the upper limit`,
"51037": `The current account risk status only supports you to place IOC orders that can reduce the risk of your account`,
"51038": `There is already an IOC order under the current risk module that reduces the risk of the account`,
"51046": `The take profit trigger price should be higher than the order price`,
"51047": `The stop loss trigger price should be lower than the order price`,
"51048": `The take profit trigger price should be lower than the order price`,
"51049": `The stop loss trigger price should be higher than the order price`,
"51050": `The take profit trigger price should be higher than the best ask price`,
"51051": `The stop loss trigger price should be lower than the best ask price`,
"51052": `The take profit trigger price should be lower than the best bid price`,
"51053": `The stop loss trigger price should be higher than the best bid price`,
"51054": `Getting information timed out, please try again later`,
"51056": `Action not allowed`,
"51058": `No available position for this algo order`,
"51059": `Strategy for the current state does not support this operation`,
"51101": `Entered amount exceeds the max pending order amount (Cont) per transaction`,
"51103": `Entered amount exceeds the max pending order count of the underlying asset`,
"51104": `Entered amount exceeds the max pending order amount (Cont) of the underlying asset`,
"51106": `Entered amount exceeds the max order amount (Cont) of the underlying asset`,
"51107": `Entered amount exceeds the max holding amount (Cont)`,
"51109": `No available offer`,
"51110": `You can only place a limit order after Call Auction has started`,
"51112": `Close order size exceeds your available size`,
"51113": `Market-price liquidation requests too frequent`,
"51115": `Cancel all pending close-orders before liquidation`,
"51117": `Pending close-orders count exceeds limit`,
"51121": `Order count should be the integer multiples of the lot size`,
"51124": `You can only place limit orders during call auction`,
"51127": `Available balance is 0`,
"51129": `The value of the position and buy order has reached the position limit, and no further buying is allowed`,
"51131": `Insufficient balance`,
"51132": `Your position amount is negative and less than the minimum trading amount`,
"51134": `Closing position failed. Please check your holdings and pending orders`,
"51139": `Reduce-only feature is unavailable for the spot transactions by simple account`,
"51143": `There is no valid quotation in the market, and the order cannot be filled in USDT mode, please try to switch to currency mode`,
"51148": `ReduceOnly cannot increase the position quantity`,
"51149": `Order timed out, please try again later`,
"51150": `The precision of the number of trades or the price exceeds the limit`,
"51201": `Value of per market order cannot exceed 1,000,000 USDT`,
"51202": `Market - order amount exceeds the max amount`,
"51204": `The price for the limit order cannot be empty`,
"51205": `Reduce-Only is not available`,
"51250": `Algo order price is out of the available range`,
"51251": `Algo order type error (when user place an iceberg order)`,
"51252": `Algo order amount is out of the available range`,
"51253": `Average amount exceeds the limit of per iceberg order`,
"51254": `Iceberg average amount error (when user place an iceberg order)`,
"51255": `Limit of per iceberg order: Total amount/1000 < x <= Total amount`,
"51256": `Iceberg order price variance error`,
"51257": `Trail order callback rate error`,
"51258": `Trail - order placement failed. The trigger price of a sell order should be higher than the last transaction price`,
"51259": `Trail - order placement failed. The trigger price of a buy order should be lower than the last transaction price`,
"51264": `Average amount exceeds the limit of per time-weighted order`,
"51265": `Time-weighted order limit error`,
"51267": `Time-weighted order strategy initiative rate error`,
"51268": `Time-weighted order strategy initiative range error`,
"51270": `The limit of time-weighted order price variance is 0 < x <= 1%`,
"51271": `Sweep ratio should be 0 < x <= 100%`,
"51272": `Price variance should be 0 < x <= 1%`,
"51274": `Total quantity of time-weighted order must be larger than single order limit`,
"51275": `The amount of single stop-market order cannot exceed the upper limit`,
"51276": `Stop - Market orders cannot specify a price`,
"51277": `TP trigger price cannot be higher than the last price`,
"51278": `SL trigger price cannot be lower than the last price`,
"51279": `TP trigger price cannot be lower than the last price`,
"51280": `SL trigger price cannot be higher than the last price`,
"51281": `trigger not support the tgtCcy parameter`,
"51288": `We are stopping the Bot. Please do not click it multiple times`,
"51289": `Bot configuration does not exist. Please try again later`,
"51290": `The Bot engine is being upgraded. Please try again later`,
"51291": `This Bot does not exist or has been stopped`,
"51292": `This Bot type does not exist`,
"51293": `This Bot does not exist`,
"51294": `This Bot cannot be created temporarily. Please try again later`,
"51300": `TP trigger price cannot be higher than the mark price`,
"51302": `SL trigger price cannot be lower than the mark price`,
"51303": `TP trigger price cannot be lower than the mark price`,
"51304": `SL trigger price cannot be higher than the mark price`,
"51305": `TP trigger price cannot be higher than the index price`,
"51306": `SL trigger price cannot be lower than the index price`,
"51307": `TP trigger price cannot be lower than the index price`,
"51308": `SL trigger price cannot be higher than the index price`,
"51309": `Cannot create trading bot during call auction`,
"51313": `Manual transfer in isolated mode does not support bot trading`,
"51341": `Position closing not allowed`,
"51342": `Closing order already exists. Please try again later`,
"51343": `TP price must be less than the lower price`,
"51344": `SL price must be greater than the upper price`,
"51345": `Policy type is not grid policy`,
"51346": `The highest price cannot be lower than the lowest price`,
"51347": `No profit available`,
"51348": `Stop loss price should be less than the lower price in the range`,
"51349": `Stop profit price should be greater than the highest price in the range`,
"51350": `No recommended parameters`,
"51351": `Single income must be greater than 0`,
"51400": `cancellation failed as the order does not exist`,
"51401": `cancellation failed as the order is already canceled`,
"51402": `cancellation failed as the order is already completed`,
"51403": `cancellation failed as the order type does not support cancellation`,
"51404": `Order cancellation unavailable during the second phase of call auction`,
"51405": `cancellation failed as you do not have any pending orders`,
"51407": `Either order ID or client order ID is required`,
"51408": `Pair ID or name does not match the order info`,
"51409": `Either pair ID or pair name ID is required`,
"51410": `cancellation pending. Duplicate order rejected`,
"51411": `Account does not have permission for mass cancellation`,
"51412": `The order has been triggered and cannot be canceled`,
"51413": `cancellation failed as the order type is not supported by endpoint`,
"51415": `Unable to place order. Spot trading only supports using the last price as trigger price. Please select "Last" and try again`,
"51500": `Either order price or amount is required`,
"51503": `Order modification failed as the order does not exist`,
"51506": `Order modification unavailable for the order type`,
"51508": `Orders are not allowed to be modified during the call auction`,
"51509": `Modification failed as the order has been canceled`,
"51510": `Modification failed as the order has been completed`,
"51511": `Operation failed as the order price did not meet the requirement for Post Only`,
"51512": `Failed to amend orders in batches. You cannot have duplicate orders in the same amend-batch-orders request`,
"51513": `Number of modification requests that are currently in progress for an order cannot exceed 3`,
"51600": `Status not found`,
"51601": `Order status and order ID cannot exist at the same time`,
"51602": `Either order status or order ID is required`,
"51603": `Order does not exist`,
"51607": `The file is generating`,
}

View File

@@ -0,0 +1,461 @@
package okcoin
import (
"context"
"errors"
"time"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"golang.org/x/time/rate"
)
// Interval instances
const (
oneSecondInterval = time.Second
twoSecondsInterval = time.Second * 2
fiveSecondsInterval = time.Second * 5
)
// RateLimit implementa a rate Limiter
type RateLimit struct {
PlaceTradeOrder *rate.Limiter
PlaceTradeMultipleOrders *rate.Limiter
CancelTradeOrder *rate.Limiter
CancelMultipleOrder *rate.Limiter
AmendTradeOrder *rate.Limiter
AmendMultipleOrders *rate.Limiter
GetOrderDetails *rate.Limiter
GetOrderList *rate.Limiter
GetOrderHistory *rate.Limiter
GetOrderhistory3Months *rate.Limiter
GetTransactionDetails3Days *rate.Limiter
GetTransactionDetails3Months *rate.Limiter
PlaceAlgoOrder *rate.Limiter
CancelAlgoOrder *rate.Limiter
CancelAdvancedAlgoOrder *rate.Limiter
GetAlgoOrderList *rate.Limiter
GetAlgoOrderHistory *rate.Limiter
GetFundingCurrencies *rate.Limiter
GetFundingAccountBalance *rate.Limiter
GetAccountAssetValuation *rate.Limiter
FundingTransfer *rate.Limiter
GetFundsTransferState *rate.Limiter
AssetBillsDetail *rate.Limiter
LightningDeposits *rate.Limiter
GetAssetDepositAddress *rate.Limiter
GetDepositHistory *rate.Limiter
PostWithdrawal *rate.Limiter
PostLightningWithdrawal *rate.Limiter
CancelWithdrawal *rate.Limiter
GetAssetWithdrawalHistory *rate.Limiter
GetAccountBalance *rate.Limiter
GetBillsDetailLast3Month *rate.Limiter
GetBillsDetail *rate.Limiter
GetAccountConfiguration *rate.Limiter
GetMaxBuySellAmountOpenAmount *rate.Limiter
GetMaxAvailableTradableAmount *rate.Limiter
GetFeeRates *rate.Limiter
GetMaxWithdrawals *rate.Limiter
GetAvailablePairs *rate.Limiter
RequestQuotes *rate.Limiter
PlaceRFQOrder *rate.Limiter
GetRFQTradeOrderDetails *rate.Limiter
GetRFQTradeOrderHistory *rate.Limiter
FiatDepositRate *rate.Limiter
FiatCancelDepositRate *rate.Limiter
FiatDepositHistoryRate *rate.Limiter
FiatWithdrawalRate *rate.Limiter
FiatCancelWithdrawalRate *rate.Limiter
FiatGetWithdrawalsRate *rate.Limiter
FiatGetChannelInfoRate *rate.Limiter
SubAccountsList *rate.Limiter
GetAPIKeyOfASubAccount *rate.Limiter
GetSubAccountTradingBalance *rate.Limiter
GetSubAccountFundingBalance *rate.Limiter
SubAccountTransferHistory *rate.Limiter
MasterAccountsManageTransfersBetweenSubaccount *rate.Limiter
GetTickers *rate.Limiter
GetTicker *rate.Limiter
GetOrderbook *rate.Limiter
GetCandlesticks *rate.Limiter
GetCandlestickHistory *rate.Limiter
GetPublicTrades *rate.Limiter
GetPublicTradeHistrory *rate.Limiter
Get24HourTradingVolume *rate.Limiter
GetOracle *rate.Limiter
GetExchangeRate *rate.Limiter
GetInstrumentsRate *rate.Limiter
GetSystemTimeRate *rate.Limiter
GetSystemStatusRate *rate.Limiter
}
// Rate of requests per interval for each end point
const (
placeTradeOrderRate = 60
placeTradeMultipleOrdersRate = 300
cancelTradeOrderRate = 60
cancelMultipleOrderRate = 300
amendTradeOrderRate = 60
amendMultipleOrdersRate = 300
getOrderDetailsRate = 60
getOrderListRate = 60
getOrderHistoryRate = 40
getOrderhistory3MonthsRate = 20
getTransactionDetails3DaysRate = 60
getTransactionDetails3MonthsRate = 10
placeAlgoOrderRate = 20
cancelAlgoOrderRate = 20
cancelAdvancedAlgoOrderRate = 20
getAlgoOrderListRate = 20
getAlgoOrderHistoryRate = 20
getFundingCurrenciesRate = 6
getFundingAccountBalanceRate = 6
getAccountAssetValuationRate = 1
fundingTransferRate = 1
getFundsTransferStateRate = 1
assetBillsDetailRate = 6
lightningDepositsRate = 2
getAssetDepositAddressRate = 6
getDepositHistoryRate = 6
postWithdrawalRate = 6
postLightningWithdrawalRate = 2
cancelWithdrawalRate = 6
getAssetWithdrawalHistoryRate = 6
getAccountBalanceRate = 10
getBillsDetailLast3MonthRate = 6
getBillsDetailRate = 6
getAccountConfigurationRate = 5
getMaxBuySellAmountOpenAmountRate = 20
getMaxAvailableTradableAmountRate = 20
getFeeRatesRate = 5
getMaxWithdrawalsRate = 20
getAvailablePairsRate = 6
requestQuotesRate = 3
placeRFQOrderRate = 3
getRFQTradeOrderDetailsRate = 6
getRFQTradeOrderHistoryRate = 6
fiatDepositRate = 6
fiatCancelDepositRate = 100
fiatDepositHistoryRate = 6
fiatWithdrawalRate = 6
fiatCancelWithdrawalRate = 100
fiatGetWithdrawalsRate = 6
fiatGetChannelInfoRate = 6
subAccountsListRate = 2
getAPIKeyOfASubAccountRate = 1
getSubAccountTradingBalanceRate = 2
getSubAccountFundingBalanceRate = 2
subAccountTransferHistoryRate = 6
masterAccountsManageTransfersBetweenSubaccountRate = 1
getTickersRate = 20
getTickerRate = 20
getOrderbookRate = 20
getCandlesticksRate = 40
getCandlestickHistoryRate = 20
getPublicTradesRate = 100
getPublicTradeHistroryRate = 10
get24HourTradingVolumeRate = 2
getOracleRate = 1
getExchangeRateRate = 1
getInstrumentsRate = 20
getSystemTimeRate = 10
getSystemStatusRate = 1
)
const (
placeTradeOrderEPL request.EndpointLimit = iota
placeTradeMultipleOrdersEPL
cancelTradeOrderEPL
cancelMultipleOrderEPL
amendTradeOrderEPL
amendMultipleOrdersEPL
getOrderDetailsEPL
getOrderListEPL
getOrderHistoryEPL
getOrderhistory3MonthsEPL
getTransactionDetails3DaysEPL
getTransactionDetails3MonthsEPL
placeAlgoOrderEPL
cancelAlgoOrderEPL
cancelAdvancedAlgoOrderEPL
getAlgoOrderListEPL
getAlgoOrderHistoryEPL
getFundingCurrenciesEPL
getFundingAccountBalanceEPL
getAccountAssetValuationEPL
fundingTransferEPL
getFundsTransferStateEPL
assetBillsDetailEPL
lightningDepositsEPL
getAssetDepositAddressEPL
getDepositHistoryEPL
postWithdrawalEPL
postLightningWithdrawalEPL
cancelWithdrawalEPL
getAssetWithdrawalHistoryEPL
getAccountBalanceEPL
getBillsDetailLast3MonthEPL
getBillsDetailEPL
getAccountConfigurationEPL
getMaxBuySellAmountOpenAmountEPL
getMaxAvailableTradableAmountEPL
getFeeRatesEPL
getMaxWithdrawalsEPL
getAvailablePairsEPL
requestQuotesEPL
placeRFQOrderEPL
getRFQTradeOrderDetailsEPL
getRFQTradeOrderHistoryEPL
fiatDepositEPL
fiatCancelDepositEPL
fiatDepositHistoryEPL
fiatWithdrawalEPL
fiatCancelWithdrawalEPL
fiatGetWithdrawalsEPL
fiatGetChannelInfoEPL
subAccountsListEPL
getAPIKeyOfASubAccountEPL
getSubAccountTradingBalanceEPL
getSubAccountFundingBalanceEPL
subAccountTransferHistoryEPL
masterAccountsManageTransfersBetweenSubaccountEPL
getTickersEPL
getTickerEPL
getOrderbookEPL
getCandlesticksEPL
getCandlestickHistoryEPL
getPublicTradesEPL
getPublicTradeHistroryEPL
get24HourTradingVolumeEPL
getOracleEPL
getExchangeRateEPL
getInstrumentsEPL
getSystemTimeEPL
getSystemStatusEPL
)
// Limit implements an endpoint limit.
func (r *RateLimit) Limit(ctx context.Context, ep request.EndpointLimit) error {
switch ep {
case placeTradeOrderEPL:
return r.PlaceTradeOrder.Wait(ctx)
case placeTradeMultipleOrdersEPL:
return r.PlaceTradeMultipleOrders.Wait(ctx)
case cancelTradeOrderEPL:
return r.CancelTradeOrder.Wait(ctx)
case cancelMultipleOrderEPL:
return r.CancelMultipleOrder.Wait(ctx)
case amendTradeOrderEPL:
return r.AmendTradeOrder.Wait(ctx)
case amendMultipleOrdersEPL:
return r.AmendMultipleOrders.Wait(ctx)
case getOrderDetailsEPL:
return r.GetOrderDetails.Wait(ctx)
case getOrderListEPL:
return r.GetOrderList.Wait(ctx)
case getOrderHistoryEPL:
return r.GetOrderHistory.Wait(ctx)
case getOrderhistory3MonthsEPL:
return r.GetOrderhistory3Months.Wait(ctx)
case getTransactionDetails3DaysEPL:
return r.GetTransactionDetails3Days.Wait(ctx)
case getTransactionDetails3MonthsEPL:
return r.GetTransactionDetails3Months.Wait(ctx)
case placeAlgoOrderEPL:
return r.PlaceAlgoOrder.Wait(ctx)
case cancelAlgoOrderEPL:
return r.CancelAlgoOrder.Wait(ctx)
case cancelAdvancedAlgoOrderEPL:
return r.CancelAdvancedAlgoOrder.Wait(ctx)
case getAlgoOrderListEPL:
return r.GetAlgoOrderList.Wait(ctx)
case getAlgoOrderHistoryEPL:
return r.GetAlgoOrderHistory.Wait(ctx)
case getFundingCurrenciesEPL:
return r.GetFundingCurrencies.Wait(ctx)
case getFundingAccountBalanceEPL:
return r.GetFundingAccountBalance.Wait(ctx)
case getAccountAssetValuationEPL:
return r.GetAccountAssetValuation.Wait(ctx)
case fundingTransferEPL:
return r.FundingTransfer.Wait(ctx)
case getFundsTransferStateEPL:
return r.GetFundsTransferState.Wait(ctx)
case assetBillsDetailEPL:
return r.AssetBillsDetail.Wait(ctx)
case lightningDepositsEPL:
return r.LightningDeposits.Wait(ctx)
case getAssetDepositAddressEPL:
return r.GetAssetDepositAddress.Wait(ctx)
case getDepositHistoryEPL:
return r.GetDepositHistory.Wait(ctx)
case postWithdrawalEPL:
return r.PostWithdrawal.Wait(ctx)
case postLightningWithdrawalEPL:
return r.PostLightningWithdrawal.Wait(ctx)
case cancelWithdrawalEPL:
return r.CancelWithdrawal.Wait(ctx)
case getAssetWithdrawalHistoryEPL:
return r.GetAssetWithdrawalHistory.Wait(ctx)
case getAccountBalanceEPL:
return r.GetAccountBalance.Wait(ctx)
case getBillsDetailLast3MonthEPL:
return r.GetBillsDetailLast3Month.Wait(ctx)
case getBillsDetailEPL:
return r.GetBillsDetail.Wait(ctx)
case getAccountConfigurationEPL:
return r.GetAccountConfiguration.Wait(ctx)
case getMaxBuySellAmountOpenAmountEPL:
return r.GetMaxBuySellAmountOpenAmount.Wait(ctx)
case getMaxAvailableTradableAmountEPL:
return r.GetMaxAvailableTradableAmount.Wait(ctx)
case getFeeRatesEPL:
return r.GetFeeRates.Wait(ctx)
case getMaxWithdrawalsEPL:
return r.GetMaxWithdrawals.Wait(ctx)
case getAvailablePairsEPL:
return r.GetAvailablePairs.Wait(ctx)
case requestQuotesEPL:
return r.RequestQuotes.Wait(ctx)
case placeRFQOrderEPL:
return r.PlaceRFQOrder.Wait(ctx)
case getRFQTradeOrderDetailsEPL:
return r.GetRFQTradeOrderDetails.Wait(ctx)
case getRFQTradeOrderHistoryEPL:
return r.GetRFQTradeOrderHistory.Wait(ctx)
case fiatDepositEPL:
return r.FiatDepositRate.Wait(ctx)
case fiatCancelDepositEPL:
return r.FiatCancelDepositRate.Wait(ctx)
case fiatDepositHistoryEPL:
return r.FiatDepositHistoryRate.Wait(ctx)
case fiatWithdrawalEPL:
return r.FiatWithdrawalRate.Wait(ctx)
case fiatCancelWithdrawalEPL:
return r.FiatCancelWithdrawalRate.Wait(ctx)
case fiatGetWithdrawalsEPL:
return r.FiatGetWithdrawalsRate.Wait(ctx)
case fiatGetChannelInfoEPL:
return r.FiatGetChannelInfoRate.Wait(ctx)
case subAccountsListEPL:
return r.SubAccountsList.Wait(ctx)
case getAPIKeyOfASubAccountEPL:
return r.GetAPIKeyOfASubAccount.Wait(ctx)
case getSubAccountTradingBalanceEPL:
return r.GetSubAccountTradingBalance.Wait(ctx)
case getSubAccountFundingBalanceEPL:
return r.GetSubAccountFundingBalance.Wait(ctx)
case subAccountTransferHistoryEPL:
return r.SubAccountTransferHistory.Wait(ctx)
case masterAccountsManageTransfersBetweenSubaccountEPL:
return r.MasterAccountsManageTransfersBetweenSubaccount.Wait(ctx)
case getTickersEPL:
return r.GetTickers.Wait(ctx)
case getTickerEPL:
return r.GetTicker.Wait(ctx)
case getOrderbookEPL:
return r.GetOrderbook.Wait(ctx)
case getCandlesticksEPL:
return r.GetCandlesticks.Wait(ctx)
case getCandlestickHistoryEPL:
return r.GetCandlestickHistory.Wait(ctx)
case getPublicTradesEPL:
return r.GetPublicTrades.Wait(ctx)
case getPublicTradeHistroryEPL:
return r.GetPublicTradeHistrory.Wait(ctx)
case get24HourTradingVolumeEPL:
return r.Get24HourTradingVolume.Wait(ctx)
case getOracleEPL:
return r.GetOracle.Wait(ctx)
case getExchangeRateEPL:
return r.GetExchangeRate.Wait(ctx)
case getInstrumentsEPL:
return r.GetInstrumentsRate.Wait(ctx)
case getSystemTimeEPL:
return r.GetSystemTimeRate.Wait(ctx)
case getSystemStatusEPL:
return r.GetSystemStatusRate.Wait(ctx)
default:
return errors.New("unknown endpoint limit")
}
}
// SetRateLimit returns a new RateLimit instance which implements request.Limiter interface.
func SetRateLimit() *RateLimit {
return &RateLimit{
PlaceTradeOrder: request.NewRateLimit(twoSecondsInterval, placeTradeOrderRate),
PlaceTradeMultipleOrders: request.NewRateLimit(twoSecondsInterval, placeTradeMultipleOrdersRate),
CancelTradeOrder: request.NewRateLimit(twoSecondsInterval, cancelTradeOrderRate),
CancelMultipleOrder: request.NewRateLimit(twoSecondsInterval, cancelMultipleOrderRate),
AmendTradeOrder: request.NewRateLimit(twoSecondsInterval, amendTradeOrderRate),
AmendMultipleOrders: request.NewRateLimit(twoSecondsInterval, amendMultipleOrdersRate),
GetOrderDetails: request.NewRateLimit(twoSecondsInterval, getOrderDetailsRate),
GetOrderList: request.NewRateLimit(twoSecondsInterval, getOrderListRate),
GetOrderHistory: request.NewRateLimit(twoSecondsInterval, getOrderHistoryRate),
GetOrderhistory3Months: request.NewRateLimit(twoSecondsInterval, getOrderhistory3MonthsRate),
GetTransactionDetails3Days: request.NewRateLimit(twoSecondsInterval, getTransactionDetails3DaysRate),
GetTransactionDetails3Months: request.NewRateLimit(twoSecondsInterval, getTransactionDetails3MonthsRate),
PlaceAlgoOrder: request.NewRateLimit(twoSecondsInterval, placeAlgoOrderRate),
CancelAlgoOrder: request.NewRateLimit(twoSecondsInterval, cancelAlgoOrderRate),
CancelAdvancedAlgoOrder: request.NewRateLimit(twoSecondsInterval, cancelAdvancedAlgoOrderRate),
GetAlgoOrderList: request.NewRateLimit(twoSecondsInterval, getAlgoOrderListRate),
GetAlgoOrderHistory: request.NewRateLimit(twoSecondsInterval, getAlgoOrderHistoryRate),
GetFundingCurrencies: request.NewRateLimit(oneSecondInterval, getFundingCurrenciesRate),
GetFundingAccountBalance: request.NewRateLimit(oneSecondInterval, getFundingAccountBalanceRate),
GetAccountAssetValuation: request.NewRateLimit(twoSecondsInterval, getAccountAssetValuationRate),
FundingTransfer: request.NewRateLimit(oneSecondInterval, fundingTransferRate),
GetFundsTransferState: request.NewRateLimit(oneSecondInterval, getFundsTransferStateRate),
AssetBillsDetail: request.NewRateLimit(oneSecondInterval, assetBillsDetailRate),
LightningDeposits: request.NewRateLimit(oneSecondInterval, lightningDepositsRate),
GetAssetDepositAddress: request.NewRateLimit(oneSecondInterval, getAssetDepositAddressRate),
GetDepositHistory: request.NewRateLimit(oneSecondInterval, getDepositHistoryRate),
PostWithdrawal: request.NewRateLimit(oneSecondInterval, postWithdrawalRate),
PostLightningWithdrawal: request.NewRateLimit(oneSecondInterval, postLightningWithdrawalRate),
CancelWithdrawal: request.NewRateLimit(oneSecondInterval, cancelWithdrawalRate),
GetAssetWithdrawalHistory: request.NewRateLimit(oneSecondInterval, getAssetWithdrawalHistoryRate),
GetAccountBalance: request.NewRateLimit(twoSecondsInterval, getAccountBalanceRate),
GetBillsDetailLast3Month: request.NewRateLimit(oneSecondInterval, getBillsDetailLast3MonthRate),
GetBillsDetail: request.NewRateLimit(oneSecondInterval, getBillsDetailRate),
GetAccountConfiguration: request.NewRateLimit(twoSecondsInterval, getAccountConfigurationRate),
GetMaxBuySellAmountOpenAmount: request.NewRateLimit(twoSecondsInterval, getMaxBuySellAmountOpenAmountRate),
GetMaxAvailableTradableAmount: request.NewRateLimit(twoSecondsInterval, getMaxAvailableTradableAmountRate),
GetFeeRates: request.NewRateLimit(twoSecondsInterval, getFeeRatesRate),
GetMaxWithdrawals: request.NewRateLimit(twoSecondsInterval, getMaxWithdrawalsRate),
GetAvailablePairs: request.NewRateLimit(oneSecondInterval, getAvailablePairsRate),
RequestQuotes: request.NewRateLimit(oneSecondInterval, requestQuotesRate),
PlaceRFQOrder: request.NewRateLimit(oneSecondInterval, placeRFQOrderRate),
GetRFQTradeOrderDetails: request.NewRateLimit(oneSecondInterval, getRFQTradeOrderDetailsRate),
GetRFQTradeOrderHistory: request.NewRateLimit(oneSecondInterval, getRFQTradeOrderHistoryRate),
FiatDepositRate: request.NewRateLimit(oneSecondInterval, fiatDepositRate),
FiatCancelDepositRate: request.NewRateLimit(twoSecondsInterval, fiatCancelDepositRate),
FiatDepositHistoryRate: request.NewRateLimit(oneSecondInterval, fiatDepositHistoryRate),
FiatWithdrawalRate: request.NewRateLimit(oneSecondInterval, fiatWithdrawalRate),
FiatCancelWithdrawalRate: request.NewRateLimit(twoSecondsInterval, fiatCancelWithdrawalRate),
FiatGetWithdrawalsRate: request.NewRateLimit(oneSecondInterval, fiatGetWithdrawalsRate),
FiatGetChannelInfoRate: request.NewRateLimit(oneSecondInterval, fiatGetChannelInfoRate),
SubAccountsList: request.NewRateLimit(twoSecondsInterval, subAccountsListRate),
GetAPIKeyOfASubAccount: request.NewRateLimit(oneSecondInterval, getAPIKeyOfASubAccountRate),
GetSubAccountTradingBalance: request.NewRateLimit(twoSecondsInterval, getSubAccountTradingBalanceRate),
GetSubAccountFundingBalance: request.NewRateLimit(twoSecondsInterval, getSubAccountFundingBalanceRate),
SubAccountTransferHistory: request.NewRateLimit(oneSecondInterval, subAccountTransferHistoryRate),
MasterAccountsManageTransfersBetweenSubaccount: request.NewRateLimit(oneSecondInterval, masterAccountsManageTransfersBetweenSubaccountRate),
GetTickers: request.NewRateLimit(twoSecondsInterval, getTickersRate),
GetTicker: request.NewRateLimit(twoSecondsInterval, getTickerRate),
GetOrderbook: request.NewRateLimit(twoSecondsInterval, getOrderbookRate),
GetCandlesticks: request.NewRateLimit(twoSecondsInterval, getCandlesticksRate),
GetCandlestickHistory: request.NewRateLimit(twoSecondsInterval, getCandlestickHistoryRate),
GetPublicTrades: request.NewRateLimit(twoSecondsInterval, getPublicTradesRate),
GetPublicTradeHistrory: request.NewRateLimit(twoSecondsInterval, getPublicTradeHistroryRate),
Get24HourTradingVolume: request.NewRateLimit(twoSecondsInterval, get24HourTradingVolumeRate),
GetOracle: request.NewRateLimit(fiveSecondsInterval, getOracleRate),
GetExchangeRate: request.NewRateLimit(twoSecondsInterval, getExchangeRateRate),
GetInstrumentsRate: request.NewRateLimit(twoSecondsInterval, getInstrumentsRate),
GetSystemTimeRate: request.NewRateLimit(twoSecondsInterval, getSystemTimeRate),
GetSystemStatusRate: request.NewRateLimit(fiveSecondsInterval, getSystemStatusRate),
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
package okcoin
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
)
// WsPlaceOrder place trade order through the websocket channel.
func (o *Okcoin) WsPlaceOrder(arg *PlaceTradeOrderParam) (*TradeOrderResponse, error) {
err := arg.validateTradeOrderParameter()
if err != nil {
return nil, err
}
var resp []TradeOrderResponse
err = o.SendWebsocketRequest("order", arg, &resp, true)
if err != nil {
return nil, err
}
if len(resp) == 0 {
return nil, errNoValidResponseFromServer
}
if resp[0].SCode != "0" {
return nil, fmt.Errorf("code: %s msg: %s", resp[0].SCode, resp[0].SMsg)
}
return &resp[0], nil
}
// WsPlaceMultipleOrder place orders in batches through the websocket stream. Maximum 20 orders can be placed per request. Request parameters should be passed in the form of an array.
func (o *Okcoin) WsPlaceMultipleOrder(args []PlaceTradeOrderParam) ([]TradeOrderResponse, error) {
var err error
if len(args) == 0 {
return nil, fmt.Errorf("%w, 0 length place order requests", errNilArgument)
}
for x := range args {
err = args[x].validateTradeOrderParameter()
if err != nil {
return nil, err
}
}
var resp []TradeOrderResponse
return resp, o.SendWebsocketRequest("batch-orders", args, &resp, true)
}
// WsCancelTradeOrder cancels a single trade order through the websocket stream.
func (o *Okcoin) WsCancelTradeOrder(arg *CancelTradeOrderRequest) (*TradeOrderResponse, error) {
if arg == nil {
return nil, errNilArgument
}
if arg.InstrumentID == "" {
return nil, errMissingInstrumentID
}
if arg.OrderID == "" && arg.ClientOrderID == "" {
return nil, errOrderIDOrClientOrderIDRequired
}
var resp []TradeOrderResponse
err := o.SendWebsocketRequest("cancel-order", &arg, &resp, true)
if err != nil {
return nil, err
}
if len(resp) == 0 {
return nil, errNoValidResponseFromServer
}
if resp[0].SCode != "0" {
return nil, fmt.Errorf("code: %s msg: %s", resp[0].SCode, resp[0].SMsg)
}
return &resp[0], nil
}
// WsCancelMultipleOrders cancel incomplete orders in batches through the websocket stream. Maximum 20 orders can be canceled per request.
// Request parameters should be passed in the form of an array.
func (o *Okcoin) WsCancelMultipleOrders(args []CancelTradeOrderRequest) ([]TradeOrderResponse, error) {
var err error
if len(args) == 0 {
return nil, fmt.Errorf("%w, 0 length place order requests", errNilArgument)
}
for x := range args {
err = args[x].validate()
if err != nil {
return nil, err
}
}
var resp []TradeOrderResponse
return resp, o.SendWebsocketRequest("batch-cancel-orders", args, &resp, true)
}
// WsAmendOrder amends an incomplete order through the websocket connection
func (o *Okcoin) WsAmendOrder(arg *AmendTradeOrderRequestParam) (*AmendTradeOrderResponse, error) {
err := arg.validate()
if err != nil {
return nil, err
}
var resp []AmendTradeOrderResponse
err = o.SendWebsocketRequest("amend-order", &arg, &resp, true)
if err != nil {
if len(resp) > 0 && resp[0].StatusCode != "0" && resp[0].StatusCode != "" {
return nil, fmt.Errorf("%w, code: %s msg: %s", err, resp[0].StatusCode, resp[0].StatusMessage)
}
return nil, err
}
if len(resp) == 0 {
return nil, errNoValidResponseFromServer
}
if resp[0].StatusCode != "0" {
return nil, fmt.Errorf("code: %s msg: %s", resp[0].StatusCode, resp[0].StatusMessage)
}
return &resp[0], nil
}
// WsAmendMultipleOrder amends multiple trade orders.
func (o *Okcoin) WsAmendMultipleOrder(args []AmendTradeOrderRequestParam) ([]AmendTradeOrderResponse, error) {
if len(args) == 0 {
return nil, fmt.Errorf("%w, please provide at least one trade order amendment request", errNilArgument)
}
for x := range args {
err := args[x].validate()
if err != nil {
return nil, err
}
}
var resp []AmendTradeOrderResponse
return resp, o.SendWebsocketRequest("batch-amend-orders", args, &resp, true)
}
// SendWebsocketRequest send a request through the websocket connection.
func (o *Okcoin) SendWebsocketRequest(operation string, data, result interface{}, authenticated bool) error {
switch {
case !o.Websocket.IsEnabled():
return errors.New(stream.WebsocketNotEnabled)
case !o.Websocket.IsConnected():
return stream.ErrNotConnected
case !o.Websocket.CanUseAuthenticatedEndpoints() && authenticated:
return errors.New("websocket connection not authenticated")
}
req := &struct {
ID string `json:"id"`
Operation string `json:"op"`
Arguments interface{} `json:"args"`
}{
ID: strconv.FormatInt(o.Websocket.Conn.GenerateMessageID(false), 10),
Operation: operation,
}
if reflect.TypeOf(data).Kind() == reflect.Slice {
req.Arguments = data
} else {
req.Arguments = []interface{}{data}
}
var byteData []byte
var err error
// TODO: ratelimits for websocket
if authenticated {
byteData, err = o.Websocket.AuthConn.SendMessageReturnResponse(req.ID, req)
} else {
byteData, err = o.Websocket.Conn.SendMessageReturnResponse(req.ID, req)
}
if err != nil {
return err
}
response := struct {
ID string `json:"id"`
Operation string `json:"op"`
Data interface{} `json:"data"`
Code string `json:"code"`
Message string `json:"msg"`
}{
Data: &result,
}
err = json.Unmarshal(byteData, &response)
if err != nil {
return err
}
if response.Code != "" && response.Code != "0" && response.Code != "1" && response.Code != "2" {
if response.Message == "" {
response.Message = websocketErrorCodes[response.Code]
}
return fmt.Errorf("%s websocket error code: %s message: %s", o.Name, response.Code, response.Message)
}
return nil
}

View File

@@ -881,6 +881,8 @@ func TestStringToOrderType(t *testing.T) {
{"trigger", Trigger, nil},
{"TRIGGER", Trigger, nil},
{"tRiGgEr", Trigger, nil},
{"conDitiOnal", ConditionalStop, nil},
{"oCo", OCO, nil},
{"woahMan", UnknownType, errUnrecognisedOrderType},
}
for i := range cases {

View File

@@ -71,6 +71,8 @@ type Submit struct {
// RetrieveFeeDelay some exchanges take time to properly save order data
// and cannot retrieve fees data immediately
RetrieveFeeDelay time.Duration
// TradeMode specifies the trading mode for margin and non-margin orders: see okcoin_wrapper.go
TradeMode string
}
// SubmitResponse is what is returned after submitting an order to an exchange
@@ -319,6 +321,8 @@ const (
Liquidation
Trigger
OptimalLimitIOC
OCO // One-cancels-the-other order
ConditionalStop // One-way stop order
)
// Side enforces a standard for order sides across the code base

View File

@@ -666,6 +666,8 @@ func (t Type) String() string {
return "IMMEDIATE_OR_CANCEL"
case Stop:
return "STOP"
case ConditionalStop:
return "CONDITIONAL"
case StopLimit:
return "STOP LIMIT"
case StopMarket:
@@ -686,6 +688,8 @@ func (t Type) String() string {
return "TRIGGER"
case OptimalLimitIOC:
return "OPTIMAL_LIMIT_IOC"
case OCO:
return "OCO"
default:
return "UNKNOWN"
}
@@ -1087,6 +1091,10 @@ func StringToOrderType(oType string) (Type, error) {
return Trigger, nil
case OptimalLimitIOC.String():
return OptimalLimitIOC, nil
case OCO.String():
return OCO, nil
case ConditionalStop.String():
return ConditionalStop, nil
default:
return UnknownType, fmt.Errorf("'%v' %w", oType, errUnrecognisedOrderType)
}
@@ -1105,7 +1113,7 @@ func StringToOrderStatus(status string) (Status, error) {
return Active, nil
case PartiallyFilled.String(), "PARTIALLY MATCHED", "PARTIALLY FILLED":
return PartiallyFilled, nil
case Filled.String(), "FULLY MATCHED", "FULLY FILLED", "ORDER_FULLY_TRANSACTED":
case Filled.String(), "FULLY MATCHED", "FULLY FILLED", "ORDER_FULLY_TRANSACTED", "EFFECTIVE":
return Filled, nil
case PartiallyCancelled.String(), "PARTIALLY CANCELLED", "ORDER_PARTIALLY_TRANSACTED":
return PartiallyCancelled, nil
@@ -1119,7 +1127,7 @@ func StringToOrderStatus(status string) (Status, error) {
return Pending, nil
case PendingCancel.String(), "PENDING CANCEL", "PENDING CANCELLATION":
return PendingCancel, nil
case Rejected.String(), "FAILED":
case Rejected.String(), "FAILED", "ORDER_FAILED":
return Rejected, nil
case Expired.String():
return Expired, nil

View File

@@ -35,7 +35,7 @@ var Exchanges = []string{
"itbit",
"kraken",
"lbank",
"okcoin international",
"okcoin",
"okx",
"poloniex",
"yobit",

View File

@@ -81,7 +81,7 @@ _b in this context is an `IBotExchange` implemented struct_
| ItBit | Yes | NA | No |
| Kraken | Yes | Yes | No |
| Lbank | Yes | No | Yes |
| OKCoin International | Yes | Yes | No |
| Okcoin | Yes | Yes | Yes |
| Okx | Yes | Yes | Yes |
| Poloniex | Yes | Yes | Yes |
| Yobit | Yes | NA | No |

View File

@@ -94,6 +94,9 @@ type Request struct {
// Used exclusively in Binance.US
ClientOrderID string `json:"clientID"`
// Used exclusively in Okcoin to classify internal represented by '3' or on chain represented by '4'
InternalTransfer bool
TradePassword string
OneTimePassword int64
PIN int64

View File

@@ -1978,7 +1978,7 @@
]
},
{
"name": "OKCOIN International",
"name": "Okcoin",
"enabled": true,
"verbose": false,
"httpTimeout": 15000000000,
@@ -1998,8 +1998,7 @@
},
"useGlobalFormat": true,
"assetTypes": [
"spot",
"margin"
"spot"
],
"pairs": {
"spot": {

View File

@@ -18,7 +18,7 @@ huobi,
itbit,
kraken,
lbank,
okcoin international,
okcoin,
okx,
poloniex,
yobit,
1 binanceus
18 itbit
19 kraken
20 lbank
21 okcoin international okcoin
22 okx
23 poloniex
24 yobit