Closed DmitryVil closed 5 years ago
They have two website domains:
One of them accessible from one part of the world, the other one from the rest of the world. The problem is that they don't have an API endpoint for fees, and to fetch them we have to load a webpage from their website and parse the fees from there. However, when accessing it from different locations, one of the domains may be inaccessible, so, it is the connection timeout upon loading fees that is causing the trouble.
There's two ways to overcome this:
import ccxt
exchange = ccxt.exmo ({
'enableRateLimit': True,
'api': {
'web': 'https://exmo.com',
},
})
import ccxt
exchange = ccxt.exmo ({
'enableRateLimit': True,
'options': {
'useWebapiForFetchingFees': False,
},
})
Let us know if that doesn't answer the question.
First advice doesn't work:
Second advice: in any case method load_markets() doesn't work
@DmitryVil can you show the error with the second option here? Please, don't post screenshots, paste text and use markup for readability as described here:
@DmitryVil also, i've just noticed, there's a typo in the first option (my bad), should be like so:
1.
import ccxt
exchange = ccxt.exmo ({
'enableRateLimit': True,
'urls': {
'api': {
'web': 'https://exmo.com',
},
},
})
import ccxt
exchange = ccxt.exmo ({
'enableRateLimit': True,
'options': {
'useWebapiForFetchingFees': False,
},
})
↑ Can you retry both and paste your results here in text?
Kroitor, the main problem is load_markets() method unavailable.
Absentness of load_fees() method is not critical.
@DmitryVil you're not understanding the callchain (loadMarkets calls loadFees in this scenario) – the loadMarkets will work, you'll get it very quickly, if you just follow precisely what i'm telling you )
This error:
First advice doesn't work:
↑ was due to a typo. I've posted a corrected version of it with my previous reply. Have you retried it?
Absentness of load_fees() method is not critical.
I know this, but this is not the point here )
Can you retry both versions from the corrected answer and paste your results here in text? Need to see the actual output to resolve this.
You are right: first advice is workable. But, to be frank, is very unuseful. This problem raised today after updating ccxt library version
You are right: first advice is workable. But, to be frank, is very unuseful.
Use the second one, basically, same thing.
This problem raised today after updating ccxt library version
Actually, the problem is raised by EXMO after blocking their website for different regions of the world. We've been looking into a solution, but they are making it hard to use their system intentionally. Before blocking the fees page, they could provide an API endpoint for it. We will keep looking for a better workaround.
Their websites will be inaccessible depending on where you launch the code, not which code you launch. So, it's beyond the scope of the lib, if the exchange is blocking itself from the outside world.
Kroitor, sorry, what I just got from anynchronius part of library:
Mistake in main module: RequestTimeout('exmo GET https://exmo.com/en/docs/fees '), exmo exmo RequestTimeout('exmo GET https://exmo.com/en/docs/fees ')
I launch my code with Great Britain IP address
@DmitryVil have you tried the second option? What does it say?
Finally, it launched but with warnings:
exmo requires to release all resources with an explicit call to the .close() coroutine. If you are creating the exchange instance from within your async coroutine, add exchange.close() to your code into a place when you're done with the exchange and don't need the exchange instance anymore (at the end of your async coroutine). Unclosed client session client_session: <aiohttp.client.ClientSession object at 0x0000026A3BC298D0>
exmo requires to release all resources with an explicit call to the .close() coroutine. If you are creating the exchange instance from within your async coroutine, add exchange.close() to your code into a place when you're done with the exchange and don't need the exchange instance anymore (at the end of your async coroutine).
This is a completely different thing, related to async_support
and to resolve this you just need to follow precisely what the message from the error is telling you (it says that you're not working with the async version as you should).
exmo requires to release all resources with an explicit call to the .close() coroutine.
If you are creating the exchange instance from within your async coroutine, add exchange.close() to your code into a place when you're done with the exchange
↑ I guess, from this it should be clear what to do. See the async examples on how to work with async sessions properly:
Also, use the search and find these 16 duplicate answers to the same question:
;))
Let us know if you still have issues with it after that.
P.S. please use proper markup in the future for readability, do not highlight everything in bold – read this very carefully on how to format the text on GitHub correctly:
Kroitor, To create the exchange instance I use exactly what you suggest as an example in ccxt. Moreover, I create in the program one after another instances for some exchanges in the loop. But this message I got only for exmo and only after using code you adviced: exchange = ccxt.exmo ({ 'enableRateLimit': True, 'options': { 'useWebapiForFetchingFees': False, }, })
@DmitryVil can you make a short but complete snippet of 10-20 lines to reproduce the issue? I mean, starting from the import
clause and up to the point of breaking.
Because if I run this:
exchange = ccxt.exmo ({
'enableRateLimit': True,
'options': {
'useWebapiForFetchingFees': False,
},
})
↑ it works on my side, so, obviously, the cause is in the other code around (that code above is not enough to tell anything). Need to see the rest of it (please make it short, but complete), otherwise we will mostly be guessing...
@DmitryVil here's an example of a proper short complete program that works with EXMO in async mode correctly and doesn't fail:
# -*- coding: utf-8 -*-
import asyncio
from pprint import pprint
import ccxt.async_support as ccxt
async def test():
exchange = ccxt.exmo({
'enableRateLimit': True, # required according to the Manual
'options': {
'useWebapiForFetchingFees': False,
}
})
try:
orderbook = await exchange.fetch_order_book('BTC/USDT')
await exchange.close()
return orderbook
except ccxt.BaseError as e:
print(type(e).__name__, str(e), str(e.args))
raise e
if __name__ == '__main__':
pprint(asyncio.get_event_loop().run_until_complete(test()))
↑ Does it work for you if you save it to a py-file and launch it with your Python3? It should output an orderbook without any errors. If you don't see an error with this code, but you see an error with your code – the issue is with your code. You should follow the error messages as was described here: https://github.com/ccxt/ccxt/issues/4950#issuecomment-480627098
(I really hope that you post your marked up and readable code and text output as shown in the example in this comment).
I initiate the instances with code like this: ##################################################################### def flrFetching(flr): ####### Request of exchange market ######## markets = asyncio.get_event_loop().run_until_complete(flr.loadMarkets(reload=True)) return markets
flrs = ['bitfinex', 'okex', 'exmo']
for flrID in flrs:
flr = getattr(ccxt, flrID)()
markets = flrFetching(flr)
print('\n\n', flr.id, '\n', markets)
#################################################################### asyncronious part of the code I copies for ccxt library. what do you think may be a source of the problem?
what do you think may be a source of the problem?
The reason is that you're not working with asyncio instances as described in the warning you're getting and in the examples above ) You don't close the session anywhere in your code. Missing await flr.close ()
in that example.
@DmitryVil the proper code could be done in many different ways, depends on the flow of your application and the design of it, for example:
# -*- coding: utf-8 -*-
import asyncio
from pprint import pprint
import ccxt.async_support as ccxt
async def run_all_exchanges (flrs):
results = {}
for flrID in flrs:
results[flrID] = await run_one_exchange (flrID)
return results
async def run_one_exchange(exchange_id):
exchange = getattr(ccxt, exchange_id) ({
'enableRateLimit': True, # required accoding to the Manual
'options': {
'useWebapiForFetchingFees': False,
}
})
try:
result = await exchange.load_markets()
await exchange.close() # ←---------------------- YOU'RE MISSING THIS
return result
except ccxt.BaseError as e:
print(type(e).__name__, str(e), str(e.args))
raise e
if __name__ == '__main__':
exchange_ids = ['bitfinex', 'okex', 'exmo']
markets = asyncio.get_event_loop().run_until_complete(run_all_exchanges(exchange_ids))
pprint([ (market, list(markets[market].keys ())) for market in markets.keys()])
↑ I'm not saying that this is the way to do it, it is just one of the examples that shows loading markets... See other examples here: https://github.com/ccxt/ccxt/tree/master/examples/py
P.S. To format your code here properly, you should surround it with triple backticks (```). Do not confuse backticks (```) with single quotes (\'\'\'). Add the language after the first three backtics for highlighting.
Example:
```Python import ccxt your code... ```
Could you please explain:
after await exchange.close()
, may I return as a result of the method an exchange instance to the upper level?
I mean return exchange
after await exchange.close(), may I return as a result of the method an exchange instance to the upper level?
Yes, however, because it's closed, you can't call the methods on the closed instance from there. So, if you don't want to close it and want to keep it further, you can do something like this:
# -*- coding: utf-8 -*-
import asyncio
import ccxt.async_support as ccxt
async def run_all_exchanges(exchange_ids):
results = {}
for exchange_id in exchange_ids:
exchange = getattr(ccxt, exchange_id)({
'enableRateLimit': True, # required accoding to the Manual
'options': {
'useWebapiForFetchingFees': False,
}
})
symbol = 'ETH/BTC'
print('Exchange:', exchange_id)
print(exchange_id, 'symbols:')
markets = await load_markets(exchange, symbol) # ←----------- STEP 1
print(list(markets.keys()))
print(symbol, 'ticker:')
ticker = await fetch_ticker(exchange, symbol) # ←------------ STEP 2
print(ticker)
print(symbol, 'orderbook:')
orderbook = await fetch_orderbook(exchange, symbol) # ←------ STEP 3
print(orderbook)
await exchange.close() # ←----------- LAST STEP GOES AFTER ALL CALLS
results[exchange_id] = ticker
return results
async def load_markets(exchange, symbol):
try:
result = await exchange.load_markets()
return result
except ccxt.BaseError as e:
print(type(e).__name__, str(e), str(e.args))
raise e
async def fetch_ticker(exchange, symbol):
try:
result = await exchange.fetch_ticker(symbol)
return result
except ccxt.BaseError as e:
print(type(e).__name__, str(e), str(e.args))
raise e
async def fetch_orderbook(exchange, symbol):
try:
result = await exchange.fetch_order_book(symbol)
return result
except ccxt.BaseError as e:
print(type(e).__name__, str(e), str(e.args))
raise e
if __name__ == '__main__':
exchange_ids = ['bitfinex', 'okex', 'exmo']
exchanges = []
results = asyncio.get_event_loop().run_until_complete(run_all_exchanges(exchange_ids))
print([(exchange_id, ticker) for exchange_id, ticker in results.items()])
Also, you can return the exchange instance (return exchange
) from one async method to another to close()
it later.
What happens after using await exchange.close()
?
Is instance exchange disappearing?
What happens after using await exchange.close()?
Here's the source code of that methods it's less than 5 lines ))
Is instance exchange disappearing?
No, the exchange class instance continues to exist, but the .close()
method shuts down the internal asyncio session that is opened automatically upon creating the exchange instance. If you don't close it, Python will complain with a warning.
Having that asyncio session and the corresponding call to the .close()
method is not the feature of this library, but is more like a requirement of the asyncio itself (this is how you do async in python, basically).
So, close()
closes the session, and you can later re-open (and re-close) it with the same exchange class instance with the corresponding .open()
method, which is here:
ATTENTION!!!
MUST READ THIS BEFORE SUBMITTING ISSUES:
https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-submit-an-issue
Method load_markets() don't work for exchange exmo in version 1.18.437. In previous versions (for example in version 1.18.406) them work.