diff --git a/cs/ccxt/base/Exchange.Misc.cs b/cs/ccxt/base/Exchange.Misc.cs index de6ef606709e9..8c34dc4187b1e 100644 --- a/cs/ccxt/base/Exchange.Misc.cs +++ b/cs/ccxt/base/Exchange.Misc.cs @@ -62,4 +62,10 @@ public List> getFetchCache() // return null; // stub to implement // } + // returns the version of the ccxt library, e.g. "4.5.54" + public virtual object getCcxtVersion() + { + return ccxtVersion; + } + } diff --git a/go/v4/exchange_interface.go b/go/v4/exchange_interface.go index 08744fe1bf6d2..e4f48570de4b7 100644 --- a/go/v4/exchange_interface.go +++ b/go/v4/exchange_interface.go @@ -228,6 +228,7 @@ type ICoreExchange interface { Init(params map[string]any) FetchDeposits(optionalArgs ...any) <-chan any Milliseconds() int64 + GetCcxtVersion() string ParseNumber(v any, a ...any) any OmitZero(v any) any FetchOHLCV(symbol any, optionalArgs ...any) <-chan any diff --git a/go/v4/exchange_metadata.go b/go/v4/exchange_metadata.go index c5b7cc9d80f23..9ea258fac9563 100644 --- a/go/v4/exchange_metadata.go +++ b/go/v4/exchange_metadata.go @@ -2,4 +2,9 @@ package ccxt var Version string = "4.5.71" +// GetCcxtVersion returns the version of the ccxt library, e.g. "4.5.54" +func (this *Exchange) GetCcxtVersion() string { + return Version +} + var Exchanges []string = []string{"aftermath", "alpaca", "apex", "ascendex", "aster", "backpack", "bequant", "bigone", "binance", "binancecoinm", "binanceus", "binanceusdm", "bingx", "bit2c", "bitbank", "bitbns", "bitfinex", "bitflyer", "bitget", "bithumb", "bitmart", "bitmex", "bitopro", "bitrue", "bitso", "bitstamp", "bitteam", "bittrade", "bitvavo", "blockchaincom", "blofin", "btcbox", "btcmarkets", "btcturk", "bullish", "bybit", "bybiteu", "bydfi", "cex", "coinbase", "coinbaseexchange", "coinbaseinternational", "coincheck", "coinex", "coinmate", "coinmetro", "coinone", "coinsph", "coinspot", "cryptocom", "cryptomus", "deepcoin", "delta", "deribit", "derive", "digifinex", "dydx", "exmo", "extended", "fmfwio", "foxbit", "gate", "gemini", "grvt", "hashkey", "hibachi", "hitbtc", "hollaex", "htx", "hyperliquid", "independentreserve", "indodax", "kraken", "krakenfutures", "kucoin", "kucoinfutures", "latoken", "lbank", "lighter", "luno", "mercado", "mexc", "modetrade", "myokx", "ndax", "novadax", "okx", "okxus", "onetrading", "p2b", "pacifica", "paradex", "paymium", "phemex", "poloniex", "tokocrypto", "toobit", "upbit", "weex", "whitebit", "woo", "woofipro", "xt", "zaif", "zebpay"} diff --git a/java/lib/src/main/java/io/github/ccxt/BaseExchange.java b/java/lib/src/main/java/io/github/ccxt/BaseExchange.java index c097d047cd027..13859c6e091a0 100644 --- a/java/lib/src/main/java/io/github/ccxt/BaseExchange.java +++ b/java/lib/src/main/java/io/github/ccxt/BaseExchange.java @@ -1159,6 +1159,11 @@ public String uuid() { return Strings.uuid(); } + // returns the version of the ccxt library, e.g. "4.5.71" + public String getCcxtVersion() { + return Version.VERSION; + } + // ======================= // Time // ======================= diff --git a/php/Exchange.php b/php/Exchange.php index 8e41b5026aba5..e914e05b99d9a 100644 --- a/php/Exchange.php +++ b/php/Exchange.php @@ -2542,6 +2542,11 @@ public static function has_web3() { return true; } + // returns the version of the ccxt library, e.g. "4.5.54" + public function get_ccxt_version() { + return static::VERSION; + } + public function check_required_dependencies() { if (!static::has_web3()) { throw new ExchangeError($this->id . ' requires web3 dependencies'); diff --git a/python/ccxt/base/exchange.py b/python/ccxt/base/exchange.py index 77eb5b6032ab3..f8adf155d9e71 100644 --- a/python/ccxt/base/exchange.py +++ b/python/ccxt/base/exchange.py @@ -1837,6 +1837,10 @@ def decode(string): def to_array(value): return list(value.values()) if type(value) is dict else value + def get_ccxt_version(self): + """returns the version of the ccxt library, e.g. "4.5.54" """ + return __version__ + def precision_from_string(self, str): # support string formats like '1e-4' if 'e' in str or 'E' in str: diff --git a/ts/src/base/Exchange.ts b/ts/src/base/Exchange.ts index 3e4612c7ae073..bee2243f63316 100644 --- a/ts/src/base/Exchange.ts +++ b/ts/src/base/Exchange.ts @@ -674,6 +674,17 @@ export class BaseExchange { return encodeURIComponent (...args); } + /** + * @method + * @name Exchange#getCcxtVersion + * @description returns the version of the ccxt library, e.g. "4.5.54", or "unknown" when the version constant is not initialized (e.g. when an exchange module is imported directly, bypassing the ccxt entry point) + * @returns {string} the semver version of the ccxt library, or "unknown" when unavailable + */ + getCcxtVersion (): string { + const staticVersion = (Exchange as any).ccxtVersion; + return (staticVersion === undefined) ? 'unknown' : staticVersion; + } + throttle (cost: Num = undefined) { return this.throttler.throttle (cost); } diff --git a/ts/src/foxbit.ts b/ts/src/foxbit.ts index cf690b17e924f..f115381c551f6 100644 --- a/ts/src/foxbit.ts +++ b/ts/src/foxbit.ts @@ -2076,6 +2076,8 @@ export default class foxbit extends Exchange { } headers = { 'Content-Type': 'application/json', + 'X-FB-CLIENT': 'ccxt', + 'X-FB-CLIENT-VERSION': this.getCcxtVersion (), }; if (urlPath === 'private') { this.checkRequiredCredentials (); diff --git a/ts/src/test/tests.ts b/ts/src/test/tests.ts index dd8ff1e539f28..f198ec6701856 100644 --- a/ts/src/test/tests.ts +++ b/ts/src/test/tests.ts @@ -2142,7 +2142,8 @@ class testMainClass { this.testModeTrade (), this.testBackpack (), this.testToobit (), - this.testWeex () + this.testWeex (), + this.testFoxbit () ]; await Promise.all (promises); const successMessage = '[' + this.lang + '][TEST_SUCCESS] brokerId tests passed.'; @@ -2807,6 +2808,25 @@ class testMainClass { clientOrderId = request['newClientOrderId']; assert (clientOrderId.startsWith (id), 'weex - newClientOrderId: ' + clientOrderId + ' for swap order does not start with id: ' + id); } + + async testFoxbit () { + const exchange = this.initOfflineExchange ('foxbit'); + let reqHeaders: Dict = {}; + const id = 'ccxt'; + try { + await exchange.createOrder ('BTC/BRL', 'limit', 'buy', 1, 20000); + } catch (e) { + // we expect an error here, we're only interested in the headers + reqHeaders = exchange.last_request_headers ? exchange.last_request_headers : {}; + } + assert (reqHeaders['X-FB-CLIENT'] === id, 'foxbit - id: ' + id + ' not in headers.'); + const version = exchange.getCcxtVersion (); + assert (reqHeaders['X-FB-CLIENT-VERSION'] === version, 'foxbit - version: ' + version + ' not in headers.'); + if (!isSync ()) { + await close (exchange); + } + return true; + } } export default testMainClass;