Есть такой брокер — Тинькофф Банк. И есть проблема в том, что на текущий момент этот брокер не имеет приказов take profit / stop loss. Поэтому, если вы хотите торговать более активно, то вам нужно костылить какое-то временное решение, пока в недрах Тинькоффа программисты разрабатывают киллер фичу take profit/stop loss, и под катом — одно из них.
update: 22.03.2019, Брокер выкатил мажорную версию 3.0.0 в Google Play, в которой take profit/stop loss все-таки появились.

Почему я решил написать эту статью здесь? Мне показалось, что Тинькофф Банк и его продукты довольно популярны среди айтишников, и, возможно, у кого-то есть такая же потребность, а желания или времени городить свой велосипед нет. Поэтому делюсь своим.

Для начала — об альтернативных возможностях, предоставляемых собственно Брокером.
Первое, у Тинькоффа есть лимитные заявки, которые появились в феврале 2019 (два года ждали, без шуток!), но они работают в пределах одного дня и что хуже — в небольшом денежном интервале, что на волатильном рынке создает неудобства. Просто нельзя задать значения меньше (больше) определенного порога, рассчитываемого от текущих котировок. Ну и задать больше одной лимитной заявки, вероятно, нельзя (у меня при попытке сохранить первую заявку мобильное приложение всегда крашится, а на сайте такой функциональности нет).
Второе, внутри их мобильного приложения можно подписаться на изменение цены, установив абсолютный порог или порог на изменение в процентах (на увеличение или уменьшение), но вы можете установить один и только один порог на актив.

Логика моего велосипеда проста:
1) у нас есть thresholds (здесь и далее — пороги) для нашей ценной бумаги (актива), на который у нас должно происходить ручное действие take profit / stop loss. Пороги рассчитываем самостоятельно, исходя из цены покупки актива;
2) мы должны парсить откуда-то данные текущей цены актива;
3) посылать себе извещение, если один из порогов был достигнут.
Несмотря на незамысловатое описание, есть нюансы в реализации :)

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

2) Поскольку моим активом была иностранная ценная бумага, которая торгуется на Санкт-Петербургской бирже, то сначала я решил парсить данные с сайта Санкт-Петербургской биржи, со следующей страницы: spbexchange.ru/ru/market-data/Default.aspx
Сортировка на СПб бирже идёт по объему торгов, и моя ценная бумага всегда находилась по первой странице. Работало замечательно, но 8 марта всё сломалось. Почему-то TSLA оказалась аж на 25-ой странице, а их пагинатор грузит данные динамически через JS. Такую проблему можно решить «в лоб»: парсить все страницы, до тех пор, пока не найдем наш актив. Но такой подход не очень эффективен, если считать время выполнения цикла скрипта. Вместо этого я решил добавить парсинг с tradingview.com. Там не нужно лопатить длинные списки на большем количестве страниц. Там у каждого актива есть примерно такая ссылка:
www.tradingview.com/symbols/NASDAQ-TSLA
Мне казалось, что всё должно завестись быстро и просто, но возникла проблема — интересующие меня данные подгружаются через JS и обычный Requests с этим не справился.
У этой проблемы есть три известных мне решения:
PyQT, selenium (webdriver) и расширение Requests-HTML. Поскольку у меня в проекте уже был Requests, было решено использовать его же расширение.
К сожалению, работало это решение не очень стабильно, пришлось поискать варианты решения.
    session = HTMLSession()
    r = session.get(url)
    my = r.html.render(timeout=30)
    selector = 'span.tv-symbol-header-quote__value.tv-symbol-header-quote__value--large.js-symbol-last'
    price = r.html.find(selector)[0].text
    r.close()
    session.close()

Обратите внимание на timeout, а также вызовы метода close(). Их не во всех примерах можно встретить, но с ними работает лучше, чем без них.

3) Регистрируемся на сервисе, который умеет посылать СМСки (sms.ru), берем их API, создаем ключ. До 5 СМСок в сутки — бесплатно. Мне — достаточно.
Ключ выглядит так:
24A41EA5-EEEE-CCCC-5555-094143C2EDDD
а отправка СМС в первых версиях была реализована вот так:
def send_message(mymessage):
    sms_url = 'https://sms.ru/sms/send?api_id=key&to=number&msg=message&json=1'
    sms_url = sms_url.replace('key', mykey)
    sms_url = sms_url.replace('number', mynumber)
    sms_url = sms_url.replace('message', mymessage)
    sms_response = requests.get(sms_url)


