empenoso

empenoso

Пишу про автоматизацию и инвестиции. IT разработчик, канд. техн. наук. Сайт-визитка: https://shardin.name/?utm_source=pikabu
Пикабушник
поставил 88 плюсов и 7 минусов
отредактировал 0 постов
проголосовал за 0 редактирований
1259 рейтинг 16 подписчиков 28 подписок 12 постов 4 в горячем

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома

Во многих современных домах подъездное освещение часто включает в себя два контура: тусклое освещение вечером и яркое днём. Но мой многоквартирный дом не настолько современный и в подъезде для освещения использовались обычные лампы с патроном e27. Они всегда горят настолько ярко, насколько мощная в них установлена лампа, а включаются по датчику движения, установленном на месте обычного выключателя.

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Подъезд немного похож на этот по планировке

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

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Фото из интернета до и после монтажа кабельного канала

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

Мне же хотелось иметь яркое освещение в подъезде на первом этаже вместо полумрака и в итоге после нескольких покупок смог найти два датчика, которые полностью обесточивают любую светодиодную лампу:

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

По времени это заняло около двух месяцев: от первого вкручивания светодиодной лампы, до их возвращения обратно. Но это не решало проблему двух контуров освещения: тусклого вечером и яркого днём.

Два контура освещения: тусклое вечером и яркое днём

В октябре 2024 года захотелось организовать два контура освещения только на своём этаже, без первого этажа. Но и здесь были некоторые проблемы: изначально хотел установить для тусклого вечернего освещения отдельные светильники, но у нас на этаже всего три квартиры и тамбур полностью выложен плиткой. Если устанавливать дополнительные светильники, то надо:

  1. Разработать новые проект освещения, наметить места где будут установлены светильники.

  2. Демонтировать плитки и потолок, которую жильцы когда-то установили.

  3. Штробить стены под новую проводку.

  4. Делать новую проводку.

  5. Укладывать новую плитку.

  6. Делать потолок.

По моим прикидкам это и получается 200 т.р. вынесенные в заголовок. Кроме того, это грязно и довольно шумно (особенно демонтаж), а ещё придётся выбирать цвета, размеры новых плиток.

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Фото из интернета - тамбур на несколько квартир

К тому же не факт, что оставшиеся квартиры тоже хотят переложить плитки и потратить больше 50 тысяч просто на то чтобы 5 секунд пока они идут от лифта до двери квартиры смотреть на новые стены...

Технические решения двух контуров освещения для подъезда - тусклое вечером и яркое днём

Тогда я стал думать как использовать разные светильники для двух контуров освещения для подъезда - тусклого вечером и яркого днём, то особо ничего не смог придумать. Думал заменить светильники на другие, но тогда бы тоже пришлось переделывать как минимум потолок.

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Арматура светильника в подъезде очень похожа на вот такую

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

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Арматура светильника в тамбуре очень похожа на вот такую

ESP8266 с встроенным Wi-Fi модулем

Подумал что можно использовать этот микроконтроллер чтобы прямо на нём реализовать логику: после заката светить тускло, а после восхода до заката - ярко. Никакой централизованный контроллер при этом не нужен. Осталось подобрать только подходящую лампу. И написать прошивку с этими правилами.

ESP8266 - это серия недорогих микроконтроллеров с встроенным Wi-Fi модулем, разработанных компанией Espressif Systems. Эти устройства широко используются для создания IoT-приложений (Интернет вещей), включая проекты в области умного дома. Основная особенность ESP8266 заключается в том, что он позволяет подключать различные датчики, исполнительные механизмы и другие электронные компоненты к сети Интернет через Wi-Fi, обеспечивая удаленное управление и мониторинг устройств.

Раньше я сталкивался с лампами с на ESP8266, например Sonoff B1, у этой лампы можно было получить доступ к контактам, очистить память и загрузить Open source firmware for ESP devices Tasmota или же использовать другую прошивку ESPHome для лёгкой интеграции с Home Assistant.

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

serial pins (3V3, RX, TX, GND)

Проблемой стало то, что модели B1 не было в продаже на сайте SONOFF, а была только новая модель B02-BL/B05-BL, но этой новой модели не было в списке совместимых с Tasmota. Поэтому не стал покупать даже на тест.

Очень многие лампы, которые были в списке совместимости templates.blakadder.com отсутствовали в продаже - ссылка вела в никуда.

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Единственной моделью рабочей моделью на ESP8266 оказалась лампа от Tuya, но чтобы заставить её заработать с Tasmota или ESPHome требовалась серьезная перепайка - на что мне не хотелось тратить время.

Zigbee

Изначально я был скептически настроен относительно использования Zigbee. Хотя у меня развернут Zigbee2MQTT на Home Assistant, но я не хотел чтобы подъездная лампа зависела от моей домашней автоматизации. К тому же логику тусклого и яркого света придется реализовывать именно на сервере, а потом отправлять на лампу, которая к тому же будет то в сети, то не в сети - ведь датчик движения разрывает фазу, питающую лампы.

Zigbee и Wi-Fi - это два разных протокола беспроводной связи, каждый из которых имеет свои особенности, преимущества и недостатки.

Я уже много лет использую Home Assistant, а до этого использовал openHAB.

Сначала я стал смотреть совместимые лампы в базе zigbee.blakadder.com, на 5 ноября она содержала 2 669 устройства, но все ссылки которые я находил на алиэкспресс стоили больше тысячи рублей - около 1,2 т.р. и выше, а я думал уложиться до тысячи за лампу. Всё таки лампы для подъезда.

Стал смотреть на озоне. Самые дешевые Zigbee лампы имели не очень хорошие отзывы. Решил купить для теста одну лампу чуть дороже - примерно за 700 рублей - это всё равно в три раза дешевле чем лампа Aqara Light Bulb T1, пару штук которых я использую в бра, но они для подъезда не подходили - во первых дорогие, а во вторых в них был функционал который в подъезде мне не нужен.

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Не самые дешевые "KOJIMA" или Tuya TS0505B_1

Когда Умная светодиодная лампочка Е27 RGB Zigbee, Яндекс Алисой, Google Home, Марусей, Smart Bulb 10W KOJIMA пришла, я сразу подключил её к Zigbee2MQTT и обнаружил что это Tuya TS0505B_1. К тому же я понял список совместимых устройств гораздо шире на самом zigbee2mqtt.io - там заявлено 3 900 устройств. Лампа KOJIMA (Tuya TS0505B_1) имеет вот такие свойства:

{
"brightness": 254,
"color": {
"h": 200,
"hue": 200,
"s": 6,
"saturation": 6,
"x": 0,
"y": 0
},
"color_mode": "color_temp",
"color_power_on_behavior": "previous",
"color_temp": 153,
"do_not_disturb": false,
"linkquality": 98,
"state": "ON"
}

Эти JSON данные содержат ключевые свойства, описывающие текущее состояние и конфигурацию лампы, подключенной по Zigbee, в настройке Zigbee2MQTT и Home Assistant.
Вот описание каждого свойства:

1. brightness

  • Значение: 254

  • Описание: это свойство представляет уровень яркости лампы, масштабируемый от 0 (выкл.) до 254 (максимальная яркость). В этом случае лампа находится на максимальной яркости.

2. color

Этот объект содержит различные атрибуты, определяющие цвет лампы в нескольких форматах. Однако будут применяться только определенные форматы на основе color_mode.

  • hue (h): 200

  • Описание: это значение определяет оттенок цвета в цветовой модели HS (Hue-Saturation), где 0-360 представляет градусы на цветовом круге (например, красный на 0, зеленый на 120 и синий на 240). Здесь 200 соответствует синему оттенку.

  • saturation (s): 6

  • Описание: насыщенность варьируется от 0 (нет цвета, оттенки серого) до 100 (полная интенсивность цвета). Если saturation установлена на 6, цвет выглядит почти ненасыщенным, близким к белому или серому.

  • x и y: 0

  • Описание: значения x и y определяют цвет в цветовой модели XY, обычно используемой лампами ZigBee для представления цветов в цветовом пространстве CIE 1931. Здесь оба установлены на 0, что необычно, так как типичные значения белого составляют около [0,3127, 0,329]. Это может означать, что xy_color либо не используется, либо установлен по умолчанию из-за активного цветового режима.

3. color_mode

  • Значение: "color_temp"

  • Описание: Это значение определяет, какую цветовую модель в данный момент использует лампа. В этом случае color_temp указывает, что лампа управляется ее цветовой температурой, а не цветовой моделью (например, xy или hs). Это означает, что значение color_temp имеет приоритет, а настройки в других цветовых форматах (hs или xy) не будут применяться.

4. color_power_on_behavior

  • Значение: "previous"

  • Описание: Это свойство определяет, как лампа ведет себя после включения. "previous" означает, что она вернется в свое последнее известное состояние перед выключением. Другие потенциальные настройки могут определять, будет ли она запускаться в состоянии по умолчанию или выключена, обеспечивая гибкость в поведении при восстановлении питания.

5. color_temp

  • Значение: 153

  • Описание: Цветовая температура измеряется в майредах (обратная цветовая температура в градусах Кельвина) и обычно находится в диапазоне от 153 (холодный белый, около 6500 К) до 500 (теплый белый, около 2000 К). Здесь 153 представляет очень холодный, похожий на дневной белый цвет.

6. do_not_disturb

  • Значение: false

  • Описание: этот параметр можно настроить для предотвращения определенных действий (например, мигания или выключения) на основе взаимодействия лампы с другими устройствами. Если установлено значение true, он ограничивает уведомления или действия, которые могут помешать работе пользователя. Здесь установлено значение false, что позволяет работать в обычном режиме.

7. linkquality

  • Значение: 98

  • Описание: Качество связи — это показатель, указывающий силу сигнала или качество соединения между лампой и координатором или маршрутизатором ZigBee. Значение обычно находится в диапазоне от 0 до 255, причем более высокие числа указывают на лучший сигнал. Качество связи 98 указывает на умеренно сильное соединение, но не на верхнюю границу диапазона.

8. state

  • Значение: "ON"

  • Описание: Это указывает на состояние питания лампы. "ON" подтверждает, что лампа активно включена и работает.

Настройки Home Assistant

Home Assistant - решение для локального умного дома. Внутри этой платформы легко совмещать совершенно разные протоколы и производителей и управлять всем парком устройств по единым правилам.

Изначально, раз лампы будут полностью обесточиваться и появляться в сети я хотел использовать параметр доступности availability в Zigbee2MQTT и при каждом их появлении в сети задавать нужные мне параметры освещения. Задал параметры, действовал по инструкции и ... ничего не происходило:

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

