Назад к блогу

Курсы валют для налоговой отчётности: руководство разработчика по конвертации для IRS, HMRC и НДС ЕС

V
Vlado Grigirov
August 20, 2026
Currency API Exchange Rates Historical Rates Tax Reporting VAT Accounting Finexly

Любая мультивалютная система рано или поздно встречается с бухгалтером. Он задаёт вопрос, который звучит тривиально, но таковым не является: «Какой курс вы использовали для этого счёта?» Если честный ответ — «тот, который вернул API в тот день, и мы его не сохранили», то у вас проблема, которую никакое количество чистого кода не решит в момент подачи отчётности.

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

В этом руководстве разобрано, чего на самом деле требуют IRS, HMRC и Директива ЕС об НДС, какие пять ошибок конвертации приводят к пересчёту отчётности и какую схему снимков курса можно внедрить уже на этой неделе.

Никто не сходится во мнении, что такое «тот самый» курс, — и в этом вся суть

Самая полезная фраза во всей этой области принадлежит самой IRS:

«У Налоговой службы США нет официального обменного курса. Как правило, она принимает любой публикуемый обменный курс, применяемый последовательно».

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

США: спот по умолчанию, среднегодовой курс как послабление

Базовый подход IRS — спот-курс: «В общем случае используйте курс, действующий на момент (т. е. спот-курс), когда вы получаете, выплачиваете или начисляете соответствующую сумму». Там, где доход начисляется равномерно — зарплата, аренда, регулярная выручка бизнеса, — IRS публикует таблицу среднегодовых обменных курсов и предписывает налогоплательщикам «разделить сумму в иностранной валюте на применимый среднегодовой обменный курс». По состоянию на последнее обновление этой страницы 24 февраля 2026 года таблица охватывает налоговые годы с 2021 по 2025.

Обратите внимание на направление операции. Таблица IRS котируется как единицы иностранной валюты за один доллар США, поэтому вы делите. Перевернёте направление по ошибке — и ошибётесь не слегка: ошибка составит квадрат курса. Для суммы в иенах это примерно четыре порядка. Подробнее о направлении курса — ниже, потому что это самая частая ошибка интеграции в этой области.

Для отчётности федеральных агентств США существует второй официальный ряд — Treasury Reporting Rates of Exchange, публикуемый ежеквартально на FiscalData.Treasury.gov в форматах CSV, JSON и XML. Казначейство описывает его как отражающий «обменные курсы, по которым правительство США может приобретать иностранную валюту для официальных расходов, согласно данным, представленным финансовыми служащими каждого представительства на последний рабочий день месяца, предшествующего дате публикуемого отчёта». Если рыночные курсы отклоняются от опубликованного на 10% и более, Казначейство выпускает поправку в середине квартала. API Fiscal Data открыт и не требует ни учётной записи, ни токена — полезно знать, если вам нужен государственный эталонный ряд для сверки.

Великобритания: VAT Notice 700 §7.6 имеет силу закона

Великобритания более предписательна, и соответствующий текст обладает силой закона согласно Приложению 6, параграфу 11 Закона об НДС 1994 года. VAT Notice 700 предлагает бизнесу три способа пересчёта поставок в иностранной валюте в фунты стерлингов:

  1. Курс продажи на рынке Великобритании на момент поставки. Это вариант по умолчанию. В Notice указано, что «курсы, публикуемые в общенациональных газетах, будут приняты в качестве подтверждения курсов на соответствующий момент времени».
  2. Периодический обменный курс HMRC, публикуемый для таможенных целей. Вы можете применять его «ко всем своим поставкам либо ко всем поставкам определённого класса или вида». Предварительное уведомление не требуется, однако «сделав такой выбор, вы не можете затем изменить его, не получив предварительно согласия путём письменного обращения в VAT Written Enquiries Team».
  3. Собственный коммерческий курс или метод, что требует письменного заявления. HMRC оценивает, определяется ли курс «со ссылкой на валютный рынок Великобритании», является ли он «объективно проверяемым» и как часто обновляется. Принципиально важно, что «форвардные курсы или методы, производные от форвардных курсов, неприемлемы» — жёсткая граница, которую стоит рассматривать вместе с разницей между спот- и форвардными курсами.

И фраза, которая определяет поведение вашего слоя кэширования: «Какой бы курс или метод вы ни выбрали, надлежащим курсом для любой поставки является тот, который действует на момент поставки». Момент поставки — не момент выставления счёта, не момент оплаты и уж точно не момент вашей ночной пакетной задачи.

