Ejemplo n.º 1
0
def _validate(df: pd.DataFrame) -> None:
    """Проверка заголовков таблицы."""
    months, _ = df.shape
    first_year = df.columns[0]
    first_month = df.index[0]
    if months != NUM_OF_MONTH:
        raise outer.DataError("Таблица должна содержать 12 строк с месяцами")
    if first_year != FIRST_YEAR:
        raise outer.DataError("Первый год должен быть 1991")
    if first_month != FIRST_MONTH:
        raise outer.DataError("Первый месяц должен быть январь")
Ejemplo n.º 2
0
    async def get(self, table_name: outer.TableName) -> pd.DataFrame:
        """Получение дивидендов для заданного тикера."""
        name = self._log_and_validate_group(table_name, outer.SMART_LAB)
        if name != outer.SMART_LAB:
            raise outer.DataError(
                f"Некорректное имя таблицы для обновления {table_name}")

        cols_desc = get_col_desc()
        df = await parser.get_df_from_url(URL, TABLE_INDEX, cols_desc)
        if FOOTER not in df.index[-1]:
            raise outer.DataError(f"Некорректная html-таблица {table_name}")
        return df.dropna()
Ejemplo n.º 3
0
def _is_common(ticker: str) -> bool:
    """Определяет является ли акция обыкновенной."""
    if len(ticker) == COMMON_TICKER_LENGTH:
        return True
    elif len(ticker) == COMMON_TICKER_LENGTH + 1:
        if ticker[COMMON_TICKER_LENGTH] == PREFERRED_TICKER_ENDING:
            return False
    raise outer.DataError(f"Некорректный тикер {ticker}")
Ejemplo n.º 4
0
def _get_table_from_html(html: str, table_num: int) -> str:
    """Выбирает таблицу по номеру из html-страницы."""
    soup = bs4.BeautifulSoup(html, "lxml")
    try:
        table = soup.find_all("table")[table_num]
    except IndexError:
        raise outer.DataError(f"На странице нет таблицы {table_num}")
    return f"<html>{table}</html>"
Ejemplo n.º 5
0
async def _get_html(url: str) -> str:
    """Загружает html-код страницы."""
    session = resources.get_aiohttp_session()
    async with session.get(url) as respond:
        try:
            respond.raise_for_status()
        except aiohttp.ClientResponseError:
            raise outer.DataError(f"Данные {url} не загружены")
        return await respond.text()
Ejemplo n.º 6
0
    async def get(self, table_name: outer.TableName) -> pd.DataFrame:
        """Получение данных по  инфляции."""
        name = self._log_and_validate_group(table_name, outer.CPI)
        if name != outer.CPI:
            raise outer.DataError(
                f"Некорректное имя таблицы для обновления {table_name}")

        df = await _load_xlsx()
        _validate(df)
        return _clean_up(df)
Ejemplo n.º 7
0
def _validate_header(columns: pd.Index, cols_desc: Descriptions) -> None:
    """Проверяет, что заголовки соответствуют описанию."""
    for desc in cols_desc:
        header = columns[desc.num]
        if not isinstance(header, tuple):
            header = [header]
        raw_name = desc.raw_name
        if all(part in name for part, name in zip(raw_name, header)):
            continue
        raise outer.DataError(
            f"Неверный заголовок: {desc.raw_name} не входит в {header}")
Ejemplo n.º 8
0
 def _log_and_validate_group(
     self,
     table_name: outer.TableName,
     loader_group: outer.GroupName,
 ) -> str:
     """Проверка корректности таблицы и логирование начала загрузки."""
     group, name = table_name
     if group != loader_group:
         raise outer.DataError(
             f"Некорректное имя таблицы для обновления {table_name}")
     self._logger.info(f"Загрузка {table_name}")
     return name
Ejemplo n.º 9
0
 async def handle_event(
     self,
     queue: EventsQueue,
     table: Optional[model.Table],
 ) -> None:
     """Узнает окончание рабочего дня и запрашивает обновление."""
     if table is None:
         raise outer.DataError("Нужна таблица")
     end_of_trading_day = services.trading_day_potential_end()
     await table.update(end_of_trading_day)
     end_of_trading_day = services.trading_day_real_end(table.df)
     await queue.put(UpdateTable(self._table_name, end_of_trading_day))
Ejemplo n.º 10
0
def _validate_data(validate: bool, df_old: pd.DataFrame,
                   df_new: pd.DataFrame) -> None:
    """Проверка совпадения данных для старых значений индекса."""
    if not validate:
        return
    if df_old is None:
        return

    df_new_val = df_new.reindex(df_old.index)
    try:
        pd.testing.assert_frame_equal(df_new_val, df_old)
    except AssertionError:
        raise outer.DataError("Новые данные не соответствуют старым")