Это немного меня опечалило, но тогда решил принудительно каждые 59 секунд задавать параметры освещение:

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

В текстовом виде автоматизация выглядит вот так:

alias: Тамбур лампы
description: ""
triggers:
- trigger: mqtt
topic: zigbee2mqtt/Тамбур лампа (ближе к ХХХХ)/availability
payload: true
enabled: false
- trigger: time_pattern
seconds: "59"
conditions: []
actions:
- if:
- condition: sun
before: sunset
after: sunrise
then:
- action: light.turn_on
metadata: {}
data:
brightness: 255
color_temp: 153
target:
device_id:
- 3593e2beeXXXXXX82ddda6e461a23105
- c5c0efa006XXXXX75b73a28b16057f85
- 46e690f49bXXXXXXXb77477270ab9587
- 45235336bXXXXXXXX51a2d9207498c0e
else:
- action: light.turn_on
metadata: {}
data:
brightness: 30
color_temp: 500
target:
device_id:
- 3593e2beeXXXXXX82ddda6e461a23105
- c5c0efa006XXXXX75b73a28b16057f85
- 46e690f49bXXXXXXXb77477270ab9587
- 45235336bXXXXXXXX51a2d9207498c0e
mode: single

Чтобы не забивать историю и журнал событий ненужной информацией полностью исключил эти лампы и автоматизацию из записи:

Как я захотел переделать освещение в подъезде на два контура (тусклый и яркий) и сэкономил 200 т.р. за счёт использования умного дома Технологии, Инновации, Длиннопост

В текстовом виде:

####################################################
# #
# Не захламлять историю #
# #
####################################################

recorder:
exclude:
entity_globs:
- light.tambur_lampa_*
- switch.tambur_lampa_*

logbook:
exclude:
entity_globs:
- light.tambur_lampa_*
- switch.tambur_lampa_*
entities:
- automation.nspanel_configuration
- automation.tambur_lampy
- sensor.date_time_iso
- sensor.date_and_time

Итоги

В итоге добился своего - теперь подъездное освещение на этаже включает в себя два контура: тусклое освещение вечером и яркое днём. И для этого не пришлось менять проводку.

Жаль что не удалось найти лампы на ESP8266 - мне кажется такое решение было бы более автономным чем Zigbee лампы. Зато Zigbee лампы обошлись примерно 700 рублей за штуку.

Автор: Михаил Шардин

7 ноября 2024 г.

Показать полностью 11

Тестирование торгового робота на Московской бирже в режиме «песочницы»

Перед тем как использовать торгового робота на живых деньгах хочется всё протестировать на демо-счете (или «песочнице»). Это когда программные ошибки не имеет особой стоимости.

Тестирование торгового робота на Московской бирже в режиме «песочницы» Финансы, Технологии, Программирование, Длиннопост

Операция продажи через OrdersService/PostOrder

Я планирую использовать робота на Московской бирже, через АПИ одного из брокеров. Чтобы частному инвестору начать торговать на бирже нужен брокерский счет. Однако минимальное число российских брокеров имеют свои API (на текущий момент я знаю только ФИНАМ, Алор, Тинькофф Инвестиции). По субъективным причинам я выбрал работать с T‑Bank Invest API (это бывший Тинькофф) через среду выполнения JavaScript Node.JS.

В статье разбираюсь как используя песочницу:

  1. Открыть счёт.

  2. Пополнить баланс счёта рублями через специальный запрос.

  3. Посмотреть все свои открытые счета в песочнице.

  4. Купить 1 акцию.

  5. Продать 1 акцию.

  6. Получить все открытые позиции указанного счёта.

  7. Закрыть счёт.

SilverFir-TradingBot\src\sandbox.js

Этот код Node.js взаимодействует с API Tinkoff Invest, позволяя имитировать торговые операции на виртуальном счете, что позволяет протестировать некоторые функции API в ручном режиме. Вот что делает этот код:

1. Импорт модулей

  • secrets: импортирует ключи доступа и идентификаторы из внешнего файла конфигурации (secrets), что помогает защитить конфиденциальную информацию.

  • logger: импортирует модуль ведения журнала, который записывает журналы в файл или консоль. Это важно для отслеживания активности бота и отладки.

  • logFunctionName: импортирует утилиту для получения имен функций, что упрощает ведение журнала текущего контекста функции.

  • TinkoffClient: импортирует клиентский модуль для взаимодействия с API Tinkoff Invest. Этот клиент обрабатывает запросы к API.

2. Настройка клиента

  • API_TOKEN: получает токен API (в режиме песочницы) из внешнего файла конфигурации (secrets) для аутентификации.

  • tinkoffClient: создает экземпляр TinkoffClient с токеном песочницы, настраивая связь API для среды песочницы.

3. Функции песочницы

  • sandboxAccount(): это основная функция, демонстрирующая различные операции с учетной записью песочницы, с несколькими действиями, которые в настоящее время закомментированы.

  • logFunctionName(): регистрирует имя функции в консоли, что полезно для отслеживания в сложных приложениях.

  • GetSandboxAccounts: получает все открытые позиции указанного счёта.

Закомментированные операции:

  • OpenSandboxAccount: регистрирует новый счет в песочнице, что позволит начать тестирование заново.

  • SandboxPayIn: зачисляет средства на счет в песочнице в российских рублях (RUB). Здесь указанная сумма составляет 30 000 руб.

  • CloseSandboxAccount: закрывает указанный счет в песочнице, используя его accountId, что позволяет выполнить сброс после тестирования.

  • GetSandboxPositions: извлекает и регистрирует все открытые позиции для указанного идентификатора счета.

  • placeMarketOrder: отправляет рыночные ордера на покупку и продажу указанного инструмента (здесь BBG004730N88). Это позволит протестировать функциональность размещения ордеров в песочнице.

Ошибки

  • sandboxAccount().catch(logger.error): запускает sandboxAccount асинхронно и регистрирует любые обнаруженные ошибки.

Эта структура кода демонстрирует, как взаимодействовать с виртуальным торговым счетом в API Тинькофф. Закомментированные блоки кода указывают на дополнительные функции, которые можно активировать при необходимости, такие как открытие, пополнение и закрытие счетов песочницы, а также размещение ордеров на покупку/продажу.

Тестирование торгового робота на Московской бирже в режиме «песочницы» Финансы, Технологии, Программирование, Длиннопост

Запрос SandboxService/GetSandboxAccounts

// Импорт необходимых модулей
const secrets = require('../config/secrets'); // Ключи доступа и идентификаторы

const logger = require('./services/logService'); // Логирование в файл и консоль
const logFunctionName = require('./services/logFunctionName'); // Получение имени функции

const TinkoffClient = require('./grpc/tinkoffClient'); // модуль для взаимодействия с API Tinkoff Invest
const API_TOKEN = secrets.TbankSandboxMode;
const tinkoffClient = new TinkoffClient(API_TOKEN);


async function sandboxAccount() {
// https://tinkoff.github.io/investAPI/swagger-ui/#/SandboxServ...
logger.info(`Запуск функции ${JSON.stringify(logFunctionName())}\n`);

// // Регистрации счёта в песочнице
// const OpenSandboxAccount = await tinkoffClient.callApi('SandboxService/OpenSandboxAccount');
// logger.info(`Регистрации счёта в песочнице:\n ${JSON.stringify(OpenSandboxAccount, null, '\t')}\n\n`);

// // Пополнение баланса счёта песочницы
// const RUB = {
// "accountId": secrets.AccountID,
// "amount": {
// "nano": 0, // Дробная часть отсутствует
// "currency": "RUB",
// "units": 30000, // Сумма в рублях
// }
// };
// const SandboxPayIn = await tinkoffClient.callApi('SandboxService/SandboxPayIn', RUB);
// logger.info(`Пополнение баланса счёта песочницы:\n ${JSON.stringify(SandboxPayIn, null, '\t')}\n\n`);

// // Закрытие счёта в песочнице
// const accountId = {
// "accountId": secrets.AccountID
// };
// const CloseSandboxAccount = await tinkoffClient.callApi('SandboxService/CloseSandboxAccount', accountId);
// logger.info(`Закрытие счёта в песочнице:\n ${JSON.stringify(CloseSandboxAccount, null, '\t')}\n\n`);

// Посмотреть счета в песочнице
const GetSandboxAccounts = await tinkoffClient.callApi('SandboxService/GetSandboxAccounts');
logger.info(`Список счетов в песочнице:\n ${JSON.stringify(GetSandboxAccounts, null, '\t')}\n\n`);

// // Получить все открытые позиции указанного счёта
// const accountId = {
// "accountId": secrets.AccountID
// };
// const GetSandboxPositions = await tinkoffClient.callApi('OperationsService/GetPositions', accountId);
// logger.info(`Все открытые позиции счёта ${secrets.AccountID}:\n ${JSON.stringify(GetSandboxPositions, null, '\t')}\n\n`);

// // Функция для отправки рыночного ордера
// tinkoffClient.placeMarketOrder('BBG004730N88', 1, 'ORDER_DIRECTION_BUY'); // Купить 1 акцию
// tinkoffClient.placeMarketOrder('BBG004730N88', 1, 'ORDER_DIRECTION_SELL'); // Продать 1 акцию
}

// ======================================================================================
// ============ Запуск функций ===================================================
// ======================================================================================

sandboxAccount().catch(logger.error);

Быстройдействие

Я не ждал какого-то особо быстродействия. Для человека это очень быстро, но вот для робота это медленно. Это придётся учесть при разработке торговой стратегии.

[Running] node "d:\Synology ...\SilverFir-TradingBot_github\src\sandbox.js"
2024-11-01 14:11:57 [INFO]: Запуск функции "sandboxAccount"

