问题
I just don't understand what is going on here. I'm a bit new to wrappers and IB. Here is my function that overrides and parses the XML. Should the XML be parsed in the main? I just want to get the fundamental data for all the symbols in my CSV file. When I comment out the loop and run an individual request it works, sometimes. What's going on here?
class TestApp(EWrapper, EClient):
def __init__(self):
EWrapper.__init__(self)
EClient.__init__(self, wrapper=self)
self.csv = pd.read_csv('getfund.csv');
self.symbols = self.csv['Symbol']
self.exchanges = self.csv['Exchange']
def nextValidId(self, reqId: int):
reqs_do()
def reqs_do():
for i in range(len(symbols)):
contract = Contract()
contract.symbol = self.symbols[i]
contract.secType = "STK"
contract.exchange = self.exchanges[i]
contract.currency = "USD"
contract.primaryExchange = "NASDAQ"
print(contract)
print(symbols[i])
print(exchanges[i])
print(i)
app.reqFundamentalData(8001 , contract, "ReportsFinSummary", [])
def error(self, reqID:TickerId, errorCode:int, errorString:str):
print("Error: ", reqID, " " , errorCode, " ", errorString)
def fundamentalData(self, reqId: TickerId, data: str):
super().fundamentalData(reqId, data)
print("FundamentalData. ", reqId, data)
e = ET.fromstring(data)
e.tag
e.attrib
##code to parse the XML file returned from the ib reqfundamentaldata function.
##there are multiple report types and I am uncertain what they mean, worth
##looking into later.
row_list = []
for atype in e.iter('TotalRevenue'):
if atype.attrib['reportType']=="A" and atype.attrib['period']=="3M":
dict1 = {"Date": atype.attrib['asofDate'],
'Revenue':atype.text}
row_list.append(dict1)
columns = ['Date', 'Revenue']
tr = pd.DataFrame(row_list, columns=columns)
row_list = []
for atype in e.iter('DividendPerShare'):
if atype.attrib['reportType']=="A" and atype.attrib['period']=="3M":
dict1 = {"Date": atype.attrib['asofDate'],
'Dividend':atype.text}
row_list.append(dict1)
columns = ['Date', 'Dividend']
dps = pd.DataFrame(row_list, columns=columns)
row_list = []
for atype in e.iter('EPS'):
if atype.attrib['reportType']=="A" and atype.attrib['period']=="3M":
dict1 = {"Date": atype.attrib['asofDate'],
'EPS':atype.text}
row_list.append(dict1)
columns = ['Date', 'EPS']
eps = pd.DataFrame(row_list, columns=columns)
temp = tr.merge(dps, left_on='Date', right_on='Date', how='left')
fin = temp.merge(eps, left_on='Date', right_on='Date', how='left')
print(fin)
#fin.to_csv("fin.csv", sep=',')
if done: app.disconnect()
def main():
app = TestApp()
app.connect("127.0.0.1", 4001, clientId=123)
print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
app.twsConnectionTime()))
app.run()
if __name__ == "__main__":
main()
回答1:
Your logic has you connecting and then requesting all the data while waiting 60 secs in between requests....and then listening for a response (app.run).
app.run() starts a loop reading from the socket for responses. Without some threading, you can't do anything after this call. You can just write the program to do things in an asynchronous manner.
Once you've got a connection with a read loop running, you can start asking for data. nextValidId is used for this purpose as it's the first response sent by TWS(IBG). So in nextValidId you really start your program.
Your code will never get to disconnect since app.run() is blocking the thread. You need to use async logic to decide when to disconnect. In this simple case just count requests.
Not a real program, just to illustrate the logic flow.
class TestApp(EWrapper, EClient):
def __init__(self):
#other stuff
#make the following members instead of global
self.csv = pd.read_csv('getfund.csv');
self.symbols = csv['Symbol']
self.exchanges = csv['Exchange']
def nextValidId(self, reqId: int):
reqs_do()
def reqs_do():
for i in range(len(symbols)):
# same, just use self.symbols etc..
def fundamentalData(self, reqId: TickerId, data: str):
# similar but disconnect after everything has been rec'd
if done: app.disconnect()
def main():
app = TestApp()
app.connect("127.0.0.1", 4001, clientId=123)
app.run()
if __name__ == "__main__": main()
- The program will work by first creating TestApp and reading the csv file.
- Then you will connect via socket to IB Gateway but not be reading until app.run().
- As soon as you start reading you will rec'v nextValidId and some informational error messages about the connection.
- Once nextValidiD is rec'd you start asking for data.
- It can come at anytime but usually right away except maybe friday nights when everything is closed.
- If rec'd it will print in the data callback you have.
来源:https://stackoverflow.com/questions/49329139/request-to-ib-responds-differently-when-in-a-loop