Иллюстрация процесса (сгенерировано https://grok.com/)
Иллюстрация процесса (сгенерировано https://grok.com/)

Всем привет.

В этой части мы изучим базовую теорию и перейдем к практическому применению.

Коротко о том, чем мы тут занимаемся

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

Для лиги лени добавляю краткое описание.

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

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

Начнем с теории

Чтобы успешно торговать, нужно сначала разобраться в базовых понятиях.

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

Брокер — это посредник, который даёт тебе доступ на биржу. Без брокера обычный человек не может просто так купить акцию Сбера. Брокер открывает тебе счёт, берёт комиссию и исполняет твои заявки. Я выбрал Т-Банк (не реклама, почему можете узнать в части 0).

Инвестиции vs спекуляции — Инвестиции — это долгосрочное вложение (годы), чтобы получать доход от роста активов или дивидендов/купонов. Спекуляции — короткие сделки на разнице цен. 

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

Риски и доходность — Выше потенциальный доход — выше риск. Например, депозит сейчас даёт 14–16% годовых почти без риска, а акции могут дать 20-30% или привести к потере 50%. Личный опыт показывает, что можно заработать 10% в меся��, а можно потерять 50% в день и получить заблокированные активы. Так что нужно быть аккуратным. 

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

Портфель — Список твоих позиций: сколько акций/облигаций/валюты, текущая стоимость, прибыль/убыток.

Стакан заявок — Таблица лучших цен покупки (bid) и продажи (ask). Показывает баланс спроса/предложения.

Обычно зелёный — bids (покупатели), красный — asks (продавцы). Спред — разница между лучшими ценами.

Что такое Биржевой стакан - Уровни и виды заявок, применение - Equity
Биржевой стакан. Иллюстрация https://equity.today/chto-takoe-birzhevoj-stakan.html

Чем можно торговать на Мосбирже, рассмотрим только базовые инструменты:

Акции → Доля в компании. Доход от роста цены и дивидендов.

Облигации → Долговые бумаги какой-то компании или государства.

Биржевые фонды → Доля в объединении денег многих инвесторов для покупки портфеля активов, управляемый некой организацией.

Валюта → Покупка иностранной валюты.

Переходим от теории к практике

Теперь, вооружившись теорией, перейдем к реализации на моем стеке.

Напомню что разработка ведется на платформе MarsX 3 версии (обоснование выбора можно узнать в части 0). Большая часть кода будет написана на Node.JS для интеграции используется API от ТБанка

Получение ключа доступа к API

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

Перейдем к получению ключа. Для этого открываем страницу настроек инвестиций https://www.tbank.ru/invest/settings/ и в самом низу находим кнопку для создания нового токена.

Токены в ТБанке
Токены в ТБанке

На данном этапе нас интересует токен для песочницы, так как своими деньгами мы рисковать пока что не готовы.

Создание токена для песочницы
Создание токена для песочницы
Токен создан
Токен создан

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

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

Использование API

Документацию можно найти тут https://developer.tbank.ru/invest/api 

В целом, ничего сложного в API нет, обычные REST запросы к внешнему сервису с токеном в заголовках запроса для авторизации.

Из интересного только способ отображение чисел, таких как цены, суммы и т.п. Для отображения числа ТБанк использует объекты с полями units и nano. units - целая часть числа, nano - дробная часть.

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

Так же стоит уточнить, для работы с большинством запросов нужно слать accountId - уникальные идентификатор счета, с которым проводятся манипуляции. Получить список этих счетов и создать новые можно с помощью API.

Базовый сервис для обработки API запросов

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

Код предназначен для MarsX 3 версии, но с небольшими исправлениями может заработать на чистом Node.JS.

В Req лежат investAccountId и investAccountIsSandbox, они парсятся из cookie запроса при каждом запросе к моему серверу.

function server() {
  const currentAccountId = Req.investAccountId;

  return {
    // UsersService
    getAccounts: async (isSandbox) => callApi('UsersService', 'GetAccounts', { status: "ACCOUNT_STATUS_UNSPECIFIED" }, isSandbox),

    // OperationsService
    getPortfolio: async () => callApi('OperationsService', 'GetPortfolio', { accountId: currentAccountId }),
    getOperations: async () => callApi('OperationsService', 'GetOperationsByCursor', { accountId: currentAccountId }),

    // OrdersService
    postOrder: async (payload) => callApi('OrdersService', 'PostOrder', payload),

    // SandboxService
    createSandboxAccount: async (name) => callApi('SandboxService', 'OpenSandboxAccount', { name: name }, true),
    closeSandboxAccount: async (accountId) => callApi('SandboxService', 'CloseSandboxAccount', { accountId }, true),
    addSandboxMoney: async (props) => callApi('SandboxService', 'SandboxPayIn', props, true), 

    // InstrumentsService
    getBonds: async () => callApi('InstrumentsService', 'Bonds', {}),
    getEtfs: async () => callApi('InstrumentsService', 'Etfs', {}),
    getCurrencies: async () => callApi('InstrumentsService', 'Currencies', {}),
    getShares: async () => callApi('InstrumentsService', 'Shares', {}),

    // MarketDataService
    getOrderBook: async (figi) => callApi('MarketDataService', 'GetOrderBook', {
      "depth": 50,
      "instrumentId": figi
    }),
  }
}


async function callApi(service, method, payload, isSandboxProp = undefined) {
  const isSandbox = isSandboxProp ?? Req.investAccountIsSandbox;
  const domain = isSandbox ? sett.sandboxUrl : sett.url;
  const token = isSandbox ? sett.sandboxToken : sett.token;

  const url = `${domain}/tinkoff.public.invest.api.contract.v1.${service}/${method}`;
  try {
    const response = await axios.post(url, payload, {
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
    });
    return response.data;
  } catch (error) {
    throw new Error(`API error: ${error.response?.status} ${error.response?.statusText}`);
  }
}

Конвертация units и nano во float

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

Для этого я сделал небольшой хелпер-конвертер значений во float тип данных.

function server(params) {
  const units = params.units;
  const nano = params.nano;
  const isExactAmount = params.isExactAmount || false;

  const decimal = parseInt(units) + parseInt(nano) / 1000000000;
  return isExactAmount ? decimal : Number(decimal.toFixed(2));
}

Что реализовано на данный момент

  1. Сервис по работе с API песочницы и с реальными деньгами, в зависимости от выбранного аккаунта

  2. возможность переключать аккаунты и создавать новые в песочнице

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

  4. выбранный аккаунт и его тип сохраняются в куках браузера

  5. просмотр портфеля по выбранному аккаунту

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

  7. просмотр стакана для выбранного инструмента

  8. возможность выставления заявки на покупку/продажу с выбором типа заявки (лимитная, рыночная, лучшая цена)

  9. просмотр совершенных операций

Скриншоты результата

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

Логотип не существует еще, так как и названия у проекта еще нет.

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

Краткосрочные планы

Как показала практика, изначальный план по 1-2 статьи в месяц провалился. Теперь цель хотя бы 1 статья в месяц.

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

Если у вас есть идеи что стоит рассмотреть подробнее — пишите комментарии.