Вступление
Предыстория
Все началось несколько лет назад со школьного проекта по Computer science. Моя идея была сделать компьютерную программу которая проанализирует историю рынка, определит комбинации из 4х свечей в кластеры по схожести, запомнит какая свеча шла после этой комбинации и в дальнейшем сможет найти кластер для реальной ситуации на рынке. На странице должна быть отображена ситуация на рынке, найденый кластер комбинаций и его статистика. Если в кластере большой процент комбинаций с последующей зеленой свечей - мы ставим на рост, и соответственно наоборот.
Изначально в качестве API для программы был выбран Forex Oanda. На тот момент это был единственный найденный нами брокер с Open API и кое-какой документацией. В планах сервер который работает с API и фронт для отображения работы
(на тот момент) индикатора, поэтому пишем на Node JS. Проект был доведен до логического завершения, он исправно находил похожие комбинации и собирал их в кластеры, был сделан интерфейс который изображал полу-статичную информацию. Однако протестировать все это мы так и не успели, забросив все после сдачи проекта.
Перерождение
Летом этого года я наконец скачал, так рекламируемое всеми, приложение Тинькофф Инвестиции, но не особо заходил туда, пока осенью я не наткнулся на их API и вспомнил про то что мы уже имели дело с брокерскими API. Окончательно сломило меня наличие готовой SDK для Node JS и протоколом Streaming.
Открыв заброшенный проект, я естественно не имел ни малейшего понятия, спустя столько времени, как что работает и за что отвечает, усугубляла ситуацию ужасная структура проекта со всем бэкендом в одном файле. Я решил начать все с нуля и постепенно подтягивать уже готовые модули из старого проекта.
P.S. Сейчас проект уже на стадии отработки стратегии и до сих пор не все модули используются в новом проекте.
Первые шаги
Соединение с API
Сразу оговорюсь - просто копируя код из этой статьи собрать целый проект не получится, однако, при наличии логики и желания, вполне реально сделать нечто похожее.
Пишем все на Typescript. Для начала определяем все необходимые переменные для соединения, а точнее: apiURL, secretToken, socketURL. Подробности авторизации и остальные детали работы с API описаны в Документации.
import OpenAPI from '@tinkoff/invest-openapi-js-sdk';
// определяем apiURL, secretToken, socketURL
const api = new OpenAPI({ apiURL, secretToken, socketURL});
export default api;
В другом файле импортируем api и уже можем работать с рынком. Обратите внимание что для Production и Sandbox окружений используются разные ссылки и настройки.
import api from './api';
let unSub = function (){};
unSub = api.candle({ figi, interval},async (candle) => {
console.log(candle);
});
Метод candle возвращает последнюю свечу по данному интервалу и Figi актива, он так же возвращает функцию для отписки, мы будем использовать ее когда пользователь прервет соединение с интерактивным сайтом.
Сбор базы данных для дальнейшего анализа
Приступим к созданию метода по сбору данных, на ходу было решено записывать все в JSON и установить лимит по количеству объектов в файле, при переполнении создавать новый файл и записывать уже туда. Этот модуль разделен на 2 части: первая часть собирает свечи непосредственно из Tinkoff партиями максимум в 1 день, вторая используется внутри первой и принимает в себя свечи из партии, формирует комбинации и записывает следующую свечу для формирования статистики в дальнейшем. После формирования массива комбинаций она записывает их в нужный файл в зависимости от наполнения. В новый модуль, отвечающий за работу с API пишем первую функцию.
import { CandleResolution } from '@tinkoff/invest-openapi-js-sdk';
import api from './api';
export async function getCandles(
// возвращает свечи с даты from до даты to
from: string,
to: string,
figi: string,
interval?: CandleResolution,
) {
try {
return await api.candlesGet({
from,
to,
figi,
interval,
});
} catch (e) {
return { tr: 1, Error: e };
}
}
У Tinkoff установлен лимит: максимум 1 день данных по методу api.candlesGet именно поэтому мы пишем свечи такими партиями. Даты - очень капризная вещь, везде разные форматы + разные временные зоны, поэтому убеждаемся что мы передаём в api дату в правильном формате, мной была написана простая функция по преобразованию даты в нужный формат. Пишем ее в модуль с различными часто используемыми функциями.
export function preoDate(date: Date) {
date.setDate(date.getDate() + 1);
const rA = date.toISOString().split(':');
rA.pop();
const rC = rA.join(':');
// addToD - GMT+addToD
return rC + ':00+0' + addtoD + ':00';
}
Непосредственная запись свечей после получения не особо интересна, к тому же если вы решите использовать сразу базу данных вместо JSON файлов, то работать все будет абсолютно по-другому. В моем случае готовые комбинации это папка файлов в которой каждый файл состоит из таких объектов:
{
"mLength": 2013,
"main": [
{
"candles": [
{
"o": 44.4375,
"c": 44.4125,
"h": 44.4375,
"l": 44.4125,
"v": 8820,
"time": "2018-01-23T13:25:00Z",
"interval": "5min",
"figi": "BBG000B9XRY4"
},
{
// candle
},
{
// candle
},
{
// candle
}
],
"afterCandle": {
// candle
}
},
...
В объект можно добавлять различные данные связанные с комбинацией, например сейчас разрабатывается метод определения и записи тренда в котором та или иная комбинация находилась.
Заключение
В следующей части мы детальнее рассмотрим структуру проекта и постепенно начнем смотреть самый главный модуль, ответственный за сборку кластеров.