GithubHelp home page GithubHelp logo

Comments (42)

jessecooper avatar jessecooper commented on May 26, 2024 3

@Robert-Zacchigna Looks like there is a short coming in the pyetrade lib that is corrected by your function. Would you mind opening up a PR that would add your method to the ETradeOrder object? That would be very appreciated I am sure by everyone in the community.

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024 2

Hi, I've been trying to automate some options trades using pytrade/etrade for some months and while I can get individual legs to excersise, there doesn't seem to be support for spreads using pyetrade. Hense I've been looking at your code example here and trying to modify that to suit my needs. Starting with the code as is, I don't seem able to get passed the etrade_oauth part. I see NameError: name 'etrade_oauth' is not defined. Did you mean: 'ETradeOAuth'? Would anyone be able to help me integrate the above code into Jesse's original outh example ?

My code above assumed you already have setup ETradeOAuth and EtradeOrder

For EtradeOAuth, in my case i named the variable etrade_oauth:

etrade_oauth = ETradeOAuth(consumer_key, consumer_secret)

You then need to create the ETradeOrder obj, in my case i named it etrade_order:

etrade_order = ETradeOrder(
    consumer_key, consumer_secret,
    oauth_token, oauth_secret, dev=False  # False for PROD, True for SANDBOX
)

Once the above is done, then you can run my code above, which i think still works. I've made some changes since then i think.

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024 1

For anyone else who comes across this thread, i was unable to get the preview_equity_order and place_equity_order functions to work but i was able to come up with this workaround.

You basically need to make the request yourself using the underlying api endpoints instead of the functions. For these function to work, you need to have already setup pyetrades oauth (in my case its etrade_oauth) and order objs (in my case etrade_order)

import json
import xmltodict
import xml.etree.ElementTree as ET

from dicttoxml2 import dicttoxml

from pyetrade.order import ETradeOrder
from pyetrade import ETradeAccounts, ETradeOAuth

Function for making the post requests to the etrade api endpoints

def _post_etrade_req(etrade_oauth: ETradeOAuth, etrade_order: ETradeOrder, account_id_key: str,
                     order_params: dict, post_endpoint: str, print_payload: bool, print_response: bool) -> dict:

    order_payload = dicttoxml(order_params, root=False, attr_type=False).decode('UTF-8')

    if print_payload:
        pretty_xml = ET.XML(order_payload)
        ET.indent(pretty_xml)
        print(f'\n{post_endpoint.capitalize()} Order Request XML Payload:\n{"="*(27+len(post_endpoint))}\n'
              f'{ET.tostring(pretty_xml, encoding="unicode")}')

    headers = {"consumerKey": etrade_oauth.consumer_key, 'Content-Type': 'application/xml'}
    post_endpoint_url = f'https://api.etrade.com/v1/accounts/{account_id_key}/orders/{post_endpoint}'

    order_response = etrade_order.session.post(post_endpoint_url, headers=headers, data=order_payload)

    order_data = json.loads(json.dumps(xmltodict.parse(order_response.text)))
    
    if print_response:
        print(f'\n{post_endpoint.capitalize()} Order JSON Response:\n{"="*(21+len(post_endpoint))}\n'
              f'{json.dumps(order_data, indent=4)}')

    return order_data

My preview_shares_order function - this returns the preview_order_params and the preview_id from the preview_order_response:

# order_action_values = ['BUY', 'SELL', 'BUY_TO_COVER', 'SELL_SHORT']
# price_types_values = ['MARKET', 'LIMIT', 'STOP', 'STOP_LIMIT', 'MARKET_ON_CLOSE']
# market_session_values = ['REGULAR', 'EXTENDED']
# order_term_values = ['GOOD_UNTIL_CANCEL', 'GOOD_FOR_DAY', 'IMMEDIATE_OR_CANCEL', 'FILL_OR_KILL']
# routing_destinations_values = ['AUTO', 'ARCA', 'NSDQ', 'NYSE']

