Как подключить 1С к API биржи EXMO для получения данных и создания ордеров?

Программист 1С v8.3 (Управляемые формы) Финансы и профессиональные услуги
← На главную

В этой статье мы подробно разберем, как наладить взаимодействие между 1С и API криптовалютной биржи EXMO. Основная сложность при такой интеграции заключается в правильной аутентификации запросов, которая требует формирования специальной цифровой подписи. Мы рассмотрим весь процесс по шагам: от получения ключей до создания функции для вызова любых методов API, включая получение баланса и создание торговых ордеров.

Проанализируем ключевые моменты: формирование POST-запроса, генерацию подписи с помощью алгоритма HMAC-SHA512 и обработку ответов от сервера биржи.

Шаг 1. Подготовка: API-ключи и адрес сервера

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

Вам понадобятся два ключа:

Важный момент: на момент написания статьи, основной домен API api.exmo.com мог быть заблокирован. Для подключения используйте актуальное зеркало — api.exmo.me.

Шаг 2. Формирование подписи (Sign) с помощью HMAC-SHA512

Это самый ответственный этап. Каждый запрос к приватным методам API должен сопровождаться заголовком Sign. Значение этого заголовка — это тело POST-запроса, подписанное вашим секретным ключом с использованием алгоритма HMAC-SHA512.

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


Функция HMAC_SHA512(СекретныйКлюч, Строка) Экспорт
    Текст = Новый COMОбъект("System.Text.UTF8Encoding");
    Криптография = Новый COMОбъект("System.Security.Cryptography.HMACSHA512");

    Криптография.Key = Текст.GetBytes_4(СекретныйКлюч);
    ХешБайт = Криптография.ComputeHash_2(Текст.GetBytes_4(Строка)).Выгрузить;

    HTML = Новый COMОбъект("htmlfile");
    HTML.Open("text/html");
    // Важно! В этой строке не должно быть лишних пробелов
    HTML.Write("ПреобразоватьСтроку = function(x,y){return x.toString(y?y:16)}"); 
    ЯваСкрипт = HTML.documentElement.document.Script;

    Хеш = "";
    Для Каждого Байт Из ХешБайт Цикл
        Символ = ЯваСкрипт.ПреобразоватьСтроку(Байт);
        Хеш = Хеш + ?(СтрДлина(Символ) = 2, Символ, "0"+Символ);
    КонецЦикла;

    Возврат Хеш;
КонецФункции

Как это работает:

  1. Создаются COM-объекты для работы с кодировкой UTF-8 и криптографией .NET.
  2. Секретный ключ и строка данных преобразуются в массивы байтов.
  3. Вычисляется хэш (также в виде массива байтов).
  4. Для преобразования массива байтов в шестнадцатеричную строку (hex) используется "трюк" с объектом htmlfile и небольшим JavaScript-кодом. Это позволяет получить результат в нужном формате.

Если возникают ошибки вида "Поле объекта не обнаружено ПреобразоватьСтроку", в первую очередь проверьте строку HTML.Write(...) на наличие лишних пробелов.

В качестве альтернативы JavaScript можно использовать функцию на чистом 1С для преобразования десятичного числа в шестнадцатеричное:


Функция DecToHex(Знач _Число)
    База = 16;
    Результат = "";
    Пока _Число <> 0 Цикл
        Поз = _Число % База;
        Результат = Сред("0123456789ABCDEF", Поз + 1, 1) + Результат;
        _Число = Цел(_Число / База);
    КонецЦикла;
    
    Если СтрДлина(Результат) = 1 Тогда
        Результат = "0" + Результат;
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

В этом случае цикл в основной функции будет выглядеть так: Символ = DecToHex(Байт); Хеш = Хеш + Символ;

Шаг 3. Создание универсальной функции для вызова API

Теперь создадим функцию, которая будет формировать запрос, подписывать его и отправлять на сервер. Она будет принимать на вход имя API-метода (например, "user_info") и параметры запроса.

Для всех запросов обязательным параметром является nonce (number used once) — целое число, которое должно увеличиваться с каждым новым запросом. Самый надежный способ его генерации — использовать UNIX-время в миллисекундах.


