cryptodatapy 0.2.14__py3-none-any.whl → 0.2.16__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.
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from time import sleep
3
- from typing import Dict, Optional, Union, Any
3
+ from typing import Dict, Optional, Union, Any, List
4
4
 
5
5
  import pandas as pd
6
6
 
@@ -13,13 +13,6 @@ from cryptodatapy.util.datacredentials import DataCredentials
13
13
  # data credentials
14
14
  data_cred = DataCredentials()
15
15
 
16
- # url endpoints
17
- urls = {'exchanges_info': 'exchanges/general', 'indexes_info': 'index/list', 'assets_info': 'all/coinlist',
18
- 'markets_info': 'v2/cccagg/pairs', 'on-chain_tickers_info': 'blockchain/list',
19
- 'on-chain_info': 'blockchain/latest?fsym=BTC', 'social_info': 'social/coin/histo/day',
20
- 'news': 'v2/news/?lang=EN', 'news_sources': 'news/feeds', 'rate_limit_info': 'rate/limit',
21
- 'top_mkt_cap_info': 'top/mktcapfull?', 'indexes': 'index/'}
22
-
23
16
 
24
17
  class CryptoCompare(DataVendor):
25
18
  """
@@ -28,15 +21,16 @@ class CryptoCompare(DataVendor):
28
21
 
29
22
  def __init__(
30
23
  self,
31
- categories=None,
24
+ categories: List[str] = ['crypto'],
32
25
  exchanges: Optional[list[str]] = None,
33
26
  indexes: Optional[list[str]] = None,
34
27
  assets: Optional[list[str]] = None,
35
28
  markets: Optional[list[str]] = None,
36
- market_types=None,
29
+ market_types: List[str] = ['spot'],
37
30
  fields: Optional[list[str]] = None,
38
- frequencies=None,
31
+ frequencies: List[str] = ['1min', '1h', 'd'],
39
32
  base_url: str = data_cred.cryptocompare_base_url,
33
+ api_endpoints: Dict[str, str] = data_cred.cryptomcompare_endpoints,
40
34
  api_key: str = data_cred.cryptocompare_api_key,
41
35
  max_obs_per_call: int = 2000,
42
36
  rate_limit: Optional[pd.DataFrame] = None
@@ -65,6 +59,9 @@ class CryptoCompare(DataVendor):
65
59
  '8h', 'd', 'w', 'm']
66
60
  base_url: str
67
61
  Base url used for GET requests. If not provided, default is set to base_url stored in DataCredentials.
62
+ api_endpoints: dict, optional, default None
63
+ Dictionary with available API endpoints. If not provided, default is set to api_endpoints stored in
64
+ DataCredentials.
68
65
  api_key: str
69
66
  Api key, e.g. 'dcf13983adf7dfa79a0dfa35adf'. If not provided, default is set to
70
67
  api_key stored in DataCredentials.
@@ -74,31 +71,17 @@ class CryptoCompare(DataVendor):
74
71
  rate_limit: pd.DataFrame, optional, Default None
75
72
  Number of API calls made and left, by time frequency.
76
73
  """
77
- DataVendor.__init__(self, categories, exchanges, indexes, assets, markets, market_types, fields,
78
- frequencies, base_url, api_key, max_obs_per_call, rate_limit)
79
-
80
- if frequencies is None:
81
- self.frequencies = ['1min', '1h', 'd']
82
- if market_types is None:
83
- self.market_types = ['spot']
84
- if categories is None:
85
- self.categories = ['crypto']
74
+ super().__init__(
75
+ categories, exchanges, indexes, assets, markets, market_types,
76
+ fields, frequencies, base_url, api_endpoints, api_key, max_obs_per_call, rate_limit
77
+ )
86
78
  if api_key is None:
87
79
  raise TypeError("Set your CryptoCompare api key in environment variables as 'CRYPTOCOMPARE_API_KEY' or "
88
80
  "add it as an argument when instantiating the class. To get an api key, visit: "
89
81
  "https://min-api.cryptocompare.com/")
