Тинькофф Инвестиции осуществляют pre-trade контроль рисков. Это значит, что сначала на стороне брокера проверяется достаточность средств для исполнения поручения и позиций для покупки или продажи, соответствие цен и после этого заявка уходит на биржу.
Плюс такого подхода — нельзя купить «лишних» бумаг и получить margin call. Но минус — дополнительные задержки при исполнении ордеров, которые в среднем составляют 200—400 мс.
Еще у брокера есть ограничение на количество выставленных заявок в единицу времени — на момент написания статьи ограничение составляет 300 поручений в минуту. Поэтому HFT-стратегии, требующие минимальных задержек и большого количества поручений, скорее не подходят для работы через Tinkoff API.
Смущает двойная обработка ошибок, например в Login. Зачем их там логировать? Напрашивается отдельный middleware-слой на потоке данных, в котором выполняется централизованное логирование.
я обычно размещаю их в месте использования, а не рядом с реализацией
Согласен. Можно легко и убедительно обосновать. Но я бы оставлял в комментариях реализуемых методов, что это реализация такого-то интерфейса. Поможет поддерживать код?
Интерфейсы UserSaver и UserProvider реализованы в Storage (как и в предыдущей статье), но тогда контекст можно вынести туда, а не таскать его каждый раз в методах SaveUser() и User(). Или я что-то не учитываю?
ведь кто сказал, что за сохранение и получение пользователей обязана отвечать одна система?
Нашёл ответ, зачем таскать контексты в каждом методе. Попахивает "предварительной оптимизацией". Даже если предположить, что источники данных для каждого интерфейса могут быть разные, у них вполне себе может быть общий слой Storage (в котором находится базовый контекст).
type My struct{}
func (My) Try() {
println("My")
}
type My2 struct {
My
}
func (My2) Try() {
println("My2")
}
func main() {
My2{}.Try() // My2
}
Понял, что для структуры serverAPI можно перезаписать методы из встроенной UnimplementedAuthServer. Но зачем прослойка в виде интерфейса Auth, можно же сразу реализовывать интерфейс AuthServer внутри services/auth?
Сервер валидирует и тупо перекладывает данные и ошибки в слой бизнес-логики (services). Но валидация - часть бизнес-логики, а перекладывать данные и ошибки - вообще сомнительное занятие.
// TODO: инициализировать объект конфига // TODO: инициализировать логгер
Лучше бы наоборот. Иначе мы не увидим в логе ошибки инициализации конфига. Но, тут возможна проблема курицы и яйца, т.к. в конфиге определяем, куда складывать логи. Вывод: нужно воспользоваться переменными окружения для конфигурирования логов.
Что-то у меня другой ответ ))
В какой-то момент потребовалось выполнить:
(обстоятельства не помню, просто оставлю тут)
А я написал продолжение! Инструкция: как поднять GitLab CI/CD на GoLang-проекте
термин МР не расшифрован
Пожалуйста, покажите рыбу проекта. Я, пока не увижу код в репке, ничего не понимаю.
https://tinkoff.github.io/investAPI/speedup/
Тинькофф Инвестиции осуществляют pre-trade контроль рисков. Это значит, что сначала на стороне брокера проверяется достаточность средств для исполнения поручения и позиций для покупки или продажи, соответствие цен и после этого заявка уходит на биржу.
Плюс такого подхода — нельзя купить «лишних» бумаг и получить margin call. Но минус — дополнительные задержки при исполнении ордеров, которые в среднем составляют 200—400 мс.
Еще у брокера есть ограничение на количество выставленных заявок в единицу времени — на момент написания статьи ограничение составляет 300 поручений в минуту. Поэтому HFT-стратегии, требующие минимальных задержек и большого количества поручений, скорее не подходят для работы через Tinkoff API.
Моё чудо
у меня все ходы записаны
Номинально присутствует метод для остановки Storage, но он не применяется для Graceful Shutdown.
Смущает двойная обработка ошибок, например в Login. Зачем их там логировать? Напрашивается отдельный middleware-слой на потоке данных, в котором выполняется централизованное логирование.
Это внешняя инфраструктурная задача относительно функциональности. Мы же не пихаем в каждый веб-сервис защиту от DDOS-атак. Например, поможет
fail2ban
Как применяется claims - не очень понятно, я бы исправил.
Согласен. Можно легко и убедительно обосновать. Но я бы оставлял в комментариях реализуемых методов, что это реализация такого-то интерфейса. Поможет поддерживать код?
Интерфейсы UserSaver и UserProvider реализованы в Storage (как и в предыдущей статье), но тогда контекст можно вынести туда, а не таскать его каждый раз в методах SaveUser() и User(). Или я что-то не учитываю?
Нашёл ответ, зачем таскать контексты в каждом методе. Попахивает "предварительной оптимизацией". Даже если предположить, что источники данных для каждого интерфейса могут быть разные, у них вполне себе может быть общий слой Storage (в котором находится базовый контекст).
Понял, что для структуры serverAPI можно перезаписать методы из встроенной UnimplementedAuthServer. Но зачем прослойка в виде интерфейса Auth, можно же сразу реализовывать интерфейс AuthServer внутри services/auth?
Сервер валидирует и тупо перекладывает данные и ошибки в слой бизнес-логики (services). Но валидация - часть бизнес-логики, а перекладывать данные и ошибки - вообще сомнительное занятие.
/config/config_local.yaml
хорошо бы прописать в.gitignore
// TODO: инициализировать объект конфига
// TODO: инициализировать логгер
Лучше бы наоборот. Иначе мы не увидим в логе ошибки инициализации конфига. Но, тут возможна проблема курицы и яйца, т.к. в конфиге определяем, куда складывать логи. Вывод: нужно воспользоваться переменными окружения для конфигурирования логов.
Просто добавить две звёздочки для подпапок:
$ protoc -I proto proto/sso/**/*.proto --go_out=./gen/go/ --go_opt=paths=source_relative --go-grpc_out=./gen/go/ --go-grpc_opt=paths=source_relative
На Маке работает, если запускать команду в терминале.
Но если запускать команду внутри go_task, то ругается на "Could not make proto path relative: proto/sso/**/*.proto: No such file or directory"
Возможно, проблема связана с тем, как
go_task
обрабатывает символы подстановки, такие как**
.Потому для
Taskfile.yaml
пришлось применить вот такой вариант:- mkdir -p gen/go & find ./proto/sso -name '*.proto' | xargs protoc -I proto --go_out=./gen/go/ --go_opt=paths=source_relative --go-grpc_out=./gen/go/ --go-grpc_opt=paths=source_relative