Вводные данные

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

  1. Быстрая обработка большого объема запросов для получения курсов валют и готовых результатов конвертации.

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

Пример конкретной задачи: Банк А принимает оплату только в PLN (польский злотый), но покупатель готов оплатить это только картой с валютой EUR. Нам необходимо определить сумму в PLN для отправки запроса к банку-эквайру. Какие есть варианты решения этой задачи?

  1. Использование среднего курса валют с небольшим процентом наценки для нивелирования недополучения дохода нашему мерчанту.

  2. Отказ от принятия оплаты в неподдерживаемой валюте (неоптимальный вариант для бизнеса, но идеальный для разработчика).

  3. Попросить банк добавить поддержку нужной валюты (часто невозможно).

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

Пример 1: У вас карта в евро. Вы совершаете покупки в отпуске в Италии тоже в евро. Сумма покупки — 50 евро, итого с вашего счёта спишется 50 евро.

Пример 2: У вас карта в евро. Вы совершаете покупку в Польше в польских злотых. В этом случае схема пересчёта следующая: польские злотые (PLN) → пересчитываются в USD по курсу Mastercard, далее USD → пересчитываются в CNY по курсу Mastercard, затем CNY → пересчитываются в евро по курсу банка.

(ref: https://telegra.ph/Izmenenie-valyuty-raschyotov-po-kartam-Mastercard-04-03)

Для точного расчета суммы после всех конвертаций нам нужна информация о курсах валют от следующих источников:

  1. "Mastercard" PLN -> USD

  2. "Mastercard" USD -> CNY

  3. "Альфа-Банк Беларусь" CNY -> EUR

С такими вводными приступаем к анализу рынка...

Анализ рынка

Напомню, мы выделили основные критерии поиска:

1) Быстрая обработка большого объема запросов для получения курсов валют и готовых результатов конвертации.

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

Сервис

Плюсы

Минусы

Xe

+ быстрый и удобный API
+ есть возможность выбора источника курса валют (но на данный момент только центральные банки нескольких стран, что недостаточно для моего кейса)
+ есть курсы криптовалюты

- дорого
- нет возможности создания собственных стратегий для конвертации

Openexchangerates

+ быстрый и удобный API
+ приятная цена

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Currencylayer

+ быстрый и удобный API
+ приятная цена

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Coinlayer

+ быстрый и удобный API
+ приятная цена
+ есть курсы криптовалюты

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Fixer

+ быстрый и удобный API
+ приятная цена

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Изначально выбрал https://openexchangerates.org и использовал именно его, но достаточно быстро появились новые бизнес-кейсы, такие как пример с "Альфа-Банк Беларусь" и покупкой в PLN, когда этого функционала перестало хватать. Об этом упоминалось выше.


Все сервисы имели почти одинаковый набор плюсов и минусов, но главное, что ни один из них не имел того, что требовалось мне. С этого момента произошло разочарование из-за отсутствия нужного инструмента, но с другой стороны появилось вдохновение от возможности создать то, что будет работать именно под мою конкретную задачу. Благодаря этому анализу у меня возникла некоторая насмотренность на то, как крупные игроки рынка делают свои API. Поэтому в моей голове уже начала складываться база того, как это должно выглядеть: source_currency, target_currency, amount, base_currency, и поехали, думал я. Но как я ошибался, что этим все ограничится.

Разработка

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

  • /api/v1/rates - эндпоинт, который позволяет получать курсы валют, указывая необходимые параметры.

{
  "rate_source_code": "alfa_bank_belarus", // Каждый источник курса имеет свой уникальный код.
  "exchange_type_code": "card", // Определяет, какой курс использовать. В банках могут быть разные курсы для карточек, наличных операций и т.д.
  "category_code": "bank", // Некоторые источники могут предоставлять курсы валют разных категорий, таких как банки и биржи.
  "branch": "main", // Некоторые источники курса имеют разные курсы валют для различных отделений или филиалов.
  "rounding": 2, // Округление результата до указанного числа цифр после запятой.
  "test_mode": true
}
  • /api/v1/conversions - этот эндпоинт выполнит конвертацию в соответствии с указанной стратегией, учитывая все соответствующие правила и параметры конвертации.