Ejemplo n.º 11
0
    async def handle_event(
        self,
        queue: EventsQueue,
        table: Optional[model.Table],
    ) -> None:
        """Обновляет таблицу и публикует результат.

        При отсутствии даты принудительно, а при наличии с учетом необходимости.
        """
        if table is None:
            raise outer.DataError("Нужна таблица")
        await table.update(self._end_of_trading_day)
        await queue.put(Result(table.name, table.df))
Ejemplo n.º 12
0
async def _dispatch_event(
    db_session: outer.AbstractDBSession,
    events_queue: events.EventsQueue,
) -> Optional[Tuple[outer.TableName, pd.DataFrame]]:
    """Выбирает способ обработки события."""
    event = await events_queue.get()
    named_df = None
    if isinstance(event, events.Result):
        events_queue.task_done()
        named_df = (event.name, event.df)
    elif isinstance(event, events.Command):
        asyncio.create_task(
            _handle_one_command(db_session, events_queue, event))
    else:
        raise outer.DataError("Неизвестный тип события")

    return named_df
Ejemplo n.º 13
0
    async def get(self, table_name: outer.TableName) -> pd.DataFrame:
        """Получение списка торгуемых акций с регистрационным номером и размером лота."""
        name = self._log_and_validate_group(table_name, outer.SECURITIES)
        if name != outer.SECURITIES:
            raise outer.DataError(
                f"Некорректное имя таблицы для обновления {table_name}")

        async with self._cache_lock:
            if self._securities_cache is not None:
                self._logger.info(f"Загрузка из кэша {table_name}")
                return self._securities_cache

            columns = ("SECID", "REGNUMBER", "LOTSIZE")
            http_session = resources.get_aiohttp_session()
            json = await aiomoex.get_board_securities(http_session,
                                                      columns=columns)
            df = pd.DataFrame(json)
            df.columns = [col.TICKER, col.REG_NUMBER, col.LOT_SIZE]
            self._securities_cache = df.set_index(col.TICKER)

            return self._securities_cache
Ejemplo n.º 14
0
 async def get(
     self,
     table_name: outer.TableName,
     last_index: Optional[str] = None,
 ) -> pd.DataFrame:
     """Получение цен закрытия индекса MCFTRR."""
     name = self._log_and_validate_group(table_name, outer.INDEX)
     if name != outer.INDEX:
         raise outer.DataError(
             f"Некорректное имя таблицы для обновления {table_name}")
     http_session = resources.get_aiohttp_session()
     json = await aiomoex.get_board_history(
         session=http_session,
         start=last_index,
         security=outer.INDEX,
         columns=("TRADEDATE", "CLOSE"),
         board="RTSI",
         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.º 15
0
def convent_to_tuple(table: model.Table) -> outer.TableTuple:
    """Конвертирует таблицу в кортеж."""
    group, name = table.name
    if (timestamp := table.timestamp) is None:
        raise outer.DataError(
            f"Попытка сериализации пустой таблицы {table.name}")
Ejemplo n.º 16
0
def _check_index(check: IndexChecks, index: pd.Index) -> None:
    """Проверка свойств индекса."""
    if check & IndexChecks.UNIQUE and not index.is_unique:
        raise outer.DataError("Индекс не уникален")
    if check & IndexChecks.ASCENDING and not index.is_monotonic_increasing:
        raise outer.DataError("Индекс не возрастает")
Ejemplo n.º 17
0
                          header=3,
                          skiprows=[4],
                          skipfooter=3,
                          index_col=0)
NUM_OF_MONTH = 12
FIRST_YEAR = 1991
FIRST_MONTH = "январь"


async def _get_xlsx_url(session: aiohttp.ClientSession) -> str:
    """Получить url для файла с инфляцией."""
    async with session.get(URL) as resp:
        html = await resp.text()
    if match := re.search(FILE_PATTERN, html):
        return match.group(0)
    raise outer.DataError("На странице отсутствует URL файла с инфляцией")


async def _load_xlsx() -> pd.DataFrame:
    """Загрузка Excel-файла с данными по инфляции."""
    session = resources.get_aiohttp_session()
    file_url = await _get_xlsx_url(session)
    async with session.get(file_url) as resp:
        xls_file = await resp.read()
    return pd.read_excel(xls_file, **PARSING_PARAMETERS)


def _validate(df: pd.DataFrame) -> None:
    """Проверка заголовков таблицы."""
    months, _ = df.shape
    first_year = df.columns[0]