Если вы выбираете второй вариант, механика приятно машиночитаема. HMRC публикует месячные курсы в предпоследний четверг каждого месяца; они применяются к следующему календарному месяцу и отражают курсы по состоянию на полдень дня, предшествующего публикации. Файлы лежат по предсказуемому URL — обратите внимание, что номер месяца не дополняется ведущим нулём:

https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/monthly_csv_2026-9.csv
https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/monthly_xml_2026-9.xml

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

Европейский союз: статья 91 Директивы об НДС

Для поставок внутри ЕС статья 91(2) Директивы Совета 2006/112/EC устанавливает правило: «последний зафиксированный курс продажи на момент возникновения обязанности по уплате НДС на наиболее репрезентативном валютном рынке или рынках соответствующего государства-члена либо курс, определённый со ссылкой на такой рынок или рынки».

Реализовать это в 27 государствах-членах было бы затруднительно, поэтому Директива добавляет практический выход: государства-члены «принимают вместо этого использование последнего обменного курса, опубликованного Европейским центральным банком на момент возникновения обязанности по уплате налога». Пересчёт между двумя неевровыми валютами выполняется «с использованием курса каждой валюты к евро» — то есть кросс-курсом через EUR, а не прямой котировкой пары. Государства-члены вправе потребовать уведомления о том, что вы пользуетесь этой возможностью.

Для импорта статья 91(1) отсылает к таможенным правилам определения стоимости для таможенных целей — принципиально другой курс, на принципиально другую дату, в той же самой книге учёта. Если ваша система трактует «НДС ЕС» как одно правило конвертации, она уже работает неверно.

В основе всего: IAS 21

Налоговые правила надстраиваются над вашей учётной политикой, а для отчитывающихся по МСФО эта политика — IAS 21. Основную работу выполняют четыре положения:

  • Операция в иностранной валюте первоначально признаётся по спот-курсу на дату операции (IAS 21.21).
  • Средний курс допускается как упрощение, но только «пока обменные курсы не колеблются значительно» (IAS 21.22). Это условие, а не значение по умолчанию, — и именно этот пункт тихо перестаёт работать в волатильном квартале.
  • Монетарные статьи пересчитываются по курсу закрытия на отчётную дату (IAS 21.23).
  • Немонетарные статьи, оцениваемые по исторической стоимости, остаются по курсу на дату операции и не пересчитываются.

US GAAP приходит к в целом схожим выводам в рамках ASC 830. Практическое следствие для разработчика: одна транзакция вполне законно может потребовать двух или трёх разных курсов за свой жизненный цикл — один при признании, один на закрытие периода, один при расчётах, — и в вашей схеме должно быть место для всех. Наше руководство по управлению валютным риском в бизнесе объясняет, что возникающие прибыли и убытки означают с коммерческой точки зрения.

Пять ошибок конвертации, которые оборачиваются пересчётом отчётности

1. Направление курса

base=USD&symbols=EUR возвращает евро за доллар. base=EUR&symbols=USD возвращает доллары за евро. Годовая таблица IRS — это иностранная валюта за USD, поэтому вы делите; ответ Finexly с base=EUR — это USD за EUR, поэтому вы умножаете. Оба варианта корректны; смешивать их нельзя.

Исправление скучное и действенное: никогда не называйте колонку rate. Назовите её quote_per_base и сделайте направление однозначным в схеме, а не в комментарии.

2. Повторный запрос вместо воспроизведения

В 2029 году аудит спрашивает о транзакции 2026 года. Если ваш отчётный код обращается к живому endpoint в момент формирования отчёта, два прогона одного и того же отчёта дадут два разных числа. Курс, применённый к транзакции, — это факт об этой транзакции, а не результат поиска: сохраняйте его в момент конвертации. Исторические endpoint существуют для дозаполнения и сверки, а не как замена хранению; паттерны дозаполнения описаны в нашем руководстве по API исторических курсов валют.

3. Средний курс там, где требуется спот

Месячные средние удобны и часто допустимы, но IAS 21.22 накладывает условие, а разовые операции по рекомендациям IRS обычно требуют курса на дату операции. Храните метод рядом с курсом, чтобы отвечать на вопрос «почему именно это число?» без археологических раскопок.

4. Отсутствующие дни

Для выходных, государственных праздников и дней, не являющихся днями TARGET, курс не публикуется. Каждой системе нужно явное правило — обычно «последний опубликованный курс на дату или ранее» — и она должна фиксировать, какое правило сработало. Молчаливый откат через полгода неотличим от бага. Это напрямую пересекается с практиками кэширования и обработки ошибок.

5. Точность и округление

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