# Reference number generated by developer. Used to ensure duplicate order is not submitted.
# Value can be of 20 alphanmeric characters or less Must be unique within this account.
# Does not appear in any API responses.
# Ref: https://apisb.etrade.com/docs/api/order/api-order-v1.html#/definitions/OrderDetail
def preview_shares_order(etrade_oauth: ETradeOAuth, etrade_order: ETradeOrder, account_id_key: str, symbol: str,
                         limit_price: float, quantity: int, print_payload: bool, print_response: bool, 
                         order_type: str = 'EQ', order_action: str = 'BUY', all_or_none: bool = False,
                         client_order_id: str = str(randint(1000000000, 9999999999)), stop_price: float = 0,
                         price_type: str = 'LIMIT', market_session: str = 'REGULAR', 
                         order_term: str = 'IMMEDIATE_OR_CANCEL', routing_destination: str = 'AUTO') -> tuple[dict, int]:

    preview_order_params = {
        'PreviewOrderRequest': {
            'orderType': order_type,
            'clientOrderId': client_order_id,
            'Order': {
                'allOrNone': all_or_none,
                'priceType': price_type,
                'orderTerm': order_term,
                'marketSession': market_session,
                'stopPrice': stop_price,
                'limitPrice': limit_price,
                'routingDestination': routing_destination,
                'Instrument': {
                    'Product': {
                        'securityType': 'EQ',
                        'symbol': symbol
                    },
                    'orderAction': order_action,
                    'quantityType': 'QUANTITY',
                    'quantity': quantity,
                }
            }
        }
    }

    preview_order_data = _post_etrade_req(etrade_oauth, etrade_order, account_id_key, preview_order_params,
                                          'preview', print_payload, print_response)

    return preview_order_params['PreviewOrderRequest'], preview_order_data['PreviewOrderResponse']['PreviewIds']['previewId']

My place_shares_order function, this is similar to the above function. This takes the preview_order_params and the preview_id from the preview_shares_order function to make the equity order. It will check and display if the order is successful or not:

def place_shares_order(etrade_oauth: ETradeOAuth, etrade_order: ETradeOrder, account_id_key: str,
                       preview_order_params: dict, preview_id: int, print_payload: bool, print_response: bool) -> None:

    # Insert preview_order_params and preview_id into new place_shares_order payload
    place_order_params = {'PlaceOrderRequest': preview_order_params}
    place_order_params['PlaceOrderRequest']['PreviewIds'] = {'previewId': preview_id}

    place_order_data = _post_etrade_order_req(etrade_oauth, etrade_order, account_id_key, place_order_params, 'place',
                                              print_payload, print_response)['PlaceOrderResponse']['Order']['messages']['Message']

    for index, msg_codes in enumerate(place_order_data):
        order_msg_code = msg_codes['code']
        order_msg_desc = msg_codes['description'].replace('|', ' - ')

        # Order success code = 1026
        # Ref: https://apisb.etrade.com/docs/api/order/api-order-v1.html#/definitions/ErrorCodes
        if order_msg_code != '1026' and index + 1 == len(place_order_data):
            raise ValueError(f"Order Msg Code: {order_msg_code}\n   Description: {order_msg_desc}")
        print(f"Order Msg Code: {order_msg_code}\n   Description: {order_msg_desc}\n")

And calling them:

preview_order_params, preview_id = preview_shares_order(etrade_oauth, etrade_order, account_id_key, 'CVNA',
                                                        1.00, 1, print_payload=False, print_response=False)

place_shares_order(etrade_oauth, etrade_order, account_id_key, preview_order_params,
                   preview_id, print_payload=False, print_response=False)

If successful your output should be:

Order Msg Code: 1026
Description: 200 - Your order was successfully entered during market hours.

You can verify even further by printing out your order history:

print('Orders:', etrade_order.list_orders(account_id_key, resp_format='json'))

from pyetrade.

sfcheng avatar sfcheng commented on May 26, 2024 1

After one day of digging, I found the root cause of this stupid issue. The string key "previewIds" need be capitalized as "PreviewIds". Otherwise, the server won't recognize the previewId parameter.

from pyetrade.

m4rkyt avatar m4rkyt commented on May 26, 2024 1

Thanks @Robert-Zacchigna that's working fine now for equity orders ! I will modify the fields to support Options orders insteadf of Equity orders and hopefully eventually get a spread to work also. Much apprecaited.

from pyetrade.

jessecooper avatar jessecooper commented on May 26, 2024 1

@Robert-Zacchigna Thank you for doing this. Give me a bit of time to look at the changes.

from pyetrade.

mkfrancis01 avatar mkfrancis01 commented on May 26, 2024

Hello yangliu2. I am also having the same issue. Matter of fact I am not even able to execute the preview_equity_order() function. Getting "missing kwargs" error. Below are the details. Hope I am not hijacking your issue request but would you know what is causing this issue since I see you are able to execute preview_equity_order?

if not all(param in kwargs for param in mandatory):
--> 135 raise OrderException
136
137 if kwargs["priceType"] == "STOP" and "stopPrice" not in kwargs

Below is the kwargs dictionary I am using in SandBox environment
kwargs = {
"accountId":"6_Dpy0rmuQ9cu9IbTfvF2A",
"symbol":"AAPL",
"orderAction":"BUY",
"clientOrderId": random.randint(10000000,99999999),
"priceType":"MARKET",
"allOrNone": True,
"limitPrice":0,
"stopPrice":0,
}

