Skip to content

Commit

Permalink
Merge pull request #95 from ThomasdenH/coincap-fix
Browse files Browse the repository at this point in the history
Fix coincap tests and linting
  • Loading branch information
xuhcc authored Jan 30, 2025
2 parents a0db0cd + a7977c7 commit 5fee4e5
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 31 deletions.
44 changes: 22 additions & 22 deletions beanprice/sources/coincap.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
"""

import datetime
from datetime import datetime, timezone, timedelta
import math
from decimal import Decimal
from typing import List, Optional, Tuple, Dict
from typing import List, Optional, Dict
import requests
from beanprice import source

Expand Down Expand Up @@ -61,27 +61,32 @@ def resolve_currency_id(base_currency: str) -> str:
base_currency_id = get_currency_id(base_currency)
if not isinstance(base_currency_id, str):
raise CoincapError(
"Could not find currency id with ticker '" + base_currency + "'"
f"Could not find currency id with ticker '{base_currency}'"
)
return base_currency_id
else:
return base_currency


def get_latest_price(base_currency: str) -> Tuple[float, float]:
def get_latest_price(base_currency: str) -> source.SourcePrice:
"""
Get the latest available price for a given currency.
"""
path = "assets/"
url = API_BASE_URL + path + resolve_currency_id(base_currency)
url = f"{API_BASE_URL}{path}{resolve_currency_id(base_currency)}"
response = requests.get(url)
data = response.json()
timestamp = data["timestamp"] / 1000.0
price_float = data["data"]["priceUsd"]
return price_float, timestamp
time = datetime.fromtimestamp(data["timestamp"] / 1000.0).replace(
tzinfo=timezone.utc
)
price = Decimal(data["data"]["priceUsd"])
return source.SourcePrice(price, time, "USD")


def get_price_series(
base_currency_id: str, time_begin: datetime.datetime, time_end: datetime.datetime
base_currency_id: str, time_begin: datetime, time_end: datetime
) -> List[source.SourcePrice]:
path = "assets/{}/history".format(base_currency_id)
path = f"assets/{base_currency_id}/history"
params = {
"interval": "d1",
"start": str(math.floor(time_begin.timestamp() * 1000.0)),
Expand All @@ -92,9 +97,7 @@ def get_price_series(
return [
source.SourcePrice(
Decimal(item["priceUsd"]),
datetime.datetime.fromtimestamp(item["time"] / 1000.0).replace(
tzinfo=datetime.timezone.utc
),
datetime.fromtimestamp(item["time"] / 1000.0).replace(tzinfo=timezone.utc),
"USD",
)
for item in response.json()["data"]
Expand All @@ -107,18 +110,15 @@ class Source(source.Source):
or by their ticker (BTC), in which case the highest ranked coin will be picked."""

def get_latest_price(self, ticker) -> source.SourcePrice:
price_float, timestamp = get_latest_price(ticker)
price = Decimal(price_float)
price_time = datetime.datetime.fromtimestamp(timestamp).replace(
tzinfo=datetime.timezone.utc
)
return source.SourcePrice(price, price_time, "USD")
return get_latest_price(ticker)

def get_historical_price(
self, ticker: str, time: datetime.datetime
self, ticker: str, time: datetime
) -> Optional[source.SourcePrice]:
for datapoint in self.get_prices_series(
ticker, time + datetime.timedelta(days=-1), time + datetime.timedelta(days=1)
ticker,
time + timedelta(days=-1),
time + timedelta(days=1),
):
# TODO(blais): This is poorly thought out, the date may not match
# that in the differing timezone. You probably want the last price
Expand All @@ -128,6 +128,6 @@ def get_historical_price(
return None

def get_prices_series(
self, ticker: str, time_begin: datetime.datetime, time_end: datetime.datetime
self, ticker: str, time_begin: datetime, time_end: datetime
) -> List[source.SourcePrice]:
return get_price_series(resolve_currency_id(ticker), time_begin, time_end)
22 changes: 13 additions & 9 deletions beanprice/sources/coincap_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
from unittest import mock
from dateutil import tz

import pytest
import requests

from beanprice import source
from beanprice.sources import coincap

timezone = tz.gettz("Europe/Amsterdam")


response_assets_bitcoin_historical = {
"data": [
{
Expand Down Expand Up @@ -111,34 +109,40 @@ def test_get_latest_price(self):
self.assertIsInstance(srcprice, source.SourcePrice)
self.assertEqual(Decimal("60748.3135183678858890"), srcprice.price)
self.assertEqual(
datetime.datetime(2021, 4, 12).replace(tzinfo=datetime.timezone.utc).date(),
datetime.datetime(2021, 4, 12)
.replace(tzinfo=datetime.timezone.utc)
.date(),
srcprice.time.date(),
)
self.assertEqual("USD", srcprice.quote_currency)

@pytest.mark.skip(reason="Query function should take into account the timezone.")
def test_get_historical_price(self):
with response(content=response_assets_bitcoin_historical):
srcprice = coincap.Source().get_historical_price(
"bitcoin", datetime.datetime(2021, 1, 6)
"bitcoin", datetime.datetime(2021, 1, 6).replace(tzinfo=timezone)
)
self.assertEqual(Decimal("34869.7692419204775049"), srcprice.price)
self.assertEqual(
datetime.datetime(2021, 1, 6).replace(tzinfo=datetime.timezone.utc).date(),
datetime.datetime(2021, 1, 6)
.replace(tzinfo=datetime.timezone.utc)
.date(),
srcprice.time.date(),
)
self.assertEqual("USD", srcprice.quote_currency)

@pytest.mark.skip(reason="Query function should take into account the timezone.")
def test_get_prices_series(self):
with response(content=response_bitcoin_history):
srcprices = coincap.Source().get_prices_series(
"bitcoin", datetime.datetime(2021, 1, 1), datetime.datetime(2021, 3, 20)
"bitcoin",
datetime.datetime(2021, 1, 1).replace(tzinfo=timezone),
datetime.datetime(2021, 3, 20).replace(tzinfo=timezone),
)
self.assertEqual(len(srcprices), 8)
self.assertEqual(Decimal("29232.6707650537687673"), srcprices[0].price)
self.assertEqual(
datetime.datetime(2021, 1, 1).replace(tzinfo=datetime.timezone.utc).date(),
datetime.datetime(2021, 1, 1)
.replace(tzinfo=datetime.timezone.utc)
.date(),
srcprices[0].time.date(),
)
self.assertEqual("USD", srcprices[0].quote_currency)
Expand Down

0 comments on commit 5fee4e5

Please sign in to comment.