Проектируйте снимок курса, а не запрос курса

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

CREATE TABLE fx_rate_snapshot (
    id                BIGSERIAL PRIMARY KEY,
    transaction_id    BIGINT      NOT NULL,
    -- direction is in the name, not in a comment
    base_currency     CHAR(3)     NOT NULL,   -- e.g. 'EUR'
    quote_currency    CHAR(3)     NOT NULL,   -- e.g. 'USD'
    quote_per_base    NUMERIC(20,10) NOT NULL,

    rate_date         DATE        NOT NULL,   -- the date the rate APPLIES to
    method            TEXT        NOT NULL,   -- 'spot' | 'monthly_period' | 'yearly_average'
    fallback_applied  TEXT,                   -- 'previous_business_day' | NULL

    source            TEXT        NOT NULL,   -- 'finexly' | 'hmrc_monthly' | 'irs_yearly'
    source_reference  TEXT,                   -- file name, request id, or table year
    retrieved_at      TIMESTAMPTZ NOT NULL,   -- when WE obtained it

    amount_base       NUMERIC(20,4) NOT NULL,
    amount_quote      NUMERIC(20,4) NOT NULL,

    created_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- one authoritative conversion per transaction per purpose
CREATE UNIQUE INDEX ux_fx_snapshot_txn_method
    ON fx_rate_snapshot (transaction_id, method, rate_date);

Основную аудиторскую нагрузку несут три колонки. rate_date — это дата, к которой относится курс, и она намеренно отделена от retrieved_at — момента, когда вы его получили: курс за 13 марта, загруженный при сентябрьском дозаполнении, совершенно легитимен, и пара меток времени честно об этом говорит. fallback_applied превращает ваше правило для выходных из невидимого поведения в задокументированное свидетельство.

Обратите внимание: строки никогда не обновляются. Если курс исправлен, вставьте новую строку и замените ею старую. Аудиторский след, который можно редактировать, — не аудиторский след.

Получение обоснованного исторического курса

Для курса на дату операции запрашивайте конкретную дату, а не текущую:

curl "https://api.finexly.com/v1/historical?date=2026-03-13&base=EUR&symbols=USD" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "base": "EUR",
  "date": "2026-03-13",
  "rates": {
    "USD": 1.0842
  }
}

При base=EUR значение выражено в долларах за евро — поэтому счёт на 10 000 € конвертируется в 10 842,00 $ умножением. Ниже — паттерн «снимок при записи» на Python, включая откат на отсутствующий день и поля, которые ожидает приведённая выше схема:

import requests
from datetime import date, timedelta
from decimal import Decimal, ROUND_HALF_UP

API = "https://api.finexly.com/v1/historical"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}


def fetch_rate(base: str, quote: str, on: date, max_lookback: int = 5):
    """Return (quote_per_base, rate_date, fallback) for a given date.

    Walks back to the most recent published rate if `on` is a weekend
    or a market holiday, and reports which day it actually landed on.
    """
    for offset in range(max_lookback + 1):
        d = on - timedelta(days=offset)
        r = requests.get(
            API,
            params={"date": d.isoformat(), "base": base, "symbols": quote},
            headers=HEADERS,
            timeout=10,
        )
        r.raise_for_status()
        rates = r.json().get("rates", {})
        if quote in rates:
            fallback = "previous_business_day" if offset else None
            return Decimal(str(rates[quote])), d, fallback

    raise LookupError(f"No {base}/{quote} rate within {max_lookback} days of {on}")


def convert_for_filing(amount_base, base, quote, transaction_date):
    """Convert once, and return everything an auditor will ask for."""
    rate, rate_date, fallback = fetch_rate(base, quote, transaction_date)
    amount = Decimal(str(amount_base))
    converted = (amount * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)

    return {
        "base_currency": base,
        "quote_currency": quote,
        "quote_per_base": rate,
        "rate_date": rate_date.isoformat(),
        "method": "spot",
        "fallback_applied": fallback,
        "source": "finexly",
        "amount_base": amount,
        "amount_quote": converted,
    }


snapshot = convert_for_filing(10000, "EUR", "USD", date(2026, 3, 13))
print(snapshot["amount_quote"], snapshot["rate_date"], snapshot["fallback_applied"])
# -> 10842.00 2026-03-13 None

Функция конвертирует и документирует одним движением. Каким бы ни был ваш слой хранения, запишите этот словарь в него до того, как число увидит что-либо ниже по потоку. Та же дисциплина окупается в мультивалютном выставлении счетов, биллинге SaaS и трансграничном расчёте зарплаты — всё это в итоге попадает в одну и ту же налоговую декларацию.

Сверка с официально опубликованным курсом

Для НДС Великобритании по второму варианту скачивайте месячный файл HMRC раз в месяц и храните его как источник истины для этого периода:

import csv, io, requests
from datetime import date

def hmrc_monthly_rates(year: int, month: int) -> dict:
    """HMRC monthly rates for VAT/customs. Note: month is NOT zero-padded."""
    url = (
        "https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/"
        f"monthly_csv_{year}-{month}.csv"
    )
    resp = requests.get(url, timeout=15)
    resp.raise_for_status()

    reader = csv.DictReader(io.StringIO(resp.text))
    # Don't hard-code the header text: find the ISO-4217 code column by shape.
    code_col = next(
        c for c in reader.fieldnames if "code" in c.strip().lower()
    )
    return {
        row[code_col].strip(): row
        for row in reader
        if row.get(code_col) and len(row[code_col].strip()) == 3
    }

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

Чек-лист мультивалютных данных перед подачей отчётности

  1. У каждой конвертированной суммы есть сохранённый курс. Ни один отчёт не пересчитывает историческую конвертацию во время выполнения.
  2. Направление курса однозначно в названиях колонок, а не в документации.
  3. rate_date и retrieved_at — отдельные поля, и оба заполнены.
  4. Правило для отсутствующих дней явное и фиксируется, а не является неявным ретраем.
  5. Один метод на класс операций, применяемый последовательно на протяжении всего периода, — фактическое юридическое требование и в США, и в Великобритании.
  6. Округление происходит один раз, на финальном шаге, с задокументированным режимом.
  7. Строки снимков только добавляются. Исправления замещают, но никогда не перезаписывают.

Проработайте эти семь пунктов — и вопрос бухгалтера перестанет пугать. Ответом станет запрос к базе.

Часто задаваемые вопросы

Какой обменный курс требует IRS для налоговой отчётности? Никакой конкретный. IRS прямо заявляет, что «не имеет официального обменного курса» и «как правило, принимает любой публикуемый обменный курс, применяемый последовательно». По умолчанию используется спот-курс, действующий на момент получения, выплаты или начисления суммы; для равномерно начисляемого дохода IRS публикует таблицу среднегодовых курсов и предписывает делить сумму в иностранной валюте на указанный курс.

Можно ли использовать API курсов валют вместо опубликованных курсов HMRC для НДС? Да, с оговорками. VAT Notice 700 §7.6 делает вариантом по умолчанию курс продажи на рынке Великобритании на момент поставки, поэтому рыночный курс из API вписывается в этот путь при условии последовательного применения. Собственный периодический курс HMRC — явная альтернатива, которую можно принять без предварительного уведомления, но, приняв её, вы не сможете вернуться назад без письменного согласования. Курс или метод, выходящий за рамки обоих путей, требует письменного заявления, а форвардные курсы не принимаются.

Нужно ли хранить обменный курс или можно запросить его позже? Храните. Сохранённый курс делает конвертацию воспроизводимой; повторный запрос превращает её в новый расчёт, который может не совпасть с уже поданной декларацией. Сохранение курса, его даты, источника и момента получения — именно то, что превращает число в доказательство.

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

Сколько десятичных знаков хранить для налоговых целей? Храните полную точность, которую возвращает ваш поставщик — от шести до десяти десятичных знаков разумная ширина колонки, — и округляйте только при проводке или отображении. Раннее и многократное округление — обычная причина расхождений при сверке, которые никто не может проследить.

Удовлетворяет ли курс ЕЦБ требованиям НДС ЕС? Статья 91(2) Директивы об НДС требует, чтобы государства-члены принимали последний курс ЕЦБ, опубликованный на момент возникновения обязанности по уплате налога, при этом пересчёт между валютами идёт через курс каждой валюты к евро. Некоторые государства-члены требуют уведомления об использовании этой возможности, а для импорта вместо этого действуют правила таможенной оценки.

Подготовьте свои курсы к аудиту

Готовы интегрировать курсы валют в реальном времени и исторические курсы в свой проект? Получите бесплатный API-ключ Finexly — банковская карта не требуется. Начните с 1 000 бесплатных запросов в месяц и переходите на более высокий тариф по мере роста. Полное описание исторического endpoint смотрите в документации API, для разовых проверок попробуйте конвертер валют, сравните API курсов валют, если выбираете поставщика, и изучите тарифные планы, когда объём вашей отчётности вырастет.

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

Vlado Grigirov

Senior Currency Markets Analyst & Financial Strategist

Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...

View full profile →