2024-11-01 14:11:58 [WARN]: Операция продажи выполнена успешно для Сбер Банк (SBER) (BBG004730N88).
2024-11-01 14:11:58 [INFO]: Детали операции:
{
"orderId": "27a35903-2134-4aaf-XXXX-3b38bc38c5e5",
"executionReportStatus": "EXECUTION_REPORT_STATUS_FILL",
"lotsRequested": "1",
"lotsExecuted": "1",
"initialOrderPrice": {
"currency": "rub",
"units": "2358",
"nano": 100000000
},
"executedOrderPrice": {
"currency": "rub",
"units": "235",
"nano": 810000000
},
"totalOrderAmount": {
"currency": "rub",
"units": "2358",
"nano": 100000000
},
"initialCommission": {
"currency": "rub",
"units": "1",
"nano": 179050000
},
"executedCommission": {
"currency": "rub",
"units": "1",
"nano": 179050000
},
"figi": "BBG004730N88",
"direction": "ORDER_DIRECTION_SELL",
"initialSecurityPrice": {
"currency": "rub",
"units": "235",
"nano": 810000000
},
"orderType": "ORDER_TYPE_MARKET",
"message": "",
"initialOrderPricePt": {
"units": "0",
"nano": 0
},
"instrumentUid": "e6123145-9665-43e0-XXXX-cd61b8aa9b13",
"orderRequestId": "",
"responseMetadata": {
"trackingId": "d059748a138038d3XXXXX93783d61a99",
"serverTime": "2024-11-01T09:11:57.919185435Z"
}
}
2024-11-01 14:11:58 [INFO]: Идентификатор продажи: 27a35903-2134-4aaf-XXXX-3b38bc38c5e5.
2024-11-01 14:11:58 [INFO]: Общая стоимость сделки: 2358.1 руб.
2024-11-01 14:11:58 [INFO]: Цена за 1 шт. Сбер Банк (SBER): 235.81 руб.
2024-11-01 14:11:58 [INFO]: Комиссия за сделку: 1.17905 руб.

[Done] exited with code=0 in 1.146 seconds

Для торгового робота 1,146 секунды от отправки ордера до его исполнения можно считать довольно медленным временем.

В высокочастотной торговле (HFT), где компании конкурируют за время исполнения менее миллисекунды, время обработки ордера более одной секунды будет непозволительно долгим. Стратегии HFT основаны на выполнении тысяч сделок за доли секунды, поэтому 1,146 секунды сделают этого робота неконкурентоспособным.

Напротив, для долгосрочной стратегии, такой как дневной торговый бот или свинг-трейдинг, это время может быть приемлемым. Скорость исполнения остается важной, но не такой критической, как в HFT. В этих случаях компромисс часто склоняется в сторону надежности и экономической эффективности, а не чистой скорости. Задержка в 1 секунду, как правило, не подорвет прибыльность в стратегии, где сделки исполняются с интервалом в несколько минут или даже часов.

Я планирую использовать свинг-трейдинг — это торговая стратегия, ориентированная на захват краткосрочных и среднесрочных ценовых движений, обычно удерживая активы в течение нескольких дней или нескольких недель. Цель — извлечь прибыль из «колебаний» цены, используя рыночный импульс, когда цены колеблются в рамках тренда или между уровнями поддержки и сопротивления.

Итоги

Проект полностью представлен на Гитхабе: https://github.com/empenoso/SilverFir-TradingBot.
Новые модули будут загружаться по мере написания и тестирования.

Автор: Михаил Шардин

5 ноября 2024 г.

Показать полностью 2

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта

Бывает, что частные инвесторы не доверяют сервисам для ведения портфеля ценных бумаг и ведут учет своих инвестиций в «Экселе» или «Гугл Таблицах».

Если количество ценных бумаг не так велико, то подобное использование таблиц оправдано:

  • не требуется платить кому-либо за хранение данных;

  • никто не удалит ваш файл, например, за неактивность;

  • отчеты можно сделать такие, как вам нравится.

Но у такого метода учета есть и свои минусы, главным образом связанные с необходимостью ручного обновления котировок. Если раз в квартал сделать это несложно и вручную, но чтобы поддерживать актуальность чаще, потребуется много времени: нужно зайти на сайт, где опубликованы текущие котировки, найти нужную цену, скопировать ее и вставить в ячейку таблицу. И так для каждой ценной бумаги в портфеле. Печально и долго.

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Зачем вообще нужны актуальные цены в таблицах:

  • Инвесторам - для эффективного управления портфелями и рисками.

  • Трейдерам - для оптимизации решений о покупке и продаже с максимальной прибыльностью.

  • Аналитикам - чтобы лучше понимать рыночные тенденции и повышать точность своих прогнозов и отчетов.

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

Проблемы получения котировок в любые таблицы

Хотя возможность автоматического получения котировок в «Эксель» или «Гугл Таблицы» упрощает ведение портфелей, существует несколько технических препятствий, с которыми можно столкнуться при парсинге или скрапинге (в общем виде это автоматический сбор данных из интернета, в таблицах работает через формулы или скрипты):

  • Динамическая загрузка контента: современные веб-сайты часто используют JavaScript для загрузки текущий цен уже после первоначальной загрузки страницы. Это создает проблему для базовых методов парсинга.

  • Ограничения API: некоторые веб-сайты и финансовые учреждения предлагают общедоступные API (например, Московская биржа или Банк России), но и они имеют свои ограничения.
    А бывает, что можно найти АПИ, например для investing.com, но чтобы воспользоваться им потребует поиск альтернативных методов - имитация человека для того чтобы получить данные - использование автоматизации браузера.

Скачиваем котировки в в Microsoft Excel

Еще недавно автозагрузка котировок для некоторых иностранных акций была доступна прямо в «Экселе» - с подпиской Microsoft 365, но с марта 2024 это не работает.

Легко масштабируемый способ это VBA - это внутренний язык программирования Microsoft Office. С его помощью придется написать макрос, мини-программу, которая выполняет сразу несколько действий. Я уже написал код — достаточно будет заменить в нем пару строк под ваши потребности и вставить в таблицу.

Хотя такие инструменты, как Power Query, также могут достигать аналогичных результатов, VBA обеспечивает большую гибкость и масштабируемость.

Для извлечения российских котировок можно использовать API, предоставляемый Московской биржей. Интегрировав этот API с Excel можно извлекать цены на облигации или другие классы активов с 15и минутной задержкой непосредственно в свои электронные таблицы без ручных обновлений:

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Цены через API, предоставляемый Московской биржей

Для популярных иностранных бумаг написал VBA:

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Цены через парсинг finance.yahoo.com

Для получения курсов от Центрального банка Российской Федерации тоже пришлось написать VBA скрипт, потому что формула недавно перестала работать:

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Котировки Банка России через API

⚠️Файл-пример скачивания котировок в Excel: Котировки любой бумаги в Excel (скачайте файл на компьютер, иначе он откроется в Гугл таблицах и будут одни ошибки).

Скачиваем котировки в Google Таблицы

Что касается Google Таблиц, для очень многих иностранных активов подойдёт встроенная функцию =GoogleFinance(), которая позволяет извлекать исторические и текущие цены на различные иностранные активы. Однако ограничением является полное отсутствие данных по российским акциям и облигациям, что является критическим пробелом:

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Получение цен через встроенную функцию

Для российских бумаг:

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Цены через API

Курсы валют Банка России:

Парсинг котировок ценных бумаг в Microsoft Excel и Google Таблицы с любого сайта Московская биржа, Финансы, Котировки, Центральный банк РФ, Финансовая грамотность, Длиннопост

Получение в отличии от Экселя через формулу

⚠️Файл-пример скачивания котировок в Google Таблицы: Котировки в Гугл Таблицы

Если вы продвинутый пользователь, то сможете найти АПИ для любого популярного сайта, например для investing.com, и с помощью автоматизации браузера, например, библиотеки Puppeteer в Node.js можно обойти защиту Cloudflare, и автоматизировать извлечение котировок. Этот метод требует более глубокого понимания, но он открывает возможности для доступа к защищенным данным, с которыми простой скрапинг уже не справляется.

Ключевые выводы

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

Для преодоление проблем веб-скрапинга: динамический веб-контент и защиту от ботов можно преодолеть с помощью API или инструментов автоматизации браузера, что делает их незаменимыми для серьезных инвесторов.

Excel против Google Sheets: хотя обе платформы предлагают решения для извлечения рыночных данных, у каждой из них есть свои сильные стороны. VBA в Excel предоставляет мощные возможности настройки, тогда как простота Google Sheets усиливается за счет подключения к облаку.

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

Автор: Михаил Шардин

21 октября 2024 г.

Показать полностью 7

Как я написал программу для поиска советов аналитиков по акциям российских компаний

Четыре года назад я написал систему поиска поиска недооцененных американских акций, используя данные Яху Финанс, ведь на американском рынке торгуется больше 10 тысяч бумаг, из которых около 4 тысяч бумаг имеют рекомендации аналитиков о прогнозируемой цене. Это большие цифры, с которыми сложно работать. Но что по России?

Как я написал программу для поиска советов аналитиков по акциям российских компаний Инновации, Программирование, Программа, Технологии, Длиннопост

Я вялотекуще пытался найти систему которая бы также отдавала рекомендации аналитиков по российским компаниям, пока недавно не нашёл такой API. Вот например какие рекомендации для оператора аренды электросамокатов WUSH:

{
"targets": [
{
"uid": "b993e814-9986-4434-ae88-b086066714a0",
"ticker": "WUSH",
"company": "SberCIB Investment Research",
"recommendation": "RECOMMENDATION_HOLD",
"recommendationDate": "2024-10-02T00:00:00Z",
"currency": "rub",
"currentPrice": {
"units": "192",
"nano": 0
},
"targetPrice": {
"units": "250",
"nano": 0
},
"priceChange": {
"units": "58",
"nano": 0
},
"priceChangeRel": {
"units": "30",
"nano": 210000000
},
"showName": "Whoosh"
},
{
"uid": "b993e814-9986-4434-ae88-b086066714a0",
"ticker": "WUSH",
"company": "Финам",
"recommendation": "RECOMMENDATION_HOLD",
"recommendationDate": "2024-09-26T00:00:00Z",
"currency": "rub",
"currentPrice": {
"units": "192",
"nano": 0
},
"targetPrice": {
"units": "250",
"nano": 0
},
"priceChange": {
"units": "58",
"nano": 0
},
"priceChangeRel": {
"units": "30",
"nano": 210000000
},
"showName": "Whoosh"
},
{
"uid": "b993e814-9986-4434-ae88-b086066714a0",
"ticker": "WUSH",
"company": "Газпромбанк",
"recommendation": "RECOMMENDATION_HOLD",
"recommendationDate": "2024-09-24T00:00:00Z",
"currency": "rub",
"currentPrice": {
"units": "192",
"nano": 0
},
"targetPrice": {
"units": "355",
"nano": 0
},
"priceChange": {
"units": "163",
"nano": 0
},
"priceChangeRel": {
"units": "84",
"nano": 900000000
},
"showName": "Whoosh"
}
],
"consensus": {
"uid": "b993e814-9986-4434-ae88-b086066714a0",
"ticker": "WUSH",
"recommendation": "RECOMMENDATION_HOLD",
"currency": "rub",
"currentPrice": {
"units": "192",
"nano": 0
},
"consensus": {
"units": "285",
"nano": 0
},
"minTarget": {
"units": "250",
"nano": 0
},
"maxTarget": {
"units": "355",
"nano": 0
},
"priceChange": {
"units": "93",
"nano": 0
},
"priceChangeRel": {
"units": "48",
"nano": 440000000
}
}
}

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

Гораздо меньшее количество бумаг, зато API выдаёт конкретные имена компаний, которые давали рекомендации, а также дату дачи прогноза и прогнозную цену. Теоретически можно составлять списки самых точных аналитиков, через какое-то время собирая цены и сопоставляя их с прогнозными.

Но мне было больше интересно составить сводную таблицу по всем доступным 89 акциям.

Код представлен на GitHub.

Что делает код?

Я написал свой код на на Node.js и обращался к T‑Bank Invest API для получения данных. Вот его функциональность:

Инициализация и настройка:

  • Скрипт начинает с импорта необходимых модулей, таких как конфигурация (secrets), утилиты ведения журнала (logService) и клиент Tinkoff (tinkoffClient), что облегчает взаимодействие с API Tinkoff Invest.

  • API_TOKEN из файла конфигурации используется для аутентификации запросов API.

Шаг 1: Получение данных по акциям:

  • Функция getStockData запрашивает у InstrumentsService Tinkoff список доступных акций. Она фильтрует эти данные, чтобы отобрать акции, котирующиеся на бирже MOEX (REAL_EXCHANGE_MOEX).

  • Отфильтрованный список и полный список акций регистрируются и возвращаются. Ключевые данные акций, такие как figi, ticker, uid и logoName, извлекаются для дальнейшей обработки.

Шаг 2: Извлечение прогнозов аналитиков:

  • Функция getForecastsForStocks проходит по отфильтрованному списку акций и извлекает прогнозы аналитиков с помощью конечной точки InstrumentsService/GetForecastBy.

  • Для каждой акции она проверяет, есть ли доступные прогнозы. Если они есть, данные прогноза (текущая цена, консенсусная цена, изменение цены и количество рекомендаций) сохраняются в массиве. Если прогнозы не найдены, это увеличивает счётчик бумаг без рекомендаций на плюс один.

  • Система обеспечивает задержку в 600 мс между вызовами API для соблюдения ограничений по частоте (100 запросов в минуту).

  • Прогнозы сортируются на основе потенциального изменения цены, с наибольшим ростом цены вверху.

Шаг 3: Генерация HTML-таблицы:

  • Функция generateHTMLTable создает HTML-файл для визуального отображения данных в таблице.

  • Она использует Google Charts для визуализации таблицы с логотипами акций, цен, консенсусных цен и количества рекомендаций аналитиков.

  • Таблица сохраняется как HTML-файл, что позволяет пользователю легко просматривать ее в браузере.

Окончательное выполнение:

  • Код оборачивает все в асинхронную функцию, которая сначала извлекает данные по акциям, затем получает прогнозы и, наконец, генерирует HTML-таблицу, обобщающую рекомендации аналитиков.

  • На выходе получается HTML-файл с данными об акциях в реальном времени из API Т-Банк: Т‑Инвестиции, отсортированных по потенциальному изменению цены, а ещё добавил логотипы акций и страну риска.

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

Какие результаты работы скрипта?

С логом работы можно познакомиться на GitHub. Готовую таблицу можно скачать с него же.

Как я написал программу для поиска советов аналитиков по акциям российских компаний Инновации, Программирование, Программа, Технологии, Длиннопост

Сгенерированная таблица

  • Каждый заголовок столбца можно отсортировать.

  • Для числовых столбцов, таких как текущая цена, консенсусная цена и потенциальное изменение цены, сортировка проста: по возрастанию или по убыванию.

  • Для текстовых столбцов, таких как имя и тикер, сортировка будет алфавитной.

  • Процентная сортировка (например, потенциальное изменение цены) помогает быстро определять акции с самым высоким потенциалом роста.

Итоги

Скрипт позволяет находить компании у которых есть рекомендации аналитиков. Однако эта выборка не является индивидуальной инвестиционной рекомендацией и может не соответствовать вашим инвестиционным целям. Это связано с тем, что скрипт - всего лишь инструмент, а решение о покупке конкретных бумаг принимает уже сам человек после изучения эмитента.

Проект полностью представлен на Гитхабе: https://github.com/empenoso/SilverFir-TradingBot. Новые модули будут загружаться по мере написания и тестирования.

Автор: Михаил Шардин

14 октября 2024 г.

Показать полностью 1

Как я решил вернуться в алготрейдинг после 10 летнего перерыва

Самое главное, что никакого отношения к слову алко это не имеет.
В течении нескольких лет я торговал в связке программы технического анализа AmiBroker + торговый терминал QUIK через .tri и .trr файлы в основном на фьючерсах на срочном рынке.
Не могу сказать что это было неудачным опытом, но со временем я узнал про распределение активов (Asset allocation) и понял что очень сложно соревноваться с бенчмарком в виде фондового индекса.

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

Форум форекс кб паук http://forex.kbpauk.ru/ (в 2024 уже не работает)

В теории это означает что можно купить индекс и забыть об этом, заниматься своими делами, бизнесом, семьёй - а индекс растёт (ну или падает, смотря какое время) и для этого не нужно прикладывать никаких действий.
А за связкой AmiBroker + QUIK постоянно нужно было присматривать, следить не отвалился ли адаптер импорта через .tri файл. А ещё иметь несколько виртуальных машин с установленными копиями Windows на каждой виртуалке на одном физическом компьютере для разных брокеров. Возможна была установка только одной пары AmiBroker + QUIK на одну винду. Всё это мне не особо нравилось.

В 2024 году захотелось что-то лёгкое - без Windows и современное - через API интерфейс. Желательно бесплатное для пользователя. Несколько лет назад я уже пытался узнать появились ли у российских брокеров API для работы с ними, но так и не собрался. Этой осенью я стал активно искать информацию - какой брокер имеет АПИ для работы с физлицами. Не смог найти никакой сводной таблицы и нашёл только три варианта:

По субъективным причинам я выбрать работать с T‑Bank Invest API (это бывший Тинькофф) через среду выполнения JavaScript Node.JS.


Немного моей истории, 2008-2012 годы: AmiBroker + QUIK

AmiBroker – это платформа для технического анализа, которая позволяет пользователям создавать свои собственные индикаторы и скрипты. Она также может интегрироваться с другими программами, такими как MetaTrader, NinjaTrader и даже с торговыми терминалами, включая QUIK.

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

AmiBroker 3D Optimization Chart

В AmiBroker'е мне очень нравилась его функция 3D Optimization Chart. На мой взгляд она позволяла избежать переподгонки показателей под кривую истории. Оптимизация в бэк-тестере поддерживалась функцией optimize. Синтаксис этой функции был следующий:

переменная = optimize("Описание", default , min , max , step );

переменная - это обычная переменная их языка AFL, которой присваивается значение, возвращаемое функцией оптимизации.
В режиме оптимизации функция optimize возвращает последовательные значения от минимума до максимума (включительно) с пошагово.
"Описание" - это строка, которая используется для идентификации переменной оптимизации и отображается как имя столбца в списке результатов оптимизации.
default — это значение по умолчанию, которое оптимизирует возврат функции в режимах исследования, индикатора, комментария, сканирования и обычного бэктеста.
min — минимальное значение оптимизируемой переменной
max — максимальное значение оптимизируемой переменной
шаг — это интервал, используемый для увеличения значения от минимума до максимума.

QUIK – это торгово-информационная система, предназначенная для предоставления участникам фондового рынка доступа к биржевым данным в реальном времени. Она используется многими брокерами и трейдерами для совершения операций на фондовых рынках.

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

Для подключения AmiBroker к QUIK необходимо было установить соответствующий плагин или модуль. Это позволяло платформе AmiBroker получать данные от QUIK и обрабатывать их для дальнейшей работы.

Пример логов работы:

09.10.2009 11:00:31: [2208:2212] Получено уведомление о выполнении транзакции , TRANS_ID=807263520;CLASSCODE=SPBFUT;ACTION=NEW_ORDER;SECCODE=GMZ9;ACCOUNT=SPBFUT0087W;PRICE=37692;QUANTITY=2;OPERATION=S;CLIENT_CODE=48560/48560;TYPE=L;EXECUTION_CONDITION=;CHECK_LIMITS=;MARKET_MAKER_ORDER=;STATUS=3;TRANS_NAME="Ввод заявки"; DESCRIPTION="[FORTS] Заявка N 761722396 успешно зарегистрирована"; ORDER_NUMBER=761722396; 09.10.2009 14:04:30: [2208:1172] Получено уведомление об отправке транзакции , TRANS_ID=2087816784;CLASSCODE=SPBFUT;ACTION=NEW_ORDER;SECCODE=VBZ9;ACCOUNT=SPBFUT0087W;PRICE=6333;QUANTITY=12;OPERATION=S;CLIENT_CODE=48560/48560;TYPE=L;EXECUTION_CONDITION=;CHECK_LIMITS=;MARKET_MAKER_ORDER=;STATUS=0;TRANS_NAME="Ввод заявки"; DESCRIPTION="Отправлена транзакция"; 09.10.2009 14:04:30: [2208:2212] Получено уведомление о выполнении транзакции , TRANS_ID=2087816784;CLASSCODE=SPBFUT;ACTION=NEW_ORDER;SECCODE=VBZ9;ACCOUNT=SPBFUT0087W;PRICE=6333;QUANTITY=12;OPERATION=S;CLIENT_CODE=48560/48560;TYPE=L;EXECUTION_CONDITION=;CHECK_LIMITS=;MARKET_MAKER_ORDER=;STATUS=3;TRANS_NAME="Ввод заявки"; DESCRIPTION="[FORTS] Заявка N 763167846 успешно зарегистрирована"; ORDER_NUMBER=763167846; 09.10.2009 15:10:10: [2208:1172] Завершен процесс отправления транзакций из файла , Входной файл-"C:\Program Files\Quik5\MTS\input.tri", Выходной файл-"C:\Program Files\Quik5\MTS\output.tro", Файл с журналом-"C:\Program Files\Quik5\MTS\log.trr", отправлено транзакций-3, выполнено транзакций-3

Насколько я понимаю AmiBroker (создан в Польше) уже несколько лет не обновляется: последний выпуск в 2015 году, а обновления в 2017 году.

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

Ещё немного моей истории, 2008-2012 годы: КБ ПАУК и Technical Analysis of STOCKS & COMMODITIES

Раньше я был активным пользователем форума КБ ПАУК. Вот даже нашёл файл HTML файл с интересующей меня темой, который пролежал 20 лет:

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

Форум форекс кб паук http://forex.kbpauk.ru/ (в 2024 уже не работает)

