tessa.price.price
Retrieve price information.
1"""Retrieve price information.""" 2 3from __future__ import annotations 4from functools import lru_cache, wraps 5from typing import Union, TYPE_CHECKING 6import pandas as pd 7from . import PriceHistory, PricePoint 8from .. import sources 9 10if TYPE_CHECKING: 11 from .. import SourceType 12 13 14def custom_cache_wrapper(func): 15 """To preserve the function's signature _and_ give access to `cache_clear` etc.""" 16 cached_func = lru_cache(maxsize=None)(func) 17 wrapped_func = wraps(func)(cached_func) 18 return wrapped_func 19 20 21@custom_cache_wrapper 22def price_history( 23 query: str, 24 source: SourceType = "yahoo", 25 currency_preference: str = "USD", 26) -> PriceHistory: 27 """Get price history and return `PriceHistory`, i.e., a tuple of a dataframe with 28 the price history and the effective currency. Note that the effective currency 29 returned might differ from the currency_preference. 30 31 - `query`: A query string that makes sense in combination with the source. E.g., 32 "BTC-USD" for "yahoo" or "bitcoin" for "coingecko". 33 - `source`: The source to query. Defaults to "yahoo". 34 - `currency_preference`: The currency the prices should be returned in; defaults 35 to "USD". The effective currency might differ and will be returned in the second 36 return value. 37 """ 38 src = sources.get_source(source) 39 src.rate_limiter.rate_limit() 40 df, effective_currency = src.get_price_history_bruteforcefully( 41 query, currency_preference 42 ) 43 return PriceHistory(df.copy(), effective_currency.upper()) 44 # (Returning a copy of the dataframe so the cached original is preserved even if it 45 # gets modified by the caller.) 46 47 48def price_point( 49 query: str, 50 when: Union[str, pd.Timestamp], 51 source: SourceType = "yahoo", 52 currency_preference: str = "USD", 53 max_date_deviation_days: Union[int, None] = 10, 54) -> PricePoint: 55 """Return the price at a given point in time given by `when`. Look for the closest 56 point in time if the exact point in time is not found. Returns a `PricePoint`, i.e., 57 a tuple of the price, the effective timestamp of the price, and the currency. 58 59 Raises a `ValueError` if the found date is more than `max_date_deviation_days` from 60 `when`. Use `None` to disable this check. 61 62 Arguments other than `when` are the same as with `price_history`. 63 64 Example call: 65 ``` 66 price_point("AAPL", "2020-01-01") 67 ``` 68 """ 69 df, currency = price_history(query, source, currency_preference) 70 71 when = pd.Timestamp(when) 72 if df.index.tz is not None: # Ensure when matches the timezone of df.index 73 when = when.tz_localize("UTC") if when.tz is None else when.tz_convert("UTC") 74 75 nearest_index = df.index.get_indexer([when], method="nearest")[0] 76 found_date = df.index[nearest_index] 77 78 if ( 79 max_date_deviation_days is not None 80 and abs((found_date - when).days) > max_date_deviation_days 81 ): 82 raise ValueError( 83 f"Found date {found_date} is more than {max_date_deviation_days} days away " 84 f"from requested date {when}" 85 ) 86 87 price = df.iloc[nearest_index] 88 return PricePoint(when=found_date, price=float(price.iloc[0]), currency=currency) 89 90 91def price_point_strict( 92 query: str, 93 when: str, 94 source: SourceType = "yahoo", 95 currency_preference: str = "USD", 96) -> PricePoint: 97 """Same as `price_point` but will raise a `KeyError` if no price is found. This 98 function is offered for backwards compatibility and is largely obsolete with the 99 introduction of `max_date_deviation_days` in `price_point`. 100 """ 101 try: 102 return price_point( 103 query, when, source, currency_preference, max_date_deviation_days=0 104 ) 105 except ValueError as e: 106 raise KeyError(f"No price found for {query} at {when}") from e 107 108 109def price_latest( 110 query: str, 111 source: SourceType = "yahoo", 112 currency_preference: str = "USD", 113) -> PricePoint: 114 """Same as `price_point` but will return the latest price.""" 115 df, currency = price_history(query, source, currency_preference) 116 return PricePoint( 117 when=df.iloc[-1].name, price=float(df.iloc[-1]["close"]), currency=currency 118 )
15def custom_cache_wrapper(func): 16 """To preserve the function's signature _and_ give access to `cache_clear` etc.""" 17 cached_func = lru_cache(maxsize=None)(func) 18 wrapped_func = wraps(func)(cached_func) 19 return wrapped_func
To preserve the function's signature _and_ give access to cache_clear
etc.
22@custom_cache_wrapper 23def price_history( 24 query: str, 25 source: SourceType = "yahoo", 26 currency_preference: str = "USD", 27) -> PriceHistory: 28 """Get price history and return `PriceHistory`, i.e., a tuple of a dataframe with 29 the price history and the effective currency. Note that the effective currency 30 returned might differ from the currency_preference. 31 32 - `query`: A query string that makes sense in combination with the source. E.g., 33 "BTC-USD" for "yahoo" or "bitcoin" for "coingecko". 34 - `source`: The source to query. Defaults to "yahoo". 35 - `currency_preference`: The currency the prices should be returned in; defaults 36 to "USD". The effective currency might differ and will be returned in the second 37 return value. 38 """ 39 src = sources.get_source(source) 40 src.rate_limiter.rate_limit() 41 df, effective_currency = src.get_price_history_bruteforcefully( 42 query, currency_preference 43 ) 44 return PriceHistory(df.copy(), effective_currency.upper()) 45 # (Returning a copy of the dataframe so the cached original is preserved even if it 46 # gets modified by the caller.)
Get price history and return PriceHistory
, i.e., a tuple of a dataframe with
the price history and the effective currency. Note that the effective currency
returned might differ from the currency_preference.
query
: A query string that makes sense in combination with the source. E.g., "BTC-USD" for "yahoo" or "bitcoin" for "coingecko".source
: The source to query. Defaults to "yahoo".currency_preference
: The currency the prices should be returned in; defaults to "USD". The effective currency might differ and will be returned in the second return value.
49def price_point( 50 query: str, 51 when: Union[str, pd.Timestamp], 52 source: SourceType = "yahoo", 53 currency_preference: str = "USD", 54 max_date_deviation_days: Union[int, None] = 10, 55) -> PricePoint: 56 """Return the price at a given point in time given by `when`. Look for the closest 57 point in time if the exact point in time is not found. Returns a `PricePoint`, i.e., 58 a tuple of the price, the effective timestamp of the price, and the currency. 59 60 Raises a `ValueError` if the found date is more than `max_date_deviation_days` from 61 `when`. Use `None` to disable this check. 62 63 Arguments other than `when` are the same as with `price_history`. 64 65 Example call: 66 ``` 67 price_point("AAPL", "2020-01-01") 68 ``` 69 """ 70 df, currency = price_history(query, source, currency_preference) 71 72 when = pd.Timestamp(when) 73 if df.index.tz is not None: # Ensure when matches the timezone of df.index 74 when = when.tz_localize("UTC") if when.tz is None else when.tz_convert("UTC") 75 76 nearest_index = df.index.get_indexer([when], method="nearest")[0] 77 found_date = df.index[nearest_index] 78 79 if ( 80 max_date_deviation_days is not None 81 and abs((found_date - when).days) > max_date_deviation_days 82 ): 83 raise ValueError( 84 f"Found date {found_date} is more than {max_date_deviation_days} days away " 85 f"from requested date {when}" 86 ) 87 88 price = df.iloc[nearest_index] 89 return PricePoint(when=found_date, price=float(price.iloc[0]), currency=currency)
Return the price at a given point in time given by when
. Look for the closest
point in time if the exact point in time is not found. Returns a PricePoint
, i.e.,
a tuple of the price, the effective timestamp of the price, and the currency.
Raises a ValueError
if the found date is more than max_date_deviation_days
from
when
. Use None
to disable this check.
Arguments other than when
are the same as with price_history
.
Example call:
price_point("AAPL", "2020-01-01")
92def price_point_strict( 93 query: str, 94 when: str, 95 source: SourceType = "yahoo", 96 currency_preference: str = "USD", 97) -> PricePoint: 98 """Same as `price_point` but will raise a `KeyError` if no price is found. This 99 function is offered for backwards compatibility and is largely obsolete with the 100 introduction of `max_date_deviation_days` in `price_point`. 101 """ 102 try: 103 return price_point( 104 query, when, source, currency_preference, max_date_deviation_days=0 105 ) 106 except ValueError as e: 107 raise KeyError(f"No price found for {query} at {when}") from e
Same as price_point
but will raise a KeyError
if no price is found. This
function is offered for backwards compatibility and is largely obsolete with the
introduction of max_date_deviation_days
in price_point
.
110def price_latest( 111 query: str, 112 source: SourceType = "yahoo", 113 currency_preference: str = "USD", 114) -> PricePoint: 115 """Same as `price_point` but will return the latest price.""" 116 df, currency = price_history(query, source, currency_preference) 117 return PricePoint( 118 when=df.iloc[-1].name, price=float(df.iloc[-1]["close"]), currency=currency 119 )
Same as price_point
but will return the latest price.