from pyetrade.

yangliu2 avatar yangliu2 commented on May 26, 2024

No problem man! I'm having the same error. I manually checked the required keys AND modified source code to check if "mandatory" have it. No luck. I don't know what's it's checking. This is where I went to Etrade sample code instead. Also remember trade sandbox have fixed response for preview and place order, so you need to make sure your placing order payload is the same as the preview response, not whatever payload you send it to them. Now I'm sticking on error 9999 for placing order.

from pyetrade.

mkfrancis01 avatar mkfrancis01 commented on May 26, 2024

Hello yangliu2

Thanks for your response. After trying a few things was able to make the preview order and place order to work. You simply have to make sure your kwargs dictionary is in the order in the mandatory list in the check order() function.

mandatory = ["accountId","symbol","orderAction","clientOrderId","priceType","quantity","orderTerm","marketSession"]

Ofcourse remember to use ** before kwargs in the paranthesis to show its a dictionary.

All this was in dev environment. I haven't tried actual prod environment..

Let me know how it goes.

from pyetrade.

mkfrancis01 avatar mkfrancis01 commented on May 26, 2024

Test these kwarg keys values,

kwargs = {"accountId":"6_Dpy0rmuQ9cu9IbTfvF2A",
"symbol":"GOGL",
"orderAction":"BUY",
"clientOrderId": random.randint(10000000,99999999),
"priceType":"MARKET",
"allOrNone": True,
"limitPrice":0,
"stopPrice":0,
"quantity":100,
"orderTerm":"GOOD_FOR_DAY",
"marketSession":"REGULAR"
}

Then after you instantiate the ETradeOrder class and create an object try calling the method below
myfirstorder.preview_equity_order(**kwargs)

from pyetrade.

yangliu2 avatar yangliu2 commented on May 26, 2024

For some reason, if I use resp_format='json', then I get a 400 response error. Without the parameter, it seems to be fine. ¯\_(ツ)_/¯

from pyetrade.

1rocketdude avatar 1rocketdude commented on May 26, 2024

from pyetrade.

gargv6880 avatar gargv6880 commented on May 26, 2024

Hello yangliu2,

I am also facing exact same issue which you faced. Please let me know how you resolved this.

Thanks a lot.

from pyetrade.

tommyhuangli avatar tommyhuangli commented on May 26, 2024

Hi, @yangliu2 were you able to resolve this and place order successfully from python code?

from pyetrade.

yangliu2 avatar yangliu2 commented on May 26, 2024

from pyetrade.

yui410122 avatar yui410122 commented on May 26, 2024

I am also trying to place an order with the ETrade API and got the following 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.'}

the preview order seems to be working ok. If anyone figures how to successfully place an order please let me know, thanks!

from pyetrade.

yui410122 avatar yui410122 commented on May 26, 2024

@yangliu2 could you please share the code ETrade support provides?

Thanks!

from pyetrade.

tommyhuangli avatar tommyhuangli commented on May 26, 2024

from pyetrade.

yangliu2 avatar yangliu2 commented on May 26, 2024

Here is the code I got from Etrade. There weren't any formating, so you may have to retype.

Below is a simple method for place order. Make sure you copy the fields from preview order into your place order and you have to pass the previewId from the response from the preview order into the place order request or it will not work. Should you questions feel free to reply to this message.

def place_order(session, account, order):

"""

Calls place order API to submit an order request for confirmation after preview order is successfully called

:param session: authenticated session

:param account: information on selected account

:param order: list of instruments from previous orders

"""

URL for the API endpoint
url = "https://api.etrade.com/v1/accounts/" + account["accountIdKey"]+ "/orders/place.json"
Add parameters and header information
headers = {"Content-Type": "application/xml", "consumerKey": config["DEFAULT"]["CONSUMER_KEY"]}
Add payload for POST Request
payload = """
{0}
{1}
{2}
false
{3}
{4}
REGULAR
{5}
{6}
{7}
{8}
QUANTITY
{9}
"""
payload = payload.format(order["order_type"], order["client_order_id"], order["preview_id"],
order["price_type"], order["order_term"], order["limitPrice"],
order["security_type"], order["symbol"], order["order_action"], order["quantity"])
Make API call for POST request
response = session.post(url, header_auth=True, headers=headers, data=payload)
logger.debug("Request Header: %s", response.request.headers)
logger.debug("Request payload: %s", payload)
Handle and parse response
if response is not None and response.status_code == 200:
parsed = json.loads(response.text)
logger.debug("Response Body: %s", json.dumps(parsed, indent=4, sort_keys=True))
data = response.json()
print("\nOrder number #"
+ str(data["PlaceOrderResponse"]["OrderIds"][0]["orderId"])
+ " successfully placed.")
else:
Handle errors
data = response.json()
if 'Error' in data and 'message' in data["Error"]and data["Error"]["message"]is not None:
print("Error: " + data["Error"]["message"])
else:
print("Error: Preview Order API service error")