Я много изучал тему посвященную AmiBroker'у. И спрашивал там. Выкладывал примеры из бумажного журнала Technical Analysis of STOCKS & COMMODITIES.

Сейчас, в 2024 году форум недоступен, но если кто-то хочет ностальгии, то нашёл его архивную копию.

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

Форум форекс кб паук http://forex.kbpauk.ru/ (в 2024 уже не работает)

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

2024 год, сейчас: T‑Bank Invest API + неофициальный SDK Node.JS. Описание функций торгового робота

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

Примерная структура робота

Осенью 2024 года решил написать торгового бота, создать структуру программы которая будет работать через API брокера.

Торговый робот должен содержать:

  1. Список бумаг - с которым он будет работать.

  2. Условие покупки.

  3. Условие продажи.

  4. CSV файл учёта

  5. Управление деньгами - процент входа.

  6. Логирование всех действий.

  7. Отображение информации, скорее всего через веб-сервер.

  8. Иметь модуль бектестинга.

T‑Bank Invest API + Node.JS:

Решил пока не лезть в срочный рынок и попробовать поработать с самими оборотистыми акциями на Московской бирже. Остаётся только их найти.

В этой статья я распишу как создал два модуля на Node.js:

  1. Взаимодействие с T‑Bank Invest API tinkoffClient.js

  2. Модуль, который ищет акции с самым большим оборотом за три последних месяца searchTradingVolumes.js

Проект представлен на Гитхабе: https://github.com/empenoso/SilverFir-TradingBot.

SilverFir-TradingBot\src\grpc\tinkoffClient.js

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

Модуль tinkoffClient.js — это специализированный клиент, разработанный для взаимодействия с T‑Bank Invest API, российской брокерской платформой. Основная цель этого модуля — предоставить боту на основе Node.js, доступ к финансовым данным для алгоритмической торговли или анализа рынка.

Вот его функциональность:

Основные функции:

1. Авторизация и настройка:

  • Модуль использует API-токены для аутентификации.

  • Он поддерживает как тестовую (песочницу), так и продовую среду, хотя по умолчанию он использует среду песочницы.

  • Заголовки API включают необходимый токен авторизации и тип контента для JSON-коммуникации.

2. Универсальный механизм вызова API:

  • Метод callApi() служит гибкой утилитой для отправки POST-запросов на конечные точки API Tinkoff.

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

3. Извлечение данных "японских свечей":

  • Метод getCandles() извлекает данные свечей для заданного финансового инструмента (тикера) за указанные интервалы.

  • Он вычисляет временной диапазон на основе предоставленного интервала и извлекает серию свечей из сервиса рыночных данных. Это необходимо для анализа рынка, технических индикаторов и торговых стратегий.

  • Обрабатывает до 1000 свечей за запрос и обеспечивает регистрацию ошибок, если запрос не выполняется или возвращает пустые данные.

Зависимости и утилиты:

  • Moment.js: Используется для форматирования дат и расчета временных диапазонов, что имеет решающее значение при работе с финансовыми данными за различные периоды времени.

  • Axios: Обрабатывает HTTP-запросы к конечным точкам API.

  • Службы ведения журналов: реализует настраиваемую систему журналов для вывода файлов и консоли, помогая в отладке и отслеживании операций.

SilverFir-TradingBot\src\searchTradingVolumes.js

Как я решил вернуться в алготрейдинг после 10 летнего перерыва Гайд, Программа, Инновации, Технологии, Программирование, Длиннопост

Модуль searchTradingVolumes.js является частью SilverFir-TradingBot, разработан для определения акций на Московской бирже (MOEX) с наибольшими объемами торгов за последние три месяца. Нужен чтобы отбросить неликвид.

Вот подробный обзор функций модуля:

Основные функции:

1. Фильтрация акций с MOEX (Московской биржи):

  • Модуль использует T‑Bank Invest API для получения полного списка доступных акций.

  • Фильтрует результаты, чтобы сосредоточиться конкретно на акциях, торгуемых на REAL_EXCHANGE_MOEX, гарантируя, что будут рассмотрены только акции Мосбиржи.

  • Отфильтрованный список включает в себя важную информацию, такую как FIGI (глобальный идентификатор финансового инструмента), тикер, ISIN и название, которые затем регистрируются для отслеживания и анализа.

2. Извлечение исторических данных по объему торгов:

  • Для каждой акции, идентифицированной на этапе фильтрации, модуль извлекает ежедневные данные свечей (OHLCV - открытие, максимум, минимум, закрытие, объем) с помощью T‑Bank Invest API.

  • Он извлекает данные за последние три месяца, рассчитывая общий объем торгов за этот период.

  • Этот шаг имеет решающее значение для измерения рыночной активности и определения наиболее активно торгуемых акций.

  1. Определение 15 лучших акций по объему:

  • После сбора данных по объему торгов модуль ранжирует все акции на основе их общего объема торгов за трехмесячный период.

  • Затем он выбирает 15 лучших акций, которые считаются имеющими самый высокий оборот, что делает их наиболее активными на рынке.

3. Ведение журнала и подготовка конфигурации:

  • 15 лучших акций регистрируются с соответствующими тикерами и идентификаторами FIGI для дальнейшего использования.

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

Зависимости и утилиты:

  • Moment.js: используется для манипулирования датами, в частности для генерации временных диапазонов (три месяца) для запросов исторических данных.

  • TinkoffClient: это выделенный клиент бота для взаимодействия с API Tinkoff Invest, облегчающий коммуникацию, необходимую для получения данных по акциям и свечам.

  • Служба пользовательского ведения журнала: модуль использует систему ведения журнала, которая регистрирует информацию как в консоли, так и во внешних файлах, помогая отслеживать фильтрацию акций, расчеты объема и любые ошибки, возникающие во время взаимодействия с API.

Результат выполнения скрипта searchTradingVolumes.js

2024-10-06 07:25:48 [INFO]: Отфильтрованных акций 170 штук.

2024-10-06 07:25:50 [INFO]: Топ 15 акций по объему за последние три месяца: [

{

"ticker": "GRNT",

"figi": "TCS10A0JV532",

"totalVolume": 7092179306

},

{

"ticker": "VTBR",

"figi": "BBG004730ZJ9",

"totalVolume": 5906896857

},

{

"ticker": "MTLR",

"figi": "BBG004S68598",

"totalVolume": 5047115732

},

{

"ticker": "UWGN",

"figi": "BBG008HD3V85",

"totalVolume": 4423660125

},

{

"ticker": "RNFT",

"figi": "BBG00F9XX7H4",

"totalVolume": 1775061013

},

{

"ticker": "EUTR",

"figi": "TCS00A1002V2",

"totalVolume": 1270913208

},

{

"ticker": "SNGSP",

"figi": "BBG004S681M2",

"totalVolume": 1092911599

},

{

"ticker": "GAZP",

"figi": "BBG004730RP0",

"totalVolume": 1027429605

},

{

"ticker": "ROSN",

"figi": "BBG004731354",

"totalVolume": 983187493

},

{

"ticker": "SBER",

"figi": "BBG004730N88",

"totalVolume": 940111321

},

{

"ticker": "SGZH",

"figi": "BBG0100R9963",

"totalVolume": 929574444

},

{

"ticker": "AFLT",

"figi": "BBG004S683W7",

"totalVolume": 632806638

},

{

"ticker": "VKCO",

"figi": "TCS00A106YF0",

"totalVolume": 595704137

},

{

"ticker": "RUAL",

"figi": "BBG008F2T3T2",

"totalVolume": 542242519

},

{

"ticker": "TATN",

"figi": "BBG004RVFFC0",

"totalVolume": 538004844

}

]

2024-10-06 07:25:50 [INFO]:

Вставка в config.js:

2024-10-06 07:25:50 [INFO]:

securitiesToMonitorTikerArray: ["GRNT","VTBR","MTLR","UWGN","RNFT","EUTR","SNGSP","GAZP","ROSN","SBER","SGZH","AFLT","VKCO","RUAL","TATN"]

2024-10-06 07:25:50 [INFO]:

securitiesToMonitorFigiArray: ["TCS10A0JV532","BBG004730ZJ9","BBG004S68598","BBG008HD3V85","BBG00F9XX7H4","TCS00A1002V2","BBG004S681M2","BBG004730RP0","BBG004731354","BBG004730N88","BBG0100R9963","BBG004S683W7","TCS00A106YF0","BBG008F2T3T2","BBG004RVFFC0"]

2024-10-06 07:25:50 [INFO]:

Для использования в скрипте download_md.sh в одну колонку:

TCS10A0JV532

BBG004730ZJ9

BBG004S68598

BBG008HD3V85

BBG00F9XX7H4

TCS00A1002V2

BBG004S681M2

BBG004730RP0

BBG004731354

BBG004730N88

BBG0100R9963

BBG004S683W7

TCS00A106YF0

BBG008F2T3T2

BBG004RVFFC0

Итоги

Проект представлен на Гитхабе: https://github.com/empenoso/SilverFir-TradingBot. Новые модули будут загружаться по мере написания и тестирования.

Модуль tinkoffClient.js для T‑Bank Invest API представлен пока только частично.

Автор: Михаил Шардин

7 октября 2024 г.

Показать полностью 7

Как я научил бухгалтерию составлять договора дарения со скоростью 1 договор в 4 секунды

В статье разбираю конкретный пример - как при помощи Google Apps Script на основании шаблона, созданного в Гугл Документах массово создавать договора дарения из строк Гугл Таблицы.

Массово создавать типовые договора можно когда есть документ-шаблон с готовым форматированием и в нём промаркированы ключевые поля, которые идут под замену для каждой новой строчки таблицы. После автозамены копия заполненного шаблона сохраняется с установленным именем в виде Гугл Документа и может сразу автоматически преобразована в PDF или файл Microsoft Word.

Автозаполнение договоров дарения

Во многих организациях бухгалтеры отвечают за составление договоров дарения от организации. Эта задача может быть однотипной, трудоемкой и подверженной ошибкам при выполнении вручную. Все данные скорее всего хранятся в 1С, но из неё можно сделать экспорт в Эксель и дальше скопировать в Гугл Таблицы:

Как я научил бухгалтерию составлять договора дарения со скоростью 1 договор в 4 секунды Программирование, Гайд, Программа, Длиннопост

Таблица с исходными данными

Используя скрипт Google Apps, этот процесс можно полностью автоматизировать. Скрипт извлекает данные из таблицы Google, содержащей сведения о сотрудниках:

  • Дата заключения договора

  • ФИО

  • Должность

  • Сумма

  • Подарок

  • Паспорт

  • ИНН

