From 5417064a0497990f26d2ec1300e36920c43d837d Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 31 Jul 2020 17:20:22 +0200 Subject: [PATCH 1/8] allow log in with 2fa --- degiroapi/__init__.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index c26e1a1..5262ea3 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -7,6 +7,7 @@ class DeGiro: __LOGIN_URL = 'https://trader.degiro.nl/login/secure/login' + __LOGIN_TOTP_URL = 'https://trader.degiro.nl/login/secure/login/totp' __CONFIG_URL = 'https://trader.degiro.nl/login/secure/config' __LOGOUT_URL = 'https://trader.degiro.nl/trading/secure/logout' @@ -34,15 +35,20 @@ class DeGiro: client_info = any confirmation_id = any - def login(self, username, password): + def login(self, username, password, totp=None): login_payload = { 'username': username, 'password': password, 'isPassCodeReset': False, 'isRedirectToMobile': False } - login_response = self.__request(DeGiro.__LOGIN_URL, None, login_payload, request_type=DeGiro.__POST_REQUEST, - error_message='Could not login.') + if totp is not None: + login_payload["oneTimePassword"] = totp + login_response = self.__request(DeGiro.__LOGIN_TOTP_URL, None, login_payload, request_type=DeGiro.__POST_REQUEST, + error_message='Could not login.') + else: + login_response = self.__request(DeGiro.__LOGIN_URL, None, login_payload, request_type=DeGiro.__POST_REQUEST, + error_message='Could not login.') self.session_id = login_response['sessionId'] client_info_payload = {'sessionId': self.session_id} client_info_response = self.__request(DeGiro.__CLIENT_INFO_URL, None, client_info_payload, From 41b0801e1cc650df44c673c9158abb4b97f7c6b6 Mon Sep 17 00:00:00 2001 From: Pablo Date: Wed, 12 Aug 2020 13:41:57 +0200 Subject: [PATCH 2/8] get account overview --- degiroapi/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index c26e1a1..15204eb 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -18,6 +18,7 @@ class DeGiro: __PRODUCT_INFO_URL = 'https://trader.degiro.nl/product_search/secure/v5/products/info' __TRANSACTIONS_URL = 'https://trader.degiro.nl/reporting/secure/v4/transactions' __ORDERS_URL = 'https://trader.degiro.nl/reporting/secure/v4/order-history' + __ACCOUNT_URL = 'https://trader.degiro.nl/reporting/secure/v6/accountoverview' __PLACE_ORDER_URL = 'https://trader.degiro.nl/trading/secure/v5/checkOrder' __ORDER_URL = 'https://trader.degiro.nl/trading/secure/v5/order/' @@ -127,6 +128,16 @@ def transactions(self, from_date, to_date, group_transactions=False): return self.__request(DeGiro.__TRANSACTIONS_URL, None, transactions_payload, error_message='Could not get transactions.')['data'] + def account_overview(self, from_date, to_date): + account_payload = { + 'fromDate': from_date.strftime('%d/%m/%Y'), + 'toDate': to_date.strftime('%d/%m/%Y'), + 'intAccount': self.client_info.account_id, + 'sessionId': self.session_id + } + return self.__request(DeGiro.__ACCOUNT_URL, None, account_payload, + error_message='Could not get account overview.')['data'] + def orders(self, from_date, to_date, not_executed=None): orders_payload = { 'fromDate': from_date.strftime('%d/%m/%Y'), From bd730591fcca295836329a203282c4d073e4bf7b Mon Sep 17 00:00:00 2001 From: konpsar Date: Wed, 9 Dec 2020 20:07:19 +0200 Subject: [PATCH 3/8] Added login_prompt(...) wrapper login function. Added to extend login function to dynamically ask password/totp from user, hiding password while typing. In this way, password doesn't have to be included in .py scripts. --- degiroapi/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index 82b67b9..5b77fd5 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -66,6 +66,16 @@ def login(self, username, password, totp=None): return client_info_response + def login_prompt(self, username=None, password=None, totp=None): + import getpass + + if not username: username = input("Username: ") + if not password: password = getpass.getpass("Password:") + if not totp: totp = getpass.getpass("totp (Leave empty if none):") + + if totp=="": return self.login(username, password) + else: return self.login(username, password, totp) + def logout(self): logout_payload = { 'intAccount': self.client_info.account_id, From 1d788eae71e61cc93a7e1261b15e55c4016c5130 Mon Sep 17 00:00:00 2001 From: konpsar Date: Wed, 9 Dec 2020 20:08:55 +0200 Subject: [PATCH 4/8] Added DeGiro Constructor Constructor enbales an option to automatically login when creating DeGiro instance. (using login_prompt) --- degiroapi/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index 5b77fd5..614f71a 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -36,6 +36,12 @@ class DeGiro: client_info = any confirmation_id = any + def __init__(self, username=None, password=None, totp=None): + if not username: # Proceed without login + pass + else: # Login prompt + DeGiro.login_prompt(self, username=username, password=password, totp=totp) + def login(self, username, password, totp=None): login_payload = { 'username': username, From 3449ae50555e2ff28a0b9745ea3c3cb8d4ff6f7d Mon Sep 17 00:00:00 2001 From: konpsar Date: Wed, 9 Dec 2020 20:10:47 +0200 Subject: [PATCH 5/8] Added examples using login_prompt and DeGiro() constructor Updated examples to include some use cases of constructor and login_prompt. --- examples/examples.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/examples.py b/examples/examples.py index 0a52da7..ab0cc9b 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -9,6 +9,21 @@ degiro = degiroapi.DeGiro() degiro.login("username", "password") +# Equivalent to: +#degiro = degiroapi.DeGiro("username", "password") # prompts for totp (optional) + +# Password can be given dynamically using login_prompt: +# -not necessary to include in .py script +degiro = degiroapi.DeGiro() +degiro.login_prompt("username") # prompts for password and totp (optional) + +#Equivalent to: +#degiro = degiroapi.DeGiro("username") # prompts for password and totp (optional) + +# To dynamically provide all credentials use: +degiro = degiroapi.DeGiro() +degiro.login_prompt() #prompts for username, password and totp (optional) + # logout degiro.logout() From b1e33eb89bc966bbdd3f7bae69c6aab29212482c Mon Sep 17 00:00:00 2001 From: Konstantinos <54744378+konpsar@users.noreply.github.com> Date: Thu, 10 Dec 2020 09:27:27 +0200 Subject: [PATCH 6/8] Update degiroapi/__init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Loucký --- degiroapi/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index 614f71a..804ceb8 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -79,8 +79,7 @@ def login_prompt(self, username=None, password=None, totp=None): if not password: password = getpass.getpass("Password:") if not totp: totp = getpass.getpass("totp (Leave empty if none):") - if totp=="": return self.login(username, password) - else: return self.login(username, password, totp) + return self.login(username, password, totp or None) def logout(self): logout_payload = { From a60653038de83c9b2e69f617b833a4cee1dac73d Mon Sep 17 00:00:00 2001 From: Konstantinos <54744378+konpsar@users.noreply.github.com> Date: Thu, 10 Dec 2020 09:27:42 +0200 Subject: [PATCH 7/8] Update degiroapi/__init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Loucký --- degiroapi/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index 804ceb8..1718e12 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -37,9 +37,7 @@ class DeGiro: confirmation_id = any def __init__(self, username=None, password=None, totp=None): - if not username: # Proceed without login - pass - else: # Login prompt + if username: # Login prompt DeGiro.login_prompt(self, username=username, password=password, totp=totp) def login(self, username, password, totp=None): From 05ec3391af1aced2f426cc313d8ff1f59f2be39f Mon Sep 17 00:00:00 2001 From: Konstantinos <54744378+konpsar@users.noreply.github.com> Date: Thu, 10 Dec 2020 09:27:50 +0200 Subject: [PATCH 8/8] Update degiroapi/__init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Loucký --- degiroapi/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/degiroapi/__init__.py b/degiroapi/__init__.py index 1718e12..c1805b0 100644 --- a/degiroapi/__init__.py +++ b/degiroapi/__init__.py @@ -38,7 +38,7 @@ class DeGiro: def __init__(self, username=None, password=None, totp=None): if username: # Login prompt - DeGiro.login_prompt(self, username=username, password=password, totp=totp) + self.login_prompt(username=username, password=password, totp=totp) def login(self, username, password, totp=None): login_payload = {