Ejemplo n.º 1
0
class InvestMintGateway(gateways.DivGateway):
    """Обновление данных с https://investmint.ru/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        cols_desc = get_col_desc(ticker)
        url = _prepare_url(ticker)

        try:
            html = await parser.get_html(url)
        except description.ParserError:
            return None

        try:
            table_index = _find_table_n(html)
        except description.ParserError:
            return None

        try:
            df = parser.get_df_from_html(html, table_index, cols_desc)
        except description.ParserError:
            return None

        return description.reformat_df_with_cur(df, ticker)
Ejemplo n.º 2
0
class CloseGateway(gateways.DivGateway):
    """Обновление данных с https://закрытияреестров.рф/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        cols_desc = _get_col_desc(ticker)
        base_ticker = ticker[:BASE_TICKER_LENGTH]
        if base_ticker == "RUAL":
            base_ticker = "RUALR"

        url = f"{URL}{base_ticker}"
        try:
            df = await parser.get_df_from_url(url, TABLE_INDEX, cols_desc)
        except description.ParserError:
            return None

        raw_data = df[ticker]
        df[col.CURRENCY] = raw_data.str.slice(-3)
        df[ticker] = raw_data.str.slice(stop=-3).astype(float)
        df = df.dropna()

        return df.sort_index()
Ejemplo n.º 3
0
class BCSGateway(gateways.DivGateway):
    """Обновление данных с https://bcs-express.ru."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        try:
            rows = await _get_rows(ticker)
        except description.ParserError:
            return None

        div_data = [(_parse_date(row), *_parse_div(row)) for row in rows]
        df = pd.DataFrame(data=div_data, columns=[col.DATE, ticker, col.CURRENCY])
        df = df.set_index(col.DATE)
        df = df.groupby(lambda date: date).agg(
            {
                ticker: "sum",
                col.CURRENCY: "last",
            },
        )

        return df.sort_index()
Ejemplo n.º 4
0
class IndexesGateway(gateways.BaseGateway):
    """Котировки различных индексов на MOEX."""

    _logger = adapters.AsyncLogger()

    async def __call__(
        self,
        ticker: str,
        start_date: Optional[str],
        last_date: str,
    ) -> pd.DataFrame:
        """Получение значений индекса на закрытие для диапазона дат."""
        self._logger(f"{ticker}({start_date}, {last_date})")
        json = await aiomoex.get_market_history(
            session=self._session,
            start=start_date,
            end=last_date,
            security=ticker,
            columns=("TRADEDATE", "CLOSE"),
            market="index",
        )
        df = pd.DataFrame(json)
        df.columns = [col.DATE, col.CLOSE]
        df[col.DATE] = pd.to_datetime(df[col.DATE])
        return df.set_index(col.DATE)
Ejemplo n.º 5
0
class SecuritiesGateway(gateways.BaseGateway):
    """Информация о всех торгующихся акциях."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, market: str, board: str) -> pd.DataFrame:
        """Получение списка торгуемых акций с ISIN и размером лота."""
        self._logger("Загрузка данных по торгуемым бумагам")

        columns = (
            "SECID",
            "ISIN",
            "LOTSIZE",
            "SECTYPE",
        )
        json = await aiomoex.get_board_securities(
            self._session,
            market=market,
            board=board,
            columns=columns,
        )
        df = pd.DataFrame(json)
        df.columns = [col.TICKER, col.ISIN, col.LOT_SIZE, col.TICKER_TYPE]

        return df.set_index(col.TICKER)
Ejemplo n.º 6
0
class AliasesGateway(gateways.BaseGateway):
    """Ищет все тикеры с эквивалентным регистрационным номером."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, isin: str) -> List[str]:
        """Ищет все тикеры с эквивалентным ISIN."""
        self._logger(isin)

        json = await aiomoex.find_securities(self._session, isin, columns=("secid", "isin"))
        return [row["secid"] for row in json if row["isin"] == isin]
Ejemplo n.º 7
0
class SmartLabGateway(gateways.DivStatusGateway):
    """Обновление данных с https://www.smart-lab.ru."""

    _logger = adapters.AsyncLogger()

    async def __call__(self) -> pd.DataFrame:
        """Получение ожидаемых дивидендов."""
        self._logger("Загрузка данных")

        cols_desc = get_col_desc()
        df = await parser.get_df_from_url(URL, TABLE_INDEX, cols_desc)
        return df.dropna()
