Improve coinmarketcap error handling and add tests.
This commit is contained in:
parent
881f3b2acf
commit
d1704615df
10 changed files with 1406 additions and 27 deletions
|
@ -5,17 +5,19 @@ class SourceError(Exception):
|
|||
class InvalidPair(SourceError, ValueError):
|
||||
"""An invalid pair was requested."""
|
||||
|
||||
def __init__(self, base, quote, source):
|
||||
def __init__(self, base, quote, source, message=None):
|
||||
self.base = base
|
||||
self.quote = quote
|
||||
self.source = source
|
||||
pair = "/".join([base, quote])
|
||||
message = (
|
||||
f"Invalid pair '{pair}'. "
|
||||
insert = message + " " if message else ""
|
||||
|
||||
full_message = (
|
||||
f"Invalid pair '{pair}'. {insert}"
|
||||
f"Run 'pricehist source {source.id()} --symbols' "
|
||||
f"for information about valid pairs."
|
||||
)
|
||||
super(InvalidPair, self).__init__(message)
|
||||
super(InvalidPair, self).__init__(full_message)
|
||||
|
||||
|
||||
class InvalidType(SourceError, ValueError):
|
||||
|
|
|
@ -5,6 +5,7 @@ from decimal import Decimal
|
|||
|
||||
import requests
|
||||
|
||||
from pricehist import exceptions
|
||||
from pricehist.price import Price
|
||||
|
||||
from .basesource import BaseSource
|
||||
|
@ -47,10 +48,13 @@ class CoinMarketCap(BaseSource):
|
|||
return list(zip(ids, descriptions))
|
||||
|
||||
def fetch(self, series):
|
||||
if series.base == "ID=" or not series.quote or series.quote == "ID=":
|
||||
raise exceptions.InvalidPair(series.base, series.quote, self)
|
||||
|
||||
data = self._data(series)
|
||||
|
||||
prices = []
|
||||
for item in data["data"]["quotes"]:
|
||||
for item in data.get("quotes", []):
|
||||
d = item["time_open"][0:10]
|
||||
amount = self._amount(next(iter(item["quote"].values())), series.type)
|
||||
prices.append(Price(d, amount))
|
||||
|
@ -82,19 +86,73 @@ class CoinMarketCap(BaseSource):
|
|||
.replace(tzinfo=timezone.utc)
|
||||
.timestamp()
|
||||
)
|
||||
- 24 * 60 * 60
|
||||
# Start one period earlier since the start is exclusive.
|
||||
)
|
||||
params["time_end"] = (
|
||||
int(
|
||||
datetime.strptime(series.end, "%Y-%m-%d")
|
||||
.replace(tzinfo=timezone.utc)
|
||||
.timestamp()
|
||||
params["time_end"] = int(
|
||||
datetime.strptime(series.end, "%Y-%m-%d")
|
||||
.replace(tzinfo=timezone.utc)
|
||||
.timestamp()
|
||||
) # Don't round up since it's inclusive of the period covering the end time.
|
||||
|
||||
try:
|
||||
response = self.log_curl(requests.get(url, params=params))
|
||||
except Exception as e:
|
||||
raise exceptions.RequestError(str(e)) from e
|
||||
|
||||
code = response.status_code
|
||||
text = response.text
|
||||
|
||||
if code == 400 and "No items found." in text:
|
||||
raise exceptions.InvalidPair(
|
||||
series.base, series.quote, self, "Bad base ID."
|
||||
)
|
||||
+ 24 * 60 * 60
|
||||
) # round up to include the last day
|
||||
|
||||
response = self.log_curl(requests.get(url, params=params))
|
||||
elif code == 400 and 'Invalid value for \\"convert_id\\"' in text:
|
||||
raise exceptions.InvalidPair(
|
||||
series.base, series.quote, self, "Bad quote ID."
|
||||
)
|
||||
|
||||
return json.loads(response.content)
|
||||
elif code == 400 and 'Invalid value for \\"convert\\"' in text:
|
||||
raise exceptions.InvalidPair(
|
||||
series.base, series.quote, self, "Bad quote symbol."
|
||||
)
|
||||
|
||||
elif code == 400 and "must be older than" in text:
|
||||
if series.start <= series.end:
|
||||
raise exceptions.BadResponse("The start date must be in the past.")
|
||||
else:
|
||||
raise exceptions.BadResponse(
|
||||
"The start date must preceed or match the end date."
|
||||
)
|
||||
|
||||
elif (
|
||||
code == 400
|
||||
and "must be a valid ISO 8601 timestamp or unix time" in text
|
||||
and series.start < "2001-09-11"
|
||||
):
|
||||
raise exceptions.BadResponse("The start date can't preceed 2001-09-11.")
|
||||
|
||||
try:
|
||||
response.raise_for_status()
|
||||
except Exception as e:
|
||||
raise exceptions.BadResponse(str(e)) from e
|
||||
|
||||
try:
|
||||
parsed = json.loads(response.content)
|
||||
except Exception as e:
|
||||
raise exceptions.ResponseParsingError(str(e)) from e
|
||||
|
||||
if type(parsed) != dict or "data" not in parsed:
|
||||
raise exceptions.ResponseParsingError("Unexpected content.")
|
||||
|
||||
elif len(parsed["data"]) == 0:
|
||||
raise exceptions.ResponseParsingError(
|
||||
"The data section was empty. This can happen when the quote "
|
||||
"currency symbol can't be found, and potentially for other reasons."
|
||||
)
|
||||
|
||||
return parsed["data"]
|
||||
|
||||
def _amount(self, data, type):
|
||||
if type in ["mid"]:
|
||||
|
@ -105,26 +163,52 @@ class CoinMarketCap(BaseSource):
|
|||
return Decimal(str(data[type]))
|
||||
|
||||
def _output_pair(self, base, quote, data):
|
||||
data_base = data["data"]["symbol"]
|
||||
data_quote = next(iter(data["data"]["quotes"][0]["quote"].keys()))
|
||||
data_base = data["symbol"]
|
||||
|
||||
lookup_quote = False
|
||||
data_quote = None
|
||||
if len(data["quotes"]) > 0:
|
||||
data_quote = next(iter(data["quotes"][0]["quote"].keys()))
|
||||
|
||||
lookup_quote = None
|
||||
if quote.startswith("ID="):
|
||||
symbols = {i["id"]: (i["symbol"] or i["code"]) for i in self._symbol_data()}
|
||||
lookup_quote = symbols[int(quote[3:])]
|
||||
|
||||
output_base = data_base
|
||||
output_quote = lookup_quote or data_quote
|
||||
output_quote = lookup_quote or data_quote or quote
|
||||
|
||||
return (output_base, output_quote)
|
||||
|
||||
def _symbol_data(self):
|
||||
fiat_url = "https://web-api.coinmarketcap.com/v1/fiat/map?include_metals=true"
|
||||
fiat_res = self.log_curl(requests.get(fiat_url))
|
||||
fiat = json.loads(fiat_res.content)
|
||||
crypto_url = (
|
||||
"https://web-api.coinmarketcap.com/v1/cryptocurrency/map?sort=cmc_rank"
|
||||
)
|
||||
crypto_res = self.log_curl(requests.get(crypto_url))
|
||||
crypto = json.loads(crypto_res.content)
|
||||
return crypto["data"] + fiat["data"]
|
||||
base_url = "https://web-api.coinmarketcap.com/v1/"
|
||||
fiat_url = f"{base_url}fiat/map?include_metals=true"
|
||||
crypto_url = f"{base_url}cryptocurrency/map?sort=cmc_rank"
|
||||
|
||||
fiat = self._get_json_data(fiat_url)
|
||||
crypto = self._get_json_data(crypto_url)
|
||||
|
||||
return crypto + fiat
|
||||
|
||||
def _get_json_data(self, url, params={}):
|
||||
try:
|
||||
response = self.log_curl(requests.get(url, params=params))
|
||||
except Exception as e:
|
||||
raise exceptions.RequestError(str(e)) from e
|
||||
|
||||
try:
|
||||
response.raise_for_status()
|
||||
except Exception as e:
|
||||
raise exceptions.BadResponse(str(e)) from e
|
||||
|
||||
try:
|
||||
parsed = json.loads(response.content)
|
||||
except Exception as e:
|
||||
raise exceptions.ResponseParsingError(str(e)) from e
|
||||
|
||||
if type(parsed) != dict or "data" not in parsed:
|
||||
raise exceptions.ResponseParsingError("Unexpected content.")
|
||||
|
||||
elif len(parsed["data"]) == 0:
|
||||
raise exceptions.ResponseParsingError("Empty data section.")
|
||||
|
||||
return parsed["data"]
|
||||
|
|
430
tests/pricehist/sources/test_coinmarketcap.py
Normal file
430
tests/pricehist/sources/test_coinmarketcap.py
Normal file
|
@ -0,0 +1,430 @@
|
|||
import logging
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
import responses
|
||||
|
||||
from pricehist import exceptions
|
||||
from pricehist.price import Price
|
||||
from pricehist.series import Series
|
||||
from pricehist.sources.coinmarketcap import CoinMarketCap
|
||||
|
||||
|
||||
def timestamp(date):
|
||||
return int(
|
||||
datetime.strptime(date, "%Y-%m-%d").replace(tzinfo=timezone.utc).timestamp()
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def src():
|
||||
return CoinMarketCap()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def type(src):
|
||||
return src.types()[0]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def requests_mock():
|
||||
with responses.RequestsMock() as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
crypto_url = "https://web-api.coinmarketcap.com/v1/cryptocurrency/map?sort=cmc_rank"
|
||||
fiat_url = "https://web-api.coinmarketcap.com/v1/fiat/map?include_metals=true"
|
||||
fetch_url = "https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def crypto_ok(requests_mock):
|
||||
json = (Path(os.path.splitext(__file__)[0]) / "crypto-partial.json").read_text()
|
||||
requests_mock.add(responses.GET, crypto_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fiat_ok(requests_mock):
|
||||
json = (Path(os.path.splitext(__file__)[0]) / "fiat-partial.json").read_text()
|
||||
requests_mock.add(responses.GET, fiat_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def recent_id_id_ok(requests_mock):
|
||||
json = (Path(os.path.splitext(__file__)[0]) / "recent-id1-id2782.json").read_text()
|
||||
requests_mock.add(responses.GET, fetch_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def recent_id_sym_ok(requests_mock):
|
||||
json = (Path(os.path.splitext(__file__)[0]) / "recent-id1-aud.json").read_text()
|
||||
requests_mock.add(responses.GET, fetch_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def recent_sym_id_ok(requests_mock):
|
||||
json = (Path(os.path.splitext(__file__)[0]) / "recent-btc-id2782.json").read_text()
|
||||
requests_mock.add(responses.GET, fetch_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def recent_sym_sym_ok(requests_mock):
|
||||
json = (Path(os.path.splitext(__file__)[0]) / "recent-btc-aud.json").read_text()
|
||||
requests_mock.add(responses.GET, fetch_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def long_sym_sym_ok(requests_mock):
|
||||
json = (
|
||||
Path(os.path.splitext(__file__)[0]) / "long-btc-aud-partial.json"
|
||||
).read_text()
|
||||
requests_mock.add(responses.GET, fetch_url, body=json, status=200)
|
||||
yield requests_mock
|
||||
|
||||
|
||||
def test_normalizesymbol(src):
|
||||
assert src.normalizesymbol("btc") == "BTC"
|
||||
assert src.normalizesymbol("id=1") == "ID=1"
|
||||
|
||||
|
||||
def test_metadata(src):
|
||||
assert isinstance(src.id(), str)
|
||||
assert len(src.id()) > 0
|
||||
|
||||
assert isinstance(src.name(), str)
|
||||
assert len(src.name()) > 0
|
||||
|
||||
assert isinstance(src.description(), str)
|
||||
assert len(src.description()) > 0
|
||||
|
||||
assert isinstance(src.source_url(), str)
|
||||
assert src.source_url().startswith("http")
|
||||
|
||||
assert datetime.strptime(src.start(), "%Y-%m-%d")
|
||||
|
||||
assert isinstance(src.types(), list)
|
||||
assert len(src.types()) > 0
|
||||
assert isinstance(src.types()[0], str)
|
||||
assert len(src.types()[0]) > 0
|
||||
|
||||
assert isinstance(src.notes(), str)
|
||||
|
||||
|
||||
def test_symbols(src, crypto_ok, fiat_ok):
|
||||
syms = src.symbols()
|
||||
assert ("id=1", "BTC Bitcoin") in syms
|
||||
assert ("id=2782", "AUD Australian Dollar") in syms
|
||||
assert len(syms) > 2
|
||||
|
||||
|
||||
def test_symbols_requests_logged(src, crypto_ok, fiat_ok, caplog):
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
src.symbols()
|
||||
logged_requests = 0
|
||||
for r in caplog.records:
|
||||
if r.levelname == "DEBUG" and " curl " in r.message:
|
||||
logged_requests += 1
|
||||
assert logged_requests == 2
|
||||
|
||||
|
||||
def test_symbols_fiat_not_found(src, requests_mock):
|
||||
requests_mock.add(responses.GET, fiat_url, body="{}", status=200)
|
||||
with pytest.raises(exceptions.ResponseParsingError) as e:
|
||||
src.symbols()
|
||||
assert "Unexpected content" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_fiat_network_issue(src, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fiat_url,
|
||||
body=requests.exceptions.ConnectionError("Network issue"),
|
||||
)
|
||||
with pytest.raises(exceptions.RequestError) as e:
|
||||
src.symbols()
|
||||
assert "Network issue" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_fiat_bad_status(src, requests_mock):
|
||||
requests_mock.add(responses.GET, fiat_url, status=500)
|
||||
with pytest.raises(exceptions.BadResponse) as e:
|
||||
src.symbols()
|
||||
assert "Server Error" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_fiat_parsing_error(src, requests_mock):
|
||||
requests_mock.add(responses.GET, fiat_url, body="NOT JSON")
|
||||
with pytest.raises(exceptions.ResponseParsingError) as e:
|
||||
src.symbols()
|
||||
assert "while parsing data" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_crypto_not_found(src, requests_mock, fiat_ok):
|
||||
requests_mock.add(responses.GET, crypto_url, body="{}", status=200)
|
||||
with pytest.raises(exceptions.ResponseParsingError) as e:
|
||||
src.symbols()
|
||||
assert "Unexpected content" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_crypto_network_issue(src, requests_mock, fiat_ok):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
crypto_url,
|
||||
body=requests.exceptions.ConnectionError("Network issue"),
|
||||
)
|
||||
with pytest.raises(exceptions.RequestError) as e:
|
||||
src.symbols()
|
||||
assert "Network issue" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_crypto_bad_status(src, requests_mock, fiat_ok):
|
||||
requests_mock.add(responses.GET, crypto_url, status=500)
|
||||
with pytest.raises(exceptions.BadResponse) as e:
|
||||
src.symbols()
|
||||
assert "Server Error" in str(e.value)
|
||||
|
||||
|
||||
def test_symbols_crypto_parsing_error(src, requests_mock, fiat_ok):
|
||||
requests_mock.add(responses.GET, crypto_url, body="NOT JSON")
|
||||
with pytest.raises(exceptions.ResponseParsingError) as e:
|
||||
src.symbols()
|
||||
assert "while parsing data" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_known_pair_id_id(src, type, recent_id_id_ok, crypto_ok, fiat_ok):
|
||||
series = src.fetch(Series("ID=1", "ID=2782", type, "2021-01-01", "2021-01-07"))
|
||||
req = recent_id_id_ok.calls[0].request
|
||||
assert req.params["id"] == "1"
|
||||
assert req.params["convert_id"] == "2782"
|
||||
assert (series.base, series.quote) == ("BTC", "AUD")
|
||||
assert len(series.prices) == 7
|
||||
|
||||
|
||||
def test_fetch_known_pair_id_sym(src, type, recent_id_sym_ok):
|
||||
series = src.fetch(Series("ID=1", "AUD", type, "2021-01-01", "2021-01-07"))
|
||||
req = recent_id_sym_ok.calls[0].request
|
||||
assert req.params["id"] == "1"
|
||||
assert req.params["convert"] == "AUD"
|
||||
assert (series.base, series.quote) == ("BTC", "AUD")
|
||||
assert len(series.prices) == 7
|
||||
|
||||
|
||||
def test_fetch_known_pair_sym_id(src, type, recent_sym_id_ok, crypto_ok, fiat_ok):
|
||||
series = src.fetch(Series("BTC", "ID=2782", type, "2021-01-01", "2021-01-07"))
|
||||
req = recent_sym_id_ok.calls[0].request
|
||||
assert req.params["symbol"] == "BTC"
|
||||
assert req.params["convert_id"] == "2782"
|
||||
assert (series.base, series.quote) == ("BTC", "AUD")
|
||||
assert len(series.prices) == 7
|
||||
|
||||
|
||||
def test_fetch_known_pair_sym_sym(src, type, recent_sym_sym_ok):
|
||||
series = src.fetch(Series("BTC", "AUD", type, "2021-01-01", "2021-01-07"))
|
||||
req = recent_sym_sym_ok.calls[0].request
|
||||
assert req.params["symbol"] == "BTC"
|
||||
assert req.params["convert"] == "AUD"
|
||||
assert len(series.prices) == 7
|
||||
|
||||
|
||||
def test_fetch_requests_and_receives_correct_times(
|
||||
src, type, recent_id_id_ok, crypto_ok, fiat_ok
|
||||
):
|
||||
series = src.fetch(Series("ID=1", "ID=2782", type, "2021-01-01", "2021-01-07"))
|
||||
req = recent_id_id_ok.calls[0].request
|
||||
assert req.params["time_start"] == str(timestamp("2020-12-31")) # back one period
|
||||
assert req.params["time_end"] == str(timestamp("2021-01-07"))
|
||||
assert series.prices[0] == Price("2021-01-01", Decimal("37914.350602379853"))
|
||||
assert series.prices[-1] == Price("2021-01-07", Decimal("49370.064689585612"))
|
||||
|
||||
|
||||
def test_fetch_requests_logged(src, type, recent_sym_sym_ok, caplog):
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
src.fetch(Series("BTC", "AUD", type, "2021-01-01", "2021-01-07"))
|
||||
assert any(
|
||||
["DEBUG" == r.levelname and " curl " in r.message for r in caplog.records]
|
||||
)
|
||||
|
||||
|
||||
def test_fetch_types_all_available(src, recent_sym_sym_ok):
|
||||
mid = src.fetch(Series("BTC", "AUD", "mid", "2021-01-01", "2021-01-07"))
|
||||
opn = src.fetch(Series("BTC", "AUD", "open", "2021-01-01", "2021-01-07"))
|
||||
hgh = src.fetch(Series("BTC", "AUD", "high", "2021-01-01", "2021-01-07"))
|
||||
low = src.fetch(Series("BTC", "AUD", "low", "2021-01-01", "2021-01-07"))
|
||||
cls = src.fetch(Series("BTC", "AUD", "close", "2021-01-01", "2021-01-07"))
|
||||
assert mid.prices[0].amount == Decimal("37914.350602379853")
|
||||
assert opn.prices[0].amount == Decimal("37658.83948707033")
|
||||
assert hgh.prices[0].amount == Decimal("38417.9137031205")
|
||||
assert low.prices[0].amount == Decimal("37410.787501639206")
|
||||
assert cls.prices[0].amount == Decimal("38181.99133300758")
|
||||
|
||||
|
||||
def test_fetch_type_mid_is_mean_of_low_and_high(src, recent_sym_sym_ok):
|
||||
mid = src.fetch(Series("BTC", "AUD", "mid", "2021-01-01", "2021-01-07")).prices
|
||||
low = src.fetch(Series("BTC", "AUD", "low", "2021-01-01", "2021-01-07")).prices
|
||||
hgh = src.fetch(Series("BTC", "AUD", "high", "2021-01-01", "2021-01-07")).prices
|
||||
assert all(
|
||||
[
|
||||
mid[i].amount == (sum([low[i].amount, hgh[i].amount]) / 2)
|
||||
for i in range(0, 7)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_fetch_long_hist_from_start(src, type, long_sym_sym_ok):
|
||||
series = src.fetch(Series("BTC", "AUD", type, src.start(), "2021-01-07"))
|
||||
assert series.prices[0] == Price("2013-04-28", Decimal("130.45956234123247"))
|
||||
assert series.prices[-1] == Price("2021-01-07", Decimal("49370.064689585612"))
|
||||
assert len(series.prices) > 13
|
||||
|
||||
|
||||
def test_fetch_from_before_start(src, type, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fetch_url,
|
||||
status=400,
|
||||
body="""{ "status": { "error_code": 400, "error_message":
|
||||
"\\"time_start\\" must be a valid ISO 8601 timestamp or unix time value",
|
||||
} }""",
|
||||
)
|
||||
with pytest.raises(exceptions.BadResponse) as e:
|
||||
src.fetch(Series("BTC", "AUD", type, "2001-09-10", "2001-10-01"))
|
||||
assert "start date can't preceed" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_to_future(src, type, recent_sym_sym_ok):
|
||||
series = src.fetch(Series("BTC", "AUD", type, "2021-01-01", "2100-01-01"))
|
||||
assert len(series.prices) > 0
|
||||
|
||||
|
||||
def test_fetch_in_future(src, type, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fetch_url,
|
||||
status=400,
|
||||
body="""{
|
||||
"status": {
|
||||
"error_code": 400,
|
||||
"error_message": "\\"time_start\\" must be older than \\"time_end\\"."
|
||||
}
|
||||
}""",
|
||||
)
|
||||
with pytest.raises(exceptions.BadResponse) as e:
|
||||
src.fetch(Series("BTC", "AUD", type, "2030-01-01", "2030-01-07"))
|
||||
assert "start date must be in the past" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_empty(src, type, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fetch_url,
|
||||
body="""{
|
||||
"status": {
|
||||
"error_code": 0,
|
||||
"error_message": null
|
||||
},
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"quotes": []
|
||||
}
|
||||
}""",
|
||||
)
|
||||
series = src.fetch(Series("BTC", "AUD", type, "2010-01-01", "2010-01-07"))
|
||||
assert len(series.prices) == 0
|
||||
|
||||
|
||||
def test_fetch_bad_base_sym(src, type, requests_mock):
|
||||
requests_mock.add(responses.GET, fetch_url, body='{"data":{}}')
|
||||
with pytest.raises(exceptions.ResponseParsingError) as e:
|
||||
src.fetch(Series("NOTABASE", "USD", type, "2021-01-01", "2021-01-07"))
|
||||
assert "quote currency symbol can't be found" in str(e.value)
|
||||
assert "other reasons" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_bad_quote_sym(src, type, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fetch_url,
|
||||
status=400,
|
||||
body="""{
|
||||
"status": {
|
||||
"error_code": 400,
|
||||
"error_message": "Invalid value for \\"convert\\": \\"NOTAQUOTE\\""
|
||||
}
|
||||
}""",
|
||||
)
|
||||
with pytest.raises(exceptions.InvalidPair) as e:
|
||||
src.fetch(Series("BTC", "NOTAQUOTE", type, "2021-01-01", "2021-01-07"))
|
||||
assert "Bad quote symbol" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_bad_base_id(src, type, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fetch_url,
|
||||
status=400,
|
||||
body="""{
|
||||
"status": {
|
||||
"error_code": 400,
|
||||
"error_message": "No items found."
|
||||
}
|
||||
}""",
|
||||
)
|
||||
with pytest.raises(exceptions.InvalidPair) as e:
|
||||
src.fetch(Series("ID=20000", "USD", type, "2021-01-01", "2021-01-07"))
|
||||
assert "Bad base ID" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_bad_quote_id(src, type, requests_mock):
|
||||
requests_mock.add(
|
||||
responses.GET,
|
||||
fetch_url,
|
||||
status=400,
|
||||
body="""{
|
||||
"status": {
|
||||
"error_code": 400,
|
||||
"error_message": "Invalid value for \\"convert_id\\": \\"20000\\""
|
||||
}
|
||||
}""",
|
||||
)
|
||||
with pytest.raises(exceptions.InvalidPair) as e:
|
||||
src.fetch(Series("BTC", "ID=20000", type, "2021-01-01", "2021-01-07"))
|
||||
assert "Bad quote ID" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_no_quote(src, type):
|
||||
with pytest.raises(exceptions.InvalidPair):
|
||||
src.fetch(Series("BTC", "", type, "2021-01-01", "2021-01-07"))
|
||||
|
||||
|
||||
def test_fetch_network_issue(src, type, requests_mock):
|
||||
body = requests.exceptions.ConnectionError("Network issue")
|
||||
requests_mock.add(responses.GET, fetch_url, body=body)
|
||||
with pytest.raises(exceptions.RequestError) as e:
|
||||
src.fetch(Series("BTC", "AUD", type, "2021-01-01", "2021-01-07"))
|
||||
assert "Network issue" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_bad_status(src, type, requests_mock):
|
||||
requests_mock.add(responses.GET, fetch_url, status=500, body="Some other reason")
|
||||
with pytest.raises(exceptions.BadResponse) as e:
|
||||
src.fetch(Series("BTC", "AUD", type, "2021-01-01", "2021-01-07"))
|
||||
assert "Internal Server Error" in str(e.value)
|
||||
|
||||
|
||||
def test_fetch_parsing_error(src, type, requests_mock):
|
||||
requests_mock.add(responses.GET, fetch_url, body="NOT JSON")
|
||||
with pytest.raises(exceptions.ResponseParsingError) as e:
|
||||
src.fetch(Series("BTC", "AUD", type, "2021-01-01", "2021-01-07"))
|
||||
assert "while parsing data" in str(e.value)
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-16T10:08:28.938Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 18,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"slug": "bitcoin",
|
||||
"rank": 1,
|
||||
"is_active": 1,
|
||||
"first_historical_data": "2013-04-28T18:47:21.000Z",
|
||||
"last_historical_data": "2021-07-16T09:59:03.000Z",
|
||||
"platform": null
|
||||
},
|
||||
{
|
||||
"id": 1027,
|
||||
"name": "Ethereum",
|
||||
"symbol": "ETH",
|
||||
"slug": "ethereum",
|
||||
"rank": 2,
|
||||
"is_active": 1,
|
||||
"first_historical_data": "2015-08-07T14:49:30.000Z",
|
||||
"last_historical_data": "2021-07-16T09:59:04.000Z",
|
||||
"platform": null
|
||||
}
|
||||
]
|
||||
}
|
30
tests/pricehist/sources/test_coinmarketcap/fiat-partial.json
Normal file
30
tests/pricehist/sources/test_coinmarketcap/fiat-partial.json
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-16T10:08:13.272Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 1,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"id": 2781,
|
||||
"name": "United States Dollar",
|
||||
"sign": "$",
|
||||
"symbol": "USD"
|
||||
},
|
||||
{
|
||||
"id": 2782,
|
||||
"name": "Australian Dollar",
|
||||
"sign": "$",
|
||||
"symbol": "AUD"
|
||||
},
|
||||
{
|
||||
"id": 3575,
|
||||
"name": "Gold Troy Ounce",
|
||||
"symbol": "",
|
||||
"code": "XAU"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-17T16:16:11.926Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 2262,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"quotes": [
|
||||
{
|
||||
"time_open": "2013-04-28T00:00:00.000Z",
|
||||
"time_close": "2013-04-28T23:59:59.999Z",
|
||||
"time_high": "2013-04-28T18:50:02.000Z",
|
||||
"time_low": "2013-04-28T20:15:02.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": null,
|
||||
"high": 132.39216797540558,
|
||||
"low": 128.52695670705936,
|
||||
"close": 130.52908647526473,
|
||||
"volume": 0,
|
||||
"market_cap": 1447740447.626921,
|
||||
"timestamp": "2013-04-28T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2013-04-29T00:00:00.000Z",
|
||||
"time_close": "2013-04-29T23:59:59.999Z",
|
||||
"time_high": "2013-04-29T13:15:01.000Z",
|
||||
"time_low": "2013-04-29T05:20:01.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 130.75666236543535,
|
||||
"high": 142.67970067891736,
|
||||
"low": 129.9456943366951,
|
||||
"close": 139.77370978254794,
|
||||
"volume": 0,
|
||||
"market_cap": 1550883729.329852,
|
||||
"timestamp": "2013-04-29T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2013-04-30T00:00:00.000Z",
|
||||
"time_close": "2013-04-30T23:59:59.999Z",
|
||||
"time_high": "2013-04-30T08:25:02.000Z",
|
||||
"time_low": "2013-04-30T18:55:01.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 139.2515230635335,
|
||||
"high": 141.93391873626476,
|
||||
"low": 129.37940647790543,
|
||||
"close": 134.06635802469137,
|
||||
"volume": 0,
|
||||
"market_cap": 1488052782.6003087,
|
||||
"timestamp": "2013-04-30T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2013-05-01T00:00:00.000Z",
|
||||
"time_close": "2013-05-01T23:59:59.999Z",
|
||||
"time_high": "2013-05-01T00:15:01.000Z",
|
||||
"time_low": "2013-05-01T19:55:01.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 134.06635802469137,
|
||||
"high": 134.88573849160971,
|
||||
"low": 104.93911468163968,
|
||||
"close": 113.79243056489595,
|
||||
"volume": 0,
|
||||
"market_cap": 1263451603.6864119,
|
||||
"timestamp": "2013-05-01T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2013-05-02T00:00:00.000Z",
|
||||
"time_close": "2013-05-02T23:59:59.999Z",
|
||||
"time_high": "2013-05-02T14:25:01.000Z",
|
||||
"time_low": "2013-05-02T14:30:02.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 113.19910247390133,
|
||||
"high": 122.60835462135991,
|
||||
"low": 90.08385249759387,
|
||||
"close": 102.63388848353591,
|
||||
"volume": 0,
|
||||
"market_cap": 1139905858.2089553,
|
||||
"timestamp": "2013-05-02T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2013-05-03T00:00:00.000Z",
|
||||
"time_close": "2013-05-03T23:59:59.999Z",
|
||||
"time_high": "2013-05-03T05:30:02.000Z",
|
||||
"time_low": "2013-05-03T03:05:01.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 103.64842454394694,
|
||||
"high": 105.43929629649027,
|
||||
"low": 77.03544845551335,
|
||||
"close": 94.77409346519293,
|
||||
"volume": 0,
|
||||
"market_cap": 1052933070.3412836,
|
||||
"timestamp": "2013-05-03T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2013-05-04T00:00:00.000Z",
|
||||
"time_close": "2013-05-04T23:59:59.999Z",
|
||||
"time_high": "2013-05-04T07:15:01.000Z",
|
||||
"time_low": "2013-05-04T06:50:01.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 95.11343656595025,
|
||||
"high": 111.49893348846227,
|
||||
"low": 89.68392476245879,
|
||||
"close": 109.07504363001745,
|
||||
"volume": 0,
|
||||
"market_cap": 1212251854.2757416,
|
||||
"timestamp": "2013-05-04T23:59:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-01T00:00:00.000Z",
|
||||
"time_close": "2021-01-01T23:59:59.999Z",
|
||||
"time_high": "2021-01-01T12:38:43.000Z",
|
||||
"time_low": "2021-01-01T00:16:43.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 37658.83948707033,
|
||||
"high": 38417.9137031205,
|
||||
"low": 37410.787501639206,
|
||||
"close": 38181.99133300758,
|
||||
"volume": 52943282221.028366,
|
||||
"market_cap": 709720173049.5383,
|
||||
"timestamp": "2021-01-01T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-02T00:00:00.000Z",
|
||||
"time_close": "2021-01-02T23:59:59.999Z",
|
||||
"time_high": "2021-01-02T19:49:42.000Z",
|
||||
"time_low": "2021-01-02T00:31:44.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 38184.98611600682,
|
||||
"high": 43096.681197423015,
|
||||
"low": 37814.17187096531,
|
||||
"close": 41760.62923079505,
|
||||
"volume": 88214867181.97835,
|
||||
"market_cap": 776278147177.8037,
|
||||
"timestamp": "2021-01-02T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-03T00:00:00.000Z",
|
||||
"time_close": "2021-01-03T23:59:59.999Z",
|
||||
"time_high": "2021-01-03T07:47:38.000Z",
|
||||
"time_low": "2021-01-03T00:20:45.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 41763.41015117659,
|
||||
"high": 44985.93247585023,
|
||||
"low": 41663.204350601605,
|
||||
"close": 42511.10646879765,
|
||||
"volume": 102011582370.28117,
|
||||
"market_cap": 790270288834.0249,
|
||||
"timestamp": "2021-01-03T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-04T00:00:00.000Z",
|
||||
"time_close": "2021-01-04T23:59:59.999Z",
|
||||
"time_high": "2021-01-04T04:07:42.000Z",
|
||||
"time_low": "2021-01-04T10:19:42.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 42548.61349648768,
|
||||
"high": 43360.96165147421,
|
||||
"low": 37133.98436952697,
|
||||
"close": 41686.38761359174,
|
||||
"volume": 105824510346.65779,
|
||||
"market_cap": 774984045201.7122,
|
||||
"timestamp": "2021-01-04T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-05T00:00:00.000Z",
|
||||
"time_close": "2021-01-05T23:59:59.999Z",
|
||||
"time_high": "2021-01-05T22:44:35.000Z",
|
||||
"time_low": "2021-01-05T06:16:41.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 41693.07321807638,
|
||||
"high": 44403.79487147647,
|
||||
"low": 39221.81167941294,
|
||||
"close": 43790.067253370056,
|
||||
"volume": 87016490203.50436,
|
||||
"market_cap": 814135603090.2502,
|
||||
"timestamp": "2021-01-05T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-06T00:00:00.000Z",
|
||||
"time_close": "2021-01-06T23:59:59.999Z",
|
||||
"time_high": "2021-01-06T23:57:36.000Z",
|
||||
"time_low": "2021-01-06T00:25:38.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 43817.35864984641,
|
||||
"high": 47186.65232598287,
|
||||
"low": 43152.60281764236,
|
||||
"close": 47115.85365360005,
|
||||
"volume": 96330948324.8061,
|
||||
"market_cap": 876019742889.9551,
|
||||
"timestamp": "2021-01-06T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-07T00:00:00.000Z",
|
||||
"time_close": "2021-01-07T23:59:59.999Z",
|
||||
"time_high": "2021-01-07T18:17:42.000Z",
|
||||
"time_low": "2021-01-07T08:25:51.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 47128.02139328098,
|
||||
"high": 51833.478207775144,
|
||||
"low": 46906.65117139608,
|
||||
"close": 50686.90986207153,
|
||||
"volume": 109124136558.20264,
|
||||
"market_cap": 942469208700.134,
|
||||
"timestamp": "2021-01-07T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
136
tests/pricehist/sources/test_coinmarketcap/recent-btc-aud.json
Normal file
136
tests/pricehist/sources/test_coinmarketcap/recent-btc-aud.json
Normal file
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-16T10:42:32.013Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 20,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"quotes": [
|
||||
{
|
||||
"time_open": "2021-01-01T00:00:00.000Z",
|
||||
"time_close": "2021-01-01T23:59:59.999Z",
|
||||
"time_high": "2021-01-01T12:38:43.000Z",
|
||||
"time_low": "2021-01-01T00:16:43.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 37658.83948707033,
|
||||
"high": 38417.9137031205,
|
||||
"low": 37410.787501639206,
|
||||
"close": 38181.99133300758,
|
||||
"volume": 52943282221.028366,
|
||||
"market_cap": 709720173049.5383,
|
||||
"timestamp": "2021-01-01T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-02T00:00:00.000Z",
|
||||
"time_close": "2021-01-02T23:59:59.999Z",
|
||||
"time_high": "2021-01-02T19:49:42.000Z",
|
||||
"time_low": "2021-01-02T00:31:44.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 38184.98611600682,
|
||||
"high": 43096.681197423015,
|
||||
"low": 37814.17187096531,
|
||||
"close": 41760.62923079505,
|
||||
"volume": 88214867181.97835,
|
||||
"market_cap": 776278147177.8037,
|
||||
"timestamp": "2021-01-02T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-03T00:00:00.000Z",
|
||||
"time_close": "2021-01-03T23:59:59.999Z",
|
||||
"time_high": "2021-01-03T07:47:38.000Z",
|
||||
"time_low": "2021-01-03T00:20:45.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 41763.41015117659,
|
||||
"high": 44985.93247585023,
|
||||
"low": 41663.204350601605,
|
||||
"close": 42511.10646879765,
|
||||
"volume": 102011582370.28117,
|
||||
"market_cap": 790270288834.0249,
|
||||
"timestamp": "2021-01-03T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-04T00:00:00.000Z",
|
||||
"time_close": "2021-01-04T23:59:59.999Z",
|
||||
"time_high": "2021-01-04T04:07:42.000Z",
|
||||
"time_low": "2021-01-04T10:19:42.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 42548.61349648768,
|
||||
"high": 43360.96165147421,
|
||||
"low": 37133.98436952697,
|
||||
"close": 41686.38761359174,
|
||||
"volume": 105824510346.65779,
|
||||
"market_cap": 774984045201.7122,
|
||||
"timestamp": "2021-01-04T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-05T00:00:00.000Z",
|
||||
"time_close": "2021-01-05T23:59:59.999Z",
|
||||
"time_high": "2021-01-05T22:44:35.000Z",
|
||||
"time_low": "2021-01-05T06:16:41.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 41693.07321807638,
|
||||
"high": 44403.79487147647,
|
||||
"low": 39221.81167941294,
|
||||
"close": 43790.067253370056,
|
||||
"volume": 87016490203.50436,
|
||||
"market_cap": 814135603090.2502,
|
||||
"timestamp": "2021-01-05T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-06T00:00:00.000Z",
|
||||
"time_close": "2021-01-06T23:59:59.999Z",
|
||||
"time_high": "2021-01-06T23:57:36.000Z",
|
||||
"time_low": "2021-01-06T00:25:38.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 43817.35864984641,
|
||||
"high": 47186.65232598287,
|
||||
"low": 43152.60281764236,
|
||||
"close": 47115.85365360005,
|
||||
"volume": 96330948324.8061,
|
||||
"market_cap": 876019742889.9551,
|
||||
"timestamp": "2021-01-06T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-07T00:00:00.000Z",
|
||||
"time_close": "2021-01-07T23:59:59.999Z",
|
||||
"time_high": "2021-01-07T18:17:42.000Z",
|
||||
"time_low": "2021-01-07T08:25:51.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 47128.02139328098,
|
||||
"high": 51833.478207775144,
|
||||
"low": 46906.65117139608,
|
||||
"close": 50686.90986207153,
|
||||
"volume": 109124136558.20264,
|
||||
"market_cap": 942469208700.134,
|
||||
"timestamp": "2021-01-07T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-16T10:42:27.169Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 19,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"quotes": [
|
||||
{
|
||||
"time_open": "2021-01-01T00:00:00.000Z",
|
||||
"time_close": "2021-01-01T23:59:59.999Z",
|
||||
"time_high": "2021-01-01T12:38:43.000Z",
|
||||
"time_low": "2021-01-01T00:16:43.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 37658.83948707033,
|
||||
"high": 38417.9137031205,
|
||||
"low": 37410.787501639206,
|
||||
"close": 38181.99133300758,
|
||||
"volume": 52943282221.028366,
|
||||
"market_cap": 709720173049.5383,
|
||||
"timestamp": "2021-01-01T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-02T00:00:00.000Z",
|
||||
"time_close": "2021-01-02T23:59:59.999Z",
|
||||
"time_high": "2021-01-02T19:49:42.000Z",
|
||||
"time_low": "2021-01-02T00:31:44.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 38184.98611600682,
|
||||
"high": 43096.681197423015,
|
||||
"low": 37814.17187096531,
|
||||
"close": 41760.62923079505,
|
||||
"volume": 88214867181.97835,
|
||||
"market_cap": 776278147177.8037,
|
||||
"timestamp": "2021-01-02T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-03T00:00:00.000Z",
|
||||
"time_close": "2021-01-03T23:59:59.999Z",
|
||||
"time_high": "2021-01-03T07:47:38.000Z",
|
||||
"time_low": "2021-01-03T00:20:45.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 41763.41015117659,
|
||||
"high": 44985.93247585023,
|
||||
"low": 41663.204350601605,
|
||||
"close": 42511.10646879765,
|
||||
"volume": 102011582370.28117,
|
||||
"market_cap": 790270288834.0249,
|
||||
"timestamp": "2021-01-03T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-04T00:00:00.000Z",
|
||||
"time_close": "2021-01-04T23:59:59.999Z",
|
||||
"time_high": "2021-01-04T04:07:42.000Z",
|
||||
"time_low": "2021-01-04T10:19:42.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 42548.61349648768,
|
||||
"high": 43360.96165147421,
|
||||
"low": 37133.98436952697,
|
||||
"close": 41686.38761359174,
|
||||
"volume": 105824510346.65779,
|
||||
"market_cap": 774984045201.7122,
|
||||
"timestamp": "2021-01-04T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-05T00:00:00.000Z",
|
||||
"time_close": "2021-01-05T23:59:59.999Z",
|
||||
"time_high": "2021-01-05T22:44:35.000Z",
|
||||
"time_low": "2021-01-05T06:16:41.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 41693.07321807638,
|
||||
"high": 44403.79487147647,
|
||||
"low": 39221.81167941294,
|
||||
"close": 43790.067253370056,
|
||||
"volume": 87016490203.50436,
|
||||
"market_cap": 814135603090.2502,
|
||||
"timestamp": "2021-01-05T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-06T00:00:00.000Z",
|
||||
"time_close": "2021-01-06T23:59:59.999Z",
|
||||
"time_high": "2021-01-06T23:57:36.000Z",
|
||||
"time_low": "2021-01-06T00:25:38.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 43817.35864984641,
|
||||
"high": 47186.65232598287,
|
||||
"low": 43152.60281764236,
|
||||
"close": 47115.85365360005,
|
||||
"volume": 96330948324.8061,
|
||||
"market_cap": 876019742889.9551,
|
||||
"timestamp": "2021-01-06T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-07T00:00:00.000Z",
|
||||
"time_close": "2021-01-07T23:59:59.999Z",
|
||||
"time_high": "2021-01-07T18:17:42.000Z",
|
||||
"time_low": "2021-01-07T08:25:51.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 47128.02139328098,
|
||||
"high": 51833.478207775144,
|
||||
"low": 46906.65117139608,
|
||||
"close": 50686.90986207153,
|
||||
"volume": 109124136558.20264,
|
||||
"market_cap": 942469208700.134,
|
||||
"timestamp": "2021-01-07T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
136
tests/pricehist/sources/test_coinmarketcap/recent-id1-aud.json
Normal file
136
tests/pricehist/sources/test_coinmarketcap/recent-id1-aud.json
Normal file
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-16T10:42:24.612Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 57,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"quotes": [
|
||||
{
|
||||
"time_open": "2021-01-01T00:00:00.000Z",
|
||||
"time_close": "2021-01-01T23:59:59.999Z",
|
||||
"time_high": "2021-01-01T12:38:43.000Z",
|
||||
"time_low": "2021-01-01T00:16:43.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 37658.83948707033,
|
||||
"high": 38417.9137031205,
|
||||
"low": 37410.787501639206,
|
||||
"close": 38181.99133300758,
|
||||
"volume": 52943282221.028366,
|
||||
"market_cap": 709720173049.5383,
|
||||
"timestamp": "2021-01-01T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-02T00:00:00.000Z",
|
||||
"time_close": "2021-01-02T23:59:59.999Z",
|
||||
"time_high": "2021-01-02T19:49:42.000Z",
|
||||
"time_low": "2021-01-02T00:31:44.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 38184.98611600682,
|
||||
"high": 43096.681197423015,
|
||||
"low": 37814.17187096531,
|
||||
"close": 41760.62923079505,
|
||||
"volume": 88214867181.97835,
|
||||
"market_cap": 776278147177.8037,
|
||||
"timestamp": "2021-01-02T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-03T00:00:00.000Z",
|
||||
"time_close": "2021-01-03T23:59:59.999Z",
|
||||
"time_high": "2021-01-03T07:47:38.000Z",
|
||||
"time_low": "2021-01-03T00:20:45.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 41763.41015117659,
|
||||
"high": 44985.93247585023,
|
||||
"low": 41663.204350601605,
|
||||
"close": 42511.10646879765,
|
||||
"volume": 102011582370.28117,
|
||||
"market_cap": 790270288834.0249,
|
||||
"timestamp": "2021-01-03T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-04T00:00:00.000Z",
|
||||
"time_close": "2021-01-04T23:59:59.999Z",
|
||||
"time_high": "2021-01-04T04:07:42.000Z",
|
||||
"time_low": "2021-01-04T10:19:42.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 42548.61349648768,
|
||||
"high": 43360.96165147421,
|
||||
"low": 37133.98436952697,
|
||||
"close": 41686.38761359174,
|
||||
"volume": 105824510346.65779,
|
||||
"market_cap": 774984045201.7122,
|
||||
"timestamp": "2021-01-04T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-05T00:00:00.000Z",
|
||||
"time_close": "2021-01-05T23:59:59.999Z",
|
||||
"time_high": "2021-01-05T22:44:35.000Z",
|
||||
"time_low": "2021-01-05T06:16:41.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 41693.07321807638,
|
||||
"high": 44403.79487147647,
|
||||
"low": 39221.81167941294,
|
||||
"close": 43790.067253370056,
|
||||
"volume": 87016490203.50436,
|
||||
"market_cap": 814135603090.2502,
|
||||
"timestamp": "2021-01-05T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-06T00:00:00.000Z",
|
||||
"time_close": "2021-01-06T23:59:59.999Z",
|
||||
"time_high": "2021-01-06T23:57:36.000Z",
|
||||
"time_low": "2021-01-06T00:25:38.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 43817.35864984641,
|
||||
"high": 47186.65232598287,
|
||||
"low": 43152.60281764236,
|
||||
"close": 47115.85365360005,
|
||||
"volume": 96330948324.8061,
|
||||
"market_cap": 876019742889.9551,
|
||||
"timestamp": "2021-01-06T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-07T00:00:00.000Z",
|
||||
"time_close": "2021-01-07T23:59:59.999Z",
|
||||
"time_high": "2021-01-07T18:17:42.000Z",
|
||||
"time_low": "2021-01-07T08:25:51.000Z",
|
||||
"quote": {
|
||||
"AUD": {
|
||||
"open": 47128.02139328098,
|
||||
"high": 51833.478207775144,
|
||||
"low": 46906.65117139608,
|
||||
"close": 50686.90986207153,
|
||||
"volume": 109124136558.20264,
|
||||
"market_cap": 942469208700.134,
|
||||
"timestamp": "2021-01-07T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"status": {
|
||||
"timestamp": "2021-07-16T10:42:21.065Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 17,
|
||||
"credit_count": 0,
|
||||
"notice": null
|
||||
},
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"quotes": [
|
||||
{
|
||||
"time_open": "2021-01-01T00:00:00.000Z",
|
||||
"time_close": "2021-01-01T23:59:59.999Z",
|
||||
"time_high": "2021-01-01T12:38:43.000Z",
|
||||
"time_low": "2021-01-01T00:16:43.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 37658.83948707033,
|
||||
"high": 38417.9137031205,
|
||||
"low": 37410.787501639206,
|
||||
"close": 38181.99133300758,
|
||||
"volume": 52943282221.028366,
|
||||
"market_cap": 709720173049.5383,
|
||||
"timestamp": "2021-01-01T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-02T00:00:00.000Z",
|
||||
"time_close": "2021-01-02T23:59:59.999Z",
|
||||
"time_high": "2021-01-02T19:49:42.000Z",
|
||||
"time_low": "2021-01-02T00:31:44.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 38184.98611600682,
|
||||
"high": 43096.681197423015,
|
||||
"low": 37814.17187096531,
|
||||
"close": 41760.62923079505,
|
||||
"volume": 88214867181.97835,
|
||||
"market_cap": 776278147177.8037,
|
||||
"timestamp": "2021-01-02T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-03T00:00:00.000Z",
|
||||
"time_close": "2021-01-03T23:59:59.999Z",
|
||||
"time_high": "2021-01-03T07:47:38.000Z",
|
||||
"time_low": "2021-01-03T00:20:45.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 41763.41015117659,
|
||||
"high": 44985.93247585023,
|
||||
"low": 41663.204350601605,
|
||||
"close": 42511.10646879765,
|
||||
"volume": 102011582370.28117,
|
||||
"market_cap": 790270288834.0249,
|
||||
"timestamp": "2021-01-03T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-04T00:00:00.000Z",
|
||||
"time_close": "2021-01-04T23:59:59.999Z",
|
||||
"time_high": "2021-01-04T04:07:42.000Z",
|
||||
"time_low": "2021-01-04T10:19:42.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 42548.61349648768,
|
||||
"high": 43360.96165147421,
|
||||
"low": 37133.98436952697,
|
||||
"close": 41686.38761359174,
|
||||
"volume": 105824510346.65779,
|
||||
"market_cap": 774984045201.7122,
|
||||
"timestamp": "2021-01-04T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-05T00:00:00.000Z",
|
||||
"time_close": "2021-01-05T23:59:59.999Z",
|
||||
"time_high": "2021-01-05T22:44:35.000Z",
|
||||
"time_low": "2021-01-05T06:16:41.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 41693.07321807638,
|
||||
"high": 44403.79487147647,
|
||||
"low": 39221.81167941294,
|
||||
"close": 43790.067253370056,
|
||||
"volume": 87016490203.50436,
|
||||
"market_cap": 814135603090.2502,
|
||||
"timestamp": "2021-01-05T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-06T00:00:00.000Z",
|
||||
"time_close": "2021-01-06T23:59:59.999Z",
|
||||
"time_high": "2021-01-06T23:57:36.000Z",
|
||||
"time_low": "2021-01-06T00:25:38.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 43817.35864984641,
|
||||
"high": 47186.65232598287,
|
||||
"low": 43152.60281764236,
|
||||
"close": 47115.85365360005,
|
||||
"volume": 96330948324.8061,
|
||||
"market_cap": 876019742889.9551,
|
||||
"timestamp": "2021-01-06T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"time_open": "2021-01-07T00:00:00.000Z",
|
||||
"time_close": "2021-01-07T23:59:59.999Z",
|
||||
"time_high": "2021-01-07T18:17:42.000Z",
|
||||
"time_low": "2021-01-07T08:25:51.000Z",
|
||||
"quote": {
|
||||
"2782": {
|
||||
"open": 47128.02139328098,
|
||||
"high": 51833.478207775144,
|
||||
"low": 46906.65117139608,
|
||||
"close": 50686.90986207153,
|
||||
"volume": 109124136558.20264,
|
||||
"market_cap": 942469208700.134,
|
||||
"timestamp": "2021-01-07T23:59:06.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue