Мультивалютные книги и курсы
1) Что такое «мультивалютные книги»
Книга (ledger) — транзакционный леджер с двойной записью (двухсторонние проводки), ведущийся в нескольких валютах одновременно:- Wallet-книга: счет игрока (игровая валюта/валюты).
- Settlement-книга: расчеты с PSP/эквайрером (валюта сеттлмента).
- Treasury-книга: банковские счета, конвертации, хедж-сделки.
- Reporting-книга: свод в отчетной валюте (например, EUR) без ретроспективной переоценки продуктовых метрик.
Каждая книга фиксирует валюту операции, валюту представления и курс на момент признания.
2) Иерархия валют и политик
1. Base / Reporting Currency — единая отчетная валюта (например, EUR).
2. Wallet Currencies — валюты кошельков (USD/EUR/TRY/UAH и т. д.).
3. Settlement Currencies — что присылает PSP (например, USD).
4. Bank Currencies — валюта счета мерчанта/казначейства.
- Продуктовые метрики (ND/NGR/ARPPU) — по историческому курсу события (обычно `settled_at`).
- Финансы/трежери — дополнительно фиксируют курс на `funded_at` и `payout_at`.
- Запрещена «скрытая» переоценка в продуктовых витринах.
3) Курсы и их источники
Intraday reference (tick/minute): Refinitiv/ECB/банки — для нормализации событий.
EOD (конец дня): для переоценки остатков (unrealized FX).
Effective FX: из файла PSP/банка (факт конвертации).
Triangulation: через якорь (EUR или USD) при отсутствии прямой котировки.
Quote policy: `mid` либо `bid/ask` → `mid ± spread_bps`. Спред хранится отдельно.
Храните: `fx_source`, `fx_pair`, `fx_rate`, `fx_timestamp`, `quote_type`, `spread_bps`, и маршрут triangulation.
4) Точки признания и слои курсов
`authorize_at` — курс не фиксируем (без захвата нет признания).
`captured/settled_at` — исторический курс для продуктового слоя и ND.
`funded_at` — курс поступления на банк (realized FX для FI/treasury).
`payout_at` — курс при выплате игроку.
`eod` — курс конца дня для переоценки остатков (unrealized FX).
5) Точность, округления, минимальные единицы
Деньги — целые minor units (int) + `scale` в справочнике валют.
Курсы — не менее 8–10 знаков после запятой.
Округления: банковское (half-even) для отчетности; в UI — локальные правила.
Вести раздельные поля: `amount_original`, `amount_wallet`, `amount_reporting`, `amount_effective`.
6) Двойная запись и GL-карта (упрощенно)
Примеры проводок:6.1. DEPOSIT_CAPTURED (GBP, отчетная — EUR)
Дт: AR: PSP (GBP)
Кт: Player Balance (GBP/EUR по кошельку)
Параллельно фиксируем `fx_rate_settle (GBP→EUR)` и `amount_reporting`.
6.2. FUNDING_RECEIVED (USD на банк)
Дт: Bank USD
Кт: AR: PSP GBP (закрываем по эквиваленту; разница → Realized FX).
6.3. WITHDRAWAL_PAID (TRY)
Дт: Liability: Player (TRY)
Кт: Bank TRY (или Bank EUR + конвертация; разница — realized FX).
7) Архитектура данных (минимальная модель)
ref. currencies (
code PK, scale, symbol, is_crypto, is_active
)
ref. fx_rates_intraday (
pair PK, ts PK, rate, quote_type, source, spread_bps, triangulation_meta
)
ref. fx_rates_eod (
pair PK, date PK, rate, source
)
ledger. entries (
entry_id PK, book, -- WALLET SETTLEMENT TREASURY REPORTING debit_account, credit_account,
amount_original, currency_original,
amount_reporting, reporting_currency,
fx_rate_at_settle, fx_source, fx_pair, fx_timestamp,
event_type, event_id, user_id, provider, method,
occurred_at, created_at, meta
)
treasury. funding_receipts (
funding_id PK, provider, bank_account,
currency, amount, fx_to_reporting, amount_reporting,
received_at, value_date, meta
)
treasury. balances (
date PK, account PK, currency PK, amount
)
dw. transactions_flat (
tx_id PK, user_id, provider, method, type, status,
amount_original, currency_original,
amount_reporting, reporting_currency, fx_rate_at_settle,
settled_at, funded_at, conversion_owner, meta
)
8) Поток нормализации (ETL/ELT)
1. Ингест сырья → нормализация статусов PSP.
2. Присвоение исторического курса на `settled_at` из `fx_rates_intraday`.
3. Запись двойной проводки в нужную книгу (wallet/settlement).
4. Отдельный импорт funding и effective FX.
5. Ежедневная reval остатков по `fx_rates_eod` (treasury-книга).
6. Построение витрин (ND/NGR/LTV) без ретро-переоценки.
9) Сверка и консистентность
Tx→File: все captured/settled попали в файл PSP (по суммам/валютам/датам).
File→Tx: все в файле отражено в книгах/проводках.
FX Reference vs Effective: считать `slippage_bps`; алерт на выход за порог.
Проверка triangulation: `A→B B→C` ≈ `A→C` в пределах bps-толеранса.
Идемпотентность: `event_id` и `idempotency_key` — защита от дублей.
10) Частые сценарии и как их вести
Multi-wallet: кошелек игрока может быть в иной валюте, чем депозит — делайте внутреннюю конвертацию по вашему курсу (политика `conversion_owner='MERCHANT'`).
PSP-conversion: храните `fx_effective`, `fx_reference` и `spread_bps` для анализа маржи PSP.
Крипто: оценка по VWAP-окну; funding в стейблах — второй слой FX.
Cross-wallet transfer: движение внутри платформы — без FX-дохода, просто перенос между книгами.
11) SQL-шаблоны
11.1. Нормализация суммы в отчетную валюту по историческому курсу
sql
SELECT t. tx_id,
t. amount_original,
t. currency_original,
r. rate AS fx_rate_at_settle,
ROUND(t. amount_original r. rate, rep. scale) AS amount_reporting
FROM raw. transactions t
JOIN ref. fx_rates_intraday r
ON r. pair = CONCAT(t. currency_original, '/',:reporting_ccy)
AND r. ts = (
SELECT MAX(ts) FROM ref. fx_rates_intraday
WHERE pair = r. pair AND ts <= t. settled_at
)
JOIN ref. currencies rep ON rep. code =:reporting_ccy
WHERE t. settled_at BETWEEN:from AND:to;
11.2. Измерение спреда PSP (effective vs reference)
sql
SELECT provider, method, DATE(settled_at) AS d,
SUM(original_amount fx_reference_rate) AS ref_in_reporting,
SUM(settlement_amount_in_reporting) AS eff_in_reporting,
10000 (SUM(settlement_amount_in_reporting) /
NULLIF(SUM(original_amount fx_reference_rate),0) - 1) AS spread_bps
FROM dw. fx_settlement_view
WHERE settled_at BETWEEN:from AND:to
GROUP BY 1,2,3;
11.3. EOD-переоценка остатков (unrealized FX)
sql
INSERT INTO treasury. fx_reval_ledger (date, currency, position_amount, rate_eod, amount_reporting_eod, reval_diff, type)
SELECT
:eod AS date, b. currency, b. amount,
e. rate AS rate_eod,
b. amount e. rate AS amount_reporting_eod,
b. amount (e. rate - COALESCE(l. rate_eod, e. rate)) AS reval_diff,
'UNREALIZED'
FROM treasury. balances b
JOIN ref. fx_rates_eod e
ON e. pair = CONCAT(b. currency, '/',:reporting_ccy) AND e. date =:eod
LEFT JOIN LATERAL (
SELECT rate_eod FROM treasury. fx_reval_ledger
WHERE currency=b. currency AND date=:eod - INTERVAL '1 day'
ORDER BY date DESC LIMIT 1
) l ON TRUE;
12) KPI и дашборды
FX Slippage (bps) по PSP/методу/MID.
Realized FX P&L (funding/payout) и Unrealized FX (EOD/EOM).
Open FX Position по валютам vs лимиты политики.
Hit-rate «вовремя полученных» курсов (stale-rates инциденты).
Доля PSP-conversion vs Merchant-conversion и ее TCO.
Точность округлений (отклонения сумм ≥ 1 minor unit — флаг).
13) Алерты и пороги
Stale rate: нет курса на момент события → fallback-источник/ретрай.
Triangulation mismatch: расхождение > X bps.
Spread spike: `spread_bps` выше порога по мажорам/мейнерам.
Open position breach: превышение лимита по любой валюте.
Reval shock: дневная переоценка < −Xσ или > +Xσ — ревью.
14) Best practices (коротко)
1. Строго разделяйте продуктовый слой (исторический FX) и FI/treasury (funding/payout/reval).
2. Используйте minor units и храните курсы с высокой точностью.
3. Логируйте conversion_owner и измеряйте маржу PSP (effective vs reference).
4. Реализуйте идемпотентность событий и двустороннюю сверку (Tx→File и File→Tx).
5. Держите anchor-валюту для triangulation и валидируйте расхождения в bps.
6. Переоценку остатков делайте EOD-процедурой с отдельным GL.
7. Учитывайте DST/таймзоны при присвоении курсов на settle/funding.
8. Регулярно тестируйте округления (property-based tests на границах scale).
15) Чек-лист внедрения
- Определена reporting currency и политика исторического FX.
- Источники курсов: intraday + EOD, fallback и SLA обновления.
- Модели `ledger.entries`, `fx_rates_`, `funding_receipts`, `balances`, витрина `transactions_flat`.
- Механизм triangulation и лог маршрута.
- Алерты: stale-rates, spread spike, triangulation mismatch, open position breach.
- Дашборды KPI и акты сверки с PSP/банком.
- Процедуры reval и раздельные GL для realized/unrealized FX.
- Тест-наборы округлений и точности хранений.
Резюме
Мультивалютные книги — это дисциплина разделения слоев: исторический FX для продукта, фактический для трежери, EOD-переоценка для балансов. С прозрачными источниками курсов, точной моделью данных, двойной записью и автоматизированной сверкой вы исключите «валютный шум» из аналитики, обеспечите аудит и получите управляемый FX-риск при глобальной монетизации.