Как я написал коннектор к REST IP Финама на Go

11.07.2024 palmax

Как я написал коннектор к REST IP Финама на Go

Предисловие

Я — профессиональный программист. Уже достаточно давно. Последние N лет разработчик БД. В основном пишу на sql процедуры и функции. Другие языки программирования начинаю забывать (так как нет практики по ним). В свое время писал на Visual FoxPro (да, это уже «мертвый» язык, он уже давно не поддерживается Microsoft). Но у нас до сих пор крутится задача, где клиентская частью написана на VFP.

Почему Go

Так вот. Встала тут задача написать небольшую консольную утилиту с доступом к БД. Сначала хотел написать на Питоне, но не хотелось на компьютере клиента качать и устанавливать его. И стал я присматриваться к другим языкам программирования. C# не хотелось, во первых чисто субъективно, во вторых, клиент в дальнейшем собирался переходить на Linux (хотя вроде есть core net под линукс). И тогда cтал я присматриваться к языку Go.

Прочитал по нему несколько статей. По описанию, он как никто подходил к поставленной задаче: крост-платформенный. Компилируется в один исполняемый файл, который не требует зависимостей.
Скачал и прочитал пару книжек. Для изучения Не первого языка программирования, Go оказался очень прост по структуре и синтаксису. Начать кодить на нем можно достаточно быстро.
Написал утилитку по работе. И этот язык мне так понравился, что я решил его изучать дальше. Но что за изучение языка без практического навыка? Обязательно в этом случае нужен «Пет-проект». А так как я уже некоторое время занимаюсь спекуляцией на рынках (давно написан и крутится в работе бот-помощник для торговли), то проект решил делать в финансовом направлении.

Выбор пал на создание коннектора к брокеру Финам к его Trade API через REST

 

Аналоги

Первоначально начал искать аналоги для ознакомления.
На сайте с примерами в основном проекты на Python. И есть один на Goland от DBoyara  (на текущий момент он в статусе архива = не поддерживается). Он реализует протокол gRPC. Для меня, только начинающего изучать эту технологию, это сложновато. Хотелось начать с чего то попроще, с REST API

Нашел хороший «звездный» проект: коннектор кBinance API . Изучил его и некоторые идеи стал использовать в своей разработке.

Trade API от Финама

Спасибо тем, кто смог дочитать до этого места.
Сразу дам ссылку проекта на github.

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

Реализован почти весь базовый функционал, который есть по протоколу REST API

// AccessTokens проверка подлинности токена
AccessTokens(ctx context.Context) (ok bool, err error)

// GetPortfolio получить данные по портфелю
GetPortfolio(ctx context.Context, opts ...Option) (Portfolio, error)

// GetSecurity получить список инструментов (Максимальное Количество запросов в минуту = 1 )
GetSecurity(ctx context.Context, board, symbol string) (Securities, error)

// GetCandles получить свечи
GetCandles(ctx context.Context, board, symbol string, timeFrame TimeFrame, opts ...Option) ([]Candle, error)

// получить список заявок
GetOrders(ctx context.Context, opts ...Option) ([]Order, error)

// отменить заявку
DeleteOrder(ctx context.Context, transactionId int64) error

// создать новую заявку
//SendOrder(ctx context.Context, order NewOrderRequest) (int64, error)
	
// купить по рынку
BuyMarket(ctx context.Context, symbol, board string, lot int32) (int64, error)
	
// выставить лимитную заявку на покупку
BuyLimit(ctx context.Context, board, symbol string, lot int32, price float64) (int64, error)
	
// продать по рынку
SellMarket(ctx context.Context, board, symbol string, lot int32) (int64, error)
	
// выставить лимитную заявку на продажу
SellLimit(ctx context.Context, board, symbol string, lot int32, price float64) (int64, error)

// TODO
// получить список стоп-заявок
// создать новую стоп-заявку
// отменить стоп-заявку

 

Не доделано выставление стоп-заявок. Возможно это будет в будущем.
В планах также реализовать создание «еванса получение новой свечи». В штатном функционале Финама этого нет (даже по протоколу gRPC).

Приведу пример кода на goland по работе с коннектором (Другие примеры можно увидеть на странице проекта в папке example):

// создание клиента
token := "ваш token"
clientId := "ваш client_id"

client, err := finam.NewClient(token, clientId)
if err != nil {
    slog.Error("main", slog.Any("ошибка создания finam.client", err))
}
// Пример получения данных о портфеле
portfolio, err := client.GetPortfolio(ctx,
    finam.WithIncludePositions(true),
    finam.WithIncludeCurrencies(true),
    finam.WithIncludeMoney(true),
    finam.WithIncludeMaxBuySell(true))

if err != nil {
    slog.Error("main.GetPortfolio", "err", err.Error())
return
}

// баланс счета
slog.Info("Balance", "Equity", portfolio.Equity, "Balance", portfolio.Balance)

// список позиций
for _, pos := range portfolio.Positions {
    slog.Info("position", slog.Any("pos", pos))
}
// список валют счета
slog.Info("portfolio.Currencies", slog.Any("Currencies", portfolio.Currencies))
// список денег
slog.Info("portfolio.Money", slog.Any("Money", portfolio.Money))

 

Что вызвало трудности (непонятки)

1. Разная структура и точки вызова свечей. Почему-то проектировщики api в финаме решили разделить дневные и внутридневные свечи.
2. Очень «мало» информации (полей) в Security (инструменты). В частности, мне для анализа, нужно поле «Открытый интерес».
3. В api нет подписок на появления новых свечей (зато есть возможность реализовать данный функционал самому 🙂 ).

Что дальше?

А дальше, уже практически готов, коннектор к брокеру Алор. К его Alor OpenAPI V2 
Базовый функционал уже реализован. Проект на github выложил в свободном доступе.
Пока не знаю, нужно ли, писать отдельную статью по коннектору к Алор?

И в работе проект по доступу к ISS Московкой биржи и его новому проекту ALGOPACK