degiro-cli 0.1.3__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/PKG-INFO +36 -11
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/README.md +34 -9
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degiro_cli.egg-info/PKG-INFO +36 -11
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degiro_cli.egg-info/SOURCES.txt +1 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degiro_cli.egg-info/entry_points.txt +1 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degiro_cli.egg-info/requires.txt +1 -1
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degirocli/login.py +28 -21
- degiro_cli-0.1.4/degirocli/portfolio.py +173 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/pyproject.toml +3 -2
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/LICENSE +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degiro_cli.egg-info/dependency_links.txt +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degiro_cli.egg-info/top_level.txt +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degirocli/__init__.py +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degirocli/helpers.py +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degirocli/history.py +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/degirocli/search.py +0 -0
- {degiro_cli-0.1.3 → degiro_cli-0.1.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: degiro-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Unofficial command line tools for Degiro
|
|
5
5
|
Author-email: ohmajesticlama <ohmajesticlama@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -16,7 +16,7 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
|
16
16
|
Requires-Python: >=3.8
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
|
-
Requires-Dist: degiroasync>=1.
|
|
19
|
+
Requires-Dist: degiroasync>=1.1.0
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: pytest>=7.0.1; extra == "dev"
|
|
22
22
|
Requires-Dist: coverage>=6.3; extra == "dev"
|
|
@@ -35,8 +35,7 @@ Dynamic: license-file
|
|
|
35
35
|
|
|
36
36
|
## Introduction
|
|
37
37
|
|
|
38
|
-
Command line tools for DEGIRO platform.
|
|
39
|
-
is to:
|
|
38
|
+
Command line tools for DEGIRO platform. Primary features:
|
|
40
39
|
- Search for STOCK products by various criteria.
|
|
41
40
|
- Access STOCK products history.
|
|
42
41
|
|
|
@@ -46,7 +45,11 @@ orders.
|
|
|
46
45
|
## Installation
|
|
47
46
|
|
|
48
47
|
``` sh
|
|
49
|
-
|
|
48
|
+
# With [uv](https://docs.astral.sh/uv/) (recommended)
|
|
49
|
+
uv tool install degiro-cli
|
|
50
|
+
|
|
51
|
+
# With pip
|
|
52
|
+
pip3 install -u degiro-cli
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
## Use
|
|
@@ -55,7 +58,7 @@ manipulation tools such as [CSV Kit](https://csvkit.rtfd.org/). Especially
|
|
|
55
58
|
the `csvlook` command if you intend to just visualize outputes from command
|
|
56
59
|
line.
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
### Login
|
|
59
62
|
|
|
60
63
|
``` sh
|
|
61
64
|
# Only the session id is stored, that means a new login will be required
|
|
@@ -63,6 +66,25 @@ line.
|
|
|
63
66
|
degiro-login
|
|
64
67
|
```
|
|
65
68
|
|
|
69
|
+
### Get portfolio
|
|
70
|
+
```sh
|
|
71
|
+
degiro-portfolio
|
|
72
|
+
# Output:
|
|
73
|
+
# position_type,exchange,isin,name,currency,size,price,value
|
|
74
|
+
# PRODUCT,EPA,FR0000121972,Schneider Electric SE,EUR,10,276.05,2760
|
|
75
|
+
# PRODUCT,SCG,DE000CL5C2Q2,SG Airbus Turbo illimités Call BAR 37.08 STR 35.6901 P 10 LV 1.23,EUR,100,15.635,1563.50
|
|
76
|
+
# CASH,N/A,EUR,EUR,EUR,3000.00,1,3000.00
|
|
77
|
+
|
|
78
|
+
# With csvlook formatting
|
|
79
|
+
degiro-portfolio | csvlook --max-column-width 30
|
|
80
|
+
# Output:
|
|
81
|
+
# | position_type | exchange | isin | name | currency | size | price | value |
|
|
82
|
+
# | ------------- | -------- | ------------ | ------------------------------ | -------- | -------- | ------- | --------- |
|
|
83
|
+
# | PRODUCT | EPA | FR0000121972 | Schneider Electric SE | EUR | 10,00 | 276,050 | 2 760,00 |
|
|
84
|
+
# | PRODUCT | SCG | DE000CL5C2Q2 | SG Airbus Turbo illimités C... | EUR | 100,00 | 15,635 | 1 563,50 |
|
|
85
|
+
# | CASH | | EUR | EUR | EUR | 3 000,00 | 1,000 | 3 000,00 |
|
|
86
|
+
```
|
|
87
|
+
|
|
66
88
|
### Find products
|
|
67
89
|
|
|
68
90
|
``` sh
|
|
@@ -91,7 +113,7 @@ degiro-search -t airbus | csvlook
|
|
|
91
113
|
# | FRA | AIRA | Airbus SE | EUR | US0092791005 |
|
|
92
114
|
```
|
|
93
115
|
|
|
94
|
-
|
|
116
|
+
### List countries available on the platform
|
|
95
117
|
``` sh
|
|
96
118
|
# List country codes available on the platform
|
|
97
119
|
degiro-search --list-countries
|
|
@@ -125,7 +147,7 @@ degiro-search --list-countries
|
|
|
125
147
|
# US
|
|
126
148
|
```
|
|
127
149
|
|
|
128
|
-
|
|
150
|
+
### By Index
|
|
129
151
|
``` sh
|
|
130
152
|
# List country codes available on the platform
|
|
131
153
|
degiro-search --list-indices
|
|
@@ -166,7 +188,7 @@ degiro-search --index 'EURO STOXX 50'
|
|
|
166
188
|
|
|
167
189
|
```
|
|
168
190
|
|
|
169
|
-
|
|
191
|
+
### Get symbol history
|
|
170
192
|
``` sh
|
|
171
193
|
degiro-history --period 1m EPA.SAF
|
|
172
194
|
# exchange,symbol,date,currency,open,high,low,close
|
|
@@ -221,11 +243,14 @@ degiro-history --period 1m EPA.SAF | csvlook
|
|
|
221
243
|
|
|
222
244
|
```
|
|
223
245
|
|
|
224
|
-
|
|
246
|
+
### Chain with other tools
|
|
225
247
|
|
|
248
|
+
degiro-cli can be chained with other command line tools to achieve more complex processing.
|
|
226
249
|
``` sh
|
|
250
|
+
degiro-login
|
|
227
251
|
# Example command line to pull history for all stocks in a country with
|
|
228
252
|
# the help of the great CLI tool csvkit
|
|
229
|
-
|
|
253
|
+
countr="NL"; degiro-search --country "$country" --no-header-row | csvcut -c 1-2 | sed 's/,/./' | xargs -n 100 degiro-history -p 5y | tee -a prices.$country.csv
|
|
230
254
|
```
|
|
231
255
|
|
|
256
|
+
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
Command line tools for DEGIRO platform.
|
|
6
|
-
is to:
|
|
5
|
+
Command line tools for DEGIRO platform. Primary features:
|
|
7
6
|
- Search for STOCK products by various criteria.
|
|
8
7
|
- Access STOCK products history.
|
|
9
8
|
|
|
@@ -13,7 +12,11 @@ orders.
|
|
|
13
12
|
## Installation
|
|
14
13
|
|
|
15
14
|
``` sh
|
|
16
|
-
|
|
15
|
+
# With [uv](https://docs.astral.sh/uv/) (recommended)
|
|
16
|
+
uv tool install degiro-cli
|
|
17
|
+
|
|
18
|
+
# With pip
|
|
19
|
+
pip3 install -u degiro-cli
|
|
17
20
|
```
|
|
18
21
|
|
|
19
22
|
## Use
|
|
@@ -22,7 +25,7 @@ manipulation tools such as [CSV Kit](https://csvkit.rtfd.org/). Especially
|
|
|
22
25
|
the `csvlook` command if you intend to just visualize outputes from command
|
|
23
26
|
line.
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
### Login
|
|
26
29
|
|
|
27
30
|
``` sh
|
|
28
31
|
# Only the session id is stored, that means a new login will be required
|
|
@@ -30,6 +33,25 @@ line.
|
|
|
30
33
|
degiro-login
|
|
31
34
|
```
|
|
32
35
|
|
|
36
|
+
### Get portfolio
|
|
37
|
+
```sh
|
|
38
|
+
degiro-portfolio
|
|
39
|
+
# Output:
|
|
40
|
+
# position_type,exchange,isin,name,currency,size,price,value
|
|
41
|
+
# PRODUCT,EPA,FR0000121972,Schneider Electric SE,EUR,10,276.05,2760
|
|
42
|
+
# PRODUCT,SCG,DE000CL5C2Q2,SG Airbus Turbo illimités Call BAR 37.08 STR 35.6901 P 10 LV 1.23,EUR,100,15.635,1563.50
|
|
43
|
+
# CASH,N/A,EUR,EUR,EUR,3000.00,1,3000.00
|
|
44
|
+
|
|
45
|
+
# With csvlook formatting
|
|
46
|
+
degiro-portfolio | csvlook --max-column-width 30
|
|
47
|
+
# Output:
|
|
48
|
+
# | position_type | exchange | isin | name | currency | size | price | value |
|
|
49
|
+
# | ------------- | -------- | ------------ | ------------------------------ | -------- | -------- | ------- | --------- |
|
|
50
|
+
# | PRODUCT | EPA | FR0000121972 | Schneider Electric SE | EUR | 10,00 | 276,050 | 2 760,00 |
|
|
51
|
+
# | PRODUCT | SCG | DE000CL5C2Q2 | SG Airbus Turbo illimités C... | EUR | 100,00 | 15,635 | 1 563,50 |
|
|
52
|
+
# | CASH | | EUR | EUR | EUR | 3 000,00 | 1,000 | 3 000,00 |
|
|
53
|
+
```
|
|
54
|
+
|
|
33
55
|
### Find products
|
|
34
56
|
|
|
35
57
|
``` sh
|
|
@@ -58,7 +80,7 @@ degiro-search -t airbus | csvlook
|
|
|
58
80
|
# | FRA | AIRA | Airbus SE | EUR | US0092791005 |
|
|
59
81
|
```
|
|
60
82
|
|
|
61
|
-
|
|
83
|
+
### List countries available on the platform
|
|
62
84
|
``` sh
|
|
63
85
|
# List country codes available on the platform
|
|
64
86
|
degiro-search --list-countries
|
|
@@ -92,7 +114,7 @@ degiro-search --list-countries
|
|
|
92
114
|
# US
|
|
93
115
|
```
|
|
94
116
|
|
|
95
|
-
|
|
117
|
+
### By Index
|
|
96
118
|
``` sh
|
|
97
119
|
# List country codes available on the platform
|
|
98
120
|
degiro-search --list-indices
|
|
@@ -133,7 +155,7 @@ degiro-search --index 'EURO STOXX 50'
|
|
|
133
155
|
|
|
134
156
|
```
|
|
135
157
|
|
|
136
|
-
|
|
158
|
+
### Get symbol history
|
|
137
159
|
``` sh
|
|
138
160
|
degiro-history --period 1m EPA.SAF
|
|
139
161
|
# exchange,symbol,date,currency,open,high,low,close
|
|
@@ -188,11 +210,14 @@ degiro-history --period 1m EPA.SAF | csvlook
|
|
|
188
210
|
|
|
189
211
|
```
|
|
190
212
|
|
|
191
|
-
|
|
213
|
+
### Chain with other tools
|
|
192
214
|
|
|
215
|
+
degiro-cli can be chained with other command line tools to achieve more complex processing.
|
|
193
216
|
``` sh
|
|
217
|
+
degiro-login
|
|
194
218
|
# Example command line to pull history for all stocks in a country with
|
|
195
219
|
# the help of the great CLI tool csvkit
|
|
196
|
-
|
|
220
|
+
countr="NL"; degiro-search --country "$country" --no-header-row | csvcut -c 1-2 | sed 's/,/./' | xargs -n 100 degiro-history -p 5y | tee -a prices.$country.csv
|
|
197
221
|
```
|
|
198
222
|
|
|
223
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: degiro-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Unofficial command line tools for Degiro
|
|
5
5
|
Author-email: ohmajesticlama <ohmajesticlama@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -16,7 +16,7 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
|
16
16
|
Requires-Python: >=3.8
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
|
-
Requires-Dist: degiroasync>=1.
|
|
19
|
+
Requires-Dist: degiroasync>=1.1.0
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: pytest>=7.0.1; extra == "dev"
|
|
22
22
|
Requires-Dist: coverage>=6.3; extra == "dev"
|
|
@@ -35,8 +35,7 @@ Dynamic: license-file
|
|
|
35
35
|
|
|
36
36
|
## Introduction
|
|
37
37
|
|
|
38
|
-
Command line tools for DEGIRO platform.
|
|
39
|
-
is to:
|
|
38
|
+
Command line tools for DEGIRO platform. Primary features:
|
|
40
39
|
- Search for STOCK products by various criteria.
|
|
41
40
|
- Access STOCK products history.
|
|
42
41
|
|
|
@@ -46,7 +45,11 @@ orders.
|
|
|
46
45
|
## Installation
|
|
47
46
|
|
|
48
47
|
``` sh
|
|
49
|
-
|
|
48
|
+
# With [uv](https://docs.astral.sh/uv/) (recommended)
|
|
49
|
+
uv tool install degiro-cli
|
|
50
|
+
|
|
51
|
+
# With pip
|
|
52
|
+
pip3 install -u degiro-cli
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
## Use
|
|
@@ -55,7 +58,7 @@ manipulation tools such as [CSV Kit](https://csvkit.rtfd.org/). Especially
|
|
|
55
58
|
the `csvlook` command if you intend to just visualize outputes from command
|
|
56
59
|
line.
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
### Login
|
|
59
62
|
|
|
60
63
|
``` sh
|
|
61
64
|
# Only the session id is stored, that means a new login will be required
|
|
@@ -63,6 +66,25 @@ line.
|
|
|
63
66
|
degiro-login
|
|
64
67
|
```
|
|
65
68
|
|
|
69
|
+
### Get portfolio
|
|
70
|
+
```sh
|
|
71
|
+
degiro-portfolio
|
|
72
|
+
# Output:
|
|
73
|
+
# position_type,exchange,isin,name,currency,size,price,value
|
|
74
|
+
# PRODUCT,EPA,FR0000121972,Schneider Electric SE,EUR,10,276.05,2760
|
|
75
|
+
# PRODUCT,SCG,DE000CL5C2Q2,SG Airbus Turbo illimités Call BAR 37.08 STR 35.6901 P 10 LV 1.23,EUR,100,15.635,1563.50
|
|
76
|
+
# CASH,N/A,EUR,EUR,EUR,3000.00,1,3000.00
|
|
77
|
+
|
|
78
|
+
# With csvlook formatting
|
|
79
|
+
degiro-portfolio | csvlook --max-column-width 30
|
|
80
|
+
# Output:
|
|
81
|
+
# | position_type | exchange | isin | name | currency | size | price | value |
|
|
82
|
+
# | ------------- | -------- | ------------ | ------------------------------ | -------- | -------- | ------- | --------- |
|
|
83
|
+
# | PRODUCT | EPA | FR0000121972 | Schneider Electric SE | EUR | 10,00 | 276,050 | 2 760,00 |
|
|
84
|
+
# | PRODUCT | SCG | DE000CL5C2Q2 | SG Airbus Turbo illimités C... | EUR | 100,00 | 15,635 | 1 563,50 |
|
|
85
|
+
# | CASH | | EUR | EUR | EUR | 3 000,00 | 1,000 | 3 000,00 |
|
|
86
|
+
```
|
|
87
|
+
|
|
66
88
|
### Find products
|
|
67
89
|
|
|
68
90
|
``` sh
|
|
@@ -91,7 +113,7 @@ degiro-search -t airbus | csvlook
|
|
|
91
113
|
# | FRA | AIRA | Airbus SE | EUR | US0092791005 |
|
|
92
114
|
```
|
|
93
115
|
|
|
94
|
-
|
|
116
|
+
### List countries available on the platform
|
|
95
117
|
``` sh
|
|
96
118
|
# List country codes available on the platform
|
|
97
119
|
degiro-search --list-countries
|
|
@@ -125,7 +147,7 @@ degiro-search --list-countries
|
|
|
125
147
|
# US
|
|
126
148
|
```
|
|
127
149
|
|
|
128
|
-
|
|
150
|
+
### By Index
|
|
129
151
|
``` sh
|
|
130
152
|
# List country codes available on the platform
|
|
131
153
|
degiro-search --list-indices
|
|
@@ -166,7 +188,7 @@ degiro-search --index 'EURO STOXX 50'
|
|
|
166
188
|
|
|
167
189
|
```
|
|
168
190
|
|
|
169
|
-
|
|
191
|
+
### Get symbol history
|
|
170
192
|
``` sh
|
|
171
193
|
degiro-history --period 1m EPA.SAF
|
|
172
194
|
# exchange,symbol,date,currency,open,high,low,close
|
|
@@ -221,11 +243,14 @@ degiro-history --period 1m EPA.SAF | csvlook
|
|
|
221
243
|
|
|
222
244
|
```
|
|
223
245
|
|
|
224
|
-
|
|
246
|
+
### Chain with other tools
|
|
225
247
|
|
|
248
|
+
degiro-cli can be chained with other command line tools to achieve more complex processing.
|
|
226
249
|
``` sh
|
|
250
|
+
degiro-login
|
|
227
251
|
# Example command line to pull history for all stocks in a country with
|
|
228
252
|
# the help of the great CLI tool csvkit
|
|
229
|
-
|
|
253
|
+
countr="NL"; degiro-search --country "$country" --no-header-row | csvcut -c 1-2 | sed 's/,/./' | xargs -n 100 degiro-history -p 5y | tee -a prices.$country.csv
|
|
230
254
|
```
|
|
231
255
|
|
|
256
|
+
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import tempfile
|
|
2
2
|
import getpass
|
|
3
|
-
import functools
|
|
4
|
-
import multiprocessing
|
|
5
3
|
import stat
|
|
6
4
|
import asyncio
|
|
7
5
|
import json
|
|
8
6
|
import time
|
|
9
|
-
import pickle
|
|
10
7
|
import sys
|
|
11
8
|
import os
|
|
12
9
|
from pathlib import Path
|
|
@@ -17,10 +14,10 @@ import degiroasync.api as dapi
|
|
|
17
14
|
import degiroasync.webapi as wapi
|
|
18
15
|
import degiroasync.core as dcore
|
|
19
16
|
|
|
20
|
-
from .helpers import ERROR_CODES
|
|
21
|
-
from .helpers import LOGGER
|
|
17
|
+
from .helpers import ERROR_CODES, LOGGER
|
|
22
18
|
|
|
23
19
|
|
|
20
|
+
_USER_MASK = stat.S_IRUSR | stat.S_IWUSR
|
|
24
21
|
|
|
25
22
|
def get_credentials() -> dapi.Credentials:
|
|
26
23
|
"""
|
|
@@ -55,10 +52,17 @@ def get_credentials() -> dapi.Credentials:
|
|
|
55
52
|
|
|
56
53
|
|
|
57
54
|
def get_tmp_path():
|
|
55
|
+
"Return temporary path specific to current user."
|
|
58
56
|
tmpdir = Path(tempfile.gettempdir())
|
|
59
|
-
return tmpdir / 'degirocli'
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
# parent folder must be readable and writable by other users on multi-user systems.
|
|
59
|
+
module_folder = tmpdir / 'degirocli'
|
|
60
|
+
module_folder.mkdir(mode=0o777, exist_ok=True)
|
|
61
|
+
|
|
62
|
+
user_path = module_folder / str(os.getuid())
|
|
63
|
+
return user_path
|
|
64
|
+
|
|
65
|
+
def _get_hash(path: Union[Path, str]) -> int:
|
|
62
66
|
with open(path, 'rb') as fh:
|
|
63
67
|
fhash = hash(fh)
|
|
64
68
|
return fhash
|
|
@@ -116,17 +120,7 @@ def expire_path(
|
|
|
116
120
|
return 0
|
|
117
121
|
|
|
118
122
|
|
|
119
|
-
|
|
120
|
-
#def expire_path(*args):
|
|
121
|
-
# # Start event loop to
|
|
122
|
-
# proc = multiprocessing.Process(
|
|
123
|
-
# target=_expire_path,
|
|
124
|
-
# args=args,
|
|
125
|
-
# daemon=False)
|
|
126
|
-
# proc.start()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
async def login():
|
|
123
|
+
async def login(*, expire_session_file: int = 3*60*60):
|
|
130
124
|
tmp_path = get_tmp_path()
|
|
131
125
|
|
|
132
126
|
if tmp_path.exists():
|
|
@@ -140,8 +134,21 @@ async def login():
|
|
|
140
134
|
# Get sessionID and write it
|
|
141
135
|
credentials = get_credentials()
|
|
142
136
|
session = await wapi.login(credentials)
|
|
143
|
-
|
|
144
|
-
tmp_path.
|
|
137
|
+
LOGGER.debug("temporary file: %s", tmp_path)
|
|
138
|
+
tmp_path.touch(exist_ok=True)
|
|
139
|
+
# Check current user owns the file.
|
|
140
|
+
tmp_stat = os.stat(tmp_path)
|
|
141
|
+
if tmp_stat.st_uid != os.getuid():
|
|
142
|
+
msg = (
|
|
143
|
+
f"Session cache file user identifier (UID) {tmp_stat.st_uid} is"
|
|
144
|
+
f" different from current user UID {os.getuid()}."
|
|
145
|
+
"This should not happen and could be a local attack. "
|
|
146
|
+
"Abort."
|
|
147
|
+
)
|
|
148
|
+
LOGGER.error(msg)
|
|
149
|
+
return
|
|
150
|
+
raise AssertionError()
|
|
151
|
+
tmp_path.chmod(_USER_MASK)
|
|
145
152
|
with open(tmp_path, 'w') as fh:
|
|
146
153
|
json.dump({
|
|
147
154
|
'version': 1,
|
|
@@ -151,7 +158,7 @@ async def login():
|
|
|
151
158
|
),
|
|
152
159
|
}, fh)
|
|
153
160
|
# Delete file in 3 hour
|
|
154
|
-
expire_path(tmp_path,
|
|
161
|
+
expire_path(tmp_path, expire_session_file)
|
|
155
162
|
|
|
156
163
|
async def _get_session_from_cache() -> dapi.Session:
|
|
157
164
|
cache_path = get_tmp_path()
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import asyncio
|
|
3
|
+
import logging
|
|
4
|
+
import io
|
|
5
|
+
import argparse
|
|
6
|
+
import csv
|
|
7
|
+
from typing import Optional, Sequence, Literal
|
|
8
|
+
|
|
9
|
+
import degiroasync.api as dapi
|
|
10
|
+
|
|
11
|
+
from .helpers import LOGGER
|
|
12
|
+
from .login import get_session_from_cache
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def run_portfolio_pipeline(
|
|
16
|
+
session: dapi.Session,
|
|
17
|
+
output_file: io.TextIOBase,
|
|
18
|
+
*,
|
|
19
|
+
headers: bool = True,
|
|
20
|
+
position_type: Optional[str] = None,
|
|
21
|
+
filter: Literal['all', 'open', 'closed'] = 'open',
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
Fetch and output portfolio data.
|
|
25
|
+
"""
|
|
26
|
+
positions: Sequence[dapi.Position] = await dapi.get_portfolio(session, filter=filter)
|
|
27
|
+
|
|
28
|
+
exc_dict: dapi.ExchangeDictionary = session.dictionary
|
|
29
|
+
writer = csv.writer(output_file)
|
|
30
|
+
if headers:
|
|
31
|
+
writer.writerow((
|
|
32
|
+
"position_type",
|
|
33
|
+
"exchange",
|
|
34
|
+
"isin",
|
|
35
|
+
"name",
|
|
36
|
+
"currency",
|
|
37
|
+
"size",
|
|
38
|
+
"price",
|
|
39
|
+
"value",
|
|
40
|
+
))
|
|
41
|
+
|
|
42
|
+
for position in positions:
|
|
43
|
+
if position_type is not None and position.position_type != position_type:
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
exchange = "N/A"
|
|
47
|
+
|
|
48
|
+
info = position.product.info
|
|
49
|
+
if hasattr(info, 'exchange_id'):
|
|
50
|
+
# Should be the case for stock products at least.
|
|
51
|
+
try:
|
|
52
|
+
exchange_obj = exc_dict.exchange_by(id=info.exchange_id)
|
|
53
|
+
exchange = exchange_obj.hiq_abbr if exchange_obj else ""
|
|
54
|
+
except KeyError:
|
|
55
|
+
LOGGER.warning("Exchange id %s unknown.", info.exchange_id)
|
|
56
|
+
exchange = "Unknown"
|
|
57
|
+
|
|
58
|
+
LOGGER.debug("position: %s", position)
|
|
59
|
+
LOGGER.debug("info: %s", info)
|
|
60
|
+
writer.writerow((
|
|
61
|
+
position.position_type,
|
|
62
|
+
exchange,
|
|
63
|
+
info.isin,
|
|
64
|
+
info.name,
|
|
65
|
+
info.currency,
|
|
66
|
+
position.size,
|
|
67
|
+
position.price,
|
|
68
|
+
position.value,
|
|
69
|
+
))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def run_portfolio_total_pipeline(
|
|
73
|
+
session: dapi.Session,
|
|
74
|
+
output_file: io.TextIOBase
|
|
75
|
+
):
|
|
76
|
+
"""
|
|
77
|
+
Fetch and output total portfolio data.
|
|
78
|
+
"""
|
|
79
|
+
total_portfolio = await dapi.get_portfolio_total(session)
|
|
80
|
+
|
|
81
|
+
writer = csv.writer(output_file)
|
|
82
|
+
|
|
83
|
+
# TotalPortfolio is an object with attributes, iterate over public ones
|
|
84
|
+
for attr_name in dir(total_portfolio):
|
|
85
|
+
if not attr_name.startswith('_'):
|
|
86
|
+
writer.writerow((attr_name, getattr(total_portfolio, attr_name)))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def main():
|
|
90
|
+
handler = logging.StreamHandler()
|
|
91
|
+
|
|
92
|
+
parser = argparse.ArgumentParser(
|
|
93
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
94
|
+
description="Get user portfolio from DEGIRO."
|
|
95
|
+
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
'-f',
|
|
98
|
+
'--filter',
|
|
99
|
+
dest='filter',
|
|
100
|
+
default='open',
|
|
101
|
+
required=False,
|
|
102
|
+
help="Get either 'all', 'open' (default) or 'closed' positions only."
|
|
103
|
+
)
|
|
104
|
+
parser.add_argument(
|
|
105
|
+
'--total',
|
|
106
|
+
dest='total',
|
|
107
|
+
default=False,
|
|
108
|
+
action='store_true',
|
|
109
|
+
required=False,
|
|
110
|
+
help="Get total portfolio summary instead of individual positions"
|
|
111
|
+
)
|
|
112
|
+
parser.add_argument(
|
|
113
|
+
'-t',
|
|
114
|
+
'--type',
|
|
115
|
+
dest='position_type',
|
|
116
|
+
default=None,
|
|
117
|
+
required=False,
|
|
118
|
+
help="Filter by position type: PRODUCT or CASH"
|
|
119
|
+
)
|
|
120
|
+
parser.add_argument(
|
|
121
|
+
'-H',
|
|
122
|
+
'--no-header-row',
|
|
123
|
+
dest='no_headers',
|
|
124
|
+
default=False,
|
|
125
|
+
action='store_true',
|
|
126
|
+
required=False,
|
|
127
|
+
help="Do not print header line"
|
|
128
|
+
)
|
|
129
|
+
parser.add_argument(
|
|
130
|
+
'--debug',
|
|
131
|
+
default=False,
|
|
132
|
+
action='store_true',
|
|
133
|
+
dest='debug',
|
|
134
|
+
help="Enable debug logging."
|
|
135
|
+
)
|
|
136
|
+
args = parser.parse_args()
|
|
137
|
+
|
|
138
|
+
print_headers = not args.no_headers
|
|
139
|
+
position_type = args.position_type
|
|
140
|
+
if position_type is not None:
|
|
141
|
+
position_type = position_type.upper()
|
|
142
|
+
get_total = args.total
|
|
143
|
+
filter = args.filter
|
|
144
|
+
if get_total and filter != 'open':
|
|
145
|
+
print("--filter does not work with --total. Abort.")
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
logging_level = logging.WARNING
|
|
149
|
+
if args.debug:
|
|
150
|
+
logging_level = logging.DEBUG
|
|
151
|
+
handler.setLevel(logging_level)
|
|
152
|
+
LOGGER.setLevel(logging_level)
|
|
153
|
+
LOGGER.addHandler(handler)
|
|
154
|
+
|
|
155
|
+
output_io: io.TextIOBase = sys.stdout # type: ignore
|
|
156
|
+
|
|
157
|
+
session = get_session_from_cache()
|
|
158
|
+
session.update_throttling(max_requests=7, period_seconds=1)
|
|
159
|
+
|
|
160
|
+
if get_total:
|
|
161
|
+
if print_headers:
|
|
162
|
+
writer = csv.writer(sys.stdout)
|
|
163
|
+
writer.writerow(("key", "value"))
|
|
164
|
+
asyncio.run(run_portfolio_total_pipeline(session, output_io))
|
|
165
|
+
else:
|
|
166
|
+
asyncio.run(
|
|
167
|
+
run_portfolio_pipeline(
|
|
168
|
+
session,
|
|
169
|
+
output_file=output_io,
|
|
170
|
+
position_type=position_type,
|
|
171
|
+
headers=print_headers,
|
|
172
|
+
)
|
|
173
|
+
)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "degiro-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
authors = [{ name = "ohmajesticlama", email = "ohmajesticlama@gmail.com" }]
|
|
9
9
|
description = "Unofficial command line tools for Degiro"
|
|
10
10
|
readme = "README.md"
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
keywords = ["degiro", "cli", "finance", "investment"]
|
|
24
24
|
|
|
25
25
|
dependencies = [
|
|
26
|
-
"degiroasync >= 1.
|
|
26
|
+
"degiroasync >= 1.1.0",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.urls]
|
|
@@ -34,6 +34,7 @@ dependencies = [
|
|
|
34
34
|
degiro-login = "degirocli.login:main"
|
|
35
35
|
degiro-history = "degirocli.history:main"
|
|
36
36
|
degiro-search = "degirocli.search:main"
|
|
37
|
+
degiro-portfolio = "degirocli.portfolio:main"
|
|
37
38
|
|
|
38
39
|
[project.optional-dependencies]
|
|
39
40
|
dev = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|