tedchou12 / webull

Unofficial APIs for Webull.
MIT License
602 stars 185 forks source link

Modify options order: #402

Open M1NL1TE opened 1 year ago

M1NL1TE commented 1 year ago

@michaelkkehoe @tedchou12 Have you been successful with a modify option order with the 'https://act.webullbroker.com/webull-paper-center/api/paper/v1/order/optionReplace' endpoint?

I keep getting this response: 2023-05-25 12:42:58,193 INFO b'{"msg":"orderId=null","traceId":"b7ef3d8e73a84dda9b3d8146e2024d20","code":"400","success":false}'

and this is the request: 2023-05-25 12:42:58,192 INFO b'{"oderId": 105353561, "orderType": "LMT", "accountId": 12345, "paperId": 1, "timeInForce": "GTC", "serialId": "XYZ", "orders": [{"quantity": 1, "action": "BUY", "tickerId": 1038356919, "tickerType": "OPTION", "orderId": 105353561}], "lmtPrice": 1.29}'

(intentionally omitted possibly sensitive info)

And here is how I implemented the modify order function in webull.py: def modify_order_option(self, order=None, lmtPrice=None, stpPrice=None, enforce=None, quant=0): ''' order: dict from get_current_orders stpPrice: float lmtPrice: float enforce: GTC / DAY quant: int ''' headers = self.build_req_headers(include_trade_token=True, include_time=True) data = { 'oderId': order[0]['orderId'], 'orderType': order[0]['orderType'], 'accountId': self._account_id, 'paperId': 1, 'timeInForce': enforce or order[0]['timeInForce'], 'serialId': str(uuid.uuid4()), 'orders': [{'quantity': quant or order[0]['totalQuantity'], 'action': order[0]['action'], 'tickerId': order[0]['ticker']['tickerId'], 'tickerType': 'OPTION', 'orderId': order[0]['orderId']}] }

if order[0]['orderType'] == 'LMT' and (lmtPrice or order.get('lmtPrice')):
    data['lmtPrice'] = lmtPrice or order[0]['lmtPrice']
elif order[0]['orderType'] == 'STP' and (stpPrice or order.get('auxPrice')):
    data['auxPrice'] = stpPrice or order[0]['auxPrice']
elif order[0]['orderType'] == 'STP LMT' and (stpPrice or order.get('auxPrice')) and (lmtPrice or order.get('lmtPrice')):
    data['auxPrice'] = stpPrice or order[0]['auxPrice']
    data['lmtPrice'] = lmtPrice or order[0]['lmtPrice']

url = 'https://act.webullbroker.com/webull-paper-center/api/paper/v1/order/optionReplace'
response = requests.post(url, json=data, headers=headers, timeout=self.timeout)

logging.info(response.request.body)
logging.info(response.content)
if response.status_code != 200:
    raise Exception('replace_option_order failed', response.status_code, response.reason)
return True

The main change I made to the regular account modify_order_option was taking out the "'comboId': order['comboId']" line in the data dictionary as I don't see that in the list of "openOrders" for the paper account. It's somehow not accepting the orderId from the request and I'm not sure why.


Here are the API endpoints:

https://act.webullbroker.com/webull-paper-center/api/paper/v1/order/getOptionAccountDetailAndPosition https://act.webullbroker.com/webull-paper-center/api/paper/v1/order/optionPlace https://act.webullbroker.com/webull-paper-center/api/paper/v1/order/optionReplace

Here is an example function to place option orders:

    def place_order_option(self, optionId=None, lmtPrice=None, stpPrice=None, action=None, orderType='LMT', enforce='DAY', quant=0):
        '''
        create buy / sell order
        stock: string
        lmtPrice: float
        stpPrice: float
        action: string BUY / SELL
        optionId: string
        orderType: MKT / LMT / STP / STP LMT
        enforce: GTC / DAY
        quant: int
        '''
        headers = self.build_req_headers(include_trade_token=True, include_time=True)
        data = {
            'orderType': orderType,
            'serialId': str(uuid.uuid4()),
            'paperId': 1,
            'accountId': self._account_id,
            'tickerId': int(optionId),
            'quantity': int(quant),
            'action': "BUY",
            'timeInForce': enforce,
            'orders': [{'quantity': int(quant), 'action': action, 'tickerId': int(optionId), 'tickerType': 'OPTION'}],
        }

        if orderType == 'LMT' and lmtPrice :
            data['lmtPrice'] = float(lmtPrice)
        elif orderType == 'STP' and stpPrice :
            data['auxPrice'] = float(stpPrice)
        elif orderType == 'STP LMT' and lmtPrice and stpPrice :
            data['lmtPrice'] = float(lmtPrice)
            data['auxPrice'] = float(stpPrice)

        url = 'https://act.webullbroker.com/webull-paper-center/api/paper/v1/order/optionPlace'
        response = requests.post(url, json=data, headers=headers, timeout=self.timeout)
        if response.status_code != 200:
            raise Exception('place_option_order failed', response.status_code, response.reason)

Originally posted by @michaelkkehoe in https://github.com/tedchou12/webull/issues/316#issuecomment-1408021185

michaelkkehoe commented 1 year ago

I haven't tried a modify order for paper options.

M1NL1TE commented 1 year ago

I haven't tried a modify order for paper options.

@michaelkkehoe May I ask how you found the endpoints for the modify options order and the other endpoints? Did you use something like wire shark or postman with the Webull desktop application? I've had difficulties with wire shark

michaelkkehoe commented 1 year ago

$ cd /usr/local/WebullDesktop $ strings wbplugins/libtradestore.so | grep paper-center

M1NL1TE commented 1 year ago

$ cd /usr/local/WebullDesktop

$ strings wbplugins/libtradestore.so | grep paper-center

@michaelkkehoe Sorry to bother you again but when I try that command in my visual studio code git bash command terminal on Windows 10, it doesn't recognize the command. I was wondering what OS are you running with what terminal and what packages or anything else I would need to make it work with that command. Here's an example of my terminal: image

michaelkkehoe commented 1 year ago

@M1NL1TE It's a standard linux command. I found this using Webull Desktop application on my Ubuntu laptop.