Затем составляется однотипный шаблон документа Google для всех сотрудников:

Как я научил бухгалтерию составлять договора дарения со скоростью 1 договор в 4 секунды Программирование, Гайд, Программа, Длиннопост

Верхняя часть однотипного шаблона документа Google

Как я научил бухгалтерию составлять договора дарения со скоростью 1 договор в 4 секунды Программирование, Гайд, Программа, Длиннопост

Нижняя часть однотипного шаблона документа Google

После этого время работы гугл скрипта.

Скрипт автозаполнения договоров

Ниже приведён скрипт автозаполнения договоров дарения, написанный на Google Apps Script. Это скриптовый язык программирования, который используется для автоматизации работы с сервисами Google, такими как Gmail, Google Docs, Sheets, Slides, Forms и другими. Он позволяет создавать пользовательские функции, макросы и приложения, которые могут взаимодействовать с данными внутри этих сервисов. Это мощный инструмент для повышения производительности труда и улучшения взаимодействия между различными компонентами экосистемы Google:

function generateDocumentsFromSpreadsheet() {

// Подробнее: https://pikabu .ru/story/kak_ya_nauchil_bukhgalteriyu_sostavlyat_dogovora_dareniya_so_skorostyu_1_dogovor_v_4_sekundyi_11859028?cid=323554940

console.log(`Функция generateDocumentsFromSpreadsheet начала работу в ${(new Date()).toLocaleString("ru-RU")}`);

// Доступ к таблице и получение данных

const ss = SpreadsheetApp.getActiveSpreadsheet();

const sheet = ss.getSheetByName("Автозаполнение"); // Измените на название вашего листа

const data = sheet.getDataRange().getValues(); // Получаем все данные с таблицы

// Открытие шаблона Google Документа

const templateDocId = "1y2XQhZBХХХХХХХХХХХХХzyfnXh8yUQ"; // Замените на настоящий идентификатор вашего шаблона

const templateDoc = DriveApp.getFileById(templateDocId);

const templateFolder = templateDoc.getParents().next(); // Получаем папку, в которой находится шаблон

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

for (let i = 1; i < data.length; i++) {

const [rawDate, fullName, position, rawAmount, gift, passport, tin] = data[i]; // Получаем данные из строки таблицы

console.log(`Работаем с ${fullName}.`);

let formattedAmount = '';

formattedAmount = rawAmount + " (" + FloatToSamplesInWordsRus(rawAmount) + ")" // Форматируем сумму как текст (включая пропись)

// Форматируем дату

let formattedDate = '';

if (rawDate instanceof Date) {

formattedDate = Utilities.formatDate(rawDate, Session.getScriptTimeZone(), "dd.MM.yyyy"); // Преобразуем дату в формат "дд.мм.гггг"

}

// Создание нового документа на основе шаблона

const copyDoc = templateDoc.makeCopy(`Заполненный - ${fullName}`); // Копируем шаблон и называем новый документ по ФИО

const copyDocId = copyDoc.getId();

// Открываем новый документ

const copyDocAsDoc = DocumentApp.openById(copyDocId);

const copyDocBody = copyDocAsDoc.getBody();

// Замена шаблонных полей на данные из таблицы

copyDocBody.replaceText('Дата', formattedDate);

copyDocBody.replaceText('ФИО', fullName);

copyDocBody.replaceText('Должность', position);

copyDocBody.replaceText('Сумма', formattedAmount);

copyDocBody.replaceText('Подарок', gift);

copyDocBody.replaceText('Паспорт', passport);

copyDocBody.replaceText('ИННномер', tin);

// Замена текста полей на соответствующие данные

// Сохранение и закрытие заполненного документа

copyDocAsDoc.saveAndClose();

// Преобразование документа в PDF, если надо

// const pdfBlob = DriveApp.getFileById(copyDocId).getAs("application/pdf");

// Сохранение копии PDF на Google Диске

// const pdfFile = templateFolder.createFile(pdfBlob).setName(`Заполненный - ${fullName}.pdf`);

// Дополнительно: удалите промежуточный Google Документ, если нужен только PDF

// DriveApp.getFileById(copyDocId).setTrashed(true);

}

console.log(`Функция generateDocumentsFromSpreadsheet закончила работу в ${(new Date()).toLocaleString("ru-RU")}`);

}

// Карта для преобразования чисел в слова (рубли) отсюда https://habr.com/ru/articles/104057/

var mapNumbers = {

0: [2, 1, "ноль"],

1: [0, 2, "один", "одна"],

2: [1, 2, "два", "две"],

3: [1, 1, "три"],

4: [1, 1, "четыре"],

5: [2, 1, "пять"],

6: [2, 1, "шесть"],

7: [2, 1, "семь"],

8: [2, 1, "восемь"],

9: [2, 1, "девять"],

10: [2, 1, "десять"],

11: [2, 1, "одиннадцать"],

12: [2, 1, "двенадцать"],

13: [2, 1, "тринадцать"],

14: [2, 1, "четырнадцать"],

15: [2, 1, "пятнадцать"],

16: [2, 1, "шестнадцать"],

17: [2, 1, "семнадцать"],

18: [2, 1, "восемнадцать"],

19: [2, 1, "девятнадцать"],

20: [2, 1, "двадцать"],

30: [2, 1, "тридцать"],

40: [2, 1, "сорок"],

50: [2, 1, "пятьдесят"],

60: [2, 1, "шестьдесят"],

70: [2, 1, "семьдесят"],

80: [2, 1, "восемьдесят"],

90: [2, 1, "девяносто"],

100: [2, 1, "сто"],

200: [2, 1, "двести"],

300: [2, 1, "триста"],

400: [2, 1, "четыреста"],

500: [2, 1, "пятьсот"],

600: [2, 1, "шестьсот"],

700: [2, 1, "семьсот"],

800: [2, 1, "восемьсот"],

900: [2, 1, "девятьсот"]

};

var mapOrders = [{

_Gender: true,

_arrStates: ["рубль", "рубля", "рублей"]

},

{

_Gender: false,

_arrStates: ["тысяча", "тысячи", "тысяч"]

},

{

_Gender: true,

_arrStates: ["миллион", "миллиона", "миллионов"]

},

{

_Gender: true,

_arrStates: ["миллиард", "миллиарда", "миллиардов"]

},

{

_Gender: true,

_arrStates: ["триллион", "триллиона", "триллионов"]

}

];

var objKop = {

_Gender: false,

_arrStates: ["копейка", "копейки", "копеек"]

};

function Value(dVal, bGender) {

var xVal = mapNumbers[dVal];

if (xVal[1] == 1) {

return xVal[2];

} else {

return xVal[2 + (bGender ? 0 : 1)];

}

}

function From0To999(fValue, oObjDesc, fnAddNum, fnAddDesc) {

var nCurrState = 2;

if (Math.floor(fValue / 100) > 0) {

var fCurr = Math.floor(fValue / 100) * 100;

fnAddNum(Value(fCurr, oObjDesc._Gender));

nCurrState = mapNumbers[fCurr][0];

fValue -= fCurr;

}

if (fValue < 20) {

if (Math.floor(fValue) > 0) {

fnAddNum(Value(fValue, oObjDesc._Gender));

nCurrState = mapNumbers[fValue][0];

}

} else {

var fCurr = Math.floor(fValue / 10) * 10;

fnAddNum(Value(fCurr, oObjDesc._Gender));

nCurrState = mapNumbers[fCurr][0];

fValue -= fCurr;

if (Math.floor(fValue) > 0) {

fnAddNum(Value(fValue, oObjDesc._Gender));

nCurrState = mapNumbers[fValue][0];

}

}

fnAddDesc(oObjDesc._arrStates[nCurrState]);

}

function FloatToSamplesInWordsRus(fAmount) {

var fInt = Math.floor(fAmount + 0.005);

var fDec = Math.floor(((fAmount - fInt) * 100) + 0.5);

var arrRet = [];

var iOrder = 0;

var arrThousands = [];

for (; fInt > 0.9999; fInt /= 1000) {

arrThousands.push(Math.floor(fInt % 1000));

}

if (arrThousands.length == 0) {

arrThousands.push(0);

}

function PushToRes(strVal) {

arrRet.push(strVal);

}

for (var iSouth = arrThousands.length - 1; iSouth >= 0; --iSouth) {

if (arrThousands[iSouth] == 0) {

continue;

}

From0To999(arrThousands[iSouth], mapOrders[iSouth], PushToRes, PushToRes);

}

if (arrThousands[0] == 0) {

// Handle zero amount

if (arrThousands.length == 1) {

PushToRes(Value(0, mapOrders[0]._Gender));

}

var nCurrState = 2;

PushToRes(mapOrders[0]._arrStates[nCurrState]);

}

if (arrRet.length > 0) {

// Capitalize first letter

arrRet[0] = arrRet[0].match(/^(.)/)[1].toLocaleUpperCase() + arrRet[0].match(/^.(.*)$/)[1];

}

arrRet.push((fDec < 10) ? ("0" + fDec) : ("" + fDec));

From0To999(fDec, objKop, function () {}, PushToRes);

return arrRet.join(" ");

}

Процесс выполнения:

Как я научил бухгалтерию составлять договора дарения со скоростью 1 договор в 4 секунды Программирование, Гайд, Программа, Длиннопост

Скорость заполнения: 3-4 секунды на 1 договор.

Результат

После выполнения скрипта создаётся необходимое количество договоров дарения в папке расположения таблицы:

Как я научил бухгалтерию составлять договора дарения со скоростью 1 договор в 4 секунды Программирование, Гайд, Программа, Длиннопост

Как воспользоваться этим кодом?

Чтобы вставить и запустить скрипт Google Apps в таблицу Google, выполните следующие действия:

  1. Откройте Google Таблицы: начните с открытия своей таблицы Google.

  2. Откройте редактор скриптов: нажмите «Расширения» в меню, затем выберите «Скрипт приложений». Это откроет редактор скриптов приложений на новой вкладке.

  3. Вставьте скрипт: в редакторе скриптов удалите код-заполнитель. Затем вставьте скрипт Google Apps выше в редактор.

  4. Сохраните скрипт: нажмите значок дискеты или нажмите «Ctrl+S», чтобы сохранить скрипт. Дайте ему осмысленное имя, если будет предложено.

  5. Авторизуйте скрипт: если ваш скрипт взаимодействует со службами Google (например, Таблицами, Календарем), вам необходимо предоставить ему разрешение. Нажмите кнопку «Запустить» (значок воспроизведения) и следуйте инструкциям по авторизации.

  6. Запустите скрипт: После авторизации снова нажмите «Запустить». Скрипт будет запущен и выполнит действия по автозаполнению договоров дарения.

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