Ejemplo n.º 8
0
class CPIGateway(gateways.BaseGateway):
    """Обновление данных инфляции с https://rosstat.gov.ru."""

    _logger = adapters.AsyncLogger()

    async def __call__(self) -> pd.DataFrame:
        """Получение данных по  инфляции."""
        self._logger("Загрузка инфляции")

        df = await _load_xlsx(self._session)
        _validate(df)
        return _clean_up(df)
Ejemplo n.º 9
0
class EventBus(Generic[EntityType]):
    """Шина для обработки событий."""

    _logger = adapters.AsyncLogger()

    def __init__(
        self,
        uow_factory: Callable[[], UoW[EntityType]],
        event_handler: domain.AbstractHandler[EntityType],
    ):
        """Для работы нужна фабрика транзакций и обработчик событий."""
        self._uow_factory = uow_factory
        self._event_handler = event_handler

    def handle_event(
        self,
        event: domain.AbstractEvent,
    ) -> None:
        """Обработка события."""
        loop = asyncio.get_event_loop()
        loop.run_until_complete(self._handle_event(event))

    async def _handle_event(
        self,
        event: domain.AbstractEvent,
    ) -> None:
        """Асинхронная обработка события и следующих за ним."""
        pending: PendingTasks = self._create_tasks([event])
        while pending:
            done, pending = await asyncio.wait(
                pending, return_when=asyncio.FIRST_COMPLETED)

            for task in done:
                pending |= self._create_tasks(task.result())

    def _create_tasks(self,
                      events: list[domain.AbstractEvent]) -> set[FutureEvent]:
        """Создает задания для событий."""
        return {
            asyncio.create_task(self._handle_one_command(event))
            for event in events
        }

    async def _handle_one_command(
            self, event: domain.AbstractEvent) -> list[domain.AbstractEvent]:
        """Обрабатывает одно событие и помечает его сделанным."""
        self._logger(str(event))

        async with self._uow_factory() as repo:
            return await self._event_handler.handle_event(event, repo)
Ejemplo n.º 10
0
class MOEXStatusGateway(gateways.DivStatusGateway):
    """Данные о закрытии реестров https://www.moex.com.

    Загружаются только данные по иностранным бумагам.
    """

    _logger = adapters.AsyncLogger()

    async def __call__(self) -> pd.DataFrame:
        """Получение ожидаемых дивидендов."""
        self._logger("Загрузка данных")

        cols_desc = get_col_desc()
        df = await parser.get_df_from_url(URL, TABLE_INDEX, cols_desc)
        return df.iloc[df.index.notnull()]
Ejemplo n.º 11
0
class TradingDatesGateway(gateways.BaseGateway):
    """Обновление для таблиц с диапазоном доступных торговых дат."""

    _logger = adapters.AsyncLogger()

    async def __call__(self) -> pd.DataFrame:
        """Получение обновленных данных о доступном диапазоне торговых дат."""
        self._logger("Загрузка данных по торговым дням")
        json = await aiomoex.get_board_dates(
            self._session,
            board="TQBR",
            market="shares",
            engine="stock",
        )
        return pd.DataFrame(json, dtype="datetime64[ns]")
Ejemplo n.º 12
0
class CloseGateway(gateways.DivGateway):
    """Обновление данных с https://закрытияреестров.рф/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        cols_desc = _get_col_desc(ticker)
        base_ticker = ticker[:BASE_TICKER_LENGTH]
        url = f"{URL}{base_ticker}"
        try:
            df = await parser.get_df_from_url(url, TABLE_INDEX, cols_desc)
        except description.ParserError:
            return None

        df[col.CURRENCY] = col.RUR
        return df
Ejemplo n.º 13
0
class FinRangeGateway(gateways.DivGateway):
    """Обновление данных с https://finrange.com/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        url = _prepare_url(ticker)
        html = await _get_page_html(url)
        cols_desc = _get_col_desc(ticker)

        try:
            df = parser.get_df_from_html(html, TABLE_NUM, cols_desc)
        except description.ParserError:
            return None

        return description.reformat_df_with_cur(df, ticker)