{
  "strategy_code": "alfa_bank_belarus_custom_1", // Код стратегии обмена, который создается отдельно (следующий эндпоинт, который ниже).
  "source_currency": "PLN",
  "target_currency": "EUR",
  "amount": 40.99,
  "source_currency_unit": "amount", // Формат суммы конвертации, который может быть как в привычном формате (1.00), так и в копеечном (100). Этот параметр регулирует формат.
  "target_currency_unit": "amount", // Как и выше, только это формат результата.
  "rounding": 2,
  "branch": "main",
  "test_mode": true
}
  • /api/v1/conversion_strategies - для создания стратегии конвертации валют.

{
  "code": "alfa_bank_belarus_custom_1",
  "name": "Custom strategy for Alfa-Bank Belarus",
  "data": [
    {
      "priority": 1, // Приоритет внутренней конвертации.
      "action_type": "accurate", // Можно задавать точный курс валют у определенного источника, либо брать средний ("average").
      "rate_source_code": "mastercard",
      "category_code": "payment_system",
      "exchange_type_code": "card",
      "target_currency": "USD",
      "base_currency": "BYN" // Валюта для конвертации, используемая в случае отсутствия у источника курса прямой конвертации запрошенных валют.
    },
    {
      "priority": 2,
      "action_type": "accurate",
      "rate_source_code": "mastercard",
      "category_code": "payment_system",
      "exchange_type_code": "card",
      "target_currency": "CNY",
      "base_currency": "BYN"
    },
    {
      "priority": 3,
      "action_type": "accurate",
      "rate_source_code": "alfa_bank_belarus",
      "category_code": "bank",
      "exchange_type_code": "card",
      "target_currency": "REQUESTED",
      "base_currency": "BYN"
    }
  ]
}

Как только все было запущено в продакшн и протестировано, я почувствовал облегчение. Однако, спустя некоторое время осознал, что получился микросервис, который по своей функциональности объединяет все доступные на рынке API-сервисы для конвертации валют и получения курсов. Кроме того, он добавляет такие возможности, как:

  1. Получение курсов из любых источников: банков, платежных систем, бирж и т.д. (ограничивается лишь вашим набором интеграций).

  2. Создание собственных стратегий для конвертации, которые позволяют решать самые сложные кейсы.

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

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

Какие функции или возможности вам кажутся наиболее важными или полезными для улучшения этого сервиса? Я открыт к обсуждению и готов рассмотреть любые предложения по его улучшению.


P.S. Сам микросервис я трансформировал в отдельное API, к которому теперь есть доступ не только у меня. Если кто-то захочет использовать его или просто "потыкать палкой", то велкоме: https://irates.io.

Комментарии (5)


  1. nanshakov
    11.05.2024 10:27

    А что внутри, редис ?какая производитель ность ?


    1. gogochikago Автор
      11.05.2024 10:27

      А что внутри, редис ?

      Rails, PG, Sidekiq, Redis. Есть планы на эксперименты с Elixir, чтобы сравнить затрату ресурсов сервера с производительностью приложения.

      какая производитель ность ?

      Если говорить про публичную версию, которая сейчас крутиться на https://irates.io, то при текущей нагрузке, хватает 1 app сервера (4GB RAM, 2 AMD vCPUs, 80 GB SSD). На такой конфигурации app сервера, я делал load test на 80rps, ничего не улетало в потолок, "average response time" запросов был 391ms


  1. Breathe_the_pressure
    11.05.2024 10:27
    +1

    Пример 1: У вас карта в евро. Вы совершаете покупки в отпуске в Италии тоже в евро.

    Ах как хорошо мы плохо жили...


  1. gudvinr
    11.05.2024 10:27
    +1

    Все популярные API скупил APILayer, теперь fixer.io & co - платные

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

    Ситуация настолько плохая, что мне пришлось библиотеку сделать, чтобы не переписывать код под каждый новый сервис. Можете посмотреть и еще пару источников себе в бэкенд утащить:

    https://bitbucket.org/gudvinr/multixchange


    1. gogochikago Автор
      11.05.2024 10:27

      Благодарю