You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

E*TRADE API报101超时错误:下单重试仍失败问题排查

E*TRADE API 下单超时错误排查

错误信息

Failed to place BUY order for JAN, status code: 
400, response: {"Error":{"code":101,"message":"For your protection, we have timed out your original order request. If you would like to place this order, please resubmit it now."}}

问题描述

已在代码中设置最多3次重试逻辑,但每次尝试下单仍返回上述超时保护错误,代码调用逻辑无误。

核心代码

def preview_order(etrade, session, ticker, quantity, limit_price, order_action):
    preview_url = etrade.base_url + "/v1/accounts/" + ETRADE_ACCOUNT_KEY + "/orders/preview.json"
    client_order_id = random.randint(1000000000, 9999999999)
 
    limit_price_rounded = "{:.2f}".format(limit_price)
 
    root = ET.Element("PreviewOrderRequest")
    ET.SubElement(root, "orderType").text = "EQ"
    ET.SubElement(root, "clientOrderId").text = str(client_order_id)
    order = ET.SubElement(root, "Order")
    ET.SubElement(order, "allOrNone").text = "false"
    ET.SubElement(order, "priceType").text = "LIMIT"
    ET.SubElement(order, "orderTerm").text = "GOOD_FOR_DAY"
    ET.SubElement(order, "marketSession").text = "REGULAR"
    ET.SubElement(order, "limitPrice").text = limit_price_rounded
    instrument = ET.SubElement(order, "Instrument")
    product = ET.SubElement(instrument, "Product")
    ET.SubElement(product, "securityType").text = "EQ"
    ET.SubElement(product, "symbol").text = ticker
    ET.SubElement(instrument, "orderAction").text = order_action.upper()
    ET.SubElement(instrument, "quantityType").text = "QUANTITY"
    ET.SubElement(instrument, "quantity").text = str(quantity)
 
    payload = ET.tostring(root, encoding='unicode')
    headers = {"Content-Type": "application/xml"}
 
    response = session.post(preview_url, header_auth=True, headers=headers, data=payload)
 
    if response.status_code == 200:
        response_data = response.json()
        if "PreviewOrderResponse" in response_data and "PreviewIds" in response_data["PreviewOrderResponse"]:
            preview_id = response_data["PreviewOrderResponse"]["PreviewIds"][0]["previewId"]
            return preview_id
        else:
            print("Preview order response is not as expected.")
            return None
    else:
        print(f"Failed to preview order, status code: {response.status_code}, response: {response.text}")
        return None
 
def place_order(etrade, session, ticker, quantity, limit_price, order_action, max_attempts=3):
    attempt = 1
    while attempt <= max_attempts:
        preview_id = preview_order(etrade, session, ticker, quantity, limit_price, order_action)
        if not preview_id:
            print("Failed to preview the order.")
            if attempt == max_attempts:
                return None
            else:
                print(f"Retrying preview order... Attempt {attempt} of {max_attempts}")
                attempt += 1
                continue
 
        order_url = etrade.base_url + "/v1/accounts/" + ETRADE_ACCOUNT_KEY + "/orders/place.json"
        limit_price_rounded = "{:.2f}".format(limit_price)
        client_order_id = random.randint(1000000000, 9999999999)
 
        root = ET.Element("PlaceOrderRequest")
        ET.SubElement(root, "orderType").text = "EQ"
        ET.SubElement(root, "clientOrderId").text = str(client_order_id)
        ET.SubElement(root, "PreviewId").text = str(preview_id)
        order = ET.SubElement(root, "Order")
        ET.SubElement(order, "allOrNone").text = "false"
        ET.SubElement(order, "priceType").text = "LIMIT"
        ET.SubElement(order, "orderTerm").text = "GOOD_FOR_DAY"
        ET.SubElement(order, "marketSession").text = "REGULAR"
        ET.SubElement(order, "limitPrice").text = limit_price_rounded
        instrument = ET.SubElement(order, "Instrument")
        product = ET.SubElement(instrument, "Product")
        ET.SubElement(product, "securityType").text = "EQ"
        ET.SubElement(product, "symbol").text = ticker
        ET.SubElement(instrument, "orderAction").text = order_action.upper()
        ET.SubElement(instrument, "quantityType").text = "QUANTITY"
        ET.SubElement(instrument, "quantity").text = str(quantity)
 
        payload = ET.tostring(root, encoding='unicode')
        headers = {"Content-Type": "application/xml"}
        response = session.post(order_url, header_auth=True, headers=headers, data=payload)
 
        if response.status_code == 201:
            response_data = response.json()
            if "OrderResponse" in response_data and "orderId" in response_data["OrderResponse"]:
                order_id = response_data["OrderResponse"]["orderId"]
                print(f"{order_action} order placed for {quantity} of {ticker} at {limit_price_rounded}, Order ID: {order_id}")
            return order_id
        else:
            print(f"Failed to place {order_action} order for {ticker}, status code: {response.status_code}, response: {response.text}")
            
            if response.status_code == 400 and "timed out" in response.text:
                print("Resubmitting order due to timeout...")
                attempt += 1
            else:
                return None
 
    return None

最小可复现代码(需配置正确密钥)

import xml.etree.ElementTree as ET
import random
from rauth import OAuth1Service
import webbrowser

