Stage 03.1 - mock exchange integration
This commit is contained in:
1
app/src/integrations/exchange/__init__.py
Normal file
1
app/src/integrations/exchange/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Exchange integration package."""
|
||||
37
app/src/integrations/exchange/mock_data.py
Normal file
37
app/src/integrations/exchange/mock_data.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from src.integrations.exchange.models import BalanceSummary, ExchangeHealth, TickerPrice
|
||||
|
||||
|
||||
def mock_exchange_health() -> ExchangeHealth:
|
||||
return ExchangeHealth(
|
||||
ok=True,
|
||||
mode="mock",
|
||||
message="Биржа работает в mock mode. Реальный API пока не подключен.",
|
||||
)
|
||||
|
||||
|
||||
def mock_ticker_price(symbol: str) -> TickerPrice:
|
||||
symbol = symbol.upper().strip()
|
||||
fake_prices = {
|
||||
"BTCUSDT": 68425.10,
|
||||
"ETHUSDT": 3521.44,
|
||||
"BNBUSDT": 612.33,
|
||||
}
|
||||
price = fake_prices.get(symbol, 100.00)
|
||||
updated_at = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||
return TickerPrice(
|
||||
symbol=symbol,
|
||||
price=price,
|
||||
source="mock",
|
||||
updated_at=updated_at,
|
||||
)
|
||||
|
||||
|
||||
def mock_balance_summary() -> list[BalanceSummary]:
|
||||
return [
|
||||
BalanceSummary(currency="USDT", available=1500.00, locked=0.0, source="mock"),
|
||||
BalanceSummary(currency="BTC", available=0.025, locked=0.0, source="mock"),
|
||||
]
|
||||
26
app/src/integrations/exchange/models.py
Normal file
26
app/src/integrations/exchange/models.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ExchangeHealth:
|
||||
ok: bool
|
||||
mode: str
|
||||
message: str
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class TickerPrice:
|
||||
symbol: str
|
||||
price: float
|
||||
source: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class BalanceSummary:
|
||||
currency: str
|
||||
available: float
|
||||
locked: float
|
||||
source: str
|
||||
38
app/src/integrations/exchange/service.py
Normal file
38
app/src/integrations/exchange/service.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from src.core.config import load_settings
|
||||
from src.integrations.exchange.mock_data import (
|
||||
mock_balance_summary,
|
||||
mock_exchange_health,
|
||||
mock_ticker_price,
|
||||
)
|
||||
from src.integrations.exchange.models import BalanceSummary, ExchangeHealth, TickerPrice
|
||||
|
||||
|
||||
class ExchangeService:
|
||||
def __init__(self) -> None:
|
||||
self.settings = load_settings()
|
||||
|
||||
def get_health(self) -> ExchangeHealth:
|
||||
if not self.settings.exchange_enabled:
|
||||
return mock_exchange_health()
|
||||
|
||||
if not self.settings.exchange_api_key or not self.settings.exchange_api_secret:
|
||||
return ExchangeHealth(
|
||||
ok=False,
|
||||
mode="configured_without_keys",
|
||||
message="Интеграция включена, но API key / secret не заданы.",
|
||||
)
|
||||
|
||||
return ExchangeHealth(
|
||||
ok=False,
|
||||
mode="real_pending",
|
||||
message="Реальный REST client еще не подключен. Пока доступен только mock mode.",
|
||||
)
|
||||
|
||||
def get_price(self, symbol: str | None = None) -> TickerPrice:
|
||||
symbol_to_use = symbol or self.settings.default_symbol
|
||||
return mock_ticker_price(symbol_to_use)
|
||||
|
||||
def get_balance_summary(self) -> list[BalanceSummary]:
|
||||
return mock_balance_summary()
|
||||
Reference in New Issue
Block a user