From 4521641565ec6ad5c92c1a03dc7528b5e17ebe4c Mon Sep 17 00:00:00 2001 From: "MohamedAMINE.BenSlama" Date: Tue, 22 Dec 2020 22:16:22 +0100 Subject: [PATCH 1/4] implement method to get security id from symbol, place order, buy and sell security --- src/wealthsimple/wealthsimple.py | 97 +++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/wealthsimple/wealthsimple.py b/src/wealthsimple/wealthsimple.py index 1ec0ca9..5bb322e 100644 --- a/src/wealthsimple/wealthsimple.py +++ b/src/wealthsimple/wealthsimple.py @@ -247,7 +247,7 @@ def get_security(self, id: str) -> dict: return response def get_securities_from_ticker(self, symbol: str) -> list: - """Get information about a securitys with matching ticker symbols + """Get information about a securities with matching ticker symbols Parameters ---------- @@ -338,3 +338,98 @@ def get_forex(self) -> dict: """ response = self.TradeAPI.makeRequest("GET", "forex") return response.json() + + def get_security_id_from_stock_symbol(self, stock_symbol: str) -> str: + """Get Wealthsimple Security ID of a specific stock symbol (ticker) + + Parameters + ---------- + stock_symbol : str + Security symbol to search for + + Returns + ------- + str + A str containing Wealthsimple Security ID for the stock + """ + response = self.TradeAPI.makeRequest("GET", f"securities?query={stock_symbol}") + response = response.json() + if response['total_count'] == 1: + # This check ensure we have an exact match for our search + return response["results"][0]['id'] + else: + return '' + + def place_order(self, account_id: str, security_id: str, quantity: int, order_type: str) -> dict: + + """Posts an order (market) to Wealthsimple API + + Parameters + ---------- + :param order_type: str + The order type ('buy_quantity', 'sell_quantity' + :param quantity: int + The The number of securities to Buy/Sell + :param security_id: + The Wealthsimple Security ID + :param account_id : str + The Wealthsimple Account id + + Returns + ------- + dict + A dict representing the order + """ + + order = { + "account_id": account_id, + "security_id": security_id, + "quantity": quantity, + "order_type": order_type, + "order_sub_type": "market", + "time_in_force": "day", + } + response = self.TradeAPI.makeRequest("POST", "orders", order) + response = response.json() + return response["results"] + + def buy(self, account_id, security_id, quantity): + + """Places a market buy order for to the Wealthsimple API under the specified account id + Parameters + ---------- + :param quantity: int + The The number of securities to Buy + :param security_id: + The Wealthsimple Security ID + :param account_id : str + The Wealthsimple Account id + + Returns + ------- + dict + A dict representing the returned order + + """ + return self.place_order(account_id, security_id, quantity, "buy_quantity") + + def sell(self, account_id, security_id, quantity): + + """Places a market sell order for to the Wealthsimple API under the specified account id + Parameters + ---------- + :param quantity: int + The The number of securities to Buy + :param security_id: + The Wealthsimple Security ID + :param account_id : str + The Wealthsimple Account id + + Returns + ------- + dict + A dict representing the returned order + + """ + + return self.place_order(account_id, security_id, quantity, "sell_quantity") From 0d00ed99e299cce28e2a745b506b2f42aa76f9f2 Mon Sep 17 00:00:00 2001 From: "MohamedAMINE.BenSlama" Date: Sat, 26 Dec 2020 13:22:08 +0100 Subject: [PATCH 2/4] implemented limit sell, limit buy, fixed quote problem for market order. --- src/wealthsimple/wealthsimple.py | 117 ++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 26 deletions(-) diff --git a/src/wealthsimple/wealthsimple.py b/src/wealthsimple/wealthsimple.py index 5bb322e..861ae2f 100644 --- a/src/wealthsimple/wealthsimple.py +++ b/src/wealthsimple/wealthsimple.py @@ -66,10 +66,10 @@ def __init__(self, email: str, password: str, two_factor_callback: callable = No self.login(email, password, two_factor_callback=two_factor_callback) def login( - self, - email: str = None, - password: str = None, - two_factor_callback: callable = None, + self, + email: str = None, + password: str = None, + two_factor_callback: callable = None, ) -> None: """Login to Wealthsimple Trade account @@ -360,40 +360,26 @@ def get_security_id_from_stock_symbol(self, stock_symbol: str) -> str: else: return '' - def place_order(self, account_id: str, security_id: str, quantity: int, order_type: str) -> dict: + def place_order(self, order: dict) -> dict: """Posts an order (market) to Wealthsimple API Parameters ---------- - :param order_type: str - The order type ('buy_quantity', 'sell_quantity' - :param quantity: int - The The number of securities to Buy/Sell - :param security_id: - The Wealthsimple Security ID - :param account_id : str - The Wealthsimple Account id + :param order: + The order dict containing the data to be submitted Returns ------- dict - A dict representing the order + A dict representing the submitted order """ - order = { - "account_id": account_id, - "security_id": security_id, - "quantity": quantity, - "order_type": order_type, - "order_sub_type": "market", - "time_in_force": "day", - } response = self.TradeAPI.makeRequest("POST", "orders", order) response = response.json() return response["results"] - def buy(self, account_id, security_id, quantity): + def market_buy(self, account_id, security_id, quantity): """Places a market buy order for to the Wealthsimple API under the specified account id Parameters @@ -411,9 +397,22 @@ def buy(self, account_id, security_id, quantity): A dict representing the returned order """ - return self.place_order(account_id, security_id, quantity, "buy_quantity") - def sell(self, account_id, security_id, quantity): + quote = self.get_security(security_id)['quote']['amount'] + if quote: + order = { + "account_id": account_id, + "security_id": security_id, + "limit_price": quote, + "quantity": quantity, + "order_type": "buy_quantity", + "order_sub_type": "market", + "time_in_force": "day", + } + return self.place_order(order) + raise RuntimeError('Failed to get quote amount when submitting market buy order') + + def market_sell(self, account_id, security_id, quantity): """Places a market sell order for to the Wealthsimple API under the specified account id Parameters @@ -431,5 +430,71 @@ def sell(self, account_id, security_id, quantity): A dict representing the returned order """ + quote = self.get_security(security_id)['quote']['amount'] + if quote: + order = { + "account_id": account_id, + "security_id": security_id, + "quantity": quantity, + "limit_price": quote, + "order_type": "sell_quantity", + "order_sub_type": "market", + "time_in_force": "day", + } + return self.place_order(order) + raise RuntimeError('Failed to get quote amount when submitting market sell order') + + def limit_buy(self, account_id, security_id, quantity, limit_price) -> dict: + + """ Places a limit buy order for the Wealthsimple API with the specified account_id and security_id + Parameters + ---------- + :param account_id: + :param security_id: + :param quantity: + :param limit_price: - return self.place_order(account_id, security_id, quantity, "sell_quantity") + Returns + ---------- + dict + A dict representing the order returned from the API + """ + + order = { + "account_id": account_id, + "security_id": security_id, + "quantity": quantity, + "limit_price": limit_price, + "order_type": "buy_quantity", + "order_sub_type": "limit", + "time_in_force": "day", + } + + return self.place_order(order) + + def limit_sell(self, account_id, security_id, quantity, limit_price) -> dict: + + """ Places a limit sell order for the Wealthsimple API with the specified parameters + Parameters + ---------- + :param account_id: + :param security_id: + :param quantity: + :param limit_price: + + Returns + ---------- + dict + A dict representing the order returned from the API + """ + + order = { + "account_id": account_id, + "security_id": security_id, + "quantity": quantity, + "limit_price": limit_price, + "order_type": "sell_quantity", + "order_sub_type": "limit", + "time_in_force": "day", + } + return self.place_order(order) From ed04b06559fb313ef13af56fd08e5061695da38a Mon Sep 17 00:00:00 2001 From: "MohamedAMINE.BenSlama" Date: Fri, 12 Feb 2021 20:36:40 +0100 Subject: [PATCH 3/4] fix --- src/wealthsimple/requestor.py | 7 ++++++- src/wealthsimple/wealthsimple.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wealthsimple/requestor.py b/src/wealthsimple/requestor.py index 2745dba..0882153 100644 --- a/src/wealthsimple/requestor.py +++ b/src/wealthsimple/requestor.py @@ -77,7 +77,12 @@ def post(self, URL, params=None): """ try: - return self.session.post(URL, params) + headers = { + 'Authorization': self.session.headers['Authorization'] + } + response = requests.post(URL, json=params, headers=headers) + response = response.json() + return response["results"] except Exception as err: print(err) diff --git a/src/wealthsimple/wealthsimple.py b/src/wealthsimple/wealthsimple.py index 861ae2f..f91d617 100644 --- a/src/wealthsimple/wealthsimple.py +++ b/src/wealthsimple/wealthsimple.py @@ -403,7 +403,7 @@ def market_buy(self, account_id, security_id, quantity): order = { "account_id": account_id, "security_id": security_id, - "limit_price": quote, + "limit_price": str(quote), "quantity": quantity, "order_type": "buy_quantity", "order_sub_type": "market", From 1a7077420a230cbf2855afdd93e5635fdebfaa0d Mon Sep 17 00:00:00 2001 From: "MohamedAMINE.BenSlama" Date: Fri, 12 Feb 2021 21:59:01 +0100 Subject: [PATCH 4/4] revert fix --- src/wealthsimple/requestor.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/wealthsimple/requestor.py b/src/wealthsimple/requestor.py index 0882153..8abc404 100644 --- a/src/wealthsimple/requestor.py +++ b/src/wealthsimple/requestor.py @@ -77,15 +77,11 @@ def post(self, URL, params=None): """ try: - headers = { - 'Authorization': self.session.headers['Authorization'] - } - response = requests.post(URL, json=params, headers=headers) - response = response.json() - return response["results"] + return self.session.post(URL, params) except Exception as err: print(err) + def get(self, URL, params=None): """Make a GET request to a given API endpoint