Ejemplo n.º 14
0
class DohodGateway(gateways.DivGateway):
    """Обновление данных с https://dohod.ru."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        cols_desc = get_col_desc(ticker)
        url = f"{URL}{ticker.lower()}"
        try:
            df = await parser.get_df_from_url(url, TABLE_INDEX, cols_desc)
        except description.ParserError:
            return None

        df = self._sort_and_agg(df)
        df[col.CURRENCY] = col.RUR
        return df
Ejemplo n.º 15
0
class StreetInsider(gateways.DivGateway):
    """Обновление данных с https://www.streetinsider.com/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        cols_desc = get_col_desc(ticker)
        international_ticker = ticker.lower()[:-3]
        url = f"{URL}{international_ticker}"
        try:
            df = await parser.get_df_from_url(url, TABLE_INDEX, cols_desc)
        except description.ParserError:
            return None

        df = self._sort_and_agg(df)
        df[col.CURRENCY] = col.USD

        return df
Ejemplo n.º 16
0
class NASDAQGateway(gateways.DivGateway):
    """Обновление данных с https://www.nasdaq.com/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        cols_desc = get_col_desc(ticker)

        url = "".join([URL_START, ticker[:-3], URL_END])
        html = await _load_ticker_page(url)
        try:
            df = parser.get_df_from_html(html, 0, cols_desc)
        except description.ParserError:
            return None

        df = df.groupby(lambda date: date).sum()
        df[col.CURRENCY] = col.USD
        return df
Ejemplo n.º 17
0
class USDGateway(gateways.BaseGateway):
    """Курс доллара."""

    _logger = adapters.AsyncLogger()

    async def __call__(
        self,
        start_date: Optional[str],
        last_date: str,
    ) -> pd.DataFrame:
        """Получение значений курса для диапазона дат."""
        self._logger(f"({start_date}, {last_date})")
        json = await aiomoex.get_market_candles(
            self._session,
            "USD000UTSTOM",
            market="selt",
            engine="currency",
            start=start_date,
            end=last_date,
        )

        return _format_candles_df(json)
Ejemplo n.º 18
0
class DividendsGateway(gateways.DivGateway):
    """Обновление данных из базы данных, заполняемой в ручную."""

    _logger = adapters.AsyncLogger()

    def __init__(
        self,
        div_col: collection.Collection = DIV_COL,
    ):
        """Сохраняет коллекцию для доступа к первоисточнику дивидендов."""
        super().__init__()
        self._collection = div_col

    async def __call__(self, ticker: str) -> pd.DataFrame:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        docs_cursor = self._collection.find(
            {"ticker": ticker},
            projection={
                "_id": False,
                "date": True,
                "dividends": True,
                "currency": True
            },
        )
        json = await docs_cursor.to_list(length=None)

        if not json:
            return pd.DataFrame(columns=[ticker, col.CURRENCY])

        df = pd.DataFrame.from_records(json, index="date")
        df.columns = [ticker, col.CURRENCY]

        cur_err = set(df[col.CURRENCY]) - {col.RUR, col.USD}
        if cur_err:
            raise WrongCurrencyError(cur_err)

        return df.sort_index(axis=0)
Ejemplo n.º 19
0
class QuotesGateway(gateways.BaseGateway):
    """Загружает котировки акций."""

    _logger = adapters.AsyncLogger()

    async def __call__(
        self,
        ticker: str,
        market: str,
        start_date: Optional[str],
        last_date: str,
    ) -> pd.DataFrame:
        """Получение котировок акций в формате OCHLV."""
        self._logger(f"{ticker}({start_date}, {last_date})")

        json = await aiomoex.get_market_candles(
            self._session,
            ticker,
            market=market,
            start=start_date,
            end=last_date,
        )

        return _format_candles_df(json)
Ejemplo n.º 20
0
class ConomyGateway(gateways.DivGateway):
    """Обновление для таблиц с дивидендами на https://www.conomy.ru/."""

    _logger = adapters.AsyncLogger()

    async def __call__(self, ticker: str) -> Optional[pd.DataFrame]:
        """Получение дивидендов для заданного тикера."""
        self._logger(ticker)

        try:
            # На некоторых компьютерах/операционных системах Chromium перестает реагировать на команды
            # Поэтому загрузка принудительно приостанавливается
            html = await asyncio.wait_for(_get_html(ticker),
                                          timeout=CHROMIUM_TIMEOUT)
        except (errors.TimeoutError, asyncio.exceptions.TimeoutError):
            return None

        cols_desc = _get_col_desc(ticker)
        df = parser.get_df_from_html(html, TABLE_INDEX, cols_desc)
        df = df.dropna()

        df = self._sort_and_agg(df)
        df[col.CURRENCY] = col.RUR
        return df
Ejemplo n.º 21
0
class TestLog:
    """Тестовый класс для проверки работы логгера."""

    logger = adapters.AsyncLogger()