CONSUMER_KEY = 'CONSUMER_KEY'
CONSUMER_SECRET = 'CONSUMER_SECRET'
ETRADE_ACCOUNT_KEY = 'ACCOUNT_KEY'

def initialize_etrade_oauth():
    etrade = OAuth1Service(
        name="etrade",
        consumer_key=CONSUMER_KEY,
        consumer_secret=CONSUMER_SECRET,
        request_token_url="https://api.etrade.com/oauth/request_token",
        access_token_url="https://api.etrade.com/oauth/access_token",
        authorize_url="https://us.etrade.com/e/t/etws/authorize?key={}&token={}",
        base_url="https://api.etrade.com"
    )
    return etrade

def place_order(etrade, session, ticker, quantity, limit_price):
    order_url = etrade.base_url + "/v1/accounts/" + ETRADE_ACCOUNT_KEY + "/orders/place.json"
    client_order_id = random.randint(1000000000, 9999999999)

    root = ET.Element("PlaceOrderRequest")
    ET.SubElement(root, "orderType").text = "EQ"
    ET.SubElement(root, "clientOrderId").text = str(client_order_id)
    order = ET.SubElement(root, "Order")
    ET.SubElement(order, "allOrNone").text = "false"
    ET.SubElement(order, "priceType").text = "LIMIT"
    ET.SubElement(order, "orderTerm").text = "GOOD_FOR_DAY"
    ET.SubElement(order, "marketSession").text = "REGULAR"
    ET.SubElement(order, "limitPrice").text = str(limit_price)
    instrument = ET.SubElement(order, "Instrument")
    product = ET.SubElement(instrument, "Product")
    ET.SubElement(product, "securityType").text = "EQ"
    ET.SubElement(product, "symbol").text = ticker
    ET.SubElement(instrument, "orderAction").text = "BUY"
    ET.SubElement(instrument, "quantityType").text = "QUANTITY"
    ET.SubElement(instrument, "quantity").text = str(quantity)

    payload = ET.tostring(root, encoding='unicode')
    headers = {"Content-Type": "application/xml"}

    response = session.post(order_url, header_auth=True, headers=headers, data=payload)

    if response.status_code == 201:
        print(f"Buy order placed for {quantity} shares of {ticker} at limit price {limit_price}")
    else:
        print(f"Failed to place order: {response.text}")

def preview_order(etrade, session, ticker, quantity, limit_price, order_action):
    preview_url = etrade.base_url + "/v1/accounts/" + ETRADE_ACCOUNT_KEY + "/orders/preview.json"
    client_order_id = random.randint(1000000000, 9999999999)

    root = ET.Element("PreviewOrderRequest")
    ET.SubElement(root, "orderType").text = "EQ"
    ET.SubElement(root, "clientOrderId").text = str(client_order_id)
    order = ET.SubElement(root, "Order")
    ET.SubElement(order, "allOrNone").text = "false"
    ET.SubElement(order, "priceType").text = "LIMIT"
    ET.SubElement(order, "orderTerm").text = "GOOD_FOR_DAY"
    ET.SubElement(order, "marketSession").text = "REGULAR"
    ET.SubElement(order, "limitPrice").text = str(limit_price)
    instrument = ET.SubElement(order, "Instrument")
    product = ET.SubElement(instrument, "Product")
    ET.SubElement(product, "securityType").text = "EQ"
    ET.SubElement(product, "symbol").text = ticker
    ET.SubElement(instrument, "orderAction").text = order_action.upper()
    ET.SubElement(instrument, "quantityType").text = "QUANTITY"
    ET.SubElement(instrument, "quantity").text = str(quantity)

    payload = ET.tostring(root, encoding='unicode')
    headers = {"Content-Type": "application/xml"}

    response = session.post(preview_url, header_auth=True, headers=headers, data=payload)

    if response.status_code == 200:
        response_data = response.json()
        if "PreviewOrderResponse" in response_data and "PreviewIds" in response_data["PreviewOrderResponse"]:
            preview_id = response_data["PreviewOrderResponse"]["PreviewIds"][0]["previewId"]
            return preview_id
    else:
        print(f"Failed to preview order, status code: {response.status_code}, response: {response.text}")
        return None

def main():
    etrade = initialize_etrade_oauth()

    request_token, request_token_secret = etrade.get_request_token(
        params={"oauth_callback": "oob", "format": "json"})

    authorize_url = etrade.authorize_url.format(etrade.consumer_key, request_token)
    print("Please authorize the application by visiting this URL: ", authorize_url)
    webbrowser.open(authorize_url)

    verifier_code = input("Enter the verification code from the browser: ")

    session = etrade.get_auth_session(request_token, request_token_secret,
                                      params={"oauth_verifier": verifier_code})

    ticker = "PLTR"
    quantity = 10
    limit_price = 17

    preview_id = preview_order(etrade, session, ticker, quantity, limit_price, "BUY")
    if preview_id is None:
        print("Failed to preview the order.")
        return

    place_order(etrade, session, ticker, quantity, limit_price, "BUY", preview_id)

if __name__ == "__main__":
    main()

请求排查

恳请帮忙排查为何反复触发该超时保护错误,且重试后仍无法解决。


内容的提问来源于stack exchange,提问作者Arnav Sivakumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:07:33