Есть такой брокер — Тинькофф Банк. И есть проблема в том, что на текущий момент этот брокер не имеет приказов 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, было решено использовать его же расширение.
К сожалению, работало это решение не очень стабильно, пришлось поискать варианты решения.
Обратите внимание на timeout, а также вызовы метода close(). Их не во всех примерах можно встретить, но с ними работает лучше, чем без них.
3) Регистрируемся на сервисе, который умеет посылать СМСки (sms.ru), берем их API, создаем ключ. До 5 СМСок в сутки — бесплатно. Мне — достаточно.
Ключ выглядит так:
24A41EA5-EEEE-CCCC-5555-094143C2EDDD
а отправка СМС в первых версиях была реализована вот так:
Во время разработки возник следующей вопрос: а что делать, если мы уже послали пользователю СМС о пересечении порога? Пока проверок никаких не было, оно посылало СМС еще раз. Каждый раз. Довольно быстро «съел» бесплатный лимит и стал думать, что с этим делать. Пришлось добавить счетчик отосланных СМС (sms_counter), который мы проверяем перед вызовом send_message.
Прицепом пойдет еще один вопрос: отлично, во время торговой сессии мы обрабатываем одно пересечение порога определенным активом, и нас это устраивает. Что делать к следующей торговой сессии? Было решено обнулять счетчик высланных СМС. Вариантов было три: хранить данные в БД (но у меня, на текущей момент, stateless приложение), парсить время/дату или перезапускать скрипт. Пока что я делаю третий вариант, но в перспективе перейду ко второму или к первому варианту.
Сейчас решение уже работоспособно, и его можно скачать с Гитхаба
Для пользователей, которые не понимают, что такое Python и как его настраивать, предлагаю попробовать запустить упакованное решение для Windows
Планы для дальнейшего развития:
1) парсить дату/время, для обнуления счетчика СМС (вместо перезапуска скрипта);
2) сейчас это stateless приложение, но намереваюсь привинтить БД;
3) после п.2, хочу добавить отслеживание резких скачков увеличение/уменьшение цены, относительно цены закрытия предыдущего дня;
4) расширить «коммуникационные» возможности: больше путей (Telegram, Viber, голосовые звонки, другие варианты) и провайдеров (намерен добавить smsc.ru, так как sms.ru иногда теряет отзывчивость, и, хоть и посылает СМС, но скрипт не выполняется дальше до тех пор, пока мы не получим sms_response).
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).
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Пользуетесь ли вы Тинькофф Инвестициями?
50.76% Да67
49.24% Нет65
Проголосовали 132 пользователя. Воздержались 19 пользователей.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Если вы пользуетесь Тинькофф Инвестициями, была ли полезна для вас эта статья?
45.16% Да28
54.84% Нет34
Проголосовали 62 пользователя. Воздержались 44 пользователя.