Rinominato 'quote_currency' in 'currency' e aggiornato il trattamento del timestamp in Price
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
from datetime import datetime
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ class ProductInfo(BaseModel):
|
|||||||
symbol: str = ""
|
symbol: str = ""
|
||||||
price: float = 0.0
|
price: float = 0.0
|
||||||
volume_24h: float = 0.0
|
volume_24h: float = 0.0
|
||||||
quote_currency: str = ""
|
currency: str = ""
|
||||||
|
|
||||||
class Price(BaseModel):
|
class Price(BaseModel):
|
||||||
"""
|
"""
|
||||||
@@ -22,7 +23,24 @@ class Price(BaseModel):
|
|||||||
open: float = 0.0
|
open: float = 0.0
|
||||||
close: float = 0.0
|
close: float = 0.0
|
||||||
volume: float = 0.0
|
volume: float = 0.0
|
||||||
timestamp_ms: int = 0 # Timestamp in milliseconds
|
timestamp: str = ""
|
||||||
|
"""Timestamp con formato YYYY-MM-DD HH:MM"""
|
||||||
|
|
||||||
|
def set_timestamp(self, timestamp_ms: int | None = None, timestamp_s: int | None = None) -> None:
|
||||||
|
"""
|
||||||
|
Imposta il timestamp in millisecondi.
|
||||||
|
Args:
|
||||||
|
timestamp (int | datetime): Il timestamp in millisecondi o come oggetto datetime.
|
||||||
|
"""
|
||||||
|
if timestamp_ms is not None:
|
||||||
|
timestamp = timestamp_ms // 1000
|
||||||
|
elif timestamp_s is not None:
|
||||||
|
timestamp = timestamp_s
|
||||||
|
else:
|
||||||
|
raise ValueError("Either timestamp_ms or timestamp_s must be provided")
|
||||||
|
assert timestamp > 0, "Invalid timestamp data received"
|
||||||
|
|
||||||
|
self.timestamp = datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M')
|
||||||
|
|
||||||
class MarketWrapper:
|
class MarketWrapper:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -10,17 +10,19 @@ def extract_product(currency: str, ticker_data: dict[str, Any]) -> ProductInfo:
|
|||||||
product.symbol = ticker_data.get('symbol', '').replace(currency, '')
|
product.symbol = ticker_data.get('symbol', '').replace(currency, '')
|
||||||
product.price = float(ticker_data.get('price', 0))
|
product.price = float(ticker_data.get('price', 0))
|
||||||
product.volume_24h = float(ticker_data.get('volume', 0))
|
product.volume_24h = float(ticker_data.get('volume', 0))
|
||||||
product.quote_currency = currency
|
product.currency = currency
|
||||||
return product
|
return product
|
||||||
|
|
||||||
def extract_price(kline_data: list[Any]) -> Price:
|
def extract_price(kline_data: list[Any]) -> Price:
|
||||||
|
timestamp = kline_data[0]
|
||||||
|
|
||||||
price = Price()
|
price = Price()
|
||||||
price.open = float(kline_data[1])
|
price.open = float(kline_data[1])
|
||||||
price.high = float(kline_data[2])
|
price.high = float(kline_data[2])
|
||||||
price.low = float(kline_data[3])
|
price.low = float(kline_data[3])
|
||||||
price.close = float(kline_data[4])
|
price.close = float(kline_data[4])
|
||||||
price.volume = float(kline_data[5])
|
price.volume = float(kline_data[5])
|
||||||
price.timestamp_ms = kline_data[0]
|
price.set_timestamp(timestamp_ms=timestamp)
|
||||||
return price
|
return price
|
||||||
|
|
||||||
class BinanceWrapper(MarketWrapper):
|
class BinanceWrapper(MarketWrapper):
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ def extract_product(product_data: GetProductResponse | Product) -> ProductInfo:
|
|||||||
return product
|
return product
|
||||||
|
|
||||||
def extract_price(candle_data: Candle) -> Price:
|
def extract_price(candle_data: Candle) -> Price:
|
||||||
|
timestamp = int(candle_data.start) if candle_data.start else 0
|
||||||
|
|
||||||
price = Price()
|
price = Price()
|
||||||
price.high = float(candle_data.high) if candle_data.high else 0.0
|
price.high = float(candle_data.high) if candle_data.high else 0.0
|
||||||
price.low = float(candle_data.low) if candle_data.low else 0.0
|
price.low = float(candle_data.low) if candle_data.low else 0.0
|
||||||
price.open = float(candle_data.open) if candle_data.open else 0.0
|
price.open = float(candle_data.open) if candle_data.open else 0.0
|
||||||
price.close = float(candle_data.close) if candle_data.close else 0.0
|
price.close = float(candle_data.close) if candle_data.close else 0.0
|
||||||
price.volume = float(candle_data.volume) if candle_data.volume else 0.0
|
price.volume = float(candle_data.volume) if candle_data.volume else 0.0
|
||||||
price.timestamp_ms = int(candle_data.start) * 1000 if candle_data.start else 0
|
price.set_timestamp(timestamp_s=timestamp)
|
||||||
return price
|
return price
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,15 @@ def extract_product(asset_data: dict[str, Any]) -> ProductInfo:
|
|||||||
return product
|
return product
|
||||||
|
|
||||||
def extract_price(price_data: dict[str, Any]) -> Price:
|
def extract_price(price_data: dict[str, Any]) -> Price:
|
||||||
|
timestamp = price_data.get('time', 0)
|
||||||
|
|
||||||
price = Price()
|
price = Price()
|
||||||
price.high = float(price_data.get('high', 0))
|
price.high = float(price_data.get('high', 0))
|
||||||
price.low = float(price_data.get('low', 0))
|
price.low = float(price_data.get('low', 0))
|
||||||
price.open = float(price_data.get('open', 0))
|
price.open = float(price_data.get('open', 0))
|
||||||
price.close = float(price_data.get('close', 0))
|
price.close = float(price_data.get('close', 0))
|
||||||
price.volume = float(price_data.get('volumeto', 0))
|
price.volume = float(price_data.get('volumeto', 0))
|
||||||
price.timestamp_ms = price_data.get('time', 0) * 1000
|
price.set_timestamp(timestamp_s=timestamp)
|
||||||
assert price.timestamp_ms > 0, "Invalid timestamp data received from CryptoCompare"
|
|
||||||
return price
|
return price
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,20 +12,22 @@ def extract_product(stock_data: dict[str, str]) -> ProductInfo:
|
|||||||
product.symbol = product.id.split('-')[0] # Rimuovi il suffisso della valuta per le crypto
|
product.symbol = product.id.split('-')[0] # Rimuovi il suffisso della valuta per le crypto
|
||||||
product.price = float(stock_data.get('Current Stock Price', f"0.0 USD").split(" ")[0]) # prende solo il numero
|
product.price = float(stock_data.get('Current Stock Price', f"0.0 USD").split(" ")[0]) # prende solo il numero
|
||||||
product.volume_24h = 0.0 # YFinance non fornisce il volume 24h direttamente
|
product.volume_24h = 0.0 # YFinance non fornisce il volume 24h direttamente
|
||||||
product.quote_currency = product.id.split('-')[1] # La valuta è la parte dopo il '-'
|
product.currency = product.id.split('-')[1] # La valuta è la parte dopo il '-'
|
||||||
return product
|
return product
|
||||||
|
|
||||||
def extract_price(hist_data: dict[str, str]) -> Price:
|
def extract_price(hist_data: dict[str, str]) -> Price:
|
||||||
"""
|
"""
|
||||||
Converte i dati storici di YFinanceTools in Price.
|
Converte i dati storici di YFinanceTools in Price.
|
||||||
"""
|
"""
|
||||||
|
timestamp = int(hist_data.get('Timestamp', '0'))
|
||||||
|
|
||||||
price = Price()
|
price = Price()
|
||||||
price.high = float(hist_data.get('High', 0.0))
|
price.high = float(hist_data.get('High', 0.0))
|
||||||
price.low = float(hist_data.get('Low', 0.0))
|
price.low = float(hist_data.get('Low', 0.0))
|
||||||
price.open = float(hist_data.get('Open', 0.0))
|
price.open = float(hist_data.get('Open', 0.0))
|
||||||
price.close = float(hist_data.get('Close', 0.0))
|
price.close = float(hist_data.get('Close', 0.0))
|
||||||
price.volume = float(hist_data.get('Volume', 0.0))
|
price.volume = float(hist_data.get('Volume', 0.0))
|
||||||
price.timestamp_ms = int(hist_data.get('Timestamp', '0'))
|
price.set_timestamp(timestamp_ms=timestamp)
|
||||||
return price
|
return price
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,25 +4,24 @@ from app.base.markets import ProductInfo, Price
|
|||||||
|
|
||||||
def aggregate_history_prices(prices: dict[str, list[Price]]) -> list[Price]:
|
def aggregate_history_prices(prices: dict[str, list[Price]]) -> list[Price]:
|
||||||
"""
|
"""
|
||||||
Aggrega i prezzi storici per symbol calcolando la media oraria.
|
Aggrega i prezzi storici per symbol calcolando la media.
|
||||||
Args:
|
Args:
|
||||||
prices (dict[str, list[Price]]): Mappa provider -> lista di Price
|
prices (dict[str, list[Price]]): Mappa provider -> lista di Price
|
||||||
Returns:
|
Returns:
|
||||||
list[Price]: Lista di Price aggregati per ora
|
list[Price]: Lista di Price aggregati per timestamp
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Costruiamo una mappa timestamp_h -> lista di Price
|
# Costruiamo una mappa timestamp -> lista di Price
|
||||||
timestamped_prices: dict[int, list[Price]] = {}
|
timestamped_prices: dict[str, list[Price]] = {}
|
||||||
for _, price_list in prices.items():
|
for _, price_list in prices.items():
|
||||||
for price in price_list:
|
for price in price_list:
|
||||||
time = price.timestamp_ms - (price.timestamp_ms % 3600000) # arrotonda all'ora (non dovrebbe essere necessario)
|
timestamped_prices.setdefault(price.timestamp, []).append(price)
|
||||||
timestamped_prices.setdefault(time, []).append(price)
|
|
||||||
|
|
||||||
# Ora aggregiamo i prezzi per ogni ora
|
# Ora aggregiamo i prezzi per ogni timestamp
|
||||||
aggregated_prices: list[Price] = []
|
aggregated_prices: list[Price] = []
|
||||||
for time, price_list in timestamped_prices.items():
|
for time, price_list in timestamped_prices.items():
|
||||||
price = Price()
|
price = Price()
|
||||||
price.timestamp_ms = time
|
price.timestamp = time
|
||||||
price.high = statistics.mean([p.high for p in price_list])
|
price.high = statistics.mean([p.high for p in price_list])
|
||||||
price.low = statistics.mean([p.low for p in price_list])
|
price.low = statistics.mean([p.low for p in price_list])
|
||||||
price.open = statistics.mean([p.open for p in price_list])
|
price.open = statistics.mean([p.open for p in price_list])
|
||||||
@@ -53,7 +52,7 @@ def aggregate_product_info(products: dict[str, list[ProductInfo]]) -> list[Produ
|
|||||||
|
|
||||||
product.id = f"{symbol}_AGGREGATED"
|
product.id = f"{symbol}_AGGREGATED"
|
||||||
product.symbol = symbol
|
product.symbol = symbol
|
||||||
product.quote_currency = next(p.quote_currency for p in product_list if p.quote_currency)
|
product.currency = next(p.currency for p in product_list if p.currency)
|
||||||
|
|
||||||
volume_sum = sum(p.volume_24h for p in product_list)
|
volume_sum = sum(p.volume_24h for p in product_list)
|
||||||
product.volume_24h = volume_sum / len(product_list) if product_list else 0.0
|
product.volume_24h = volume_sum / len(product_list) if product_list else 0.0
|
||||||
|
|||||||
@@ -41,10 +41,6 @@ class TestPredictor:
|
|||||||
inputs = self.inputs()
|
inputs = self.inputs()
|
||||||
unified_checks(AppModels.GEMINI, inputs)
|
unified_checks(AppModels.GEMINI, inputs)
|
||||||
|
|
||||||
def test_ollama_qwen_1b_model_output(self):
|
|
||||||
inputs = self.inputs()
|
|
||||||
unified_checks(AppModels.OLLAMA_QWEN_1B, inputs)
|
|
||||||
|
|
||||||
def test_ollama_qwen_4b_model_output(self):
|
def test_ollama_qwen_4b_model_output(self):
|
||||||
inputs = self.inputs()
|
inputs = self.inputs()
|
||||||
unified_checks(AppModels.OLLAMA_QWEN_4B, inputs)
|
unified_checks(AppModels.OLLAMA_QWEN_4B, inputs)
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ class TestBinance:
|
|||||||
assert isinstance(history, list)
|
assert isinstance(history, list)
|
||||||
assert len(history) == 5
|
assert len(history) == 5
|
||||||
for entry in history:
|
for entry in history:
|
||||||
assert hasattr(entry, 'timestamp_ms')
|
assert hasattr(entry, 'timestamp')
|
||||||
assert hasattr(entry, 'close')
|
assert hasattr(entry, 'close')
|
||||||
assert hasattr(entry, 'high')
|
assert hasattr(entry, 'high')
|
||||||
assert entry.close > 0
|
assert entry.close > 0
|
||||||
assert entry.high > 0
|
assert entry.high > 0
|
||||||
assert entry.timestamp_ms > 0
|
assert entry.timestamp != ''
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ class TestCoinBase:
|
|||||||
assert isinstance(history, list)
|
assert isinstance(history, list)
|
||||||
assert len(history) == 5
|
assert len(history) == 5
|
||||||
for entry in history:
|
for entry in history:
|
||||||
assert hasattr(entry, 'timestamp_ms')
|
assert hasattr(entry, 'timestamp')
|
||||||
assert hasattr(entry, 'close')
|
assert hasattr(entry, 'close')
|
||||||
assert hasattr(entry, 'high')
|
assert hasattr(entry, 'high')
|
||||||
assert entry.close > 0
|
assert entry.close > 0
|
||||||
assert entry.high > 0
|
assert entry.high > 0
|
||||||
assert entry.timestamp_ms > 0
|
assert entry.timestamp != ''
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ class TestCryptoCompare:
|
|||||||
assert isinstance(history, list)
|
assert isinstance(history, list)
|
||||||
assert len(history) == 5
|
assert len(history) == 5
|
||||||
for entry in history:
|
for entry in history:
|
||||||
assert hasattr(entry, 'timestamp_ms')
|
assert hasattr(entry, 'timestamp')
|
||||||
assert hasattr(entry, 'close')
|
assert hasattr(entry, 'close')
|
||||||
assert hasattr(entry, 'high')
|
assert hasattr(entry, 'high')
|
||||||
assert entry.close > 0
|
assert entry.close > 0
|
||||||
assert entry.high > 0
|
assert entry.high > 0
|
||||||
assert entry.timestamp_ms > 0
|
assert entry.timestamp != ''
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ class TestYFinance:
|
|||||||
assert isinstance(history, list)
|
assert isinstance(history, list)
|
||||||
assert len(history) == 5
|
assert len(history) == 5
|
||||||
for entry in history:
|
for entry in history:
|
||||||
assert hasattr(entry, 'timestamp_ms')
|
assert hasattr(entry, 'timestamp')
|
||||||
assert hasattr(entry, 'close')
|
assert hasattr(entry, 'close')
|
||||||
assert hasattr(entry, 'high')
|
assert hasattr(entry, 'high')
|
||||||
assert entry.close > 0
|
assert entry.close > 0
|
||||||
assert entry.high > 0
|
assert entry.high > 0
|
||||||
assert entry.timestamp_ms > 0
|
assert entry.timestamp != ''
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from datetime import datetime
|
||||||
from app.base.markets import ProductInfo, Price
|
from app.base.markets import ProductInfo, Price
|
||||||
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
|
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
|
||||||
|
|
||||||
@@ -13,12 +14,12 @@ class TestMarketDataAggregator:
|
|||||||
prod.symbol=symbol
|
prod.symbol=symbol
|
||||||
prod.price=price
|
prod.price=price
|
||||||
prod.volume_24h=volume
|
prod.volume_24h=volume
|
||||||
prod.quote_currency=currency
|
prod.currency=currency
|
||||||
return prod
|
return prod
|
||||||
|
|
||||||
def __price(self, timestamp_ms: int, high: float, low: float, open: float, close: float, volume: float) -> Price:
|
def __price(self, timestamp_s: int, high: float, low: float, open: float, close: float, volume: float) -> Price:
|
||||||
price = Price()
|
price = Price()
|
||||||
price.timestamp_ms = timestamp_ms
|
price.set_timestamp(timestamp_s=timestamp_s)
|
||||||
price.high = high
|
price.high = high
|
||||||
price.low = low
|
price.low = low
|
||||||
price.open = open
|
price.open = open
|
||||||
@@ -43,7 +44,7 @@ class TestMarketDataAggregator:
|
|||||||
avg_weighted_price = (50000.0 * 1000.0 + 50100.0 * 1100.0 + 49900.0 * 900.0) / (1000.0 + 1100.0 + 900.0)
|
avg_weighted_price = (50000.0 * 1000.0 + 50100.0 * 1100.0 + 49900.0 * 900.0) / (1000.0 + 1100.0 + 900.0)
|
||||||
assert info.price == pytest.approx(avg_weighted_price, rel=1e-3) # type: ignore
|
assert info.price == pytest.approx(avg_weighted_price, rel=1e-3) # type: ignore
|
||||||
assert info.volume_24h == pytest.approx(1000.0, rel=1e-3) # type: ignore
|
assert info.volume_24h == pytest.approx(1000.0, rel=1e-3) # type: ignore
|
||||||
assert info.quote_currency == "USD"
|
assert info.currency == "USD"
|
||||||
|
|
||||||
def test_aggregate_product_info_multiple_symbols(self):
|
def test_aggregate_product_info_multiple_symbols(self):
|
||||||
products = {
|
products = {
|
||||||
@@ -67,13 +68,13 @@ class TestMarketDataAggregator:
|
|||||||
avg_weighted_price_btc = (50000.0 * 1000.0 + 50100.0 * 1100.0) / (1000.0 + 1100.0)
|
avg_weighted_price_btc = (50000.0 * 1000.0 + 50100.0 * 1100.0) / (1000.0 + 1100.0)
|
||||||
assert btc_info.price == pytest.approx(avg_weighted_price_btc, rel=1e-3) # type: ignore
|
assert btc_info.price == pytest.approx(avg_weighted_price_btc, rel=1e-3) # type: ignore
|
||||||
assert btc_info.volume_24h == pytest.approx(1050.0, rel=1e-3) # type: ignore
|
assert btc_info.volume_24h == pytest.approx(1050.0, rel=1e-3) # type: ignore
|
||||||
assert btc_info.quote_currency == "USD"
|
assert btc_info.currency == "USD"
|
||||||
|
|
||||||
assert eth_info is not None
|
assert eth_info is not None
|
||||||
avg_weighted_price_eth = (4000.0 * 2000.0 + 4050.0 * 2100.0) / (2000.0 + 2100.0)
|
avg_weighted_price_eth = (4000.0 * 2000.0 + 4050.0 * 2100.0) / (2000.0 + 2100.0)
|
||||||
assert eth_info.price == pytest.approx(avg_weighted_price_eth, rel=1e-3) # type: ignore
|
assert eth_info.price == pytest.approx(avg_weighted_price_eth, rel=1e-3) # type: ignore
|
||||||
assert eth_info.volume_24h == pytest.approx(2050.0, rel=1e-3) # type: ignore
|
assert eth_info.volume_24h == pytest.approx(2050.0, rel=1e-3) # type: ignore
|
||||||
assert eth_info.quote_currency == "USD"
|
assert eth_info.currency == "USD"
|
||||||
|
|
||||||
def test_aggregate_product_info_with_no_data(self):
|
def test_aggregate_product_info_with_no_data(self):
|
||||||
products: dict[str, list[ProductInfo]] = {
|
products: dict[str, list[ProductInfo]] = {
|
||||||
@@ -94,27 +95,36 @@ class TestMarketDataAggregator:
|
|||||||
assert info.symbol == "BTC"
|
assert info.symbol == "BTC"
|
||||||
assert info.price == pytest.approx(50000.0, rel=1e-3) # type: ignore
|
assert info.price == pytest.approx(50000.0, rel=1e-3) # type: ignore
|
||||||
assert info.volume_24h == pytest.approx(1000.0, rel=1e-3) # type: ignore
|
assert info.volume_24h == pytest.approx(1000.0, rel=1e-3) # type: ignore
|
||||||
assert info.quote_currency == "USD"
|
assert info.currency == "USD"
|
||||||
|
|
||||||
def test_aggregate_history_prices(self):
|
def test_aggregate_history_prices(self):
|
||||||
"""Test aggregazione di prezzi storici usando aggregate_history_prices"""
|
"""Test aggregazione di prezzi storici usando aggregate_history_prices"""
|
||||||
|
timestamp_now = datetime.now()
|
||||||
|
timestamp_1h_ago = int(timestamp_now.replace(hour=timestamp_now.hour - 1).timestamp())
|
||||||
|
timestamp_2h_ago = int(timestamp_now.replace(hour=timestamp_now.hour - 2).timestamp())
|
||||||
|
|
||||||
prices = {
|
prices = {
|
||||||
"Provider1": [
|
"Provider1": [
|
||||||
self.__price(1685577600000, 50000.0, 49500.0, 49600.0, 49900.0, 150.0),
|
self.__price(timestamp_1h_ago, 50000.0, 49500.0, 49600.0, 49900.0, 150.0),
|
||||||
self.__price(1685581200000, 50200.0, 49800.0, 50000.0, 50100.0, 200.0),
|
self.__price(timestamp_2h_ago, 50200.0, 49800.0, 50000.0, 50100.0, 200.0),
|
||||||
],
|
],
|
||||||
"Provider2": [
|
"Provider2": [
|
||||||
self.__price(1685577600000, 50100.0, 49600.0, 49700.0, 50000.0, 180.0),
|
self.__price(timestamp_1h_ago, 50100.0, 49600.0, 49700.0, 50000.0, 180.0),
|
||||||
self.__price(1685581200000, 50300.0, 49900.0, 50100.0, 50200.0, 220.0),
|
self.__price(timestamp_2h_ago, 50300.0, 49900.0, 50100.0, 50200.0, 220.0),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
price = Price()
|
||||||
|
price.set_timestamp(timestamp_s=timestamp_1h_ago)
|
||||||
|
timestamp_1h_ago = price.timestamp
|
||||||
|
price.set_timestamp(timestamp_s=timestamp_2h_ago)
|
||||||
|
timestamp_2h_ago = price.timestamp
|
||||||
|
|
||||||
aggregated = aggregate_history_prices(prices)
|
aggregated = aggregate_history_prices(prices)
|
||||||
assert len(aggregated) == 2
|
assert len(aggregated) == 2
|
||||||
assert aggregated[0].timestamp_ms == 1685577600000
|
assert aggregated[0].timestamp == timestamp_1h_ago
|
||||||
assert aggregated[0].high == pytest.approx(50050.0, rel=1e-3) # type: ignore
|
assert aggregated[0].high == pytest.approx(50050.0, rel=1e-3) # type: ignore
|
||||||
assert aggregated[0].low == pytest.approx(49550.0, rel=1e-3) # type: ignore
|
assert aggregated[0].low == pytest.approx(49550.0, rel=1e-3) # type: ignore
|
||||||
assert aggregated[1].timestamp_ms == 1685581200000
|
assert aggregated[1].timestamp == timestamp_2h_ago
|
||||||
assert aggregated[1].high == pytest.approx(50250.0, rel=1e-3) # type: ignore
|
assert aggregated[1].high == pytest.approx(50250.0, rel=1e-3) # type: ignore
|
||||||
assert aggregated[1].low == pytest.approx(49850.0, rel=1e-3) # type: ignore
|
assert aggregated[1].low == pytest.approx(49850.0, rel=1e-3) # type: ignore
|
||||||
|
|||||||
Reference in New Issue
Block a user