This repository has been archived by the owner on Jun 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
/
degiro.py
215 lines (183 loc) · 7.55 KB
/
degiro.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import requests
import json
import getpass
from datetime import datetime
from collections import defaultdict
class degiro:
def __init__(self):
self.user = dict()
self.data = None
def login(self, conf_path=None, with2fa:bool=False):
if(conf_path==None):
conf = dict(username=input("Username: "), password=getpass.getpass())
else:
conf = json.load(open(conf_path))
self.sess = requests.Session()
# Login
url = 'https://trader.degiro.nl/login/secure/login'
payload = {'username': conf['username'],
'password': conf['password'],
'isPassCodeReset': False,
'isRedirectToMobile': False}
header={'content-type': 'application/json'}
if(with2fa):
payload['oneTimePassword']=getpass.getpass("2FA Token: ")
url+='/totp'
r = self.sess.post(url, headers=header, data=json.dumps(payload))
print('Login')
print('\tStatus code: {}'.format(r.status_code))
# Get session id
self.sessid = r.headers['Set-Cookie']
self.sessid = self.sessid.split(';')[0]
self.sessid = self.sessid.split('=')[1]
print('\tSession id: {}'.format(self.sessid))
# This contain loads of user data, main interest here is the 'intAccount'
def getConfig(self):
url = 'https://trader.degiro.nl/pa/secure/client'
payload = {'sessionId': self.sessid}
r = self.sess.get(url, params=payload)
print('Get config')
print('\tStatus code: {}'.format(r.status_code))
data = r.json()
self.user['intAccount'] = data['data']['intAccount']
print('\tAccount id: {}'.format(self.user['intAccount']))
# This gets a lot of data, orders, news, portfolio, cash funds etc.
def getData(self):
url = 'https://trader.degiro.nl/trading/secure/v5/update/'
url += str(self.user['intAccount'])+';'
url += 'jsessionid='+self.sessid
payload = {'portfolio': 0,
'totalPortfolio': 0,
'orders': 0,
'historicalOrders': 0,
'transactions': 0,
'alerts': 0,
'cashFunds': 0,
'intAccount': self.user['intAccount'],
'sessionId': self.sessid}
r = self.sess.get(url, params=payload)
print('Get data')
print('\tStatus code: {}'.format(r.status_code))
self.data = r.json()
# Get the cash funds
def getCashFunds(self):
if self.data == None:
self.getData()
cashFunds = dict()
for cf in self.data['cashFunds']['value']:
entry = dict()
for y in cf['value']:
# Useful if the currency code is the key to the dict
if y['name'] == 'currencyCode':
key = y['value']
continue
entry[y['name']] = y['value']
cashFunds[key] = entry
return cashFunds
# Only returns a summary of the portfolio
def getPortfolioSummary(self):
pf = self.getPortfolio()
cf = self.getCashFunds()
tot = 0
for eq in pf['PRODUCT'].values():
tot += eq['value']
pfSummary = dict()
pfSummary['equity'] = tot
pfSummary['cash'] = cf['EUR']['value']
return pfSummary
# Returns the entire portfolio
def getPortfolio(self):
if self.data == None:
self.getData()
portfolio = []
for row in self.data['portfolio']['value']:
entry = dict()
for y in row['value']:
k = y['name']
v = None
if 'value' in y:
v = y['value']
entry[k] = v
# Also historic equities are returned, let's omit them
if entry['size'] != 0:
portfolio.append(entry)
## Restructure portfolio and add extra data
portf_n = defaultdict(dict)
# Restructuring
for r in portfolio:
pos_type = r['positionType']
pid = r['id'] # Product ID
del(r['positionType'])
del(r['id'])
portf_n[pos_type][pid]= r
# Adding extra data
url = 'https://trader.degiro.nl/product_search/secure/v5/products/info'
params = {'intAccount': str(self.user['intAccount']),
'sessionId': self.sessid}
header={'content-type': 'application/json'}
pid_list = list(portf_n['PRODUCT'].keys())
r = self.sess.post(url, headers=header, params=params, data=json.dumps(pid_list))
print('\tGetting extra data')
print('\t\tStatus code: {}'.format(r.status_code))
for k,v in r.json()['data'].items():
del(v['id'])
# Some bonds tend to have a non-unit size
portf_n['PRODUCT'][k]['size'] *= v['contractSize']
portf_n['PRODUCT'][k].update(v)
return portf_n
# Returns all account transactions
# fromDate and toDate are strings in the format: dd/mm/yyyy
def getAccountOverview(self, fromDate, toDate):
url = 'https://trader.degiro.nl/reporting/secure/v4/accountoverview'
payload = {'fromDate': fromDate,
'toDate': toDate,
'intAccount': self.user['intAccount'],
'sessionId': self.sessid}
r = self.sess.get(url, params=payload)
print('Get account overview')
print('\tStatus code: {}'.format(r.status_code))
data = r.json()
movs = []
for rmov in data['data']['cashMovements']:
mov = dict()
# Reformat timezone part: +01:00 -> +0100
date = ''.join(rmov['date'].rsplit(':',1))
date = datetime.strptime(date,'%Y-%m-%dT%H:%M:%S%z')
mov['date'] = date
mov['change'] = rmov['change']
mov['currency'] = rmov['currency']
mov['description'] = rmov['description']
mov['type'] = rmov['type']
if 'orderId' in rmov:
mov['orderId'] = rmov['orderId']
if 'productId' in rmov:
mov['productId'] = rmov['productId']
movs.append(mov)
return movs
# Returns historical transactions
# fromDate and toDate are strings in the format: dd/mm/yyyy
def getTransactions(self, fromDate, toDate):
url = 'https://trader.degiro.nl/reporting/secure/v4/transactions'
payload = {'fromDate': fromDate,
'toDate': toDate,
'intAccount': self.user['intAccount'],
'sessionId': self.sessid}
r = self.sess.get(url, params=payload)
print('Get Transactions overview')
print('\tStatus code: {}'.format(r.status_code))
data = r.json()['data']
return data
# Returns product info
# ids is a list of product ID (from Degiro)
def getProductByIds(self, ids):
url = "https://trader.degiro.nl/product_search/secure/v5/products/info"
header = {'content-type': 'application/json'}
params = {'intAccount': str(self.user['intAccount']), 'sessionId': self.sessid}
r = self.sess.post(url, headers=header, params=params, data=json.dumps([str(id) for id in ids]))
print(f'Get Products info for {ids}')
print('\tStatus code: {}'.format(r.status_code))
data = r.json()['data']
return data
if __name__ =='__main__':
deg = degiro()
deg.login(with2fa=True)