Во время разработки возник следующей вопрос: а что делать, если мы уже послали пользователю СМС о пересечении порога? Пока проверок никаких не было, оно посылало СМС еще раз. Каждый раз. Довольно быстро «съел» бесплатный лимит и стал думать, что с этим делать. Пришлось добавить счетчик отосланных СМС (sms_counter), который мы проверяем перед вызовом send_message.

    global sms_counter
    sms_counter = sms_counter + 1


Прицепом пойдет еще один вопрос: отлично, во время торговой сессии мы обрабатываем одно пересечение порога определенным активом, и нас это устраивает. Что делать к следующей торговой сессии? Было решено обнулять счетчик высланных СМС. Вариантов было три: хранить данные в БД (но у меня, на текущей момент, stateless приложение), парсить время/дату или перезапускать скрипт. Пока что я делаю третий вариант, но в перспективе перейду ко второму или к первому варианту.

Сейчас решение уже работоспособно, и его можно скачать с Гитхаба
Для пользователей, которые не понимают, что такое Python и как его настраивать, предлагаю попробовать запустить упакованное решение для Windows

Планы для дальнейшего развития:
1) парсить дату/время, для обнуления счетчика СМС (вместо перезапуска скрипта);
2) сейчас это stateless приложение, но намереваюсь привинтить БД;
3) после п.2, хочу добавить отслеживание резких скачков увеличение/уменьшение цены, относительно цены закрытия предыдущего дня;
4) расширить «коммуникационные» возможности: больше путей (Telegram, Viber, голосовые звонки, другие варианты) и провайдеров (намерен добавить smsc.ru, так как sms.ru иногда теряет отзывчивость, и, хоть и посылает СМС, но скрипт не выполняется дальше до тех пор, пока мы не получим sms_response).

Комментарии (10)


  1. Milein
    21.03.2019 14:54

    Поэтому, если вы хотите торговать более активно, то вам нужно костылить какое-то временное решение


    Как насчёт того чтобы просто принять волевое решение и уйти к брокеру, у которого есть нормальные терминалы?


    1. Areso Автор
      21.03.2019 15:10

      Со временем, некоторые клиенты так и поступают.
      Учитывая тот невеселый факт, что с Тинькофф Брокера вывести деньги можно только в Тинькофф Банк. А вот далее, у него комиссия при обналички более 150 тысяч рублей.


      1. VGoudkov
        21.03.2019 15:55

        Двухходовка: сначала банковским переводом на счёт «до востребования» в Сбер (правда идти может до трёх дней), потом в офисе сбера снимаем у операциониста со счёта (НЕ с карты) сколько надо. Если это самое надо больше 300-400К — лучше заказать деньги заранее.


      1. Milein
        21.03.2019 16:23

        У меня есть счета у двух наших брокеров, оба можно пополнять банковским переводом (думаю вообще все можно), а за рублёвый перевод тинькофф комиссию не берёт.


  1. fuCtor
    21.03.2019 15:50
    +2

    В последней версии появились, уже можно не костылить так:

    • Стоп-лосс / тейк-профит
    • Стакан (на тарифах Трейдер и Премиум)
    • Несколько уведомлений на цену
    • Аналитика по портфелю
    • Инвестиционное профилирование и обновленный робот-советник

    И даже такое есть www.tinkoff.ru/invest/web-terminal


    1. Areso Автор
      21.03.2019 16:08

      Странно, у меня в Андроид версии все без изменений.


      1. fuCtor
        21.03.2019 16:55

        Вчера выехала, версия 3.0.0


        1. Areso Автор
          21.03.2019 17:03

          Сегодня из Google Play ставил, 2.9.1


          1. fuCtor
            21.03.2019 17:16

            Видимо еще не доехало обновление, сам недавно только обновился.


            1. Areso Автор
              21.03.2019 17:23

              Мне в техподдержке Тинькофф рекомендовали по пятницам проверять багфиксы всех моих сообщений об ошибках. Завтра доедет, наверное)