90
- if exchanges is None:
91
- self.exchanges = self.get_exchanges_info(as_list=True)
92
- if indexes is None:
93
- self.indexes = self.get_indexes_info(as_list=True)
94
- if assets is None:
95
- self.assets = self.get_assets_info(as_list=True)
96
- if markets is None:
97
- self.markets = self.get_markets_info(as_list=True)
98
- if fields is None:
99
- self.fields = self.get_fields_info(data_type=None)
100
- if rate_limit is None:
101
- self.rate_limit = self.get_rate_limit_info()
82
+ self.data_req = None
83
+ self.data_resp = None
84
+ self.data = pd.DataFrame()
102
85
 
103
86
  def req_meta(self, info_type: str) -> Dict[str, Any]:
104
87
  """
@@ -116,7 +99,9 @@ class CryptoCompare(DataVendor):
116
99
  meta: dictionary
117
100
  Metadata in JSON format.
118
101
  """
119
- return DataRequest().get_req(url=self.base_url + urls[info_type], params={'api_key': self.api_key})
102
+ self.data_resp = DataRequest().get_req(url=self.base_url + self.api_endpoints[info_type],
103
+ params={'api_key': self.api_key})
104
+ return self.data_resp
120
105
 
121
106
  def get_exchanges_info(self, as_list: bool = False) -> Union[list[str], pd.DataFrame]:
122
107
  """
@@ -133,11 +118,11 @@ class CryptoCompare(DataVendor):
133
118
  List or dataframe with info on available indexes.
134
119
  """
135
120
  # data req
136
- data_resp = self.req_meta(info_type='exchanges_info')
121
+ self.req_meta(info_type='exchanges_info')
137
122
  # wrangle data resp
138
- exch = WrangleInfo(data_resp).cc_exch_info(as_list=as_list)
123
+ self.exchanges = WrangleInfo(self.data_resp).cc_exch_info(as_list=as_list)
139
124
 
140
- return exch
125
+ return self.exchanges
141
126
 
142
127
  def get_indexes_info(self, as_list: bool = False) -> Union[list[str], pd.DataFrame]:
143
128
  """
@@ -154,11 +139,11 @@ class CryptoCompare(DataVendor):
154
139
  List or dataframe with info on available indexes.
155
140
  """
156
141
  # data req
157
- data_resp = self.req_meta(info_type='indexes_info')
142
+ self.req_meta(info_type='indexes_info')
158
143
  # wrangle data resp
159
- indexes = WrangleInfo(data_resp).cc_indexes_info(as_list=as_list)
144
+ self.indexes = WrangleInfo(self.data_resp).cc_indexes_info(as_list=as_list)
160
145
 
161
- return indexes
146
+ return self.indexes
162
147
 
163
148
  def get_assets_info(self, as_list: bool = False) -> Union[list[str], pd.DataFrame]:
164
149
  """
@@ -175,11 +160,11 @@ class CryptoCompare(DataVendor):
175
160
  List or dataframe with info on available assets.
176
161
  """
177
162
  # data req
178
- data_resp = self.req_meta(info_type='assets_info')
163
+ self.req_meta(info_type='assets_info')
179
164
  # wrangle data resp
180
- assets = WrangleInfo(data_resp).cc_assets_info(as_list=as_list)
165
+ self.assets = WrangleInfo(self.data_resp).cc_assets_info(as_list=as_list)
181
166
 
182
- return assets
167
+ return self.assets
183
168
 
184
169
  def get_markets_info(self, as_list: bool = False) -> Union[list[str], dict[str]]:
185
170
  """
@@ -196,11 +181,11 @@ class CryptoCompare(DataVendor):
196
181
  Dictionary or list with info on available markets.
197
182
  """
198
183
  # data req
199
- data_resp = self.req_meta(info_type='markets_info')
184
+ self.req_meta(info_type='markets_info')
200
185
  # wrangle data resp
201
- mkts = WrangleInfo(data_resp).cc_mkts_info(as_list=as_list)
186
+ self.markets = WrangleInfo(self.data_resp).cc_mkts_info(as_list=as_list)
202
187
 
203
- return mkts
188
+ return self.markets
204
189
 
205
190
  def get_onchain_tickers_info(self, as_list: bool = False) -> Union[list[str], pd.DataFrame]:
206
191
  """
@@ -217,18 +202,12 @@ class CryptoCompare(DataVendor):
217
202
  list or dataframe with info on tickers with available on-chain data.
218
203
  """
219
204
  # data req
220
- data_resp = self.req_meta(info_type='on-chain_tickers_info')
205
+ self.req_meta(info_type='on-chain_tickers_info')
221
206
  # wrangle data resp
222
- tickers = WrangleInfo(data_resp).cc_onchain_tickers_info(as_list=as_list)
207
+ tickers = WrangleInfo(self.data_resp).cc_onchain_tickers_info(as_list=as_list)
223
208
 
224
209
  return tickers
225
210
 
226
- def req_onchain(self) -> Dict[str, Any]:
227
- """
228
- Get request for on-chain info.
229
- """
230
- return DataRequest().get_req(url=self.base_url + urls['on-chain_info'], params={'api_key': self.api_key})
231
-
232
211
  def get_onchain_info(self) -> list[str]:
233
212
  """
234
213
  Get on-chain fields info.
@@ -239,9 +218,9 @@ class CryptoCompare(DataVendor):
239
218
  List of available on-chain fields.
240
219
  """
241
220
  # data req
242
- data_resp = self.req_meta(info_type='on-chain_info')
221
+ self.req_meta(info_type='on-chain_info')
243
222
  # wrangle data resp
244
- onchain_fields = WrangleInfo(data_resp).cc_onchain_info()
223
+ onchain_fields = WrangleInfo(self.data_resp).cc_onchain_info()
245
224
 
246
225
  return onchain_fields
247
226
 
@@ -255,9 +234,9 @@ class CryptoCompare(DataVendor):
255
234
  List of available social fields.
256
235
  """
257
236
  # data req
258
- data_resp = self.req_meta(info_type='social_info')
237
+ self.req_meta(info_type='social_info')
259
238
  # wrangle data resp
260
- social_fields = WrangleInfo(data_resp).cc_social_info()
239
+ social_fields = WrangleInfo(self.data_resp).cc_social_info()
261
240
 
262
241
  return social_fields
263
242
 
@@ -277,24 +256,26 @@ class CryptoCompare(DataVendor):
277
256
  """
278
257
  ohlcv_list = ['open', 'high', 'low', 'close', 'volumefrom']
279
258
 
280
- # fields list
259
+ # fields
281
260
  if data_type == 'market':
282
- fields_list = ohlcv_list
261
+ self.fields = ohlcv_list
283
262
  elif data_type == 'on-chain':
284
- fields_list = self.get_onchain_info()
263
+ self.fields = self.get_onchain_info()
285
264
  elif data_type == 'off-chain':
286
- fields_list = self.get_social_info()
265
+ self.fields = self.get_social_info()
287
266
  else:
288
- fields_list = ohlcv_list + self.get_onchain_info() + self.get_social_info()
267
+ self.fields = ohlcv_list + self.get_onchain_info() + self.get_social_info()
289
268
 
290
- return fields_list
269
+ return self.fields
291
270
 
292
271
  def req_rate_limit(self) -> Dict[str, Any]:
293
272
  """
294
273
  Get request for rate limit info.
295
274
  """
296
- return DataRequest().get_req(url=self.base_url.replace('data', 'stats') + urls['rate_limit_info'],
297
- params={'api_key': self.api_key})
275
+ self.data_resp = DataRequest().get_req(url=self.base_url.replace('data', 'stats') +
276
+ self.api_endpoints['rate_limit_info'],
277
+ params={'api_key': self.api_key})
278
+ return self.data_resp
298
279
 
299
280
  def get_rate_limit_info(self) -> pd.DataFrame:
300
281
  """
@@ -306,11 +287,11 @@ class CryptoCompare(DataVendor):
306
287
  DataFrame with API calls left and made by period (hour, day, month).
307
288
  """
308
289
  # data req
309
- data_resp = self.req_rate_limit()
290
+ self.req_rate_limit()
310
291
  # wrangle data resp
311
- rate_limit = WrangleInfo(data_resp).cc_rate_limit_info()
292
+ self.rate_limit = WrangleInfo(self.data_resp).cc_rate_limit_info()
312
293
 
313
- return rate_limit
294
+ return self.rate_limit
314
295
 
315
296
  def get_news(self) -> pd.DataFrame:
316
297
  """
@@ -322,9 +303,9 @@ class CryptoCompare(DataVendor):
322
303
  News articles from various sources with title, source, body, ...
323
304
  """
324
305
  # data req
325
- data_resp = self.req_meta(info_type='news')
306
+ self.req_meta(info_type='news')
326
307
  # wrangle data resp
327
- news = WrangleInfo(data_resp).cc_news()
308
+ news = WrangleInfo(self.data_resp).cc_news()
328
309
 
329
310
  return news
330
311
 
@@ -338,9 +319,9 @@ class CryptoCompare(DataVendor):
338
319
  News source info.
339
320
  """
340
321
  # data req
341
- data_resp = self.req_meta(info_type='news_sources')
322
+ self.req_meta(info_type='news_sources')
342
323
  # wrangle data resp
343
- news_sources = WrangleInfo(data_resp).cc_news_sources()
324
+ news_sources = WrangleInfo(self.data_resp).cc_news_sources()
344
325
 
345
326
  return news_sources
346
327
 
@@ -348,12 +329,15 @@ class CryptoCompare(DataVendor):
348
329
  """
349
330
  Get request for top mkt cap coins info.
350
331
  """
351
- return DataRequest().get_req(url=self.base_url + urls['top_mkt_cap_info'],
352
- params={
353
- 'limit': n,
354
- 'tsym': 'USD',
355
- 'api_key': self.api_key
356
- })
332
+ self.data_resp = DataRequest().get_req(
333
+ url=self.base_url + self.api_endpoints['top_mkt_cap_info'],
334
+ params={
335
+ 'limit': n,
336
+ 'tsym': 'USD',
337
+ 'api_key': self.api_key
338
+ }
339
+ )
340
+ return self.data_resp
357
341
 
358
342
  def get_top_mkt_cap_info(self, n: int = 100) -> list[str]:
359
343
  """
@@ -374,13 +358,13 @@ class CryptoCompare(DataVendor):
374
358
  raise ValueError("Maximum number of assets is 100. Change n parameter and try again.")
375
359
 
376
360
  # date req
377
- data_resp = self.req_top_mkt_cap(n=n)
361
+ self.req_top_mkt_cap(n=n)
378
362
  # wrangle data resp
379
- tickers = WrangleInfo(data_resp).cc_top_mkt_cap_info()
363
+ tickers = WrangleInfo(self.data_resp).cc_top_mkt_cap_info()
380
364
 
381
365
  return tickers
382
366
 
383
- def set_urls_params(self, data_req: DataRequest, data_type: str, ticker: str) -> Dict[str, Union[str, int]]:
367
+ def set_urls_params(self, data_req: DataRequest, data_type: str, ticker: str) -> Dict[str, Union[str, Any]]:
384
368
  """
385
369
  Sets url and params for get request.
386
370
 
@@ -400,25 +384,26 @@ class CryptoCompare(DataVendor):
400
384
 
401
385
  """
402
386
  # convert data req params
403
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
387
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
404
388
 
405
389
  # set params
406
390
  if data_type == 'indexes':
407
- url = self.base_url + urls['indexes'] + cc_data_req['freq'][:5] + "/" + cc_data_req['freq'][5:]
391
+ url = (self.base_url + self.api_endpoints['indexes'] + self.data_req.source_freq[:5] + "/" +
392
+ self.data_req.source_freq[5:])
408
393
  params = {
409
394
  'indexName': ticker,
410
- 'toTs': cc_data_req['end_date'],
395
+ 'toTs': self.data_req.source_end_date,
411
396
  'limit': self.max_obs_per_call,
412
397
  'api_key': self.api_key
413
398
  }
414
399
  elif data_type == 'ohlcv':
415
- url = self.base_url + f"v2/{cc_data_req['freq']}"
400
+ url = self.base_url + f"v2/{self.data_req.source_freq}"
416
401
  params = {
417
402
  'fsym': ticker,
418
- 'tsym': cc_data_req['quote_ccy'],
403
+ 'tsym': self.data_req.quote_ccy,
419
404
  'limit': self.max_obs_per_call,
420
- 'e': cc_data_req['exch'],
421
- 'toTs': cc_data_req['end_date'],
405
+ 'e': self.data_req.exch,
406
+ 'toTs': self.data_req.source_end_date,
422
407
  'api_key': self.api_key
423
408
  }
424
409
 
@@ -427,16 +412,16 @@ class CryptoCompare(DataVendor):
427
412
  params = {
428
413
  'fsym': ticker,
429
414
  'limit': self.max_obs_per_call,
430
- 'toTs': cc_data_req['end_date'],
415
+ 'toTs': self.data_req.source_end_date,
431
416
  'api_key': self.api_key
432
417
  }
433
418
 
434
419
  elif data_type == 'social':
435
- url = self.base_url + "social/coin/" + cc_data_req['freq'][:5] + '/' + cc_data_req['freq'][5:]
420
+ url = self.base_url + "social/coin/" + self.data_req.source_freq[:5] + '/' + self.data_req.source_freq[5:]
436
421
  params = {
437
422
  'coinId': int(self.get_assets_info().loc[ticker.upper(), 'Id']),
438
423
  'limit': self.max_obs_per_call,
439
- 'toTs': cc_data_req['end_date'],
424
+ 'toTs': self.data_req.source_end_date,
440
425
  'api_key': self.api_key
441
426
  }
442
427
 
@@ -444,7 +429,7 @@ class CryptoCompare(DataVendor):
444
429
  url = self.base_url
445
430
  params = {}
446
431
 
447
- return {'url': url, 'params': params}
432
+ return url, params
448
433
 
449
434
  def req_data(self, data_req: DataRequest, data_type: str, ticker: str) -> Dict[str, Any]:
450
435
  """
@@ -465,13 +450,12 @@ class CryptoCompare(DataVendor):
465
450
  Data response in JSON format.
466
451
  """
467
452
  # set params
468
- urls_params = self.set_urls_params(data_req, data_type, ticker)
469
- url, params = urls_params['url'], urls_params['params']
453
+ url, params = self.set_urls_params(data_req, data_type, ticker)
470
454
 
471
455
  # data req
472
- data_resp = DataRequest().get_req(url=url, params=params)
456
+ self.data_req = data_req.get_req(url=url, params=params)
473
457
 
474
- return data_resp
458
+ return self.data_req
475
459
 
476
460
  def get_all_data_hist(self, data_req: DataRequest, data_type: str, ticker: str) -> pd.DataFrame:
477
461
  """
@@ -494,11 +478,10 @@ class CryptoCompare(DataVendor):
494
478
 
495
479
  """
496
480
  # convert data req params
497
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
481
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
498
482
 
499
483
  # set params
500
- urls_params = self.set_urls_params(data_req, data_type, ticker)
501
- url, params = urls_params['url'], urls_params['params']
484
+ url, params = self.set_urls_params(data_req, data_type, ticker)
502
485
 
503
486
  # create empty df
504
487
  df = pd.DataFrame()
@@ -509,26 +492,25 @@ class CryptoCompare(DataVendor):
509
492
  while missing_vals:
510
493
 
511
494
  # data req
512
- data_resp = DataRequest().get_req(url=url, params=params)
495
+ self.data_resp = DataRequest().get_req(url=url, params=params)
513
496
 
514
497
  # add data resp to df
515
- if data_resp:
498
+ if self.data_resp:
516
499
  if data_type == 'indexes' or data_type == 'social':
517
- df1 = pd.DataFrame(data_resp['Data'])
500
+ df1 = pd.DataFrame(self.data_resp['Data'])
518
501
  else:
519
- df1 = pd.DataFrame(data_resp['Data']['Data'])
502
+ df1 = pd.DataFrame(self.data_resp['Data']['Data'])
520
503
  df = pd.concat([df, df1]) # add data to empty df
521
504
 
522
505
  # check if all data has been extracted
523
- if len(df1) < (self.max_obs_per_call - 1) or df1.time[0] <= cc_data_req['start_date'] or \
506
+ if len(df1) < (self.max_obs_per_call - 1) or df1.time[0] <= self.data_req.source_start_date or \
524
507
  all(df1.drop(columns=['time']).iloc[0] == 0) or \
525
508
  all(df1.drop(columns=['time']).iloc[0].astype(str) == 'nan'):
526
509
  missing_vals = False
527
510
  # reset end date and pause before calling API again
528
511
  else:
529
- # change end date
530
512
  params['toTs'] = df1.time[0]
531
- sleep(0.1)
513
+ sleep(self.data_req.pause)
532
514
 
533
515
  return df
534
516
 
@@ -549,7 +531,6 @@ class CryptoCompare(DataVendor):
549
531
  df: pd.DataFrame
550
532
  Wrangled dataframe with DatetimeIndex and values in tidy format.
551
533
  """
552
-
553
534
  return WrangleData(data_req, data_resp).cryptocompare()
554
535
 
555
536
  def get_tidy_data(self, data_req: DataRequest, data_type: str, ticker: str) -> pd.DataFrame:
@@ -595,18 +576,18 @@ class CryptoCompare(DataVendor):
595
576
  Dataframe with DatetimeIndex (level 0), ticker (level 1) and values for fields (cols), in tidy data format.
596
577
  """
597
578
  # convert data request parameters to CryptoCompare format
598
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
579
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
599
580
 
600
581
  # empty df to add data
601
582
  df = pd.DataFrame()
602
583
 
603
584
  # loop through tickers
604
- for ticker in cc_data_req['tickers']:
585
+ for ticker in self.data_req.source_tickers:
605
586
 
606
587
  try:
607
588
  df0 = self.get_tidy_data(data_req, data_type, ticker)
608
- except Exception:
609
- logging.info(f"Failed to get {data_type} data for {ticker} after many attempts.")
589
+ except Exception as e:
590
+ logging.info(f"Failed to get {data_type} data for {ticker} after many attempts: {e}.")
610
591
  else:
611
592
  # add ticker to index
612
593
  df0['ticker'] = ticker
@@ -630,23 +611,16 @@ class CryptoCompare(DataVendor):
630
611
  df: pd.DataFrame - MultiIndex
631
612
  DataFrame with DatetimeIndex (level 0), ticker (level 1), and index values (cols), in tidy format.
632
613
  """
633
- # convert data request parameters to CryptoCompare format
634
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
635
-
636
- # fields list
637
- market_fields = self.get_fields_info(data_type='market')
638
-
639
- # check if tickers and fields are correct
640
- if any([ticker in self.indexes for ticker in cc_data_req['tickers']]) and \
641
- any([field in market_fields for field in cc_data_req['fields']]):
642
- try:
643
- df = self.get_all_tickers(data_req, data_type='indexes')
614
+ # convert params
615
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
644
616
 
645
- except Exception as e:
646
- logging.warning(e)
617
+ # get indexes
618
+ try:
619
+ df = self.get_all_tickers(data_req, data_type='indexes')
620
+ return df
647
621
 
648
- else:
649
- return df
622
+ except Exception as e:
623
+ logging.warning(e)
650
624
 
651
625
  def get_ohlcv(self, data_req: DataRequest) -> pd.DataFrame:
652
626
  """
@@ -662,23 +636,16 @@ class CryptoCompare(DataVendor):
662
636
  df: pd.DataFrame - MultiIndex
663
637
  DataFrame with DatetimeIndex (level 0), ticker (level 1), and OHLCV values (cols), in tidy format.
664
638
  """
665
- # convert data request parameters to CryptoCompare format
666
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
667
-
668
- # fields list
669
- market_fields = self.get_fields_info(data_type='market')
639
+ # convert params
640
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
670
641
 
671
- # check if tickers and fields are correct
672
- if any([ticker in self.assets for ticker in cc_data_req['tickers']]) and \
673
- any([field in market_fields for field in cc_data_req['fields']]):
674
- try:
675
- df = self.get_all_tickers(data_req, data_type='ohlcv')
676
-
677
- except Exception as e:
678
- logging.warning(e)
642
+ # get ohlcv
643
+ try:
644
+ df = self.get_all_tickers(data_req, data_type='ohlcv')
645
+ return df
679
646
 
680
- else:
681
- return df
647
+ except Exception as e:
648
+ logging.warning(e)
682
649
 
683
650
  def get_onchain(self, data_req: DataRequest) -> pd.DataFrame:
684
651
  """
@@ -695,28 +662,16 @@ class CryptoCompare(DataVendor):
695
662
  DataFrame with DatetimeIndex (level 0), ticker (level 1), and values for on-chain fields (cols),
696
663
  in tidy format.
697
664
  """
698
- # convert data request parameters to CryptoCompare format
699
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
700
-
701
- # check if frequency daily
702
- if cc_data_req['freq'] != 'histoday':
703
- raise ValueError(f"On-chain data is only available on a daily frequency."
704
- f" Change data request frequency to 'd' and try again.")
665
+ # convert params
666
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
705
667
 
706
- # fields list
707
- onchain_fields = self.get_fields_info(data_type='on-chain')
708
-
709
- # check if tickers and fields are correct
710
- if any([ticker in self.assets for ticker in cc_data_req['tickers']]) and \
711
- any([field in onchain_fields for field in cc_data_req['fields']]):
712
- try:
713
- df = self.get_all_tickers(data_req, data_type='on-chain')
714
-
715
- except Exception as e:
716
- logging.warning(e)
668
+ # get on-chain
669
+ try:
670
+ df = self.get_all_tickers(data_req, data_type='on-chain')
671
+ return df
717
672
 
718
- else:
719
- return df
673
+ except Exception as e:
674
+ logging.warning(e)
720
675
 
721
676
  def get_social(self, data_req: DataRequest) -> pd.DataFrame:
722
677
  """
@@ -733,50 +688,53 @@ class CryptoCompare(DataVendor):
733
688
  DataFrame with DatetimeIndex (level 0), ticker (level 1), and values for social media fields (cols),
734
689
  in tidy format.
735
690
  """
736
- # convert data request parameters to CryptoCompare format
737
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
738
-
739
- # check frequency
740
- if cc_data_req['freq'] == 'histominute':
741
- raise ValueError(f"Social media data is only available on a daily and hourly frequency."
742
- f" Change data request frequency to 'd' or '1h' and try again.")
743
-
744
- # fields list
745
- social_fields = self.get_fields_info(data_type='off-chain')
746
-
747
- # check if tickers and fields are correct
748
- if any([ticker in self.assets for ticker in cc_data_req['tickers']]) and \
749
- any([field in social_fields for field in cc_data_req['fields']]):
750
- try:
751
- df = self.get_all_tickers(data_req, data_type='social')
752
-
753
- except Exception as e:
754
- logging.warning(e)
691
+ # convert params
692
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
755
693
 
756
- else:
757
- return df
694
+ # get social
695
+ try:
696
+ df = self.get_all_tickers(data_req, data_type='social')
697
+ return df
698
+ except Exception as e:
699
+ logging.warning(e)
758
700
 
759
701
  def check_params(self, data_req: DataRequest) -> None:
760
702
  """
761
703
  Checks the parameters of the data request before requesting data to reduce API calls
762
704
  and improve efficiency.
763
705
  """
764
- # convert data request parameters to CryptoCompare format
765
- cc_data_req = ConvertParams(data_req).to_cryptocompare()
706
+ # convert params
707
+ self.data_req = ConvertParams(data_req).to_cryptocompare()
766
708
 
767
- # tickers lists
768
- assets_list = self.assets
769
- idx_list = self.indexes
770
- tickers_list = assets_list + idx_list
709
+ # tickers list
710
+ self.get_assets_info(as_list=True)
711
+ self.get_indexes_info(as_list=True)
712
+ tickers_list = self.assets + self.indexes
771
713
 
772
- # check tickers and fields
773
- if not all([ticker in tickers_list for ticker in cc_data_req['tickers']]):
714
+ # tickers
715
+ if not all([ticker in tickers_list for ticker in self.data_req.source_tickers]):
774
716
  raise ValueError("Some assets are not available. "
775
- "Check assets and indexes attributes to see all available asset and indexes.")
717
+ "Check available assets and indexes with get_assets_info() or get_indexes_info().")
776
718
 
777
- if len(cc_data_req['fields']) == 0:
719
+ # fields
720
+ if not all([field in self.get_fields_info() for field in self.data_req.source_fields]):
778
721
  raise ValueError("Some fields are not available. "
779
- "Check fields attribute to see all available fields.")
722
+ "Check available fields with get_fields_info().")
723
+
724
+ # check freq
725
+ if self.data_req.source_freq not in ['histoday', 'histohour', 'histominute']:
726
+ raise ValueError(f"Frequency {self.data_req.source_freq} not available. "
727
+ f"Check available frequencies with get_frequencies().")
728
+
729
+ # on-chain freq
730
+ if self.data_req.source_fields in self.get_onchain_info() and self.data_req.source_freq != 'histoday':
731
+ raise ValueError(f"On-chain data is only available on a daily frequency."
732
+ f" Change data request frequency to 'd' and try again.")
733
+
734
+ # social freq
735
+ if self.data_req.source_fields in self.get_social_info() and self.data_req.source_freq == 'histominute':
736
+ raise ValueError(f"Social media data is only available on a daily and hourly frequency."
737
+ f" Change data request frequency to 'd' or '1h' and try again.")
780
738
 
781
739
  def get_data(self, data_req: DataRequest) -> pd.DataFrame:
782
740
  """
@@ -798,16 +756,13 @@ class CryptoCompare(DataVendor):
798
756
  # check data req params
799
757
  self.check_params(data_req)
800
758
 
801
- # df to store data
802
- df = pd.DataFrame()
803
-
804
759
  # get indexes
805
760
  try:
806
761
  df0 = self.get_indexes(data_req)
807
762
  except Exception as e:
808
763
  logging.warning(e)
809
764
  else:
810
- df = pd.concat([df, df0])
765
+ self.data = pd.concat([self.data, df0])
811
766
 
812
767
  # get ohlcv
813
768
  try:
@@ -815,7 +770,7 @@ class CryptoCompare(DataVendor):
815
770
  except Exception as e:
816
771
  logging.warning(e)
817
772
  else:
818
- df = pd.concat([df, df1])
773
+ self.data = pd.concat([self.data, df1])
819
774
 
820
775
  # get onchain
821
776
  try:
@@ -823,7 +778,7 @@ class CryptoCompare(DataVendor):
823
778
  except Exception as e:
824
779
  logging.warning(e)
825
780
  else:
826
- df = pd.concat([df, df2], axis=1)
781
+ self.data = pd.concat([self.data, df2], axis=1)
827
782
 
828
783
  # get social
829
784
  try:
@@ -831,16 +786,16 @@ class CryptoCompare(DataVendor):
831
786
  except Exception as e:
832
787
  logging.warning(e)
833
788
  else:
834
- df = pd.concat([df, df3], axis=1)
789
+ self.data = pd.concat([self.data, df3], axis=1)
835
790
 
836
791
  # check if df empty
837
- if df.empty:
792
+ if self.data.empty:
838
793
  raise Exception('No data returned. Check data request parameters and try again.')
839
794
 
840
795
  # filter df for desired fields and sort index by date
841
- fields = [field for field in data_req.fields if field in df.columns]
842
- df = df.loc[:, fields]
796
+ fields = [field for field in data_req.fields if field in self.data.columns]
797
+ self.data = self.data.loc[:, fields].sort_index()
843
798
 
844
799
  logging.info("Data retrieved from CryptoCompare.")
845
800
 
846
- return df.sort_index()
801
+ return self.data