from pyetrade.

yui410122 avatar yui410122 commented on May 26, 2024

Thanks @yangliu2 !

"Make sure you copy the fields from preview order into your place order and you have to pass the previewId from the response from the preview order into the place order request or it will not work."

This comment is really useful! I tried to include the previewID and now placing the order works!

Thanks a lot!

from pyetrade.

jessecooper avatar jessecooper commented on May 26, 2024

@yangliu2 Can you please open a PR with any changes that are needed in pyetrade to better support this?

from pyetrade.

alanoatwork avatar alanoatwork commented on May 26, 2024

Thanks @yangliu2 !

"Make sure you copy the fields from preview order into your place order and you have to pass the previewId from the response from the preview order into the place order request or it will not work."

This comment is really useful! I tried to include the previewID and now placing the order works!

Thanks a lot!

I tried including the previewId in the order but I still get error 400 after the place_equity_order is called. Any clue why this isn't working??

   resp = orders.preview_equity_order(
        accountId=self.account_id,
        symbol="IBM",
        orderAction="BUY",
        clientOrderId="1",
        priceType="MARKET",
        quantity="1",
        orderTerm="GOOD_UNTIL_CANCEL",
        marketSession="REGULAR"
    )

    preview_id = resp['PreviewOrderResponse']['PreviewIds']['previewId'].get_cdata()

    resp = orders.place_equity_order(
        previewId=preview_id,
        accountId=self.account_id,
        symbol="IBM",
        orderAction="BUY",
        clientOrderId="1",
        priceType="MARKET",
        quantity="1",
        orderTerm="GOOD_UNTIL_CANCEL",
        marketSession="REGULAR"
    )

from pyetrade.

Lucifer-lab74 avatar Lucifer-lab74 commented on May 26, 2024

I've tried all of above solutions but None is working for me, place order keep responding same error and preview order working correctly

from pyetrade.

windrider09 avatar windrider09 commented on May 26, 2024

Looots of inconsistency in Etrade API. Sometimes the first character is capped and sometimes it isn't.

from pyetrade.

sfcheng avatar sfcheng commented on May 26, 2024

I do have another issue with etrade api. During authentication, from time to time, I got this error. All I can do is to restart the code and then it could pass without error.

