-
Notifications
You must be signed in to change notification settings - Fork 6
/
fiscalcrypt
executable file
·242 lines (173 loc) · 9.01 KB
/
fiscalcrypt
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/usr/bin/env python3
"""
Main script to run fiscalcrypt tool
.. moduleauthor:: Armand BENETEAU <armand.beneteau@iot.bzh>
*Date: 24/04/2021*
*License:*
Copyright (C) 2021 Armand Bénéteau
This file is part of the Fiscal Crypt project.
GNU General Public License Usage
This file may be used under the terms of the GNU General \
Public license version 3. This license is as published by the Free Software \
Foundation and appearing in the file LICENSE included in the packaging \
of this file. Please review the following information to ensure the GNU \
General Public License requirements will be met \
https://www.gnu.org/licenses/gpl-3.0.html.
"""
import json
import sys
from dateutil.parser import isoparse
from decimal import *
from typing import Dict, List
from fiscal_crypt.price_finder.abs_price_finder import PriceFinder
from fiscal_crypt.price_finder.cryptowatch_finder import CryptowatchFinder
from fiscal_crypt.price_finder.coinbasepro_finder import CoinbaseProFinder
from fiscal_crypt.platforms.abs_platforms import PlatformInterface
from fiscal_crypt.platforms.coinbase import CoinbaseInterface
from fiscal_crypt.platforms.coinbase_pro import CoinbaseProInterface
from fiscal_crypt.tax_processing.french_taxes import FrenchTaxes
from fiscal_crypt.fcrypt_logging import fcrypt_log
class FCryptError(Exception):
pass
class NoPriceFindersError(FCryptError):
pass
class PriceFinderBadlyDefined(FCryptError):
pass
class NoExchangePlatformFound(FCryptError):
pass
class ExchangePlatformBadlyDefined(FCryptError):
pass
def get_price_finders_from_config(config_file: str) -> Dict[str, PriceFinder]:
"""
This function allows to get a dictionary containing all the prices finders
from the configuration file given by the user
:param config_file: Path to the configuration file given by the user
:type config_file: str
:returns: Dict[PriceFinder] -- Dictionary containing the price finders
"""
# Create the resulting dictionary
result = {}
# Try to read the file
with open(config_file) as cfg_file:
# Read the config
config = json.load(cfg_file)
# Try to get the "price_finders" list
price_finders_list = config.get("price_finders", [])
# If empty list, raise an exception
if len(price_finders_list) <= 0:
raise NoPriceFindersError
# Loop over the list and create every price finders
for price_finder in price_finders_list:
# Get the type of price finder to create
pfinder_type = price_finder.get("type")
if pfinder_type is None:
raise PriceFinderBadlyDefined("No type found for one price finder")
# According to the type, create it
if pfinder_type == "cryptowatch":
# Get the "name", "api_key" and "exchange"
pfinder_name = price_finder.get("name", "")
pfinder_key = price_finder.get("api_key", "")
pfinder_exchange = price_finder.get("exchange", "")
if (pfinder_name == "") or (pfinder_key == "") or (pfinder_exchange == ""):
raise PriceFinderBadlyDefined("One of the following field is empty for \
the cryptowatch price finder: \"name\", \"api_key\" or \"exchange\"")
# Create the price finder
result[pfinder_name] = CryptowatchFinder(pfinder_key, pfinder_exchange)
elif pfinder_type == "coinbase-pro":
# Get the "name"
pfinder_name = price_finder.get("name", "")
if (pfinder_name == ""):
raise PriceFinderBadlyDefined("The \"name\" field is empty for the coinbase-pro price finder")
# Create the price finder
result[pfinder_name] = CoinbaseProFinder()
return result
def get_platforms_from_config(config_file: str, finders: Dict[str, PriceFinder]) -> List[PlatformInterface]:
"""
This function allows to get a list containing all the exchanges platform objects
necessary to calculate the tax declarations.
In order to get that, the function needs the configuration file path and the dictionary
containing the price finders.
:param config_file: Path to the configuration file given by the user
:type config_file: str
:param finders: Dictionary containing the price finders as defined by the user
:type finders: Dict[str, PriceFinder]
:returns: List[PlatformInterface] -- List containing the exchanges interfaces
"""
# Create the resulting list
result = []
# Try to read the file
with open(config_file) as cfg_file:
# Read the config
config = json.load(cfg_file)
# Try to get the "platforms" list
platforms_list = config.get("platforms", [])
# If empty list, raise an exception
if len(platforms_list) <= 0:
raise NoExchangePlatformFound
# Loop over the list and create every price finders
for platform in platforms_list:
# Get the type of price finder to create
platform_type = platform.get("type")
if platform_type is None:
raise ExchangePlatformBadlyDefined("No type found for one platform")
# According to the type, create it
if platform_type == "coinbase":
# Get the "api_key" and "api_secret"
platform_key = platform.get("api_key", "")
platform_secret = platform.get("api_secret", "")
if (platform_key == "") or (platform_secret == ""):
raise ExchangePlatformBadlyDefined("One of the following field is empty for \
the coinbase platform: \"api_key\" or \"api_secret\"")
# Get the price finders for this platform
platform_finders = platform.get("price_finders", [])
if len(platform_finders) <= 0:
raise ExchangePlatformBadlyDefined("No price finder defined for coinbase platform")
# Create the list containing the finders
finders_obj_list = []
for finder in platform_finders:
finders_obj_list.append(finders[finder])
# Create the platform and add it to the list
coinbase_platform = CoinbaseInterface(platform_key, platform_secret, finders_obj_list)
result.append(coinbase_platform)
elif platform_type == "coinbase-pro":
# Get the "api_key", "api_secret" and "api_passphrase"
platform_key = platform.get("api_key", "")
platform_secret = platform.get("api_secret", "")
platform_passphrase = platform.get("api_passphrase", "")
if (platform_key == "") or (platform_secret == "") or (platform_passphrase == ""):
raise ExchangePlatformBadlyDefined("One of the following field is empty for \
the coinbase platform: \"api_key\", \"api_secret\" or \"api_passphrase\"")
# Get the price finders for this platform
platform_finders = platform.get("price_finders", [])
if len(platform_finders) <= 0:
raise ExchangePlatformBadlyDefined("No price finder defined for coinbase-pro platform")
# Create the list containing the finders
finders_obj_list = []
for finder in platform_finders:
finders_obj_list.append(finders[finder])
# Create the platform and add it to the list
coinbase_pro_platform = CoinbaseProInterface(platform_key, platform_secret,
platform_passphrase, finders_obj_list)
result.append(coinbase_pro_platform)
return result
if __name__ == "__main__":
try:
# Try to get the file passed in argument
if len(sys.argv) < 2:
config_file = "fiscalcrypt_config.json"
else:
config_file = sys.argv[1]
# Request the year wanted for tax declaration to the user
fiscal_year = input("[FISCALCRYPT] Please enter the year wanted for tax declaration (ex: 2020) > ")
# Create the price finders dictionaries from the configuration file
price_finders_dict = get_price_finders_from_config(config_file)
# Create the platforms objects from configuration files and price finders dictionaries
platform_list = get_platforms_from_config(config_file, price_finders_dict)
tax_model = FrenchTaxes("EUR", platform_list)
# Call the function allowing to calculate the taxes
tax_model.get_tax_declaration_for("EUR",
isoparse(f"{fiscal_year}-01-01T00:00:00Z"),
isoparse(f"{fiscal_year}-12-31T23:59:59Z"))
except Exception as err:
fcrypt_log.error("[Exception] The following exception occured while fiscalcrypt was running:", str(err))
sys.exit(1)