Где ещё можно использовать?

Подобные скрипты могут использоваться и для других целей:

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

  • Создание юридических документов
    Юридические отделы часто обрабатывают большой объем стандартизированных договоров и соглашений, в которых от клиента к клиенту меняется лишь несколько деталей. Извлекая данные из электронной таблицы (имя клиента, сумма контракта, даты), этот скрипт может автоматически генерировать соответствующие документы за считанные секунды.

  • Табели успеваемости или сертификаты школьников
    Школы и университеты могут использовать подобный скрипт для создания табелей успеваемости или сертификатов для учащихся. Сохраняя имена, оценки и достижения учащихся в электронной таблице, скрипт может генерировать персонализированный отчет или сертификат для каждого учащегося.

  • Персонализированные приглашения и таблички для мероприятий
    Организаторам мероприятий часто требуется отправлять персонализированные приглашения или создавать именные значки для участников. Используя подобный скрипт можно извлекать данные участников из электронной таблицы и генерировать пригласительные письма или таблички в формате PDF, готовые к печати.

Итоги

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

Автор: Михаил Шардин

30 сентября 2024 г.

Показать полностью 5

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API

Уже полгода хожу в фитнес клуб World Class или как пишут в самом клубе - являюсь его резидентом. Выбрал этот клуб в основном из-за наличия в нём бассейна. Потом заинтересовался групповыми программами и частенько хожу на сайкл тренировки - это тренировки на специальном велотренажере.

И единственное меня раздражает, что для просмотра расписания занятий на следующую неделю каждый раз приходилось идти на сайт сети Ворд Класс, переходить в мой клуб, отбиваться от нескольких назойливых баннеров которые предлагают перезвонить через 3 секунды для того чтобы стать их клиентом. И только после этого найти в огромном расписании несколько строчек которые я ищу. На неделе таких занятий может проходить несколько и я вносил их в свой календарь, чтобы сходить хотя бы на одно в неделю.
Вся это операция с поиском и занесением в календарь занимала минут 15. И так каждую неделю.

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API Программирование, API, Программист, Open Source, Длиннопост

Автоматически созданное при помощи скрипта событие в моём гугл календаре

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

Некоторым препятствием стало то, что сайт World Class динамически загружает контент с помощью JavaScript после начальной загрузки страницы. Зато нашлась конечная точка API и теперь занятия по сайклу каждый понедельник ночью добавляются в мой календарь за 3 секунды работы скрипта вместо 15 минут моей жизни каждую неделю.

Веб-сайт с общедоступным расписанием клуба World Class

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API Программирование, API, Программист, Open Source, Длиннопост

Обычно расписание приветствует вот так

На сайте используется динамическая загрузка контента с помощью JavaScript. Это значит что сайт, который динамически загружает контент с помощью JavaScript после первоначальной загрузки страницы, - это тот, на котором не вся информация сразу доступна при первом появлении страницы. Вместо этого дополнительные данные или контент извлекаются с сервера и отображаются по мере взаимодействия со страницей. Этот метод обычно используется в современных веб-приложениях. Это устраняет необходимость перезагружать всю страницу и делает процесс более быстрым и плавным для пользователя.

Конечная точка API - это определенный URL-адрес, который позволяет внешним приложениям взаимодействовать с ним. API позволяют различным программным системам взаимодействовать друг с другом, отправляя запросы и получая ответы.

Когда взаимодействую с сайтом, который динамически загружает контент, то сайт часто запрашивает данные со своего сервера с помощью API. Сервер обрабатывает запрос и возвращает необходимые данные, которые затем отображаются на веб-странице. В контексте фитнес-клуба World Class конечной точкой API будет определенный URL-адрес, который предоставляет данные о расписании занятий. Отправив запрос на эту конечную точку, можно получить данные о расписании напрямую, минуя необходимость вручную перемещаться по сайту.

Поворотный момент и техническая проблема

В какой-то момент я наткнулся на чистую ссылку, которая ведёт только на само расписание фитнес-клуба World Class без любой рекламы. Ссылка выглядит следующим образом:

https://my.worldclass.ru/scheduling?clubs=d35ba5fc-1f7e-11ec-b664-50e548298f06

Где вместо d35ba5fc-1f7e-11ec-b664-50e548298f06 должен стоять идентификатор вашего клуба. Выше это идентификатор клуба в городе Перми.

Все доступные идентификаторы других клубов можно посмотреть прямо в браузере в режиме просмотра страницы:

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API Программирование, API, Программист, Open Source, Длиннопост

Список доступных клубов

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

ICG Color Cycle (сайкл)

В пермском клубе World Class не обязательно записываться на занятия по сайклу заранее - достаточно прийти примерно за полчаса до занятия и взять на входе черную карточку для участия - места есть до тех пор пока карточки не закончатся. Правда бывают приходят и те кто записались онлайн, но карточку не взяли - просто не знали про это и мест не хватает. Это некоторая путаница.

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API Программирование, API, Программист, Open Source, Длиннопост

Примерно так выглядят занятия по сайклу

Создание решения

Поскольку я использую Гугл календарь, то написал Google Apps скрипт. Apps Script - платформа на основе JavaScript для быстрой и простой разработки решений.

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

Скрипт работает следующим образом:

  1. Получение расписания: скрипт отправляет запрос в API World Class с идентификатором определенного спортзала. Далее извлекает расписание на следующие семь дней.

  2. Фильтрация соответствующих занятий: после извлечения расписания скрипт отфильтровывает занятия «ICG Color Cycle» и «CORE», которые я хочу посещать. Все дальнейшие действия происходят только для отобранной выборки.

  3. Создание событий календаря: для каждой отфильтрованной тренировки скрипт автоматически создает событие в Google календарь по умолчанию. Каждое событие включает:

  • Название: название тренировки (в моём случае либо «ICG Color Cycle», либо «CORE»).

  • Продолжительность: каждое событие запланировано на один час.

  • Описание: подробное объяснение зачем нужна эта тренировка.

  • Расположение: конкретный адрес клуба World Class, где проходит занятие.

  • Ведение журнала и обработка ошибок: скрипт регистрирует свой ход выполнения, указывая, когда он начинается и заканчивается, и предоставляя подробную информацию о каждом созданном событии. Если запрос API не выполняется или возвращает ошибку, скрипт регистрирует сообщение об ошибке для устранения неполадок.

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API Программирование, API, Программист, Open Source, Длиннопост

Файл где можно посмотреть токен, который понадобится для обращения к API

По сути, этот скрипт - инструмент экономии времени для резидентов клуба World Class, которые могут быть уверены, что всегда будут знать когда проходят их любимые занятия.

Версия скрипта полного дня:

function WorldclassAPISchedulingPerm() {

console.log(`Функция WorldclassAPISchedulingPerm начала работу в ${(new Date()).toLocaleString("ru-RU")}`);

const url = 'https://my.worldclass.ru/api/v1/clubs/scheduling';

const currentDate = new Date();

const endDate = new Date(currentDate);

endDate.setDate(currentDate.getDate() + 7);

// Подробное описание: https://pikabu .ru/story/kak_ya_uluchshil_svoyo_vzaimodeystvie_s_fitnesklubom_world_class_naydya_i_ispolzuya_ikh_api_11835205

// Это версия скрипта полного дня

const payload = {

"gymList": [

"d35ba5fc-1f7e-11ec-b664-50e548298f06" // это World Class в Перми

],

"startDate": currentDate.toISOString().split('.')[0],

"endDate": endDate.toISOString().split('.')[0],

"chain": 1,

"token": "70a69ca6-XXXX-XXXX-a975-005056b1372d"

};

const options = {

method: 'post',

contentType: 'application/json',

payload: JSON.stringify(payload),

muteHttpExceptions: true,

headers: {

'brand': 'WorldClass',

'language': 'Ru',

'chain': '1',

'Accept': '*/*',

'Origin': 'https://my.worldclass.ru',

'Referer': 'https://my.worldclass.ru/scheduling?clubs='

},

timeoutSeconds: 30

};

try {

const response = UrlFetchApp.fetch(url, options);

const responseCode = response.getResponseCode();

console.log(`Код ответа: ${responseCode}`);

const responseText = response.getContentText();

const responseData = JSON.parse(responseText); // Разбираем JSON-строку

if (responseCode === 200) {

// Фильтрация для "ICG Color Cycle (сайкл)" и "CORE"

const filteredDates = responseData.data

.filter(item => item.service.name === "ICG Color Cycle (сайкл)" || item.service.name === "CORE")

.map(item => ({

name: item.service.name,

startDate: item.startDate,

employee: item.employee.firstName + " " + item.employee.lastName,

shortDescription: item.service.shortDescription

}));

console.log('Отфильтрованные даты:', filteredDates);

// Создаем события в календаре для каждой отфильтрованной даты

filteredDates.forEach(eventData => {

const startTime = new Date(eventData.startDate);

const endTime = new Date(startTime);

endTime.setHours(startTime.getHours() + 1); // Устанавливаем продолжительность события на 1 час

let eventTitle = `${eventData.name} - ${eventData.employee}`;

let eventDescription = '';

eventDescription = eventData.shortDescription +

'\n\nhttps://my.worldclass.ru/scheduling?clubs=d35ba5fc-1f7e-11ec...' +

'\nСоздано автоматически ' + (new Date()).toLocaleString("ru-RU");

CalendarApp.getDefaultCalendar().createEvent(

eventTitle,

startTime,

endTime, {

description: eventDescription,

location: 'Фитнес клуб World Class, Пермская ул., 33, Пермь, Пермский край, Россия, 614045'

}

);

console.log(`Событие создано для: ${startTime} - ${eventTitle}`);

});

} else {

console.error(`Ошибка: получен статус ${responseCode} с ответом: ${responseText}`);

}

} catch (error) {

console.error('Ошибка запроса:', error.message);

}

console.log(`Функция WorldclassAPISchedulingPerm закончила работу в ${(new Date()).toLocaleString("ru-RU")}`);

}

Как я улучшил своё взаимодействие с фитнес-клубом World Class, найдя и используя их API Программирование, API, Программист, Open Source, Длиннопост

Результат выполнения скрипта

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

Ниже версия скрипта для дневного браслета, когда обязательный выход из зала до 17:00:

// Фильтрация для "ICG Color Cycle (сайкл)" и "CORE", а также по времени начала (до 17:00)

const filteredDates = responseData.data

.filter(item => (item.service.name === "ICG Color Cycle (сайкл)" || item.service.name === "CORE") &&

new Date(item.startDate).getHours() < 17)

.map(item => ({

name: item.service.name,

startDate: item.startDate,

employee: item.employee.firstName + " " + item.employee.lastName,

shortDescription: item.service.shortDescription

}));

console.log('Отфильтрованные даты:', filteredDates);

Как Вы можете воспользоваться этим скриптом?

Если вы новичок и хотите тоже автоматизировать получение определенных занятий, то скрипт Google Apps это мощный инструмент, который может вам помочь:

Шаг 1: Доступ к скрипту Google Apps

  1. Откройте Google Drive: начните с перехода на Google Drive.

  2. Создайте новый скрипт:

  • Нажмите кнопку Создать в верхнем левом углу.

  • Выберите Еще в раскрывающемся меню.

  • Нажмите Скрипт Google Apps. Откроется редактор скриптов Google Apps на новой вкладке.

Шаг 2: Назовите свой проект

  1. Назовите свой скрипт: как только откроется редактор скриптов приложений, вы увидите проект без названия. Нажмите на заголовок (обычно это «Проект без названия») и дайте ему осмысленное имя, например «Расписание World Class».

Шаг 3: Скопируйте код

  1. Удалите код по умолчанию: в редакторе вы увидите код по умолчанию (function myFunction() {}). Вы можете удалить его, чтобы освободить место для нового скрипта.

  2. Скопируйте и вставьте код:

  • Перейдите к статье с кодом скрипта Google Apps.

  • Скопируйте весь скрипт, предоставленный в статье.

  • Вернитесь в редактор скриптов приложений и вставьте код в пустое место.

Шаг 4: Сохраните свой скрипт

  1. Сохраните свою работу: Щелкните значок дискеты или нажмите Ctrl + S (или Cmd + S на Mac), чтобы сохранить свой скрипт.

Шаг 5: Запустите скрипт

  1. Запустите свой скрипт: Чтобы протестировать скрипт, щелкните значок воспроизведения (▶) в верхней части редактора. Если вы запускаете скрипт впервые, Google запросит авторизацию.

  2. Авторизуйте свой скрипт: Следуйте инструкциям, чтобы разрешить скрипту доступ к вашему Google Calendar и другим необходимым службам.

Шаг 6: Проверьте вывод

  1. Проверьте журналы: После запуска скрипта вы можете проверить сообщения журнала, чтобы убедиться, что он работает правильно. Перейдите в Просмотр > Журналы в редакторе скриптов приложений, чтобы увидеть вывод.

Шаг 7: Автоматизируйте его

  1. Установите триггер: если вы хотите, чтобы этот скрипт запускался автоматически через регулярные интервалы, вы можете настроить триггер:

  • Нажмите на значок часов на панели инструментов (Триггеры).

  • Нажмите + Добавить триггер в правом нижнем углу.

  • Установите запуск скрипта еженедельно, например на ночь между понедельником и вторником.

И это все! Вы успешно создали скрипт Google Apps, который автоматизирует добавление расписания в ваш календарь Google.

Результаты

При использовании гугл календаря этот скрипт представляет удобный инструмент который ищет интересующие групповые события и добавляет их автоматически в Ваш собственный Гугл Календарь.

Автор: Михаил Шардин

Показать полностью 6

Как я при помощи двух скриптов смог автоматически сгенерировать опись документов для 700 страниц

Иногда бывают такие задачи за которые браться не хочется - например на фотографии реальная пачка документов около 700 страниц для которой надо составить сопроводительное письмо - то есть сделать опись документов. По примерной прикидке - ручной работы на целый день как минимум.

Как я при помощи двух скриптов смог автоматически сгенерировать опись документов для 700 страниц Программирование, Малый бизнес, Длиннопост

Реальная фотография с документами

Ситуацию несколько облегчает то, что на эти распечатанные документы есть исходные Excel файлы. В итоге поиск и написание решения заняло около часа и в случае повторной работы займёт около 5 минут собственного времени.

Часть 1: Visual Basic for Applications (VBA)

Visual Basic for Applications (VBA) – это язык программирования, который позволяет автоматизировать задачи и создавать макросы для приложений Microsoft Office. Проще говоря, VBA помогает пользователям автоматизировать повторяющиеся задачи, такие как создание отчетов, форматирование документов и многое другое.

В данном случае преимуществом было то, что все документы однотипные и созданы по шаблону - по форме КС-3. Форма КС-3 относится к документации в сфере строительства и представляет собой "Справку о стоимости выполненных работ и затрат".

Как я при помощи двух скриптов смог автоматически сгенерировать опись документов для 700 страниц Программирование, Малый бизнес, Длиннопост

Эта форма для каждого адреса хранилась в файле который назывался "+КС-3.xlsx": внутри основного каталога было множество подкаталогов и файл имел две очень важные ячейки:

  • Ячейка A10 - содержала название.

  • Ячейка I36 - содержала стоимость.

Во всех документах эти ячейки не меняются и данные можно автоматически собрать в Экселе при помощи скрипта, который обходит основной каталог и все вложенные:

Sub CopyDataFromFiles()
Dim FileSystem As Object
Dim objFile As Object
Dim objFolder As Object
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim DestRow As Long
Dim FileExt As String
Dim FilePath As String
Dim DestColumn As Long

' pikabu. ru/story/kak_ya_pri_pomoshchi_dvukh_skriptov_smog_avtomaticheski_sgenerirovat_opis_dokumentov_dlya_700_stranits_11812093

Set FileSystem = CreateObject("Scripting.FileSystemObject")
Set wsDest = ThisWorkbook.Sheets(1) ' Данные будут скопированы на первый лист
DestColumn = 2 ' Столбец B

Application.ScreenUpdating = False

' Вызов рекурсивной функции для обработки каждого файла
ProcessFiles FileSystem.GetFolder(ThisWorkbook.Path), wsDest, DestColumn

Application.ScreenUpdating = True
End Sub

Sub ProcessFiles(ByVal objFolder As Object, ByVal wsDest As Worksheet, ByVal DestColumn As Long)
Dim objFile As Object
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim DestRow As Long

' Пройтись по каждому файлу в каталоге
For Each objFile In objFolder.Files
If InStr(objFile.Name, "+КС-3.xlsx") > 0 Then
' Открытие исходную рабочую книгу
Set wbSource = Workbooks.Open(objFile.Path)
' Установка исходного рабочего листа
Set wsSource = wbSource.Sheets(1) ' Данные будут скопированы на первый лист

' Найти следующую доступную строку на листе
DestRow = wsDest.Cells(wsDest.Rows.Count, DestColumn).End(xlUp).Row + 1

' Копировать значение из ячейки A10 исходного листа в следующую доступную строку на целевом листе
wsDest.Cells(DestRow, 1).Value = wsSource.Range("A10").Value

' Копировать значение из I36 исходного листа в следующую доступную строку на целевом листе.
wsDest.Cells(DestRow, DestColumn).Value = wsSource.Range("I36").Value

' Закрыть исходную книгу без сохранения изменений
wbSource.Close SaveChanges:=False
End If
Next objFile

' Рекурсивная обработка подкаталогов
For Each objFolder In objFolder.SubFolders
ProcessFiles objFolder, wsDest, DestColumn
Next objFolder
End Sub

Результат работы скрипта - созданная таблица:

Как я при помощи двух скриптов смог автоматически сгенерировать опись документов для 700 страниц Программирование, Малый бизнес, Длиннопост

Половина работы сделана - адреса и суммы уже автоматически собраны в одну таблицу.

Часть 2: Google Apps Script

Google Apps Script – это язык программирования, созданный компанией Google для работы с различными сервисами Google, такими как Gmail, Calendar, Drive и другими. Он позволяет разработчикам создавать скрипты, которые могут автоматически выполнять определенные задачи например, управление файлами, создание отчётов - на самом деле практически любые действия.

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

Так что я перенёс таблицу из Экселя в Гугл таблицу и написал скрипт, который генерирует текст письма по простому шаблону:

function generateLetters() {
// https://pikabu. ru/story/kak_ya_pri_pomoshchi_dvukh_skriptov_smog_avtomaticheski_sgenerirovat_opis_dokumentov_dlya_700_stranits_11812093

// Получить активную таблицу и её ID
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
var spreadsheetId = spreadsheet.getId();

// Получить родительскую папку нахождения таблицы
var file = DriveApp.getFileById(spreadsheetId);
var parentFolder = file.getParents().next(); // Получить родительскую папку

// Получить все данные из таблицы
var data = sheet.getRange(2, 1, sheet.getLastRow() - 1, 2).getValues();

// Создать новый Google Документ в той же папке, что и таблица
var doc = DocumentApp.create('Автосозданое сопроводительное письмо');
var docFile = DriveApp.getFileById(doc.getId());
parentFolder.addFile(docFile); // Добавить документ в родительскую папку

var body = doc.getBody();

// Обработать каждую строку в таблице
for (var i = 0; i < data.length; i++) {
var Description = data[i][0]; // Колонка A (описание)
var price = data[i][1]; // Колонка B (цена)

// Добавить описание в виде параграфа
var paragraph = body.appendParagraph('');
paragraph.appendText((i + 1) + ". ").setBold(true);
paragraph.appendText(Description + ":");

// Создать маркированный список для каждого документа
body.appendListItem("Справка КС-3 на сумму " + price + " руб. - 2 экз.");
body.appendListItem("Акт приемки законченного строительством ХХХХХХХ - 1 экз.");
body.appendListItem("Акт выполненных работ – 2 экз.");
body.appendListItem("ЛСР - 2 экз.");
body.appendListItem("ЛСР НЦС - 2 экз.");
body.appendListItem("Единичные расценки стоимости работ на 1 стр - 1 экз.");
body.appendListItem("Расчёт затрат на командировочные расходы на 1 стр - 1 экз.");

// Добавить пустую строку между секциями
body.appendParagraph("");
}

// Сохранить и закрыть документ
doc.saveAndClose();

// Получить URL документа
var docUrl = doc.getUrl();
console.log(`Письмо создано. Можно просмотреть документ по следующей ссылке: ${docUrl}`);
}

Процесс генерации занял 4 секунды:

Как я при помощи двух скриптов смог автоматически сгенерировать опись документов для 700 страниц Программирование, Малый бизнес, Длиннопост

После этого проверил цель всей работы - созданное сопроводительное письмо и сразу с форматированием:

Как я при помощи двух скриптов смог автоматически сгенерировать опись документов для 700 страниц Программирование, Малый бизнес, Длиннопост

Итоги

В целом при помощи двух программных «костылей» смог автоматически генерировать опись документов для любой толщины папки и любого количества файлов.

Автор: Михаил Шардин

16 сентября 2024 г.

Показать полностью 4
Отличная работа, все прочитано!