Exception has occurred: UnicodeDecodeError
'ascii' codec can't decode byte 0xe2 in position 60: ordinal not in range(128)
File "I:\projects\EtradePythonClient\auto_trade.py", line 577, in
session = etrade.get_auth_session(request_token,
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 60: ordinal not in range(128)

from pyetrade.

m4rkyt avatar m4rkyt commented on May 26, 2024

For anyone else who comes across this thread, i was unable to get the preview_equity_order and place_equity_order functions to work but i was able to come up with this workaround.

You basically need to make the request yourself using the underlying api endpoints instead of the functions. For these function to work, you need to have already setup pyetrades oauth obj (in my case its etrade_oauth)

import json
import xmltodict
import xml.etree.ElementTree as ET

from dicttoxml2 import dicttoxml

from pyetrade.order import ETradeOrder
from pyetrade import ETradeAccounts, ETradeOAuth

Function for making the post requests to the etrade api endpoints

def _post_etrade_req(etrade_oauth: ETradeOAuth, etrade_order: ETradeOrder, account_id_key: str,
                     order_params: dict, post_endpoint: str, print_payload: bool, print_response: bool) -> dict:

    order_payload = dicttoxml(order_params, root=False, attr_type=False).decode('UTF-8')

    if print_payload:
        pretty_xml = ET.XML(order_payload)
        ET.indent(pretty_xml)
        print(f'\n{post_endpoint.capitalize()} Order Request XML Payload:\n{"="*(27+len(post_endpoint))}\n'
              f'{ET.tostring(pretty_xml, encoding="unicode")}')

    headers = {"consumerKey": etrade_oauth.consumer_key, 'Content-Type': 'application/xml'}
    post_endpoint_url = f'https://api.etrade.com/v1/accounts/{account_id_key}/orders/{post_endpoint}'

    order_response = etrade_order.session.post(post_endpoint_url, headers=headers, data=order_payload)

    order_data = json.loads(json.dumps(xmltodict.parse(order_response.text)))
    
    if print_response:
        print(f'\n{post_endpoint.capitalize()} Order JSON Response:\n{"="*(21+len(post_endpoint))}\n'
              f'{json.dumps(order_data, indent=4)}')

    return order_data

My preview_shares_order function - this returns the preview_order_params and the preview_id from the preview_order_response:

# order_action_values = ['BUY', 'SELL', 'BUY_TO_COVER', 'SELL_SHORT']
# price_types_values = ['MARKET', 'LIMIT', 'STOP', 'STOP_LIMIT', 'MARKET_ON_CLOSE']
# market_session_values = ['REGULAR', 'EXTENDED']
# order_term_values = ['GOOD_UNTIL_CANCEL', 'GOOD_FOR_DAY', 'IMMEDIATE_OR_CANCEL', 'FILL_OR_KILL']
# routing_destinations_values = ['AUTO', 'ARCA', 'NSDQ', 'NYSE']

# Reference number generated by developer. Used to ensure duplicate order is not submitted.
# Value can be of 20 alphanmeric characters or less Must be unique within this account.
# Does not appear in any API responses.
# Ref: https://apisb.etrade.com/docs/api/order/api-order-v1.html#/definitions/OrderDetail
def preview_shares_order(etrade_oauth: ETradeOAuth, etrade_order: ETradeOrder, account_id_key: str, symbol: str,
                         limit_price: float, quantity: int, print_payload: bool, print_response: bool, 
                         order_type: str = 'EQ', order_action: str = 'BUY', all_or_none: bool = False,
                         client_order_id: str = str(randint(1000000000, 9999999999)), stop_price: float = 0,
                         price_type: str = 'LIMIT', market_session: str = 'REGULAR', 
                         order_term: str = 'IMMEDIATE_OR_CANCEL', routing_destination: str = 'AUTO') -> tuple[dict, int]:

    preview_order_params = {
        'PreviewOrderRequest': {
            'orderType': order_type,
            'clientOrderId': client_order_id,
            'Order': {
                'allOrNone': all_or_none,
                'priceType': price_type,
                'orderTerm': order_term,
                'marketSession': market_session,
                'stopPrice': stop_price,
                'limitPrice': limit_price,
                'routingDestination': routing_destination,
                'Instrument': {
                    'Product': {
                        'securityType': 'EQ',
                        'symbol': symbol
                    },
                    'orderAction': order_action,
                    'quantityType': 'QUANTITY',
                    'quantity': quantity,
                }
            }
        }
    }

    preview_order_data = _post_etrade_req(etrade_oauth, etrade_order, account_id_key, preview_order_params,
                                          'preview', print_payload, print_response)

    return preview_order_params['PreviewOrderRequest'], preview_order_data['PreviewOrderResponse']['PreviewIds']['previewId']

My place_shares_order function, this is similar to the above function. This takes the preview_order_params and the preview_id from the preview_shares_order function to make the equity order. It will check and display if the order of successful or not:

def place_shares_order(etrade_oauth: ETradeOAuth, etrade_order: ETradeOrder, account_id_key: str,
                       preview_order_params: dict, preview_id: int, print_payload: bool,print_response: bool) -> None:

    # Insert preview_order_params and preview_id into new place_shares_order payload
    place_order_params = {'PlaceOrderRequest': preview_order_params}
    place_order_params['PlaceOrderRequest']['PreviewIds'] = {'previewId': preview_id}

    place_order_data = _post_etrade_req(etrade_oauth, etrade_order, account_id_key, place_order_params,
                                        'place', print_payload, print_response)

    order_msg_code = place_order_data['PlaceOrderResponse']['Order']['messages']['Message']['code']
    order_msg_desc = place_order_data['PlaceOrderResponse']['Order']['messages']['Message']['description'].replace('|', ' - ')

    # Order success code = 1026
    # Ref: https://apisb.etrade.com/docs/api/order/api-order-v1.html#/definitions/ErrorCodes
    if order_msg_code != '1026':
        raise ValueError(f"Order Msg Code: {order_msg_code}\n   Description: {order_msg_desc}")
    print(f"\nOrder Msg Code: {order_msg_code}\n   Description: {order_msg_desc}\n")

And calling them:

preview_order_params, preview_id = preview_shares_order(etrade_oauth, etrade_order, account_id_key, 'CVNA',
                                                        1.00, 1, print_payload=False, print_response=False)

place_shares_order(etrade_oauth, etrade_order, account_id_key, preview_order_params,
                   preview_id, print_payload=False, print_response=False)

If successful your output should be:

Order Msg Code: 1026
Description: 200 - Your order was successfully entered during market hours.

You can verify even further by printing out your order history:

print('Orders:', etrade_order.list_orders(account_id_key, resp_format='json'))

from pyetrade.

m4rkyt avatar m4rkyt commented on May 26, 2024

Hi, I've been trying to automate some options trades using pytrade/etrade for some months and while I can get individual legs to excersise, there doesn't seem to be support for spreads using pyetrade. Hense I've been looking at your code example here and trying to modify that to suit my needs. Starting with the code as is, I don't seem able to get passed the etrade_oauth part. I see NameError: name 'etrade_oauth' is not defined. Did you mean: 'ETradeOAuth'? Would anyone be able to help me integrate the above code into Jesse's original outh example ?

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024

@m4rkyt No problem, glad you were able to make it work.

@jessecooper I'd be happy to, i haven't looked too deeply into the source code so it might take me a little bit to get up to speed. By method do you mean _post_etrade_req or do you mean a fix for the preview_equity_order and place_equity_order functions in order.py?

from pyetrade.

jessecooper avatar jessecooper commented on May 26, 2024

@m4rkyt No problem, glad you were able to make it work.

@jessecooper I'd be happy to, i haven't looked too deeply into the source code so it might take me a little bit to get up to speed. By method do you mean _post_etrade_req or do you mean a fix for the preview_equity_order and place_equity_order functions in order.py?

The fix for preview_equity_order and place_equity_order in order.py

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024

@jessecooper Ok so after digging through some things, I was actually able to get the functions already in order.py to work and place equity orders. You'll notice for both of them that i dont have resp_format specified.

This works to retrieve a previewId:

client_order_id = str(randint(1000000000, 9999999999))

preview_id = etrade_order.preview_equity_order(accountId=account_id_key, symbol='SPY', clientOrderId=client_order_id, limitPrice=300.0,
                                               quantity=1, orderType='EQ', orderAction='BUY', allOrNone=False, stopPrice=0,
                                               priceType='LIMIT', marketSession='REGULAR', orderTerm='FILL_OR_KILL',
                                               routingDestination='AUTO')['PreviewOrderResponse']['PreviewIds']['previewId']
print('PreviewID:', preview_id)

This code also successfully places the equity order without a previewId (verified in etrade under the orders tab):

client_order_id = str(randint(1000000000, 9999999999))

kwargs = {'accountId': account_id_key, 'symbol': 'SPY', 'orderAction': 'BUY', 'clientOrderId': client_order_id,
          'priceType': 'LIMIT', 'quantity': 1, 'orderTerm': 'FILL_OR_KILL', 'marketSession': 'REGULAR', 'limitPrice': 300,
          'orderType': 'EQ', 'allOrNone': False, 'stopPrice': 0, 'routingDestination': 'AUTO'}

print(etrade_order.place_equity_order(**kwargs))

AND

client_order_id = str(randint(1000000000, 9999999999))

print(etrade_order.place_equity_order(accountId=account_id_key, symbol='SPY', orderAction='BUY',
                                      clientOrderId=client_order_id, priceType='LIMIT', quantity=1,
                                      orderTerm='FILL_OR_KILL', marketSession='REGULAR', limitPrice=300,
                                      orderType='EQ', allOrNone=False, stopPrice=0, routingDestination='AUTO'))

Looking at it all, i think whats going on is a combination of misunderstanding the variable accountId name, the json resp_format option and what the kwargs payload should look like.

  • First, the accountId param, this is kinda confusing because the etrade accountId is actually the 8 digit number in etrade, where these requests require the accountId key to make the request (retrieved from the etrade_accounts.list_accounts() function). Therefore, my recommendation would be to change the name of the param to accountIdKey instead.
  • Second, for whatever reason specifying json for the resp_format for either of these function always results in a http 500 error (no matter what i tried to get it to work). Since it appears that the etrade API randomly supports json and xml in various areas (honestly what the heck were these devs doing then they created the API), my recommendation would be to hard code xml as the format for these functions to avoid this issue.
  • Lastly, I think the final part of this is that people might be creating the kwargs payload incorrectly, thus throwing the 500 error once more due to the incorrect params. My recommendation would be to either provide an example in the documentation of what a basic payload should look like OR, instead of utilizing kwargs, specify the params directly in the function to avoid the confusion and allow function hinting on what is needed and what is optional for the request (for both preview and place).

I can make the PR if you agree with the above, but please double check yourself that what i stated above is the same for you before we make any changes. Let me know what you find and if you agree with my assessment, thanks.

from pyetrade.

jessecooper avatar jessecooper commented on May 26, 2024

I do agree. The orders.py module is actually fairly older code and is not following the same patterns as refactored modules like the accounts.py module.
The newer modules all use xmltodict (https://github.com/jessecooper/pyetrade/blob/master/pyetrade/accounts.py#L10) and all methods are defaulted to xml (https://github.com/jessecooper/pyetrade/blob/master/pyetrade/accounts.py#L61).
Like you have noticed the json support is spotty for whatever reason in the ETrade API. I have been meaning to refactor all modules to follow this new pattern and use type hints where possible. I agree with all your above assertions and would really appreciated the contribution and modernization of that orders module. Thanks in advance.

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024

@jessecooper Sounds good, I've given it all a first run through, please check it out here and let me know what you think: #78

from pyetrade.

mw66 avatar mw66 commented on May 26, 2024

... hopefully eventually get a spread to work also.

@m4rkyt are you able to get the spread to work? can you create a PR to share the code?

from pyetrade.

m4rkyt avatar m4rkyt commented on May 26, 2024

Hi @mw66,
Currently my code still places all option legs individually and waits for confirmation on long fills before placing the short since my account won't let me trade naked shorts. It's a bit messy doing this as I can lose a few seconds waiting for confirmation of a fill so I do plan to modify this to use a spread. I will try this over the next couple of weeks and report back.

from pyetrade.

windrider09 avatar windrider09 commented on May 26, 2024

... hopefully eventually get a spread to work also.

@m4rkyt are you able to get the spread to work? can you create a PR to share the code?

I'd love to see the spread order working too.

from pyetrade.

korivernon avatar korivernon commented on May 26, 2024

Hi all, I'm new here. I'm trying to call the preview_equity_order method along with the place_equity_order method. I have a pretty lengthy question with two parts (1 is for options order, 2 is for equity order). I'm sure I'm doing something wrong somewhere and I'd appreciate some assistance with order functionality!

  1. I attempted to place an option order but I get the following response:
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.etrade.com', port=443): Read timed out.

Below is what I pass in to preview_equity_order

etrade_order.preview_equity_order(
        securityType="OPTN",
        orderType="OPTN",
        accountIdKey="XXXXXXXXXXXXXX",
        symbol="BAC",
        orderAction="SELL_CLOSE",
        clientOrderId="6591041807",
        priceType="MARKET",
        quantity=3,
        callPut="CALL",
        expiryDate=datetime.datetime(2023,4,21), # modified to take datetime object
        marketSession="REGULAR",
        orderTerm= "GOOD_FOR_DAY",
        strikePrice=30
    )

Here is the Payload

{ 
'PreviewOrderRequest': {
      'orderType': 'OPTN', 
      'clientOrderId': '6591041807', 
      'Order': {
            'securityType': 'OPTN', 
            'orderType': 'OPTN', 
            'accountIdKey': 'zBRmF6b_gzE-mkO74Vbaag', 
            'symbol': 'BAC', 
            'orderAction':  'SELL_CLOSE', 
            'clientOrderId': '6591041807', 
            'priceType': 'MARKET', 
            'quantity': 3, 
            'callPut': 'CALL', 
            'marketSession': 'REGULAR', 
            'orderTerm': 'GOOD_FOR_DAY', 
            'strikePrice': 30, 'Instrument': {
                        'Product': {
                              'securityType': 'OPTN', 
                              'symbol': 'BAC', 
                              'expiryDay': 21, 
                              'expiryMonth': 4, 
                              'expiryYear': 2023, 
                              'callPut': 'CALL', 
                              'strikePrice': 30
                                    }, 
                        'orderAction': 'SELL_CLOSE', 
                        'quantityType': 'QUANTITY', 
                        'quantity': 3
                  }
            }
      }
}
  1. Also having an issue when trying to place an equity order.
etrade_order.preview_equity_order(
        securityType="EQ",
        orderType="EQ",
        accountIdKey="XXXXXXXXXXXXXX",
        symbol="AAPL",
        orderAction="SELL",
        clientOrderId="6591041907",
        priceType="MARKET",
        quantity=1,
        marketSession="REGULAR",
        orderTerm="GOOD_FOR_DAY",
    )

Below is the preview order request.

{
'PreviewOrderRequest':  {
      'orderType': 'EQ', 
      'clientOrderId': '6591041907', 
      'Order': {
            'securityType': 'EQ', 
            'orderType': 'EQ', 
            'accountIdKey': 'XXXXXXXXXXXXXXX, 
            'symbol': 'AAPL', 
            'orderAction': 'SELL', 
            'clientOrderId': '6591041907', 
            'priceType': 'MARKET', 
            'quantity': 1, 
            'marketSession': 'REGULAR', 
            'orderTerm': 'GOOD_FOR_DAY', 
            'Instrument': {
                  'Product': {
                        'securityType': 'EQ', 
                        'symbol': 'AAPL'
                  }, 
            'orderAction': 'SELL', 
            'quantityType': 'QUANTITY', 
            'quantity': 1
                  }
            }
      }
}

I get the following response:

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.etrade.com', port=443): Read timed out.

Thanks for taking a look!
-Kori

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024

@korivernon I havent seen that error before, could be something with your network or something else.

  • Are you able to make other calls with the api?
  • Did you try this during trading hours or after hours?
  • Furthermore, one of the weird quirks of the API is that it wont let you preview or attempt to place an equity order if the order itself is more than the available cash you have to spend in your account. Don't know why it is that way, just something I've observed during my usage with the API.
    • Although that would usually kick out a different error than the one above (which is why i think it could be something with your network connection).

from pyetrade.

korivernon avatar korivernon commented on May 26, 2024

from pyetrade.

korivernon avatar korivernon commented on May 26, 2024

I'm still getting an issue trying to submit my order (using my own order version) during market hours... Successfully Previews but I get this

Error: For your protection, we have timed out your original order request. If you would like to place this order, please resubmit it now.

When I use the order functionality from EtradeOrder, I get this issue:

xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 4

Does anyone mind sending their kwargs with sensitive information redacted? Below are mine for an options order. I modified to take in datetime object

{'securityType': 'OPTN', 
'orderType': 'OPTN', 
'accountIdKey': 'XXXXXXXXXXX', 
'symbol': 'BAC', 
'orderAction': 'SELL_CLOSE', 
'clientOrderId': '6591041807', 
'priceType': 'MARKET', 
'quantity': 3, 
'callPut': 'CALL', 
'expiryDate': datetime.datetime(2023, 4, 21, 0, 0), 
'marketSession': 'REGULAR', 
'orderTerm': 'GOOD_FOR_DAY', 
'strikePrice': 30}

Thanks,
Kori

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024

@korivernon I think you might be missing some params, try adding these 3 params as well to your kwargs:

"allOrNone": False, "stopPrice": 0, "routingDestination": 'AUTO'

The etrade api uses a mix of json and xml endpoints (who knows why), so the error above seems to indicate the xml payload is malformed (which could be the result of missing params).

I dont have much experience with options orders but it should be similar enough to equity orders.

from pyetrade.

korivernon avatar korivernon commented on May 26, 2024

@korivernon I think you might be missing some params, try adding these 3 params as well to your kwargs:

"allOrNone": False, "stopPrice": 0, "routingDestination": 'AUTO'

The etrade api uses a mix of json and xml endpoints (who knows why), so the error above seems to indicate the xml payload is malformed (which could be the result of missing params).

I dont have much experience with options orders but it should be similar enough to equity orders.

It seems like that may have done the trick!

Sometimes the read times out. Other times it seems to execute without issue. This may be because I'm trying to place the order outside of market hours, so I'll give it another try in the morning.

In the meantime, have you ever gotten this:

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.etrade.com', port=443): Read timed out.

Additionally, when it "seems to run without issue," this is the dictionary that is the result of the preview_equity_order function. This is not because I'm outside of market hours, as I would expect a 200 response ( 200 | The market was closed when we received your order. It has been entered into our system and will be reviewed prior to market open on the next regular trading day. After market open, please check to make sure your order was accepted.).

{'html': {'body': {'b': 'Http/1.1 400 Bad Request'}}}

Here are the kwargs I'm passing in:

{
'securityType': 'OPTN', 
'orderType': 'OPTN', 
'accountIdKey': 'XXXXXXXXXX', 
'symbol': 'BAC', 
'orderAction': 'SELL_CLOSE', 
'clientOrderId': '6591041807', 
'priceType': 'MARKET', 
'quantity': 3, 
'callPut': 'CALL', 
'expiryDate': datetime.datetime(2023, 4, 21, 0, 0), 
'marketSession': 'REGULAR', 
'orderTerm': 'GOOD_FOR_DAY', 
'strikePrice': 30, 
'allOrNone': False, 
'stopPrice': 0, 
'routingDestination': 'AUTO'
}

from pyetrade.

Robert-Zacchigna avatar Robert-Zacchigna commented on May 26, 2024

I see you mentioned using a custom order function, did you by chance specify a timeout in the request? From what i can tell its possible the timeout is being reached before the request has time to be completed.

As for the 400 error im not too sure, it strange that it happens when you call the preview_equity_order function directly and not when you try to place an equity as well.

I say that because if you look at the code for the order functions, preview_equity_order is called within the place_equity_order function and the place_options_order function calls the place_equity_order function.

  • Just to be clear: option_order -> place_order -> preview_order

If the order is executed then i wouldn't be too concerned about it, i would take a guess that it might be related to the timeout issue.

from pyetrade.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.