Функция ПолучитьНонс()
    // Разница в секундах между 01.01.1970 и 01.01.0001
    КонстантаСмещения = 62135596800;
    // Текущая дата в секундах + смещение, умноженное на 1000 для получения миллисекунд
    Nonce = (УниверсальноеВремя(ТекущаяДата()) + КонстантаСмещения) * 1000;
    Возврат Формат(Nonce, "ЧГ=0");
КонецФункции

Теперь напишем саму функцию для вызова API. Она будет принимать имя метода и структуру с параметрами.


Функция ВызовФункцииAPIЭксмо(ИмяМетода, ПараметрыЗапроса = Неопределено)
    // Вставьте сюда свои ключи
    apikey = "K-ВАШ_ПУБЛИЧНЫЙ_КЛЮЧ";
    apisecret = "S-ВАШ_СЕКРЕТНЫЙ_КЛЮЧ";
    
    // Формируем тело POST-запроса
    ПостСообщение = "nonce=" + ПолучитьНонс();
    
    Если ПараметрыЗапроса <> Неопределено Тогда
        Для Каждого Элемент Из ПараметрыЗапроса Цикл
            ПостСообщение = ПостСообщение + "&" + Элемент.Ключ + "=" + Элемент.Значение;
        КонецЦикла;
    КонецЕсли;

    // Генерируем подпись
    Сигнатура = HMAC_SHA512(apisecret, ПостСообщение);
    
    // Формируем заголовки
    ЗаголовокHTTP = Новый Соответствие;
    ЗаголовокHTTP.Вставить("Sign", Сигнатура);
    ЗаголовокHTTP.Вставить("Key", apikey);
    ЗаголовокHTTP.Вставить("Content-Type", "application/x-www-form-urlencoded");
    
    // Для отправки используем более современный объект HTTPЗапрос
    HTTPЗапрос = Новый HTTPЗапрос("/v1/" + ИмяМетода);
    HTTPЗапрос.Заголовки = ЗаголовокHTTP;
    HTTPЗапрос.УстановитьТелоИзСтроки(ПостСообщение, КодировкаТекста.UTF8);

    SSL = Новый ЗащищенноеСоединениеOpenSSL;
    HTTPСоединение = Новый HTTPСоединение("api.exmo.me", , , , , , SSL);

    Попытка
        HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос,);
        Если HTTPОтвет.КодСостояния = 200 Тогда
            Возврат HTTPОтвет.ПолучитьТелоКакСтроку();
        Иначе
            Сообщить("Ошибка HTTP: " + HTTPОтвет.КодСостояния);
            Сообщить(HTTPОтвет.ПолучитьТелоКакСтроку());
            Возврат Неопределено;
        КонецЕсли;
    Исключение
        Сообщить(ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

Шаг 4. Примеры использования

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

Пример 1: Получение баланса пользователя

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


Процедура ПолучитьБаланс()
    РезультатJSON = ВызовФункцииAPIЭксмо("user_info");
    
    Если РезультатJSON <> Неопределено Тогда
        // Для удобной работы с JSON преобразуем его в структуру или соответствие
        ЧтениеJSON = Новый ЧтениеJSON;
        ЧтениеJSON.УстановитьСтроку(РезультатJSON);
        Данные = ПрочитатьJSON(ЧтениеJSON);
        
        // Теперь можно обращаться к балансам
        Сообщить("Баланс USD: " + Данные.balances.USD);
        Сообщить("Баланс BTC: " + Данные.balances.BTC);
    КонецЕсли;
КонецПроцедуры

Пример 2: Создание ордера на покупку

Для создания ордера используется метод order_create. Ему необходимо передать параметры: валютную пару, количество, цену и тип ордера.


Процедура СоздатьОрдер()
    // Создаем структуру с параметрами
    ПараметрыОрдера = Новый Структура;
    ПараметрыОрдера.Вставить("pair", "BTC_USD");
    ПараметрыОрдера.Вставить("quantity", "0.01"); // Количество BTC
    ПараметрыОрдера.Вставить("price", "20000");  // Цена за 1 BTC в USD
    ПараметрыОрдера.Вставить("type", "buy");     // Тип ордера - покупка
    
    РезультатJSON = ВызовФункцииAPIЭксмо("order_create", ПараметрыОрдера);
    
    Если РезультатJSON <> Неопределено Тогда
        Сообщить("Ответ сервера на создание ордера:");
        Сообщить(РезультатJSON);
    КонецЕсли;
КонецПроцедуры

Возможные ошибки и их решение

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

← На главную