IB_insync - 一个成功的订单后出现 Sanic 错误,阻止任何进一步的订单

问题描述 投票:0回答:7

我正在使用 ib_insync、Sanic 和 ngrok 编写一个 API,将 webhook 信号从 Tradingview 转发到盈透证券。它仅在第一次尝试时有效,并且会抛出以下错误,阻止任何进一步的订单:

[错误]处理 uri 时发生异常: 'http://url.ngrok.io/webhook' 回溯(最新的 最后调用):文件“handle_request”,第103行,在handle_request中 “_future_listeners”,sanic.exceptions.ServerError:无效的响应类型无(需要 HTTPResponse)

代码如下:

from datetime import datetime
from sanic import Sanic    
from sanic import response
from ib_insync import *

#Create Sanic object
app = Sanic(__name__)
app.ib = None

#Create root
@app.route('/')
async def root(request):
    return response.text('online')

#Listen for signals and execute orders
@app.route('/webhook', methods=['POST'])
async def webhook(request):
    if request.method == 'POST':
        await checkIfReconnect()
        #Parse alert data
        alert = request.json
        order = MarketOrder(alert['action'],alert['quantity'],account=app.ib.wrapper.accounts[0])
        #Submit market order
        stock_contract = Stock('NVDA','SMART','USD')
        app.ib.placeOrder(stock_contract,order)

#Reconnect if needed
async def checkIfReconnect():
    if not app.ib.isConnected() or not app.ib.client.isConnected():
        app.ib.disconnect()
        app.ib = IB()
        app.ib.connect('127.0.0.1',7496,clientId=1)

#Run app
if __name__ == '__main__':
    #Connect to IB
    app.ib = IB()
    app.ib.connect('127.0.0.1',7496,clientId=1)
    app.run(port=5000)
python ngrok tradingview-api interactive-brokers sanic
7个回答
0
投票

您看到此错误是因为您忘记发送对第一个 POST 请求的响应。所有 HTTP 请求都需要相应的响应,即使只是为了触发某个操作。

即,将您的 webhook 代码更改为:

@app.route('/webhook', methods=['POST'])
async def webhook(request):
    if request.method == 'POST':
        await checkIfReconnect()
        #Parse alert data
        alert = request.json
        order = MarketOrder(alert['action'],alert['quantity'],account=app.ib.wrapper.accounts[0])
        #Submit market order
        stock_contract = Stock('NVDA','SMART','USD')
        app.ib.placeOrder(stock_contract,order)
        return HTTPResponse("ok", 200)  #<-- This line added
    return HTTPResponse("", 405)  #<-- else return this


0
投票

我正在使用相同的代码,并在每个 POST 正确触发时使用断点。我完全明白你的意思,每次启动应用程序时只能下 1 个订单。我尝试使用 ib.qualifyContract(Stock) 但它会在 webhook 循环中产生错误。我想知道您是否可以将订单放置移到任何循环函数之外。当我有时间时我会尝试并报告回来。


0
投票

我使用的脚本与您几乎相同。 我猜你的问题不是前面提到的http响应(我不使用它)。 问题是,发送到 IB 的每个订单都必须有一个唯一的标识符,但我没有看到您应用到您的代码。 您可以在这里阅读相关内容(https://interactivebrokers.github.io/tws-api/order_submission.html)。 我找到了一种方法来做到这一点,但我在这里解释起来很复杂。 基本上,您必须将订单 ID 添加到发送的每个订单中,并且有两种方法可以选择:

  1. 正确连接到IBAPI并检查当前可用的唯一订单ID
  2. 使用您自己的 ID(数字),例如以循环的形式,并在每次重新启动脚本时重置 TWS 中的序列,如我添加的链接所示。

0
投票

我在处理相同的代码时遇到了同样的问题(_future_listeners)。一直在寻找解决方案,但到目前为止没有一个有效。我分享这个是为了看看你们是否能够修复它。

我尝试过(或打算尝试)这些解决方案: 1-我在这两个地方都使用了异步连接(app.ib.connectAsync)而不是app.ib.connect。但它返回了等待警告错误。第二个 app.ib.connectAsync 位于异步函数之外,因此无法等待。您可以运行代码,但它会给出另一个错误:MarketOrder 函数的“列表索引超出范围”。

2-我添加了 app.ib.qualifyContracts 。但它也没有解决问题。我用了它,连第一笔订单都没有发送到TWS。

3- 添加唯一的 orderid。我没有尝试过,因为我不确定它是否有效。我打印了订单,好像已经下单了。


0
投票

我从您正在使用的相同广泛分布的样板代码开始。进行下面概述的更改后,我的代码可以运行。我缺乏专业知识来解释为什么会这样——但它确实如此。

假设您安装了以下软件: Python 3.10.7_64 萨尼克 22.6.2 ib_insync 0.9.71

(1) pip install --升级 sanic-cors sanic-plugin-toolkit 参考:IB_insync - 一个成功的订单后出现 Sanic 错误,阻止任何进一步的订单 (不确定是否需要)

(2)添加: 导入时间(参见下面的 clientId 注释)

(3)添加: 导入nest_asyncio
Nest_asyncio.apply() #ref: RuntimeError: 此事件循环已在 python 中运行

(4) 在底部初始连接中使用异步连接(但不在重连区域中) app.ib.connectAsync('127.0.0.1',7497,clientId=见下文) # 7946=live, 7947=paper
参考:IB_insync - 一个成功的订单后出现 Sanic 错误,阻止任何进一步的订单

(5) 在两个 connect 语句中使用时间派生出唯一的、升序的 clientId clientId=int(int((time.time()*1000)-1663849395690)/1000000)) 这有助于避免重新连接时出现“套接字正在使用”的情况

(6) 按照上面的建议添加 HTTPResponse 语句。

(7) Per Ewald de Wit,ib_insync 作者: "orderId无需设置,订单自动下发 已下订单。”


0
投票

还有一个替代方案,在异步函数末尾返回

return response.json({})
webhook

........
from sanic import response
......
#Listen for signals and execute orders
@app.route('/webhook', methods=['POST'])
async def webhook(request):
    if request.method == 'POST':
        await checkIfReconnect()
        #Parse alert data
        alert = request.json
        order = MarketOrder(alert['action'],alert['quantity'],account=app.ib.wrapper.accounts[0])
        #Submit market order
        stock_contract = Stock('NVDA','SMART','USD')
        app.ib.placeOrder(stock_contract,order)
    return response.json({})  # return a empty JSON

0
投票

当我尝试编译代码时遇到此错误

“不允许在 Sanic 实例上设置变量。您应该更改 Sanic 实例以使用 instance.ctx.ib。”

我正在使用 Visual Studio 2022

知道我需要在这里改变什么吗?

谢谢你

© www.soinside.com 2019 - 2024. All rights reserved.