Closed rorymac closed 4 years ago
In fact the most likely situation here is that you have a problem linking to IB or with ib-insync which is the intermediary layer I use between myself and the IB server. This is the key error mesage:
Exception: Couldn't evaluate ibFxPricesData(self.ib_conn, log=self.log.setup(component='ibFxPricesData')) This might be because (a) IB gateway not running, or (b) it is missing from sysproduction.data.get_data imports or arguments don't follow pattern
And here you can see the source of the problem is in the ib_insync layer:
File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/ib.py", line 271, in connect return self._run(self.connectAsync( File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/ib.py", line 310, in _run return util.run(*awaitables, timeout=self.RequestTimeout) File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/util.py", line 317, in run result = loop.run_until_complete(task) File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete return future.result() File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/ib.py", line 1656, in connectAsync await asyncio.wait_for( File "/usr/lib/python3.8/asyncio/tasks.py", line 490, in wait_for raise exceptions.TimeoutError() asyncio.exceptions.TimeoutError
... basically ib_insync was waiting too long for the IB server to get back to it. This may also be relevant:
_GatheringFuture exception was never retrieved future: <_GatheringFuture finished exception=CancelledError()>
So we know this is probably a problem with your IB setup/connection or ib_inysnc. You really need to look at the log on the IB API to try and see if something obvious is going wrong, as the python stack error (as here) isn't really sufficient.
There might be something wrong with your IB connection, setup; but assuming there isn't what else could it be?
You can then go to the docs or forum for ib_insync. I then noticed that other people have had this problem here. The fix appears to be specifying the account when connecting. Since doing this wont' break anything else, I've pushed this change to the code. Hopefully that will fix your problem, but as I said it could be an issue with your IB connection in which case you need to look carefully at the IB server logs. You might also want to run the ib_insync notebooks; if they don't run then its definitely not a pysystemtrade issue!
To answer your other question:
In fact it can now trade automatically and I am in the process of documenting it more fully (with the usual huge amount of caveats that you run a big risk using someone elses code to trade with, and this is especially true if it's a hobby project written by an amateur developer).
As a follow up, even with the fix (specifying account on connection) I'm having a similar problem, although if I try and run the service again it usually connects. So some kind of intermittent connection delay issue might be the cause here.
As a final follow up, I updated both ib_insync and the IB gateway (to 978h I think) and [touch wood] the problem seems to be fixed.
Rob Thank you. I have gone down the rabbit hole a tad.. (These comments are hopefully helpful to others, I realize this is my problem not yours!) My first approach was to try the ib_insync notebooks to try and get a connection working: Did not work - tracking the error down, firstly to your earlier link https://groups.io/g/insync/topic/77437738#5313 and from the error code (from the notebookexample) to : https://bugs.python.org/issue32751 I am running python 3.8.5 Nonetheless I tried ( in the notebook https://nbviewer.jupyter.org/github/erdewit/ib_insync/blob/master/notebooks/bar_data.ipynb copied this one) to specify the account, it connects briefly and then TimeoutError. Here is the full error:
TimeoutError Traceback (most recent call last)
<ipython-input-2-89a5ea6cd62f> in <module>
1 ib = IB()
2 #ib.connect('127.0.0.1', 4001, clientId=20,account="UXXXXX")
----> 3 ib.connect('127.0.0.1', 4001, clientId=21,account='FXXXXX')
4
~/.local/lib/python3.8/site-packages/ib_insync/ib.py in connect(self, host, port, clientId, timeout, readonly, account)
269 account: Main account to receive updates for.
270 """
--> 271 return self._run(self.connectAsync(
272 host, port, clientId, timeout, readonly, account))
273
~/.local/lib/python3.8/site-packages/ib_insync/ib.py in _run(self, *awaitables)
308
309 def _run(self, *awaitables: Awaitable):
--> 310 return util.run(*awaitables, timeout=self.RequestTimeout)
311
312 def waitOnUpdate(self, timeout: float = 0) -> bool:
~/.local/lib/python3.8/site-packages/ib_insync/util.py in run(timeout, *awaitables)
315 globalErrorEvent.connect(onError)
316 try:
--> 317 result = loop.run_until_complete(task)
318 except asyncio.CancelledError as e:
319 raise globalErrorEvent.value() or e
~/.local/lib/python3.8/site-packages/nest_asyncio.py in run_until_complete(self, future)
93 raise RuntimeError(
94 'Event loop stopped before Future completed.')
---> 95 return f.result()
96 finally:
97 events._set_running_loop(old_running_loop)
/usr/lib/python3.8/asyncio/futures.py in result(self)
176 self.__log_traceback = False
177 if self._exception is not None:
--> 178 raise self._exception
179 return self._result
180
/usr/lib/python3.8/asyncio/tasks.py in __step(***failed resolving arguments***)
278 # We use the `send` method directly, because coroutines
279 # don't have `__iter__` and `__next__` methods.
--> 280 result = coro.send(None)
281 else:
282 result = coro.throw(exc)
~/.local/lib/python3.8/site-packages/ib_insync/ib.py in connectAsync(self, host, port, clientId, timeout, readonly, account)
1654 # request updates for sub-accounts, if there are not too many
1655 if len(accounts) <= self.MaxSyncedSubAccounts:
-> 1656 await asyncio.wait_for(
1657 asyncio.gather(
1658 *(self.reqAccountUpdatesMultiAsync(a)
/usr/lib/python3.8/asyncio/tasks.py in wait_for(fut, timeout, loop)
488 # See https://bugs.python.org/issue32751
489 await _cancel_and_wait(fut, loop=loop)
--> 490 raise exceptions.TimeoutError()
491 finally:
492 timeout_handle.cancel()
TimeoutError:
the first timestamp in the API log is 12:55:09:449 to the last 12:55:09:620 not much time at all before the TimeoutError I do have ib_insync 0.9.62 and the Gateway build 980.4n I spent some time with IB and can get the API to work with their test program. (almost enough to qualify for a pension...) So the error appears to be with ib_sync, or more specifically with asyncio, though the issue is marked as resolved. https://bugs.python.org/issue32751
Tried again from the command line after updating the pysystemtrade from the repository and updating the private_config.YAML with the account number. No luck. The problem I think is in ib-sync and in asnycio. going to go down that rabbit hole next.
Don't apologise! I had to fix this error anyway it's just that you prompted me to do it quicker. Good luck!
An update: I found this discussion (https://github.com/erdewit/ib_insync/issues/30) Net result the recent upgrade to gateway version 980 is not working with ib-sync and causing the TimeoutError. 972 works with ib-sync (according to a user on that discussion)
I downgraded my gateway from 980 to 978 (all I could find) and that works with the ib-sync notebooks (rather amazingly well.)
I tried update_fx_prices and that did not work. I did a restart on my system and that did not work either. The IB log is bland (setting offset times) , and there is no client log. So the asyncio issue has disappeared. BUT the error message has changed, does shed any light? There is no attempt to connect as there was previously. It seems the client id is the issue. Do I need to set up the email? could that be causing a subtle error? I have tried a few of my email addresses and none will connect probably due to the security issues. I do see you hard coded the port 576. I had ambitions to try and write some code for that,(put the port in the private_config.yaml and use smtplib to add a security layers TLS and SSL) but wanted to get the system up and running first...
2020-10-21:1925.21 {'type': 'Update-FX-Prices'} *CRITICAL* Couldn't evaluate ibFxPricesData(self.ib_conn, log=self.log.setup(component='ibFxPricesData')) This might be because (a) IB gateway not running, or (b) it is missing from sysproduction.data.get_data imports or arguments don't follow pattern
2020-10-21:1925.21 {'type': 'Update-FX-Prices'} Problem "Can't find key 'email_address' in private config file '/home/rorym/pysystemtrade/private/private_config.yaml'" sending email, will store message instead
2020-10-21:1925.21 {'type': 'Update-FX-Prices'} [Error] Couldn't email user
Traceback (most recent call last):
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 264, in process_class_id
resolved_instance = eval(to_eval)
File "<string>", line 1, in <module>
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 161, in ib_conn
ib_conn = connectionIB()
File "/home/rorym/pysystemtrade/sysbrokers/IB/ibConnection.py", line 107, in __init__
client = self.db_id_tracker.return_valid_client_id(client)
File "/home/rorym/pysystemtrade/sysbrokers/IB/ibConnection.py", line 208, in return_valid_client_id
clientid_to_use = self.get_next_clientid()
File "/home/rorym/pysystemtrade/sysbrokers/IB/ibConnection.py", line 237, in get_next_clientid
next_id = min(missing_values)
ValueError: min() arg is an empty sequence
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "run.py", line 64, in <module>
func(*args, **kwargs)
File "/home/rorym/pysystemtrade/sysproduction/update_fx_prices.py", line 22, in update_fx_prices
update_fx_prices_object.update_fx_prices()
File "/home/rorym/pysystemtrade/sysproduction/update_fx_prices.py", line 34, in update_fx_prices
broker_fx_source = dataBroker(data)
File "/home/rorym/pysystemtrade/sysproduction/data/broker.py", line 31, in __init__
data.add_class_list(
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 207, in add_class_list
self._add_class_element(class_name)
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 218, in _add_class_element
attr_name, resolved_instance = self.process_class_id(class_name)
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 270, in process_class_id
raise Exception(msg)
Exception: Couldn't evaluate ibFxPricesData(self.ib_conn, log=self.log.setup(component='ibFxPricesData')) This might be because (a) IB gateway not running, or (b) it is missing from sysproduction.data.get_data imports or arguments don't follow pattern
No the lack of email isn't a problem - and it's only trying to send an email because an error is already thrown. It's having a problem finding the next available client id from the database (line 229 onwards in ibConnection). This is now my fault! Here's the original code:
def get_next_clientid(self):
current_list = self._get_list_of_clientids()
if len(current_list) == 0:
next_id = self._idoffset
else:
full_set = set(
range(self._idoffset, max(current_list) + 2)
)
missing_values = full_set - set(current_list)
next_id = min(missing_values)
There are a few options here:
We should never be in a situation when the unused range is empty, which is what the error is thrown. Nevertheless, I've changed the code to make this more explicit and hopefully this will also fix the problem:
def get_next_clientid(self) -> int:
current_list_of_ids = self._get_list_of_clientids()
next_id = get_next_id_from_current_list(current_list_of_ids, id_offset=self._idoffset)
def get_next_id_from_current_list(current_list_of_ids: list, id_offset: int = 0) -> int:
if len(current_list_of_ids) == 0:
# no IDS in use
return id_offset
full_set_of_available_ids = set(
range(id_offset, max(current_list_of_ids) + 1)
)
next_id = get_next_id_from_current_list_and_full_set(current_list_of_ids, full_set_of_available_ids)
return next_id
def get_next_id_from_current_list_and_full_set(current_list_of_ids: list, full_set_of_available_ids: set) -> int:
unused_values = full_set_of_available_ids - set(current_list_of_ids)
if len(unused_values)==0:
# no gaps, return the higest number plus 1
return max(current_list_of_ids) + 1
else:
# there is a gap, use the lowest numbered one
return min(unused_values)
Update updated from the repository and ran update_fx_prices from the terminal. Did not work. BUT Made a connection on the gateway and have a log from the gateway. The gateway hangs when I try to export the log so here is a screen shot.
The issue appears to be that the account code 'arg not supplied'
I checked my private_config.yaml the line is there : broker_account:'UXXXXX'
the error message is as follows:
rorym@mintservertwo:~/pysystemtrade/sysproduction/linux/scripts$ . update_fx_prices
/home/rorym/.local/lib/python3.8/site-packages/arctic/_util.py:6: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
from pandas.util.testing import assert_frame_equal
/home/rorym/.local/lib/python3.8/site-packages/arctic/store/_pandas_ndarray_store.py:6: FutureWarning: The Panel class is removed from pandas. Accessing it from the top-level namespace will also be removed in the next version
from pandas import DataFrame, Series, Panel
sysproduction.update_fx_prices.update_fx_prices:
Update FX prices stored in Arctic (Mongo) with interactive brokers prices (usually going back about a year)
:return: Nothing
Arguments:
[]
Error 321, reqId 2147483647: Error validating request.-'bq' : cause - Invalid account code 'arg not supplied'.
2020-10-22:0739.49 {'type': 'Update-FX-Prices'} *CRITICAL* Couldn't evaluate ibFxPricesData(self.ib_conn, log=self.log.setup(component='ibFxPricesData')) This might be because (a) IB gateway not running, or (b) it is missing from sysproduction.data.get_data imports or arguments don't follow pattern
2020-10-22:0739.49 {'type': 'Update-FX-Prices'} Problem "Can't find key 'email_address' in private config file '/home/rorym/pysystemtrade/private/private_config.yaml'" sending email, will store message instead
2020-10-22:0739.49 {'type': 'Update-FX-Prices'} [Error] Couldn't email user
Traceback (most recent call last):
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 264, in process_class_id
resolved_instance = eval(to_eval)
File "<string>", line 1, in <module>
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 161, in ib_conn
ib_conn = connectionIB()
File "/home/rorym/pysystemtrade/sysbrokers/IB/ibConnection.py", line 122, in __init__
ib.connect(ipaddress, port, clientId=client, account=account)
File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/ib.py", line 271, in connect
return self._run(self.connectAsync(
File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/ib.py", line 310, in _run
return util.run(*awaitables, timeout=self.RequestTimeout)
File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/util.py", line 317, in run
result = loop.run_until_complete(task)
File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/home/rorym/.local/lib/python3.8/site-packages/ib_insync/ib.py", line 1647, in connectAsync
await asyncio.wait_for(
File "/usr/lib/python3.8/asyncio/tasks.py", line 490, in wait_for
raise exceptions.TimeoutError()
asyncio.exceptions.TimeoutError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "run.py", line 64, in <module>
func(*args, **kwargs)
File "/home/rorym/pysystemtrade/sysproduction/update_fx_prices.py", line 22, in update_fx_prices
update_fx_prices_object.update_fx_prices()
File "/home/rorym/pysystemtrade/sysproduction/update_fx_prices.py", line 34, in update_fx_prices
broker_fx_source = dataBroker(data)
File "/home/rorym/pysystemtrade/sysproduction/data/broker.py", line 31, in __init__
data.add_class_list(
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 207, in add_class_list
self._add_class_element(class_name)
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 218, in _add_class_element
attr_name, resolved_instance = self.process_class_id(class_name)
File "/home/rorym/pysystemtrade/sysproduction/data/get_data.py", line 270, in process_class_id
raise Exception(msg)
Exception: Couldn't evaluate ibFxPricesData(self.ib_conn, log=self.log.setup(component='ibFxPricesData')) This might be because (a) IB gateway not running, or (b) it is missing from sysproduction.data.get_data imports or arguments don't follow pattern
_GatheringFuture exception was never retrieved
future: <_GatheringFuture finished exception=CancelledError()>
asyncio.exceptions.CancelledError
To make sure it was not an ib-sync issue checked that the ib-sync notebook is working, it is and can retrieve data. In my rather bad attempt to do the code trace, the broker_account variable is in pysystemtrade/sysbrokers/IB/ibConnection.py line 61
def get_broker_account() -> str:
account_id = get_private_then_default_key_value(
"broker_account", raise_error=False
)
if account_id is missing_data:
return arg_not_supplied
else:
return account_id
but does not appear in the error trace.
Any ideas?
It's not in the trace because get_broker_account is returning something, albeit not something that IB likes. I've just updated the code so it logs an error if it can't find the account ID, to make things clearer/
What happens if you run
from sysbrokers.IB.ibConnection import *
get_broker_account()
Rob My error! Bad format in private_config.yaml, (no space after colon) so the system could not read the the variable. Bugger sorry about that it is running as we speak. I have a few warnings in the output:
2020-10-22:0917.16 {'type': 'Update-FX-Prices'} FX Codes: ['AUDUSD', 'CADUSD', 'CHFUSD', 'EURUSD', 'GBPUSD', 'HKDUSD', 'JPYUSD', 'KRWUSD']
Library created, but couldn't enable sharding: no such command: 'enablesharding', full error: {'ok': 0.0, 'errmsg': "no such command: 'enablesharding'", 'code': 59, 'codeName': 'CommandNotFound'}. This is OK if you're not 'admin'
2020-10-22:0917.18 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'AUDUSD'} Downloaded 259 prices
2020-10-22:0917.18 {'type': 'Update-FX-Prices', 'fx_code': 'AUDUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0917.29 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'CADUSD'} Downloaded 259 prices
2020-10-22:0917.30 {'type': 'Update-FX-Prices', 'fx_code': 'CADUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0917.41 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'CHFUSD'} Downloaded 259 prices
2020-10-22:0917.41 {'type': 'Update-FX-Prices', 'fx_code': 'CHFUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0917.52 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'EURUSD'} Downloaded 259 prices
2020-10-22:0917.52 {'type': 'Update-FX-Prices', 'fx_code': 'EURUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0918.03 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'GBPUSD'} Downloaded 259 prices
2020-10-22:0918.03 {'type': 'Update-FX-Prices', 'fx_code': 'GBPUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0918.14 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'HKDUSD'} Downloaded 259 prices
2020-10-22:0918.14 {'type': 'Update-FX-Prices', 'fx_code': 'HKDUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0918.25 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'JPYUSD'} Downloaded 259 prices
2020-10-22:0918.25 {'type': 'Update-FX-Prices', 'fx_code': 'JPYUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
2020-10-22:0918.37 {'type': 'Update-FX-Prices', 'component': 'ibFxPricesData', 'currency_code': 'KRWUSD'} Downloaded 259 prices
2020-10-22:0918.37 {'type': 'Update-FX-Prices', 'fx_code': 'KRWUSD'} [Warning] Something went wrong with FX update type object 'Series' has no attribute 'from_array'
I trust they are not fatal?
Yes they are! What pandas version are you using?
pandas 1.1.3
OK. Pandas broke a lot of stuff by changing APIs radically when they moved to version 1. pysystemtrade is still at version 0.25.2
You have two choices:
To badly paraphrase McArthur ... I shall revert! Worked perfectly, thank you for your responses and patience.
Closing this, if something else goes wrong let's have a new issue :-)
I have tried a number of clean installs, including the operating system (my linux skills are below average, I assume the error was in my setup / installation of packages) for the production system of pysystemtrade. I keep failing at the same point in trying to set up the production system and following the Quick start guide in production.md When running
. /home/rorym/pysystemtrade/sysproduction/linux/scripts/update_fx_prices
I get an error message (the details are below)I have a number of questions
Is anyone using this as a non automated platform? That is using the system to do all the calculations and trading manually? I assume they have got sufficient data and can update that and run a "backtest" they like. ( I recall reading that Rob Carver had got pysystemtrade to the point of being able to do manual trades). Or have I jumped the gun?
Has anyone managed to download the FX data from IB?
Looking at the logs in the mongo shell:
the key seems to be ibFxPricesData, the gateway is running and a connection is briefly made (the GUI show it) in running the code. Can anyone point me in the right direction? My assumption is that there is some simple variable or something I have left out.
Data
the error message / output from the terminal: