cryptodatapy 0.2.10__py3-none-any.whl → 0.2.12__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/extract/data_vendors/tiingo_api.py +89 -130
- cryptodatapy/transform/convertparams.py +162 -71
- cryptodatapy/transform/impute.py +2 -1
- cryptodatapy/transform/wrangle.py +14 -13
- {cryptodatapy-0.2.10.dist-info → cryptodatapy-0.2.12.dist-info}/METADATA +5 -5
- {cryptodatapy-0.2.10.dist-info → cryptodatapy-0.2.12.dist-info}/RECORD +8 -8
- {cryptodatapy-0.2.10.dist-info → cryptodatapy-0.2.12.dist-info}/WHEEL +1 -1
- {cryptodatapy-0.2.10.dist-info → cryptodatapy-0.2.12.dist-info}/LICENSE +0 -0
@@ -20,14 +20,15 @@ class Tiingo(DataVendor):
|
|
20
20
|
|
21
21
|
def __init__(
|
22
22
|
self,
|
23
|
-
categories=
|
23
|
+
categories: List[str] = ["crypto", "fx", "eqty"],
|
24
24
|
exchanges: Optional[Dict[str, List[str]]] = None,
|
25
25
|
indexes: Optional[Dict[str, List[str]]] = None,
|
26
26
|
assets: Optional[Dict[str, List[str]]] = None,
|
27
27
|
markets: Optional[Dict[str, List[str]]] = None,
|
28
|
-
market_types=
|
28
|
+
market_types: List[str] = ["spot"],
|
29
29
|
fields: Dict[str, List[str]] = None,
|
30
|
-
frequencies=
|
30
|
+
frequencies: List[str] = ["1min", "5min", "10min", "15min", "30min", "1h",
|
31
|
+
"2h", "4h", "8h", "d", "w", "m", "q", "y"],
|
31
32
|
base_url: str = data_cred.tiingo_base_url,
|
32
33
|
api_key: str = data_cred.tiingo_api_key,
|
33
34
|
max_obs_per_call: Optional[int] = None,
|
@@ -71,53 +72,18 @@ class Tiingo(DataVendor):
|
|
71
72
|
rate_limit: pd.DataFrame, optional, Default None
|
72
73
|
Number of API calls made and left, by time frequency.
|
73
74
|
"""
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
exchanges,
|
78
|
-
indexes,
|
79
|
-
assets,
|
80
|
-
markets,
|
81
|
-
market_types,
|
82
|
-
fields,
|
83
|
-
frequencies,
|
84
|
-
base_url,
|
85
|
-
api_key,
|
86
|
-
max_obs_per_call,
|
87
|
-
rate_limit,
|
75
|
+
super().__init__(
|
76
|
+
categories, exchanges, indexes, assets, markets, market_types,
|
77
|
+
fields, frequencies, base_url, api_key, max_obs_per_call, rate_limit
|
88
78
|
)
|
89
79
|
|
90
|
-
if frequencies is None:
|
91
|
-
self.frequencies = [
|
92
|
-
"1min",
|
93
|
-
"5min",
|
94
|
-
"10min",
|
95
|
-
"15min",
|
96
|
-
"30min",
|
97
|
-
"1h",
|
98
|
-
"2h",
|
99
|
-
"4h",
|
100
|
-
"8h",
|
101
|
-
"d",
|
102
|
-
"w",
|
103
|
-
"m",
|
104
|
-
"q",
|
105
|
-
"y",
|
106
|
-
]
|
107
|
-
if market_types is None:
|
108
|
-
self.market_types = ["spot"]
|
109
|
-
if categories is None:
|
110
|
-
self.categories = ["crypto", "fx", "eqty"]
|
111
80
|
if api_key is None:
|
112
81
|
raise TypeError("Set your Tiingo api key in environment variables as 'TIINGO_API_KEY' or "
|
113
82
|
"add it as an argument when instantiating the class. To get an api key, visit: "
|
114
83
|
"https://www.tiingo.com/")
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
self.assets = self.get_assets_info(as_list=True)
|
119
|
-
if fields is None:
|
120
|
-
self.fields = self.get_fields_info()
|
84
|
+
|
85
|
+
self.data_req = None
|
86
|
+
self.data = pd.DataFrame()
|
121
87
|
|
122
88
|
def get_exchanges_info(
|
123
89
|
self, cat: Optional[str] = None
|
@@ -266,8 +232,10 @@ class Tiingo(DataVendor):
|
|
266
232
|
"""
|
267
233
|
# data req
|
268
234
|
data_resp = self.req_crypto()
|
235
|
+
|
269
236
|
# wrangle data resp
|
270
237
|
crypto = pd.DataFrame(data_resp).set_index('ticker')
|
238
|
+
|
271
239
|
# as list
|
272
240
|
if as_list:
|
273
241
|
crypto = crypto.index.to_list()
|
@@ -302,15 +270,15 @@ class Tiingo(DataVendor):
|
|
302
270
|
crypto = crypto.index.to_list()
|
303
271
|
|
304
272
|
# add to dict
|
305
|
-
|
273
|
+
self.assets = {'eqty': eqty,
|
306
274
|
'crypto': crypto,
|
307
275
|
'fx': f"For more information, see FX documentation: {fx_url}."}
|
308
276
|
|
309
277
|
# filter cat
|
310
278
|
if cat is not None:
|
311
|
-
|
279
|
+
self.assets = self.assets[cat]
|
312
280
|
|
313
|
-
return
|
281
|
+
return self.assets
|
314
282
|
|
315
283
|
def get_markets_info(self) -> None:
|
316
284
|
"""
|
@@ -357,16 +325,17 @@ class Tiingo(DataVendor):
|
|
357
325
|
fx_fields_list = ["open", "high", "low", "close"]
|
358
326
|
|
359
327
|
# fields dict
|
360
|
-
fields = {
|
328
|
+
self.fields = {
|
361
329
|
"crypto": crypto_fields_list,
|
362
330
|
"fx": fx_fields_list,
|
363
331
|
"eqty": equities_fields_list,
|
364
332
|
}
|
333
|
+
|
365
334
|
# fields obj
|
366
335
|
if cat is not None:
|
367
|
-
fields = fields[cat]
|
336
|
+
self.fields = self.fields[cat]
|
368
337
|
|
369
|
-
return fields
|
338
|
+
return self.fields
|
370
339
|
|
371
340
|
def get_rate_limit_info(self) -> None:
|
372
341
|
"""
|
@@ -394,21 +363,20 @@ class Tiingo(DataVendor):
|
|
394
363
|
|
395
364
|
"""
|
396
365
|
# convert data req params
|
397
|
-
|
366
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
398
367
|
|
399
368
|
url, params, headers = None, {}, {}
|
400
369
|
|
401
370
|
# eqty daily
|
402
371
|
if data_type == 'eqty':
|
403
|
-
url = self.base_url + f"daily/prices"
|
372
|
+
url = self.base_url + f"daily/{ticker}/prices"
|
404
373
|
headers = {
|
405
374
|
"Content-Type": "application/json",
|
406
375
|
"Authorization": f"Token {self.api_key}",
|
407
376
|
}
|
408
377
|
params = {
|
409
|
-
"
|
410
|
-
"
|
411
|
-
"endDate": tg_data_req["end_date"],
|
378
|
+
"startDate": self.data_req.source_start_date,
|
379
|
+
"endDate": self.data_req.source_end_date
|
412
380
|
}
|
413
381
|
|
414
382
|
# eqty intraday
|
@@ -419,9 +387,9 @@ class Tiingo(DataVendor):
|
|
419
387
|
"Authorization": f"Token {self.api_key}",
|
420
388
|
}
|
421
389
|
params = {
|
422
|
-
"startDate":
|
423
|
-
"endDate":
|
424
|
-
"resampleFreq":
|
390
|
+
"startDate": self.data_req.source_start_date,
|
391
|
+
"endDate": self.data_req.source_end_date,
|
392
|
+
"resampleFreq": self.data_req.source_freq
|
425
393
|
}
|
426
394
|
|
427
395
|
# crypto
|
@@ -433,14 +401,13 @@ class Tiingo(DataVendor):
|
|
433
401
|
}
|
434
402
|
params = {
|
435
403
|
"tickers": ticker,
|
436
|
-
"startDate":
|
437
|
-
"endDate":
|
438
|
-
"resampleFreq":
|
404
|
+
"startDate": self.data_req.source_start_date,
|
405
|
+
"endDate": self.data_req.source_end_date,
|
406
|
+
"resampleFreq": self.data_req.source_freq
|
439
407
|
}
|
440
408
|
|
441
409
|
# fx
|
442
410
|
elif data_type == 'fx':
|
443
|
-
# url = f"https://api.tiingo.com/tiingo/fx/{ticker}/prices"
|
444
411
|
url = self.base_url + f"fx/prices"
|
445
412
|
headers = {
|
446
413
|
"Content-Type": "application/json",
|
@@ -448,9 +415,9 @@ class Tiingo(DataVendor):
|
|
448
415
|
}
|
449
416
|
params = {
|
450
417
|
"tickers": ticker,
|
451
|
-
"startDate":
|
452
|
-
"endDate":
|
453
|
-
"resampleFreq":
|
418
|
+
"startDate": self.data_req.source_start_date,
|
419
|
+
"endDate": self.data_req.source_end_date,
|
420
|
+
"resampleFreq": self.data_req.source_freq
|
454
421
|
}
|
455
422
|
|
456
423
|
return {'url': url, 'params': params, 'headers': headers}
|
@@ -526,6 +493,7 @@ class Tiingo(DataVendor):
|
|
526
493
|
"""
|
527
494
|
# get entire data history
|
528
495
|
df = self.req_data(data_req, data_type, ticker)
|
496
|
+
|
529
497
|
# wrangle df
|
530
498
|
df = self.wrangle_data_resp(data_req, df, data_type)
|
531
499
|
|
@@ -549,19 +517,17 @@ class Tiingo(DataVendor):
|
|
549
517
|
Dataframe with DatetimeIndex (level 0), ticker (level 1) and values for fields (cols), in tidy data format.
|
550
518
|
"""
|
551
519
|
# convert data request parameters to CryptoCompare format
|
552
|
-
|
520
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
553
521
|
|
554
522
|
# empty df to add data
|
555
523
|
df = pd.DataFrame()
|
556
524
|
|
557
525
|
if data_type == 'crypto':
|
558
|
-
|
559
|
-
for mkt, ticker in zip(tg_data_req['mkts'], data_req.tickers):
|
526
|
+
for market, ticker in zip(self.data_req.source_markets, self.data_req.tickers):
|
560
527
|
try:
|
561
|
-
df0 = self.get_tidy_data(data_req, data_type,
|
562
|
-
|
563
|
-
|
564
|
-
logging.info(f"Failed to get {data_type} data for {ticker} after many attempts.")
|
528
|
+
df0 = self.get_tidy_data(self.data_req, data_type, market)
|
529
|
+
except Exception as e:
|
530
|
+
logging.info(f"Failed to get {data_type} data for {ticker} after many attempts: {e}.")
|
565
531
|
else:
|
566
532
|
# add ticker to index
|
567
533
|
df0['ticker'] = ticker.upper()
|
@@ -570,29 +536,27 @@ class Tiingo(DataVendor):
|
|
570
536
|
df = pd.concat([df, df0])
|
571
537
|
|
572
538
|
elif data_type == 'fx':
|
573
|
-
|
574
|
-
for mkt, ticker in zip(tg_data_req['mkts'], data_req.tickers):
|
539
|
+
for market, ticker in zip(self.data_req.source_markets, self.data_req.tickers):
|
575
540
|
try:
|
576
|
-
df0 = self.get_tidy_data(data_req, data_type,
|
577
|
-
except Exception:
|
578
|
-
logging.info(f"Failed to get {data_type} data for {
|
541
|
+
df0 = self.get_tidy_data(self.data_req, data_type, market)
|
542
|
+
except Exception as e:
|
543
|
+
logging.info(f"Failed to get {data_type} data for {market} after many attempts: {e}.")
|
579
544
|
else:
|
580
545
|
# add ticker to index
|
581
|
-
df0['ticker'] =
|
546
|
+
df0['ticker'] = market.upper()
|
582
547
|
df0.set_index(['ticker'], append=True, inplace=True)
|
583
548
|
# concat df and df1
|
584
549
|
df = pd.concat([df, df0])
|
585
550
|
|
586
551
|
else:
|
587
|
-
|
588
|
-
for tg_ticker, dr_ticker in zip(tg_data_req['tickers'], data_req.tickers):
|
552
|
+
for ticker in self.data_req.tickers:
|
589
553
|
try:
|
590
|
-
df0 = self.get_tidy_data(data_req, data_type,
|
591
|
-
except Exception:
|
592
|
-
logging.info(f"Failed to get {data_type} data for {
|
554
|
+
df0 = self.get_tidy_data(self.data_req, data_type, ticker)
|
555
|
+
except Exception as e:
|
556
|
+
logging.info(f"Failed to get {data_type} data for {ticker} after many attempts: {e}.")
|
593
557
|
else:
|
594
558
|
# add ticker to index
|
595
|
-
df0['ticker'] =
|
559
|
+
df0['ticker'] = ticker.upper()
|
596
560
|
df0.set_index(['ticker'], append=True, inplace=True)
|
597
561
|
# concat df and df1
|
598
562
|
df = pd.concat([df, df0])
|
@@ -614,19 +578,17 @@ class Tiingo(DataVendor):
|
|
614
578
|
DataFrame with DatetimeIndex (level 0), ticker (level 1) and equities OHLCV values (cols).
|
615
579
|
"""
|
616
580
|
# convert data request parameters to CryptoCompare format
|
617
|
-
|
581
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
618
582
|
|
619
|
-
#
|
620
|
-
|
621
|
-
|
622
|
-
try:
|
623
|
-
df = self.get_all_tickers(data_req, data_type='eqty')
|
583
|
+
# get eqty data
|
584
|
+
try:
|
585
|
+
df = self.get_all_tickers(self.data_req, data_type='eqty')
|
624
586
|
|
625
|
-
|
626
|
-
|
587
|
+
except Exception as e:
|
588
|
+
logging.warning(e)
|
627
589
|
|
628
|
-
|
629
|
-
|
590
|
+
else:
|
591
|
+
return df
|
630
592
|
|
631
593
|
def get_eqty_iex(self, data_req: DataRequest) -> pd.DataFrame:
|
632
594
|
"""
|
@@ -643,19 +605,17 @@ class Tiingo(DataVendor):
|
|
643
605
|
DataFrame with DatetimeIndex (level 0), ticker (level 1) and equities OHLCV values (cols).
|
644
606
|
"""
|
645
607
|
# convert data request parameters to CryptoCompare format
|
646
|
-
|
608
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
647
609
|
|
648
|
-
#
|
649
|
-
|
650
|
-
|
651
|
-
try:
|
652
|
-
df = self.get_all_tickers(data_req, data_type='iex')
|
610
|
+
# get iex data
|
611
|
+
try:
|
612
|
+
df = self.get_all_tickers(self.data_req, data_type='iex')
|
653
613
|
|
654
|
-
|
655
|
-
|
614
|
+
except Exception as e:
|
615
|
+
logging.warning(e)
|
656
616
|
|
657
|
-
|
658
|
-
|
617
|
+
else:
|
618
|
+
return df
|
659
619
|
|
660
620
|
def get_crypto(self, data_req: DataRequest) -> pd.DataFrame:
|
661
621
|
"""
|
@@ -672,20 +632,17 @@ class Tiingo(DataVendor):
|
|
672
632
|
DataFrame with DatetimeIndex (level 0), ticker (level 1) and crypto OHLCV values (cols).
|
673
633
|
"""
|
674
634
|
# convert data request parameters to CryptoCompare format
|
675
|
-
|
635
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
676
636
|
|
677
|
-
#
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
try:
|
682
|
-
df = self.get_all_tickers(data_req, data_type='crypto')
|
637
|
+
# get crypto data
|
638
|
+
try:
|
639
|
+
df = self.get_all_tickers(self.data_req, data_type='crypto')
|
683
640
|
|
684
|
-
|
685
|
-
|
641
|
+
except Exception as e:
|
642
|
+
logging.warning(e)
|
686
643
|
|
687
|
-
|
688
|
-
|
644
|
+
else:
|
645
|
+
return df
|
689
646
|
|
690
647
|
def get_fx(self, data_req: DataRequest) -> pd.DataFrame:
|
691
648
|
"""
|
@@ -702,19 +659,17 @@ class Tiingo(DataVendor):
|
|
702
659
|
DataFrame with DatetimeIndex (level 0), ticker (level 1) and FX OHLC values (cols).
|
703
660
|
"""
|
704
661
|
# convert data request parameters to CryptoCompare format
|
705
|
-
|
662
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
706
663
|
|
707
|
-
#
|
708
|
-
|
709
|
-
|
710
|
-
try:
|
711
|
-
df = self.get_all_tickers(data_req, data_type='fx')
|
664
|
+
# get fx data
|
665
|
+
try:
|
666
|
+
df = self.get_all_tickers(self.data_req, data_type='fx')
|
712
667
|
|
713
|
-
|
714
|
-
|
668
|
+
except Exception as e:
|
669
|
+
logging.warning(e)
|
715
670
|
|
716
|
-
|
717
|
-
|
671
|
+
else:
|
672
|
+
return df
|
718
673
|
|
719
674
|
def check_params(self, data_req: DataRequest) -> None:
|
720
675
|
"""
|
@@ -722,23 +677,27 @@ class Tiingo(DataVendor):
|
|
722
677
|
and improve efficiency.
|
723
678
|
|
724
679
|
"""
|
725
|
-
|
680
|
+
self.data_req = ConvertParams(data_req).to_tiingo()
|
681
|
+
|
682
|
+
# get metada
|
683
|
+
self.get_assets_info(as_list=True)
|
684
|
+
self.get_fields_info()
|
726
685
|
|
727
686
|
# check cat
|
728
|
-
if data_req.cat is None:
|
687
|
+
if self.data_req.cat is None:
|
729
688
|
raise ValueError(
|
730
689
|
f"Cat cannot be None. Please provide category. Categories include: {self.categories}."
|
731
690
|
)
|
732
691
|
|
733
692
|
# check assets
|
734
|
-
if not any([ticker.upper() in self.assets[data_req.cat] for ticker in
|
693
|
+
if not any([ticker.upper() in self.assets[self.data_req.cat] for ticker in self.data_req.tickers]) and \
|
735
694
|
data_req.cat != 'fx':
|
736
695
|
raise ValueError(
|
737
696
|
f"Selected tickers are not available. Use assets attribute to see available tickers."
|
738
697
|
)
|
739
698
|
|
740
|
-
|
741
|
-
if not any([field in self.fields[data_req.cat] for field in data_req.fields]):
|
699
|
+
# check fields
|
700
|
+
if not any([field in self.fields[data_req.cat] for field in self.data_req.fields]):
|
742
701
|
raise ValueError(
|
743
702
|
f"Selected fields are not available. Use fields attribute to see available fields."
|
744
703
|
)
|
@@ -339,34 +339,31 @@ class ConvertParams:
|
|
339
339
|
"source_fields": self.data_req.source_fields,
|
340
340
|
}
|
341
341
|
|
342
|
-
def to_tiingo(self) ->
|
342
|
+
def to_tiingo(self) -> DataRequest:
|
343
343
|
"""
|
344
344
|
Convert tickers from CryptoDataPy to Tiingo format.
|
345
345
|
"""
|
346
|
-
#
|
347
|
-
if self.data_req.source_tickers is
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
# convert freq
|
353
|
-
if self.data_req.source_freq is not None:
|
354
|
-
freq = self.data_req.source_freq
|
355
|
-
self.data_req.freq = self.data_req.source_freq
|
356
|
-
else:
|
346
|
+
# tickers
|
347
|
+
if self.data_req.source_tickers is None:
|
348
|
+
self.data_req.source_tickers = [ticker.lower() for ticker in self.data_req.tickers]
|
349
|
+
|
350
|
+
# freq
|
351
|
+
if self.data_req.source_freq is None:
|
357
352
|
if self.data_req.freq is None:
|
358
|
-
|
353
|
+
self.data_req.source_freq = "1day"
|
359
354
|
elif self.data_req.freq[-3:] == "min":
|
360
|
-
|
355
|
+
self.data_req.source_freq = self.data_req.freq
|
361
356
|
elif self.data_req.freq[-1] == "h":
|
362
|
-
|
357
|
+
self.data_req.source_freq = "1hour"
|
363
358
|
else:
|
364
|
-
|
365
|
-
|
359
|
+
self.data_req.source_freq = "1day"
|
360
|
+
|
361
|
+
# quote ccy
|
366
362
|
if self.data_req.quote_ccy is None:
|
367
|
-
quote_ccy = "usd"
|
363
|
+
self.data_req.quote_ccy = "usd"
|
368
364
|
else:
|
369
|
-
quote_ccy = self.data_req.quote_ccy.lower()
|
365
|
+
self.data_req.quote_ccy = self.data_req.quote_ccy.lower()
|
366
|
+
|
370
367
|
# convert exch
|
371
368
|
if (
|
372
369
|
self.data_req.exch is None
|
@@ -374,64 +371,40 @@ class ConvertParams:
|
|
374
371
|
and self.data_req.freq
|
375
372
|
in ["1min", "5min", "10min", "15min", "30min", "1h", "2h", "4h", "8h"]
|
376
373
|
):
|
377
|
-
exch = "iex"
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
self.data_req.
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
ticker.lower() + quote_ccy for ticker in self.data_req.tickers
|
392
|
-
]
|
393
|
-
# convert start date
|
394
|
-
if self.data_req.start_date is None and self.data_req.cat == 'crypto':
|
395
|
-
start_date = datetime(2010, 1, 1, 0, 0)
|
374
|
+
self.data_req.exch = "iex"
|
375
|
+
|
376
|
+
# markets
|
377
|
+
if self.data_req.source_markets is None:
|
378
|
+
if self.data_req.cat == 'fx':
|
379
|
+
fx_list = self.convert_fx_tickers(quote_ccy=self.data_req.quote_ccy)
|
380
|
+
self.data_req.source_markets = [ticker.lower().replace("/", "") for ticker in fx_list]
|
381
|
+
elif self.data_req.cat == 'crypto':
|
382
|
+
self.data_req.source_markets = [ticker.lower() +
|
383
|
+
self.data_req.quote_ccy for ticker in self.data_req.tickers]
|
384
|
+
|
385
|
+
# start date
|
386
|
+
if self.data_req.start_date is None:
|
387
|
+
self.data_req.source_start_date = '1990-01-01'
|
396
388
|
else:
|
397
|
-
|
398
|
-
|
389
|
+
self.data_req.source_start_date = self.data_req.start_date
|
390
|
+
|
391
|
+
# end date
|
399
392
|
if self.data_req.end_date is None:
|
400
|
-
|
393
|
+
self.data_req.source_end_date = str(pd.Timestamp.utcnow().date())
|
401
394
|
else:
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
self.data_req.
|
407
|
-
|
408
|
-
fields = self.convert_fields(data_source='tiingo')
|
395
|
+
self.data_req.source_end_date = self.data_req.end_date
|
396
|
+
|
397
|
+
# fields
|
398
|
+
if self.data_req.source_fields is None:
|
399
|
+
self.data_req.source_fields = self.convert_fields(data_source='tiingo')
|
400
|
+
|
409
401
|
# tz
|
410
402
|
if self.data_req.cat == 'eqty' or self.data_req.cat == 'fx':
|
411
|
-
tz = "America/New_York"
|
403
|
+
self.data_req.tz = "America/New_York"
|
412
404
|
else:
|
413
|
-
tz = "UTC"
|
405
|
+
self.data_req.tz = "UTC"
|
414
406
|
|
415
|
-
return
|
416
|
-
"tickers": tickers,
|
417
|
-
"freq": freq,
|
418
|
-
"quote_ccy": quote_ccy,
|
419
|
-
"exch": exch,
|
420
|
-
"ctys": None,
|
421
|
-
"mkt_type": self.data_req.mkt_type,
|
422
|
-
"mkts": mkts_list,
|
423
|
-
"start_date": start_date,
|
424
|
-
"end_date": end_date,
|
425
|
-
"fields": fields,
|
426
|
-
"tz": tz,
|
427
|
-
"inst": None,
|
428
|
-
"cat": self.data_req.cat,
|
429
|
-
"trials": self.data_req.trials,
|
430
|
-
"pause": self.data_req.pause,
|
431
|
-
"source_tickers": self.data_req.source_tickers,
|
432
|
-
"source_freq": self.data_req.source_freq,
|
433
|
-
"source_fields": self.data_req.source_fields,
|
434
|
-
}
|
407
|
+
return self.data_req
|
435
408
|
|
436
409
|
def to_ccxt(self) -> DataRequest:
|
437
410
|
"""
|
@@ -1020,7 +993,7 @@ class ConvertParams:
|
|
1020
993
|
List of fields in data source format.
|
1021
994
|
|
1022
995
|
"""
|
1023
|
-
#
|
996
|
+
# x fields
|
1024
997
|
with resources.path("cryptodatapy.conf", "fields.csv") as f:
|
1025
998
|
fields_dict_path = f
|
1026
999
|
fields_df, fields_list = (
|
@@ -1045,3 +1018,121 @@ class ConvertParams:
|
|
1045
1018
|
)
|
1046
1019
|
|
1047
1020
|
return fields_list
|
1021
|
+
|
1022
|
+
def to_dydx_dict(self) -> Dict[str, Union[list, str, int, float, None]]:
|
1023
|
+
"""
|
1024
|
+
Convert parameters from CryptoDataPy to dYdX format.
|
1025
|
+
"""
|
1026
|
+
if self.data_req.source_tickers is not None:
|
1027
|
+
tickers = self.data_req.source_tickers
|
1028
|
+
self.data_req.tickers = self.data_req.source_tickers
|
1029
|
+
else:
|
1030
|
+
tickers = [ticker.upper() for ticker in self.data_req.tickers]
|
1031
|
+
|
1032
|
+
# convert markets (if needed)
|
1033
|
+
markets = [f"{ticker}-USD" for ticker in tickers]
|
1034
|
+
|
1035
|
+
# convert freq
|
1036
|
+
if self.data_req.source_freq is not None:
|
1037
|
+
freq = self.data_req.source_freq
|
1038
|
+
self.data_req.freq = self.data_req.source_freq
|
1039
|
+
else:
|
1040
|
+
if self.data_req.freq is None:
|
1041
|
+
freq = "1DAY"
|
1042
|
+
elif self.data_req.freq == "1min":
|
1043
|
+
freq = "1MIN"
|
1044
|
+
elif self.data_req.freq == "5min":
|
1045
|
+
freq = "5MINS"
|
1046
|
+
elif self.data_req.freq == "15min":
|
1047
|
+
freq = "15MINS"
|
1048
|
+
elif self.data_req.freq == "30min":
|
1049
|
+
freq = "30MINS"
|
1050
|
+
elif self.data_req.freq == "1h":
|
1051
|
+
freq = "1HOUR"
|
1052
|
+
elif self.data_req.freq == "4h":
|
1053
|
+
freq = "4HOURS"
|
1054
|
+
elif self.data_req.freq in ["1d", "d"]:
|
1055
|
+
freq = "1DAY"
|
1056
|
+
else:
|
1057
|
+
freq = "1DAY" # Default to daily
|
1058
|
+
|
1059
|
+
# convert fields
|
1060
|
+
if self.data_req.source_fields is not None:
|
1061
|
+
fields = self.data_req.source_fields
|
1062
|
+
self.data_req.fields = self.data_req.source_fields
|
1063
|
+
else:
|
1064
|
+
# Map our standard fields to dYdX field names
|
1065
|
+
field_mapping = {
|
1066
|
+
'open': 'open',
|
1067
|
+
'high': 'high',
|
1068
|
+
'low': 'low',
|
1069
|
+
'close': 'close',
|
1070
|
+
'volume': 'baseTokenVolume',
|
1071
|
+
'funding_rate': 'nextFundingRate',
|
1072
|
+
'oi': 'openInterest'
|
1073
|
+
}
|
1074
|
+
|
1075
|
+
fields = []
|
1076
|
+
for field in self.data_req.fields:
|
1077
|
+
if field in field_mapping:
|
1078
|
+
fields.append(field_mapping[field])
|
1079
|
+
else:
|
1080
|
+
logging.warning(f"Field {field} not available in dYdX API")
|
1081
|
+
return {
|
1082
|
+
"tickers": tickers, # List of market tickers
|
1083
|
+
"freq": freq, # Converted frequency
|
1084
|
+
"quote_ccy": self.data_req.quote_ccy,
|
1085
|
+
"exch": "dydx",
|
1086
|
+
"mkt_type": self.data_req.mkt_type,
|
1087
|
+
"mkts": markets, # Market identifiers
|
1088
|
+
"start_date": self.data_req.start_date,
|
1089
|
+
"end_date": self.data_req.end_date,
|
1090
|
+
"fields": fields, # Converted field names
|
1091
|
+
"tz": self.data_req.tz or "UTC",
|
1092
|
+
"cat": "crypto",
|
1093
|
+
"trials": self.data_req.trials,
|
1094
|
+
"pause": self.data_req.pause,
|
1095
|
+
"source_tickers": self.data_req.source_tickers,
|
1096
|
+
"source_freq": self.data_req.source_freq,
|
1097
|
+
"source_fields": self.data_req.source_fields,
|
1098
|
+
}
|
1099
|
+
|
1100
|
+
def to_dydx(self) -> DataRequest:
|
1101
|
+
|
1102
|
+
# tickers
|
1103
|
+
if self.data_req.source_tickers is None:
|
1104
|
+
self.data_req.source_tickers = [ticker.upper() for ticker in self.data_req.tickers]
|
1105
|
+
|
1106
|
+
# markets
|
1107
|
+
if self.data_req.source_markets is None:
|
1108
|
+
self.data_req.source_markets = [f"{ticker}-USD"
|
1109
|
+
for ticker in self.data_req.source_tickers]
|
1110
|
+
|
1111
|
+
if self.data_req.source_freq is None:
|
1112
|
+
if self.data_req.freq is None:
|
1113
|
+
self.data_req.source_freq = "1DAY"
|
1114
|
+
elif self.data_req.freq == "1min":
|
1115
|
+
self.data_req.source_freq = "1MIN"
|
1116
|
+
elif self.data_req.freq == "5min":
|
1117
|
+
self.data_req.source_freq = "5MINS"
|
1118
|
+
elif self.data_req.freq == "15min":
|
1119
|
+
self.data_req.source_freq = "15MINS"
|
1120
|
+
elif self.data_req.freq == "30min":
|
1121
|
+
self.data_req.source_freq = "30MINS"
|
1122
|
+
elif self.data_req.freq == "1h":
|
1123
|
+
self.data_req.source_freq = "1HOUR"
|
1124
|
+
elif self.data_req.freq == "4h":
|
1125
|
+
self.data_req.source_freq = "4HOURS"
|
1126
|
+
elif self.data_req.freq in ["1d", "d"]:
|
1127
|
+
self.data_req.source_freq = "1DAY"
|
1128
|
+
|
1129
|
+
field_mapping = {
|
1130
|
+
'open': 'open',
|
1131
|
+
'high': 'high',
|
1132
|
+
'low': 'low',
|
1133
|
+
'close': 'close',
|
1134
|
+
'volume': 'baseTokenVolume',
|
1135
|
+
'funding_rate': 'nextFundingRate',
|
1136
|
+
'oi': 'openInterest'
|
1137
|
+
}
|
1138
|
+
return self.data_req
|
cryptodatapy/transform/impute.py
CHANGED
@@ -121,7 +121,8 @@ class Impute:
|
|
121
121
|
self.imputed_df = pd.DataFrame(imp_yhat, index=self.filtered_df.index, columns=self.filtered_df.columns)
|
122
122
|
|
123
123
|
# type conversion
|
124
|
-
self.imputed_df = self.imputed_df.
|
124
|
+
self.imputed_df = self.imputed_df.convert_dtypes()
|
125
|
+
|
125
126
|
|
126
127
|
# plot
|
127
128
|
if self.plot:
|
@@ -640,27 +640,34 @@ class WrangleData:
|
|
640
640
|
|
641
641
|
"""
|
642
642
|
# create df
|
643
|
-
if data_type == '
|
643
|
+
if data_type == 'crypto':
|
644
644
|
self.data_resp = pd.DataFrame(self.data_resp[0]['priceData'])
|
645
645
|
else:
|
646
646
|
self.data_resp = pd.DataFrame(self.data_resp)
|
647
|
+
|
647
648
|
# convert fields to lib
|
648
649
|
self.convert_fields_to_lib(data_source='tiingo')
|
650
|
+
|
649
651
|
# convert to datetime
|
650
652
|
self.data_resp['date'] = pd.to_datetime(self.data_resp['date'])
|
653
|
+
|
651
654
|
# set index
|
652
655
|
self.data_resp = self.data_resp.set_index('date').sort_index()
|
653
656
|
self.data_resp.index = self.data_resp.index.tz_localize(None)
|
657
|
+
|
654
658
|
# resample
|
655
659
|
self.data_resp = self.data_resp.resample(self.data_req.freq).last()
|
660
|
+
|
656
661
|
# reformat index
|
657
662
|
if self.data_req.freq in ['d', 'w', 'm', 'q']:
|
658
663
|
self.data_resp.reset_index(inplace=True)
|
659
664
|
self.data_resp.date = pd.to_datetime(self.data_resp.date.dt.date)
|
660
665
|
# reset index
|
661
666
|
self.data_resp.set_index('date', inplace=True)
|
667
|
+
|
662
668
|
# type conversion
|
663
|
-
self.data_resp = self.data_resp.
|
669
|
+
self.data_resp = self.data_resp.convert_dtypes()
|
670
|
+
|
664
671
|
# remove bad data
|
665
672
|
self.data_resp = self.data_resp[~self.data_resp.index.duplicated()] # duplicate rows
|
666
673
|
self.data_resp = self.data_resp.dropna(how='all').dropna(how='all', axis=1) # entire row or col NaNs
|
@@ -911,13 +918,10 @@ class WrangleData:
|
|
911
918
|
# tickers
|
912
919
|
tickers_dict = {source_ticker: ticker for source_ticker, ticker in zip(self.data_req.source_tickers,
|
913
920
|
self.data_req.tickers)}
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
self.data_resp.index.names = ['Date', 'Ticker']
|
919
|
-
self.data_resp.index = self.data_resp.index.set_levels(self.data_resp.index.levels[1].map(tickers_dict),
|
920
|
-
level=1)
|
921
|
+
self.data_resp = self.data_resp.stack(future_stack=True)
|
922
|
+
self.data_resp.columns.name = None
|
923
|
+
self.data_resp.index = self.data_resp.index.set_levels(self.data_resp.index.levels[1].map(tickers_dict),
|
924
|
+
level=1)
|
921
925
|
self.data_resp.reset_index(inplace=True)
|
922
926
|
|
923
927
|
# fields
|
@@ -932,11 +936,8 @@ class WrangleData:
|
|
932
936
|
resample(self.data_req.freq, level='date').\
|
933
937
|
last().swaplevel('ticker', 'date').sort_index()
|
934
938
|
|
935
|
-
# re-order cols
|
936
|
-
self.data_resp = self.data_resp.loc[:, ['open', 'high', 'low', 'close', 'close_adj', 'volume']]
|
937
|
-
|
938
939
|
# type conversion
|
939
|
-
self.data_resp = self.data_resp.
|
940
|
+
self.data_resp = self.data_resp.convert_dtypes()
|
940
941
|
|
941
942
|
# remove bad data
|
942
943
|
self.data_resp = self.data_resp[self.data_resp != 0] # 0 values
|
@@ -1,17 +1,17 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: cryptodatapy
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.12
|
4
4
|
Summary: Cryptoasset data library
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: Systamental
|
7
|
-
Requires-Python: >=3.
|
7
|
+
Requires-Python: >=3.9,<4.0
|
8
8
|
Classifier: License :: OSI Approved :: Apache Software License
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
|
-
Classifier: Programming Language :: Python :: 3.8
|
11
10
|
Classifier: Programming Language :: Python :: 3.9
|
12
11
|
Classifier: Programming Language :: Python :: 3.10
|
13
12
|
Classifier: Programming Language :: Python :: 3.11
|
14
13
|
Classifier: Programming Language :: Python :: 3.12
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
15
15
|
Requires-Dist: DBnomics (>=1.2.3)
|
16
16
|
Requires-Dist: ccxt (>=1.91.52)
|
17
17
|
Requires-Dist: coinmetrics-api-client (>=2022.6.17) ; python_version >= "3.7"
|
@@ -20,7 +20,7 @@ Requires-Dist: investpy (>=1.0.8)
|
|
20
20
|
Requires-Dist: matplotlib (>=3.5.2)
|
21
21
|
Requires-Dist: numpy (>=1.23.2)
|
22
22
|
Requires-Dist: openpyxl (>=3.1.2)
|
23
|
-
Requires-Dist: pandas (>=
|
23
|
+
Requires-Dist: pandas (>=2.2.3)
|
24
24
|
Requires-Dist: pandas-datareader (>=0.10.0)
|
25
25
|
Requires-Dist: prophet (>=1.1) ; python_version >= "3.7"
|
26
26
|
Requires-Dist: pyarrow (>=17.0.0)
|
@@ -31,7 +31,7 @@ cryptodatapy/extract/data_vendors/coinmetrics_api.py,sha256=2fnsgKkBWjzMa1jzfVa7
|
|
31
31
|
cryptodatapy/extract/data_vendors/cryptocompare_api.py,sha256=3oBfQioBz1vrs9JNtwE0hBLI4BTtpFBBEEsDawmobE8,28872
|
32
32
|
cryptodatapy/extract/data_vendors/datavendor.py,sha256=kGKxHcPng6JiGGhcuPx87ij0DXl4E-OSqxlvxhJ1HQo,12642
|
33
33
|
cryptodatapy/extract/data_vendors/glassnode_api.py,sha256=PuuJOjHztoJyFijb5XU1zm1S_2NAj7MX-wC89DL_bWQ,13103
|
34
|
-
cryptodatapy/extract/data_vendors/tiingo_api.py,sha256=
|
34
|
+
cryptodatapy/extract/data_vendors/tiingo_api.py,sha256=aS7SzWjaPcWcSp7MMm329jW0_ukV5Bkr-WH7RWOG0P8,25047
|
35
35
|
cryptodatapy/extract/datarequest.py,sha256=Yi1pVe-ljv_su6kwEw5uylhG3XtneujBaNS2pmAIyk0,25879
|
36
36
|
cryptodatapy/extract/exchanges/__init__.py,sha256=VKTNzrbe-wltGHWH9lK5RLZoXCGHp-UGGZ4gMVHJXrQ,113
|
37
37
|
cryptodatapy/extract/exchanges/dydx.py,sha256=Oifb4sKbPRKArdZBx9q5ob4yTFkd65n0zXiS7hga0mk,4199
|
@@ -48,15 +48,15 @@ cryptodatapy/extract/web/aqr.py,sha256=LS1D7QzG6UWkLUfDMgBFtiHpznnnAUOpec5Sx3vRG
|
|
48
48
|
cryptodatapy/extract/web/web.py,sha256=R1xEnHE1McxSWxp4vrTfgh9gW6FF6XDlp0gmp2NmWOM,12126
|
49
49
|
cryptodatapy/transform/__init__.py,sha256=Spb5cGJ3V_o8hgSWOSrF8J_vsSZpFk0uzW7RpkgfbFE,131
|
50
50
|
cryptodatapy/transform/clean.py,sha256=C9VypQOjdJ987TcD-qAHh7qYaoJBotvp3cWTr3ttSGM,12807
|
51
|
-
cryptodatapy/transform/convertparams.py,sha256=
|
51
|
+
cryptodatapy/transform/convertparams.py,sha256=P1ZOtbUf-2po0oerQvL0BIZekMD0zK6ujSvQI6nUbRQ,43319
|
52
52
|
cryptodatapy/transform/filter.py,sha256=KYYyta0uREAjBkYTVyvhOCCLSKR_qPSlqj5Nl7l4iBk,9064
|
53
|
-
cryptodatapy/transform/impute.py,sha256=
|
53
|
+
cryptodatapy/transform/impute.py,sha256=8vfmWLN--6MUOv3zrflfE_dM6f11GZQR_le2xzJHCnU,5482
|
54
54
|
cryptodatapy/transform/od.py,sha256=z__CWiN70f1leqx12SS9pIvTggxpUPrg1falJIKMZCc,31031
|
55
|
-
cryptodatapy/transform/wrangle.py,sha256=
|
55
|
+
cryptodatapy/transform/wrangle.py,sha256=nBtUvqY0MOYC-KuNTH_78yCFfYaJRrSIgybPTu7G2s8,42254
|
56
56
|
cryptodatapy/util/__init__.py,sha256=zSQ2HU2QIXzCuptJjknmrClwtQKCvIj4aNysZljIgrU,116
|
57
57
|
cryptodatapy/util/datacatalog.py,sha256=qCCX6srXvaAbVAKuA0M2y5IK_2OEx5xA3yRahDZlC-g,13157
|
58
58
|
cryptodatapy/util/datacredentials.py,sha256=fXuGgI2NKCLlcnK8M37CtdyAc3O_YCV23x3KTlfakjA,2160
|
59
|
-
cryptodatapy-0.2.
|
60
|
-
cryptodatapy-0.2.
|
61
|
-
cryptodatapy-0.2.
|
62
|
-
cryptodatapy-0.2.
|
59
|
+
cryptodatapy-0.2.12.dist-info/LICENSE,sha256=sw4oVq8bDjT3uMtaFebQ-xeIVP4H-bXldTs9q-Jjeks,11344
|
60
|
+
cryptodatapy-0.2.12.dist-info/METADATA,sha256=8y7UYpoTVqDUtDAC-n0uvJmBsyZIkcFdmEwDH7FryxI,6428
|
61
|
+
cryptodatapy-0.2.12.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
62
|
+
cryptodatapy-0.2.12.dist-info/RECORD,,
|
File without changes
|