cryptodatapy 0.2.5__py3-none-any.whl → 0.2.6__py3-none-any.whl
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.
- cryptodatapy/conf/tickers.csv +0 -1
- cryptodatapy/extract/data_vendors/CoinMetrics.ipynb +747 -0
- cryptodatapy/extract/data_vendors/coinmetrics_api.py +279 -209
- cryptodatapy/extract/data_vendors/cryptocompare_api.py +3 -5
- cryptodatapy/extract/data_vendors/datavendor.py +32 -12
- cryptodatapy/extract/data_vendors/glassnode_api.py +3 -2
- cryptodatapy/extract/data_vendors/tiingo_api.py +3 -2
- cryptodatapy/extract/datarequest.py +55 -9
- cryptodatapy/extract/libraries/ccxt_api.py +13 -2
- cryptodatapy/transform/cc_onchain_data.csv +118423 -0
- cryptodatapy/transform/clean.py +17 -15
- cryptodatapy/transform/clean_onchain_data.ipynb +4750 -0
- cryptodatapy/transform/clean_perp_futures_ohlcv.ipynb +1597 -1178
- cryptodatapy/transform/convertparams.py +28 -18
- cryptodatapy/transform/credit_data.ipynb +291 -0
- cryptodatapy/transform/eqty_data.ipynb +809 -0
- cryptodatapy/transform/filter.py +13 -10
- cryptodatapy/transform/global_credit_data_daily.parquet +0 -0
- cryptodatapy/transform/od.py +1 -0
- cryptodatapy/transform/rates_data.ipynb +465 -0
- cryptodatapy/transform/us_rates_daily.csv +227752 -0
- cryptodatapy/util/datacredentials.py +28 -7
- {cryptodatapy-0.2.5.dist-info → cryptodatapy-0.2.6.dist-info}/METADATA +2 -2
- {cryptodatapy-0.2.5.dist-info → cryptodatapy-0.2.6.dist-info}/RECORD +26 -28
- cryptodatapy/.DS_Store +0 -0
- cryptodatapy/.idea/.gitignore +0 -3
- cryptodatapy/.idea/cryptodatapy.iml +0 -12
- cryptodatapy/.idea/csv-plugin.xml +0 -16
- cryptodatapy/.idea/inspectionProfiles/Project_Default.xml +0 -6
- cryptodatapy/.idea/inspectionProfiles/profiles_settings.xml +0 -6
- cryptodatapy/.idea/misc.xml +0 -4
- cryptodatapy/.idea/modules.xml +0 -8
- cryptodatapy/.idea/vcs.xml +0 -6
- cryptodatapy/extract/libraries/ccxt.ipynb +0 -873
- {cryptodatapy-0.2.5.dist-info → cryptodatapy-0.2.6.dist-info}/LICENSE +0 -0
- {cryptodatapy-0.2.5.dist-info → cryptodatapy-0.2.6.dist-info}/WHEEL +0 -0
@@ -84,8 +84,9 @@ class CryptoCompare(DataVendor):
|
|
84
84
|
if categories is None:
|
85
85
|
self.categories = ['crypto']
|
86
86
|
if api_key is None:
|
87
|
-
raise TypeError("Set your
|
88
|
-
"
|
87
|
+
raise TypeError("Set your CryptoCompare api key in environment variables as 'CRYPTOCOMPARE_API_KEY' or "
|
88
|
+
"add it as an argument when instantiating the class. To get an api key, visit: "
|
89
|
+
"https://min-api.cryptocompare.com/")
|
89
90
|
if exchanges is None:
|
90
91
|
self.exchanges = self.get_exchanges_info(as_list=True)
|
91
92
|
if indexes is None:
|
@@ -467,9 +468,6 @@ class CryptoCompare(DataVendor):
|
|
467
468
|
urls_params = self.set_urls_params(data_req, data_type, ticker)
|
468
469
|
url, params = urls_params['url'], urls_params['params']
|
469
470
|
|
470
|
-
# # data req
|
471
|
-
# data_resp = DataRequest().get_req(url=url, params=params)
|
472
|
-
|
473
471
|
# data req
|
474
472
|
data_resp = DataRequest().get_req(url=url, params=params)
|
475
473
|
|
@@ -92,7 +92,7 @@ class DataVendor(ABC):
|
|
92
92
|
|
93
93
|
@exchanges.setter
|
94
94
|
def exchanges(
|
95
|
-
self, exchanges: Optional[Union[str, List[str], Dict[str, List[str]]]]
|
95
|
+
self, exchanges: Optional[Union[str, List[str], Dict[str, List[str]], pd.DataFrame]]
|
96
96
|
):
|
97
97
|
"""
|
98
98
|
Sets a list of available exchanges for the data vendor.
|
@@ -101,6 +101,7 @@ class DataVendor(ABC):
|
|
101
101
|
exchanges is None
|
102
102
|
or isinstance(exchanges, list)
|
103
103
|
or isinstance(exchanges, dict)
|
104
|
+
or isinstance(exchanges, pd.DataFrame)
|
104
105
|
):
|
105
106
|
self._exchanges = exchanges
|
106
107
|
elif isinstance(exchanges, str):
|
@@ -126,11 +127,16 @@ class DataVendor(ABC):
|
|
126
127
|
return self._indexes
|
127
128
|
|
128
129
|
@indexes.setter
|
129
|
-
def indexes(self, indexes: Optional[Union[str, List[str], Dict[str, List[str]]]]):
|
130
|
+
def indexes(self, indexes: Optional[Union[str, List[str], Dict[str, List[str]], pd.DataFrame]]):
|
130
131
|
"""
|
131
132
|
Sets a list of available indexes for the data vendor.
|
132
133
|
"""
|
133
|
-
if
|
134
|
+
if (
|
135
|
+
indexes is None
|
136
|
+
or isinstance(indexes, list)
|
137
|
+
or isinstance(indexes, dict)
|
138
|
+
or isinstance(indexes, pd.DataFrame)
|
139
|
+
):
|
134
140
|
self._indexes = indexes
|
135
141
|
elif isinstance(indexes, str):
|
136
142
|
self._indexes = [indexes]
|
@@ -155,11 +161,16 @@ class DataVendor(ABC):
|
|
155
161
|
return self._assets
|
156
162
|
|
157
163
|
@assets.setter
|
158
|
-
def assets(self, assets: Optional[Union[str, List[str], Dict[str, List[str]]]]):
|
164
|
+
def assets(self, assets: Optional[Union[str, List[str], Dict[str, List[str]], pd.DataFrame]]):
|
159
165
|
"""
|
160
166
|
Sets a list of available assets for the data vendor.
|
161
167
|
"""
|
162
|
-
if
|
168
|
+
if (
|
169
|
+
assets is None
|
170
|
+
or isinstance(assets, list)
|
171
|
+
or isinstance(assets, dict)
|
172
|
+
or isinstance(assets, pd.DataFrame)
|
173
|
+
):
|
163
174
|
self._assets = assets
|
164
175
|
elif isinstance(assets, str):
|
165
176
|
self._assets = [assets]
|
@@ -184,11 +195,16 @@ class DataVendor(ABC):
|
|
184
195
|
return self._markets
|
185
196
|
|
186
197
|
@markets.setter
|
187
|
-
def markets(self, markets: Optional[Union[str, List[str], Dict[str, List[str]]]]):
|
198
|
+
def markets(self, markets: Optional[Union[str, List[str], Dict[str, List[str]], pd.DataFrame]]):
|
188
199
|
"""
|
189
200
|
Sets a list of available markets for the data vendor.
|
190
201
|
"""
|
191
|
-
if
|
202
|
+
if (
|
203
|
+
markets is None
|
204
|
+
or isinstance(markets, list)
|
205
|
+
or isinstance(markets, dict)
|
206
|
+
or isinstance(markets, pd.DataFrame)
|
207
|
+
):
|
192
208
|
self._markets = markets
|
193
209
|
elif isinstance(markets, str):
|
194
210
|
self._markets = [markets]
|
@@ -251,11 +267,16 @@ class DataVendor(ABC):
|
|
251
267
|
return self._fields
|
252
268
|
|
253
269
|
@fields.setter
|
254
|
-
def fields(self, fields: Optional[Union[str, List[str], Dict[str, List[str]]]]):
|
270
|
+
def fields(self, fields: Optional[Union[str, List[str], Dict[str, List[str]], pd.DataFrame]]):
|
255
271
|
"""
|
256
272
|
Sets a list of available fields for the data vendor.
|
257
273
|
"""
|
258
|
-
if
|
274
|
+
if (
|
275
|
+
fields is None
|
276
|
+
or isinstance(fields, list)
|
277
|
+
or isinstance(fields, dict)
|
278
|
+
or isinstance(fields, pd.DataFrame)
|
279
|
+
):
|
259
280
|
self._fields = fields
|
260
281
|
elif isinstance(fields, str):
|
261
282
|
self._fields = [fields]
|
@@ -280,9 +301,7 @@ class DataVendor(ABC):
|
|
280
301
|
return self._frequencies
|
281
302
|
|
282
303
|
@frequencies.setter
|
283
|
-
def frequencies(
|
284
|
-
self, frequencies: Optional[Union[str, List[str], Dict[str, List[str]]]]
|
285
|
-
):
|
304
|
+
def frequencies(self, frequencies: Optional[Union[str, List[str], Dict[str, List[str]], pd.DataFrame]]):
|
286
305
|
"""
|
287
306
|
Sets a list of available data frequencies for the data vendor.
|
288
307
|
"""
|
@@ -290,6 +309,7 @@ class DataVendor(ABC):
|
|
290
309
|
frequencies is None
|
291
310
|
or isinstance(frequencies, list)
|
292
311
|
or isinstance(frequencies, dict)
|
312
|
+
or isinstance(frequencies, pd.DataFrame)
|
293
313
|
):
|
294
314
|
self._frequencies = frequencies
|
295
315
|
elif isinstance(frequencies, str):
|
@@ -79,8 +79,9 @@ class Glassnode(DataVendor):
|
|
79
79
|
if categories is None:
|
80
80
|
self.categories = ['crypto']
|
81
81
|
if api_key is None:
|
82
|
-
raise TypeError("Set your
|
83
|
-
"
|
82
|
+
raise TypeError("Set your Glassnode api key in environment variables as 'GLASSNODE_API_KEY' or "
|
83
|
+
"add it as an argument when instantiating the class. To get an api key, visit: "
|
84
|
+
"https://docs.glassnode.com/basic-api/api-key")
|
84
85
|
if assets is None:
|
85
86
|
self.assets = self.get_assets_info(as_list=True)
|
86
87
|
if fields is None:
|
@@ -109,8 +109,9 @@ class Tiingo(DataVendor):
|
|
109
109
|
if categories is None:
|
110
110
|
self.categories = ["crypto", "fx", "eqty"]
|
111
111
|
if api_key is None:
|
112
|
-
raise TypeError("Set your
|
113
|
-
"
|
112
|
+
raise TypeError("Set your Tiingo api key in environment variables as 'TIINGO_API_KEY' or "
|
113
|
+
"add it as an argument when instantiating the class. To get an api key, visit: "
|
114
|
+
"https://www.tiingo.com/")
|
114
115
|
if exchanges is None:
|
115
116
|
self.exchanges = self.get_exchanges_info()
|
116
117
|
if assets is None:
|
@@ -197,7 +197,9 @@ class DataRequest:
|
|
197
197
|
"y": "yearly",
|
198
198
|
}
|
199
199
|
|
200
|
-
if frequency
|
200
|
+
if frequency is None:
|
201
|
+
self._frequency = frequency
|
202
|
+
elif frequency not in list(freq_dict.keys()):
|
201
203
|
raise ValueError(
|
202
204
|
f"{frequency} is an invalid data frequency. Valid frequencies are: {freq_dict}"
|
203
205
|
)
|
@@ -555,15 +557,59 @@ class DataRequest:
|
|
555
557
|
# get request
|
556
558
|
try:
|
557
559
|
resp = requests.get(url, params=params, headers=headers)
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
560
|
+
# check for status code
|
561
|
+
resp.raise_for_status()
|
562
|
+
|
563
|
+
return resp.json()
|
564
|
+
|
565
|
+
# handle HTTP errors
|
566
|
+
except requests.exceptions.HTTPError as http_err:
|
567
|
+
status_code = resp.status_code
|
568
|
+
|
569
|
+
# Tailored handling for different status codes
|
570
|
+
if status_code == 400:
|
571
|
+
logging.warning(f"Bad Request (400): {resp.text}")
|
572
|
+
elif status_code == 401:
|
573
|
+
logging.warning("Unauthorized (401): Check the authentication credentials.")
|
574
|
+
elif status_code == 403:
|
575
|
+
logging.warning("Forbidden (403): You do not have permission to access this resource.")
|
576
|
+
elif status_code == 404:
|
577
|
+
logging.warning("Not Found (404): The requested resource could not be found.")
|
578
|
+
elif status_code == 500:
|
579
|
+
logging.error("Internal Server Error (500): The server encountered an error.")
|
580
|
+
elif status_code == 503:
|
581
|
+
logging.error("Service Unavailable (503): The server is temporarily unavailable.")
|
582
|
+
else:
|
583
|
+
logging.error(f"HTTP error occurred: {http_err} (Status Code: {status_code})")
|
584
|
+
logging.error(f"Response Content: {resp.text}")
|
585
|
+
|
586
|
+
# Increment attempts and log warning
|
587
|
+
attempts += 1
|
588
|
+
logging.warning(f"Attempt #{attempts}: Failed to get data due to: {http_err}")
|
589
|
+
sleep(self.pause) # Pause before retrying
|
590
|
+
if attempts == self.trials:
|
591
|
+
logging.error("Max attempts reached. Unable to fetch data.")
|
592
|
+
break
|
593
|
+
|
594
|
+
# handle non-HTTP exceptions (e.g., network issues)
|
595
|
+
except requests.exceptions.RequestException as req_err:
|
562
596
|
attempts += 1
|
563
|
-
logging.warning(f"
|
597
|
+
logging.warning(f"Request error on attempt #{attempts}: {req_err}. "
|
598
|
+
f"Retrying after {self.pause} seconds...")
|
564
599
|
sleep(self.pause)
|
565
|
-
if attempts ==
|
600
|
+
if attempts == self.trials:
|
601
|
+
logging.error("Max attempts reached. Unable to fetch data due to request errors.")
|
566
602
|
break
|
567
603
|
|
568
|
-
|
569
|
-
|
604
|
+
# handle other exceptions
|
605
|
+
except Exception as e:
|
606
|
+
attempts += 1
|
607
|
+
logging.warning(f"An unexpected error occurred: {e}. "
|
608
|
+
f"Retrying after {self.pause} seconds...")
|
609
|
+
sleep(self.pause)
|
610
|
+
if attempts == self.trials:
|
611
|
+
logging.error("Max attempts reached. Unable to fetch data due to request errors.")
|
612
|
+
break
|
613
|
+
|
614
|
+
# return None if the API call fails
|
615
|
+
return None
|
@@ -273,6 +273,7 @@ class CCXT(Library):
|
|
273
273
|
data_type: str,
|
274
274
|
ticker: str,
|
275
275
|
start_date: str = None,
|
276
|
+
end_date: str = None,
|
276
277
|
) -> pd.DataFrame:
|
277
278
|
"""
|
278
279
|
Sends data request to Python client.
|
@@ -287,6 +288,8 @@ class CCXT(Library):
|
|
287
288
|
Ticker symbol to request data for.
|
288
289
|
start_date: str
|
289
290
|
Start date in 'YYYY-MM-DD' format.
|
291
|
+
end_date: str
|
292
|
+
End date in 'YYYY-MM-DD' format.
|
290
293
|
|
291
294
|
|
292
295
|
Returns
|
@@ -298,6 +301,8 @@ class CCXT(Library):
|
|
298
301
|
cx_data_req = ConvertParams(data_req).to_ccxt()
|
299
302
|
if start_date is None:
|
300
303
|
start_date = cx_data_req['start_date']
|
304
|
+
if end_date is None:
|
305
|
+
end_date = cx_data_req['end_date']
|
301
306
|
|
302
307
|
# data types
|
303
308
|
data_types = {'ohlcv': 'fetchOHLCV', 'funding_rates': 'fetchFundingRateHistory'}
|
@@ -313,12 +318,14 @@ class CCXT(Library):
|
|
313
318
|
cx_data_req["freq"],
|
314
319
|
since=start_date,
|
315
320
|
limit=self.max_obs_per_call,
|
321
|
+
params={'until': end_date}
|
316
322
|
)
|
317
323
|
elif data_type == 'funding_rates':
|
318
324
|
data_resp = getattr(exch, data_types[data_type])(
|
319
325
|
ticker,
|
320
326
|
since=start_date,
|
321
327
|
limit=1000,
|
328
|
+
params={'until': end_date}
|
322
329
|
)
|
323
330
|
|
324
331
|
return data_resp
|
@@ -349,6 +356,7 @@ class CCXT(Library):
|
|
349
356
|
# convert data request parameters to CCXT format and set start date
|
350
357
|
cx_data_req = ConvertParams(data_req).to_ccxt()
|
351
358
|
start_date = cx_data_req['start_date']
|
359
|
+
end_date = cx_data_req['end_date']
|
352
360
|
|
353
361
|
# create empty df
|
354
362
|
df = pd.DataFrame()
|
@@ -362,7 +370,8 @@ class CCXT(Library):
|
|
362
370
|
data_resp = self.req_data(data_req=data_req,
|
363
371
|
data_type='ohlcv',
|
364
372
|
ticker=ticker,
|
365
|
-
start_date=start_date
|
373
|
+
start_date=start_date,
|
374
|
+
end_date=end_date)
|
366
375
|
|
367
376
|
if data_resp is None:
|
368
377
|
attempts += 1
|
@@ -420,6 +429,7 @@ class CCXT(Library):
|
|
420
429
|
# convert data request parameters to CCXT format and set start date
|
421
430
|
cx_data_req = ConvertParams(data_req).to_ccxt()
|
422
431
|
start_date = cx_data_req['start_date']
|
432
|
+
end_date = cx_data_req['end_date']
|
423
433
|
|
424
434
|
# create empty df
|
425
435
|
df = pd.DataFrame()
|
@@ -433,7 +443,8 @@ class CCXT(Library):
|
|
433
443
|
data_resp = self.req_data(data_req=data_req,
|
434
444
|
data_type='funding_rates',
|
435
445
|
ticker=ticker,
|
436
|
-
start_date=start_date
|
446
|
+
start_date=start_date,
|
447
|
+
end_date=end_date)
|
437
448
|
|
438
449
|
if data_resp is None:
|
439
450
|
attempts += 1
|