from abc import ABC, abstractmethod from datetime import datetime from types import ModuleType from dataclasses import dataclass from importlib import import_module from .constant import Interval, Exchange from .object import BarData, TickData from .setting import SETTINGS from .utility import ZoneInfo from .locale import _ DB_TZ = ZoneInfo(SETTINGS["database.timezone"]) def convert_tz(dt: datetime) -> datetime: """ Convert timezone of datetime object to DB_TZ. """ dt = dt.astimezone(DB_TZ) return dt.replace(tzinfo=None) @dataclass class BarOverview: """ Overview of bar data stored in database. """ symbol: str = "" exchange: Exchange | None = None interval: Interval | None = None count: int = 0 start: datetime | None = None end: datetime | None = None @dataclass class TickOverview: """ Overview of tick data stored in database. """ symbol: str = "" exchange: Exchange | None = None count: int = 0 start: datetime | None = None end: datetime | None = None class BaseDatabase(ABC): """ Abstract database class for connecting to different database. """ @abstractmethod def save_bar_data(self, bars: list[BarData], stream: bool = False) -> bool: """ Save bar data into database. """ pass @abstractmethod def save_tick_data(self, ticks: list[TickData], stream: bool = False) -> bool: """ Save tick data into database. """ pass @abstractmethod def load_bar_data( self, symbol: str, exchange: Exchange, interval: Interval, start: datetime, end: datetime ) -> list[BarData]: """ Load bar data from database. """ pass @abstractmethod def load_tick_data( self, symbol: str, exchange: Exchange, start: datetime, end: datetime ) -> list[TickData]: """ Load tick data from database. """ pass @abstractmethod def delete_bar_data( self, symbol: str, exchange: Exchange, interval: Interval ) -> int: """ Delete all bar data with given symbol + exchange + interval. """ pass @abstractmethod def delete_tick_data( self, symbol: str, exchange: Exchange ) -> int: """ Delete all tick data with given symbol + exchange. """ pass @abstractmethod def get_bar_overview(self) -> list[BarOverview]: """ Return bar data avaible in database. """ pass @abstractmethod def get_tick_overview(self) -> list[TickOverview]: """ Return tick data avaible in database. """ pass database: BaseDatabase | None = None def get_database() -> BaseDatabase: """""" # Return database object if already inited global database if database: return database # Read database related global setting database_name: str = SETTINGS["database.name"] module_name: str = f"vnpy_{database_name}" # Try to import database module try: module: ModuleType = import_module(module_name) except ModuleNotFoundError: print(_("找不到数据库驱动{},使用默认的SQLite数据库").format(module_name)) module = import_module("vnpy_sqlite") # Create database object from module database = module.Database() return database