Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有asyncio的Python IB API的自包含可复制示例_Python_Callback_Python Asyncio_Asynccallback_Tws - Fatal编程技术网

带有asyncio的Python IB API的自包含可复制示例

带有asyncio的Python IB API的自包含可复制示例,python,callback,python-asyncio,asynccallback,tws,Python,Callback,Python Asyncio,Asynccallback,Tws,卓越的使用内置的asyncio模块为异步IB API提供了更高级别的同步接口。然而,在某些情况下,人们可能更愿意避免依赖第三方模块。我的尝试是向社区提供一个自包含的可重复的示例,说明如何将本机ibapi与Python内置的asyncio模块一起使用来处理回调。例如,假设您想添加一种方法,将权重向量转换为要交易的实际股票数量。这需要在同一方法中调用reqAccountSummary(检查账户中的现金金额)和reqMktData(获取市场价格快照),并分别等待回调,accountSummaryEnd

卓越的使用内置的asyncio模块为异步IB API提供了更高级别的同步接口。然而,在某些情况下,人们可能更愿意避免依赖第三方模块。我的尝试是向社区提供一个自包含的可重复的示例,说明如何将本机
ibapi
与Python内置的
asyncio
模块一起使用来处理回调。例如,假设您想添加一种方法,将权重向量转换为要交易的实际股票数量。这需要在同一方法中调用
reqAccountSummary
(检查账户中的现金金额)和
reqMktData
(获取市场价格快照),并分别等待回调,
accountSummaryEnd
tickSnapshotEnd

下面是一个(更简单的)示例,我调用
reqContractDetails
并在同一方法
runSyncContractReq
中等待回调
contractDetailsEnd
。理论上,相同的逻辑可以应用于具有关联回调的所有请求。不幸的是,由于程序永远“等待”将来的回调,所以这还没有完全起作用

我希望社区的一位成员能够帮助这个例子正确运行,以帮助像我这样的
ibapi
asyncio
新手

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import asyncio


class TwsApp(EWrapper, EClient):
    def __init__(self):
        self._nextValidId = None
        EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)
        # self.future stores IDs associated with asyncio.Future() objects.
        self.future = dict()

    def get_nextValidId(self):
        """Returns a valid ID useful to send requests to TWS or place orders."""
        reqId = self._nextValidId
        self._nextValidId += 1
        return reqId

    def nextValidId(self, orderId: int):
        """This method receives valid OrderIds form TWS whenever calling
        self.run() or self.reqIds()."""
        self._nextValidId = orderId
        self.runSyncContractReq()

    async def reqContractDetails(self, reqId, contractDetails):
        print('reqContractDetails STARTED')
        super().reqContractDetails(reqId, contractDetails)
        print('reqContractDetails AWAITING for Future to be done.')
        await self.future[reqId]
        print('reqContractDetails AWAITED!')

    def contractDetails(self, reqId: int, contractDetails):
        print('contractDetails RECEIVED!')

    def contractDetailsEnd(self, reqId):
        print('contractDetailsEnd STARTED')
        self.future[reqId] = self.future[reqId].set_result('done')
        print('contractDetailsEnd FINISHED')

    def runSyncContractReq(self):
        # Prepare data.
        contract = Contract()
        contract.conId = 756733
        contract.exchange = 'SMART'
        idReq = self.get_nextValidId()

        # asyncio.
        self.future[idReq] = asyncio.Future()
        loop = asyncio.get_event_loop()
        print('Running asyncio.ensure_future')
        asyncio.ensure_future(self.reqContractDetails(idReq, contract))
        print('Running loop.run_until_complete')
        loop.run_until_complete(self.future[idReq])
        loop.close()


if __name__ == '__main__':
    app = TwsApp()
    app.connect(host='127.0.0.1', port=7497, clientId=0)
    app.run()

### OUTPUT
Running asyncio.ensure_future
Running loop.run_until_complete
reqContractDetails STARTED
reqContractDetails AWAITING for Future to be done.

# However, contract details are somehow returned once the application is stopped.
ERROR:root:ERROR -1 2104 Market data farm connection is OK:usfuture
ERROR:root:ERROR -1 2104 Market data farm connection is OK:afarm
ERROR:root:ERROR -1 2104 Market data farm connection is OK:usfarm
ERROR:root:ERROR -1 2106 HMDS data farm connection is OK:ushmds
contractDetails RECEIVED!
contractDetailsEnd STARTED
contractDetailsEnd FINISHED

目前还不清楚如何使用asyncio处理这段代码。如果您有
app.run()
,这意味着asyncio事件循环根本没有运行。理想情况下,可以将异步IO事件循环挂接到
ibapi
事件循环或其他方式,但这相当复杂。更现实的选择是在单独的线程中运行
TwsApp
,然后使用
call\u later\u threadsafe
和类似的原语在异步级别上调度相应的协程。