Инструменты робота, торгующего на Московской бирже через API брокера
- вторник, 12 ноября 2024 г. в 00:00:05
Поскольку хочу использовать для среднесрочной алгоритмической торговли на российском рынке скрипт - робота, то мне необходимо получать от брокера актуальную информацию о текущих ценах и сопутствующую информацию:
Время работы биржи через InstrumentsService/TradingSchedules
.
Основную информацию об инструменте через InstrumentsService/GetInstrumentBy
.
Последнюю котировку по инструменту через MarketDataService/GetLastPrices
.
Торговые лоты - это определенное количество акций, которые можно купить или продать в рамках одной сделки.
Свечи по инструменту для разных временных интервалов через MarketDataService/GetCandles
.
Технические индикаторы через MarketDataService/GetTechAnalysis
.
Понятное имя инструмента через InstrumentsService/FindInstrument
.
В статье разбираюсь как проделать все эти операции при помощи программного кода.
Частному лицу для начала торговли на бирже частному инвестору необходим брокерский счёт. Но лишь у немногих российских брокеров есть собственные API (точно есть у ФИНАМ, Алор, Тинькофф Инвестиции). По личным предпочтениям я решил использовать API от T-Банк (ранее известный как Тинькофф), работая в среде исполнения JavaScript Node.js.
Этот модуль служит для проверки части функций, которые будут использоваться потом в автоматическом режиме. Что он делает? Импортирует необходимые модули:
secrets
и config
для конфиденциальной информации и настроек конфигурации.
Службы для рисования диаграмм (chart
), обработки CSV-файлов (csvHandler
), решений о покупке/продаже (buyDecision
и sellDecision
) и расчета доходности (yieldCalculator
).
Служба ведения журнала (logger
) для отслеживания действий и ошибок.
TinkoffClient
, модуль для взаимодействия с Tinkoff Invest API, и API_TOKEN
для аутентификации.
Основные функции
Функция test()
:
Цель: Тестирование функциональности API и регистрация данных для конкретных биржевых инструментов.
Примеры операций:
Получить основную информацию об инструменте - вызывает InstrumentsService/GetInstrumentBy
для получения информации о определенном инструменте с использованием его идентификатора.
Получить список всех акций - вызывает InstrumentsService/Shares
для составления списка акций и регистрации первых нескольких результатов.
Функция instruments()
:
Цель: Основная функция для извлечения данных и подготовки к торговле.
Примеры операций:
Получение времени работы биржи - получает и регистрирует часы торговли.
Найти всю информацию об акциях в списке файла config - отображает всю информацию о каждом из тикеров в JSON формате.
Последние цены и торговые лоты - извлекает последние цены акций и проверяет размеры лотов (это определенное количество акций, которые можно купить или продать в рамках одной сделки).
Данные свечей - собирает данные свечей (ценовые точки с течением времени) в различные интервалы (5 минут, час, день).
Технические индикаторы - извлекает индикаторы, такие как SMA (простая скользящая средняя), для анализа тенденций акций. По выходным данных нет, хотя свечи за это же время присутствуют.
Разместить рыночный ордер - строки кода для прямого размещения ордеров на покупку/продажу.
Позиции портфеля - перечисляет текущие активы и вычисляет годовую доходность.
В конце код запускает test()
и instruments()
с обработкой ошибок, регистрируя все возникшие проблемы.
Файл instruments.js
это ещё одна часть бота, которая позволяет частному инвестору отслеживать и взаимодействовать с платформой Tinkoff, обрабатывая все: от анализа цен акций и тенденций до размещения сделок. Настройка этого бота подходит для среднесрочной торговли на основе данных, используя Node.js для быстрой обработки данных и взаимодействия с API.
// Импорт необходимых модулей
const secrets = require('../config/secrets'); // Ключи доступа и идентификаторы
const config = require('../config/config'); // Параметры
const chart = require('./services/chartService'); // Отрисовка графиков
const csvHandler = require('./services/csvHandler'); // Работа с CSV файлами
const buyDecision = require('./services/buyDecision'); // Функции покупки
const sellDecision = require('./services/sellDecision'); // Функции продажи
const yieldCalculator = require('./services/yieldCalculator'); // Расчёт годовой доходности от Торгового робота
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 test() {
logger.info(`Запуск функции ${JSON.stringify(logFunctionName())}\n`);
// // Получить основную информацию об инструменте InstrumentsService/GetInstrumentBy
// const testPayload = {
// idType: "INSTRUMENT_ID_TYPE_FIGI", // Тип идентификатора INSTRUMENT_ID_TYPE_FIGI / INSTRUMENT_ID_TYPE_UID / INSTRUMENT_ID_TYPE_TICKER
// id: "BBG004730N88" // Идентификатор инструмента
// };
// const response = await tinkoffClient.callApi('InstrumentsService/GetInstrumentBy', testPayload);
// logger.info(`InstrumentsService/GetForecastBy: ${JSON.stringify(response, null, 2)}`); // Отображение ответа от API
// // Получить список акций InstrumentsService/Shares
// const testPayload = {
// "instrumentStatus": "INSTRUMENT_STATUS_BASE", // https://russianinvestments.github.io/investAPI/instruments/#instrumentsrequest
// "instrumentExchange": "INSTRUMENT_EXCHANGE_UNSPECIFIED"
// };
// const response = await tinkoffClient.callApi('InstrumentsService/Shares', testPayload);
// // Отображение ответа от API
// logger.info(`Ответ: ${JSON.stringify(response, null, 2)}`); // выводится только 3 первых значения .slice(0, 3)
}
async function instruments() {
logger.info(`Запуск функции ${JSON.stringify(logFunctionName())}\n`);
// // Получение времени работы биржи
// const response = await tinkoffClient.callApi('InstrumentsService/TradingSchedules', {});
// logger.info(`Получение времени работы биржи: ${JSON.stringify(response, null, 2)}`);
// await tinkoffClient.getExchangeOpen();
// // Найти всю информацию об акциях в списке файла config
// for (const stock of config.securitiesToMonitorTikerArray) { // securitiesToMonitorFigiArray или securitiesToMonitorTikerArray
// const securitiesToMonitorTikerArrayPayload = {
// "query": stock,
// "instrumentKind": "INSTRUMENT_TYPE_SHARE"
// };
// try {
// const FindInstrument = await tinkoffClient.callApi('InstrumentsService/FindInstrument', securitiesToMonitorTikerArrayPayload);
// logger.info(`Ищем тикер ${stock}:\n${JSON.stringify(FindInstrument, null, 2)}\n\n`);
// } catch (error) {
// logger.error(`Ошибка ${stock}:`, error.message);
// }
// }
// // Получить последнюю цену для акций из списка в файле config
// for (const stock of config.securitiesToMonitorFigiArray) {
// try {
// const quote = await tinkoffClient.getQuote(stock);
// const name = await tinkoffClient.getName(stock);
// logger.info(`Цена акции ${name.nameCombination} [${stock}]: ${quote} руб.`);
// } catch (error) {
// logger.error(`Ошибка ${stock}:`, error.message);
// }
// }
// // Получение торговых лотов - это определенное количество акций, которые можно купить или продать в рамках одной сделки
// for (const stock of config.securitiesToMonitorFigiArray) {
// try {
// const quote = await tinkoffClient.getLot(stock);
// const name = await tinkoffClient.getName(stock);
// logger.info(`Торговый лот акции ${name.nameCombination} [${stock}] = ${quote} шт.`);
// } catch (error) {
// logger.error(`Ошибка ${stock}:`, error.message);
// }
// }
// Получение понятного имени инструмента
for (const stock of config.securitiesToMonitorFigiArray) {
try {
const name = await tinkoffClient.getName(stock);
const nameUid = name.uid;
logger.info(`${name.nameCombination} это ${stock} или ${nameUid}.`);
} catch (error) {
logger.error(`Ошибка ${stock}:`, error.message);
}
}
// // Тест корректности размера лотов:
// const figi = 'BBG004730N88'; // Пример ФИГИ
// const price = await tinkoffClient.getQuote(figi);
// const quantity = await config.getPurchaseQuantity(price, figi);
// logger.info(`Тест количества лотов ${figi} для покупки: ${quantity}`);
// // Получение свечей по инструменту
// for (const stock of config.securitiesToMonitorFigiArray) {
// try {
// const name = await tinkoffClient.getName(stock);
// const candles5Min = await tinkoffClient.getCandles(stock, "CANDLE_INTERVAL_5_MIN");
// logger.info(`5-минутные свечи для ${name.nameCombination}: ${JSON.stringify(candles5Min.slice(0, 3), null, 2)}`); // выводится только 3 первых значения
// const candlesHour = await tinkoffClient.getCandles(stock, "CANDLE_INTERVAL_HOUR");
// logger.info(`Часовые свечи для ${name.nameCombination}: ${JSON.stringify(candlesHour.slice(0, 3), null, 2)}`); // выводится только 3 первых значения
// const candlesDay = await tinkoffClient.getCandles(stock, "CANDLE_INTERVAL_DAY");
// logger.info(`Дневные свечи для ${name.nameCombination}: ${JSON.stringify(candlesDay.slice(0, 3), null, 2)}`); // выводится только 3 первых значения
// } catch (error) {
// logger.error(`Ошибка ${stock}:`, error.message);
// }
// }
// // Получение технических индикаторов по инструменту
// for (const stock of config.securitiesToMonitorFigiArray) {
// try {
// const instrument = await tinkoffClient.getName(stock);
// const instrumentUid = instrument.uid;
// const indicatorType = "INDICATOR_TYPE_SMA"; // Пример типа индикатора (SMA, RSI, MACD и т.д.)
// const interval = "INDICATOR_INTERVAL_FIVE_MINUTES"; // Пример интервала (5 минут, час, день) INDICATOR_INTERVAL_ONE_HOUR
// const typeOfPrice = "TYPE_OF_PRICE_CLOSE"; // Тип цены (например, закрытие)
// const indicators = await tinkoffClient.getTechIndicators(instrumentUid, indicatorType, interval, typeOfPrice);
// logger.info(`Индикатор ${indicatorType} для ${instrument.nameCombination}: ${JSON.stringify(indicators.slice(0, 3), null, 2)}`); // выводится только 3 первых значения
// } catch (error) {
// logger.error(`Ошибка ${stock}: ${error.message}`);
// }
// }
// // Создание графиков пересечения свечей и индикатора для акций из списка в файле config
// for (const stock of config.securitiesToMonitorFigiArray) {
// try {
// const charts = chart.generateCandlestickChart(stock);
// } catch (error) {
// logger.error(`Ошибка ${stock}:`, error.message);
// }
// }
// // Функция для отправки рыночного ордера
// tinkoffClient.placeMarketOrder('BBG004730N88', 1, 'ORDER_DIRECTION_BUY'); // Купить акцию
// tinkoffClient.placeMarketOrder('BBG004730N88', 1, 'ORDER_DIRECTION_SELL'); // Продать акцию
// // Получить все открытые позиции счёта
// const GetSandboxPositions = await tinkoffClient.getPortfolio();
// logger.info(`Все открытые позиции счёта ${secrets.AccountID}:\n ${JSON.stringify(GetSandboxPositions, null, '\t')}\n\n`);
// // Расчёт годовой доходности от Торгового робота
// const SilverFirBotYield = await yieldCalculator.calculateAnnualYield();
// logger.info(`Годовая доходность от Торгового робота SilverFir Bot: ${SilverFirBotYield}%.`);
// // Получить прогнозов инвестдомов по инструменту InstrumentsService/GetForecastBy
// const ForecastPayload = {
// "instrumentId": "1c69e020-f3b1-455c-affa-45f8b8049234" // У Аэрофлот (AFLT), BBG004S683W7 [1c69e020-f3b1-455c-affa-45f8b8049234] нет данных аналитиков.
// };
// const response = await tinkoffClient.callApi('InstrumentsService/GetForecastBy', ForecastPayload);
// logger.info(`InstrumentsService/GetForecastBy: ${JSON.stringify(response, null, 2)}`); // Отображение ответа от API
}
// ======================================================================================
// ============ Запуск функций ===================================================
// ======================================================================================
test().catch(logger.error);
instruments().catch(err => logger.error(err));
Многие строки закомментированы, но это не потому что они не рабочие, а потому что они используются для тестов той или иной функции.
Проект полностью представлен на Гитхабе: https://github.com/empenoso/SilverFir-TradingBot.
Новые модули будут загружаться по мере написания и тестирования.
Автор: Михаил Шардин
11 ноября 2024 г.