WLM1ke / apimoex

Сlient for MOEX ISS
https://wlm1ke.github.io/apimoex/
The Unlicense
88 stars 26 forks source link

Проверка факта активности торгов на бирже #32

Open AlekseyGur opened 1 year ago

AlekseyGur commented 1 year ago

Добрый день!

Вопрос: как можно проверить факт текущей активности торгов для акций (TQBR) ? Это необходимо, чтобы в ночью/выходные/праздники не делать лишних запросов к бирже.

Смотрю документацию: https://iss.moex.com/iss/reference/28

Подставляю нужное: https://iss.moex.com/iss/engines/stock/markets/shares/boards.xml

Тут есть флаг "is_traded". Это он отвечает за активность? Или путаю его с чем-то?

Пожалуйста, поделитесь, если есть другие решения для проверки активности?

WLM1ke commented 1 year ago

Я проверяю с помощью этого https://iss.moex.com/iss/reference/26

AlekseyGur commented 1 year ago

Я проверяю с помощью этого https://iss.moex.com/iss/reference/26

Но там в "till" показываются дата последней дневной свечи. Например, сейчас 6 июня, а в "till" стоит 5 июня. Из этого не получится понять идут ли торги прямо сейчас, в эту минуту.

http://iss.moex.com/iss/history/engines/stock/markets/shares/boards/TQBR/dates.xml

Есть ли какой способ проверить, что торги идут прямо сейчас?

AlekseyGur commented 1 year ago

Получил ответ на свой вопрос от саппорта моекса (цитата):

Просто следуйте расписанию работы биржи и тогда вам не потребуется делать запросы в те дни и часы, когда она не работает.

Думаю, стоит добавить функцию, которая будет возвращать True/False, если биржа открыта/закрыта. Причём даты работы биржи должны браться с её самой (с учётом праздников/перенесённых и сокращённых дней). Где-то в api я уже видел подобные данные, но не могу найти их сейчас...

UPD. Нашёл: https://iss.moex.com/iss/engines/stock.xml

WLM1ke commented 1 year ago

А для каких целей вам нужно знать идут ли торги сейчас. ISS не предназначен для получения данных в риалтайм. Данные отдаются с задержкой, и если их много раз полить в течении дня вас с высокой вероятностью забанят. Для этого лучше у брокеров канал запрашивать. И эта табличка вам не скажет про торги в субботу из-за переноса рабочих дней, насколько я понимаю

AlekseyGur commented 1 year ago

У некоторых брокеров есть лимит на запросы. И иногда эти лимиты довольно малы, потому что надо как загрузить данные котировок, так и проверить/выставить позиции.

С моекса беру дневные и часовые свечи. Они приходят без задержек. У них только в общем доступе нет свечей на короткие периоды, на последние 15 минут.

P.S. Про граничения. Например, у Тинькоффа ограничение 100 запросов в немонятно сколько минут. И беда со свечами: они открываются/закрываются не в начале/конце периода, а по первому/последнему тику, который может быть непонятно когда. Из-за этого много неудобств.

Пока писать глобальную очередь с задержками для системы торгов не хочу. Легче брать котировки с моекса.

AlekseyGur commented 1 year ago

И эта табличка вам не скажет про торги в субботу из-за переноса рабочих дней, насколько я понимаю

Насколько понимаю, скажет. Например, 5 марта 2022 года (суббота) биржа работала, запись об этом исключении есть:

row date="2022-03-05" is_work_day="1" start_time="06:20:00" stop_time="23:59:59"

Для получения этих данных предлагаю добавить следующий метод в requests:

def get_work_time(
    session: requests.Session,
    engine: str = "stock",
    table: str = "timetable",
):
    """Получить данные по датам активности торговых сессий.

    Описание запроса - https://iss.moex.com/iss/reference/41

    :param session:
        Сессия интернет соединения.
    :param engine:
        Движок - по умолчанию акции.
    :param table:
        Таблица с данными, которую нужно вернуть:
            timetable - флаги активности торгов на рабочую неделю,
            dailytable - исключения из торгов

    :return:
        Список словарей, которые напрямую конвертируется в pandas.DataFrame.
    """
    url = f"https://iss.moex.com/iss/engines/{engine}.json"
    query = _make_query(table=table)
    return _get_short_data(session, url, table, query)

Возможно, не стоит добавлять в систему именно функцию проверки активности торгов. Потому что логично в ней использовать кеширование результата. А все его делают по-разному. Но вот мой вариант реализации без кеширования:

def is_trading_active(
    session: requests.Session,
    engine: str = "stock",
) -> bool:
    """Делает проверку активны ли сейчас торги на бирже.

    :param session:
        Сессия интернет соединения.
    :param engine:
        Движок - по умолчанию акции.

    :return:
        True - торги идут прямо сейчас
        False - торги остановлены
    """

    from datetime import datetime, time
    from zoneinfo import ZoneInfo

    now = datetime.now(ZoneInfo('Europe/Moscow'))
    cur_weekday = now.weekday()+1 # нумерация дней на moex [1..7]
    cur_date = now.strftime("%Y-%m-%d")
    cur_time = now.time()

    # находится ли текущий день в исключениях, идут ли сейчас торги
    wt = get_work_time(session=session, engine=engine, table="dailytable")
    ar_res = [i for i in wt if i['date']==cur_date]

    if ar_res: # попали в исключение
        res = ar_res[-1]

        if not res['is_work_day']:
            return False # торгов сегодня вообще нет
        elif cur_time < time.fromisoformat(res['start_time']):
            return False # торги ещё не начались
        elif cur_time >= time.fromisoformat(res['stop_time']):
            return False # торги уже закончились
        else:
            return True # день-исключение, когда торги идут

    # идут ли торги в текущем дне недели, в текущее время
    wt = get_work_time(session=session, engine=engine, table="timetable")
    res = [i for i in wt if i['week_day']==cur_weekday][-1]

    if not res['is_work_day']:
        return False # торгов сегодня вообще нет
    elif cur_time < time.fromisoformat(res['start_time']):
        return False # торги ещё не начались
    elif cur_time >= time.fromisoformat(res['stop_time']):
        return False # торги уже закончились

    return True # торги идут
WLM1ke commented 1 year ago

Не знаю как сейчас, но раньше последняя свеча была битая - там все равно задержка 15 минут. Ну и проблема в том, что людей реально банили

AlekseyGur commented 1 year ago

раньше последняя свеча была битая - там все равно задержка 15 минут

Интересная информация. Прослежу изменяются ли данные часовых свечей со временем.

Пожалуйста, подскажите, а откуда обычно берете котировки? С какого сервиса?

Сам сейчас качаю с моекса каждый час все 400 акций TQBR, их данные последней свечи (если предыдущая история есть). Раз в день качаю ещё и дневные свечи. Пока что ни разу не схватил бан от моекса, даже если загружаю историю дневных свечей за последние 10 лет по всем инструментам без задержек между запросами внутри инструмента. Поэтому ничего плохого вообще сказать про апи моекса не могу. Очень нравится, ни одного бана не полуил (тьфу-тьфу-тьфу).

А вот от Тинькоффа очень много банов словил. Например, чтобы открыть позицию надо сделать запрос на ордер, стоп лос, проверить портфолио несколько раз (до и после) и т.д. И всё это по каждой позиции. И если позиций штук 10 одновременно надо открыть, то легко лювлю бан. Их лимит непонятно как работает...

WLM1ke commented 1 year ago

Я сам не ловил, но люди ловили

Я торгую на дневках и качаю их раз в день в час ночи по 1000 бумагам с использованием асинхронной версии этой библиотеки - соответсвенно посылаю много конкурентных запросов одновременно

Просто ISS это все-таки не риал-тайм API, по нему нет никаких SLA и закладываться на него опасно