跨国银行现金流数据集市(Cash Flow Data Mart)设计理念
以下以一家外企银行、跨国银行的司库与流动性管理场景为例,技术栈和模型均为简化示意,不涉及任何真实机构机密。
在跨国银行里,司库和流动性团队每天都要回答几个非常具体的问题:
- 昨天日终,各法人、各币种、各账户到底还有多少钱?
- 今天日间,可用头寸够不够?什么时候最紧?
- 今天发生了哪些大额收付?净流入还是净流出?
- 未来几天、几周,有哪些定期存款到期?会不会造成资金缺口?

这些问题如果让业务人员直接去数据湖里捞原始表,就像让他们去天然水库里自己挑水、过滤、烧开。于是,银行需要一个 现金流数据集市(Cash Flow Data Mart) ------它像司库部门门口的"直饮水站",只提供四类最关键的现金流数据:EOD 金额、Intraday 金额、Transaction、Term Deposit。
一、现金流 Data Mart 的定位
现金流 Data Mart 是数据仓库或 Lakehouse 之上的一个部门级消费层,面向司库、流动性风险、财务和资金运营团队。
它不追求全行大而全,而是聚焦现金流主题:
| 主题 | 含义 | 典型问题 |
|---|---|---|
| EOD 金额 | 日终余额与可用余额 | 昨天结束各账户剩多少? |
| Intraday 金额 | 日间快照余额与头寸 | 今天 10 点、14 点、16 点可用资金多少? |
| Transaction | 现金交易流水与汇总 | 今天收付了多少?净流量多少? |
| Term Deposit | 定期存款本金、利率、到期日 | 未来 7 天、30 天有多少定存到期? |
一句话:
Data Lake 是"原材料水库",Data Warehouse / Lakehouse 是"智能水厂",现金流 Data Mart 是"司库直饮水站"。
二、设计理念:六个原则
1. 业务驱动,只服务现金流场景
不复制全行数据,只保留 EOD、Intraday、Transaction、Term Deposit 四条主线,服务司库日常监控和短期预测。
2. 统一口径,单一事实来源
"可用余额""日间头寸""净交易流""定存到期金额"必须有统一业务定义,避免司库、财务、风险各算各的。
3. 分层建模,不跳层
推荐链路:
源系统 → 数据湖 / 数仓基础层 → 现金流 Data Mart → 语义层 / BI / API
Data Mart 可以依赖集团数仓或 Lakehouse,也可以混合部分源系统,但不能变成新的烟囱。
4. 维度建模,面向分析
采用星型模型:事实表记录 EOD 余额、Intraday 快照、交易流水、定期存款;维度表统一日期、法人、币种、账户、产品、交易对手、期限桶等。
5. 历史快照与审计追踪
EOD 按日快照,Intraday 按时间点快照,Transaction 保留明细,Term Deposit 保留状态变化,满足审计和追溯要求。
6. 安全、可扩展、可消费
支持多法人、多币种、多时区;行级权限按法人/区域隔离;通过 BI、Excel、API 让业务自助分析。
三、整体架构
某外企银行的现金流 Data Mart 可放在 Lakehouse 的 Gold 层:
| 层级 | 内容 |
|---|---|
| 源系统 | 核心银行、支付系统、资金交易、总账、定期存款系统 |
| 接入层 | CDC、ETL/ELT、Kafka、Spark |
| 基础层 | 清洗、标准化、整合、历史拉链 |
| 现金流集市 | EOD、Intraday、Transaction、Term Deposit 事实表与汇总表 |
| 语义层 | 指标定义、业务术语、权限 |
| 消费层 | Power BI / Tableau、Excel、API、司库头寸报表 |
技术栈示例:Snowflake / BigQuery / Databricks + dbt + Airflow + Great Expectations。
四、数据模型设计
维度表
dim_date:日期、月份、季度、工作日标志dim_entity:法人、区域、分行、合并层级dim_currency:币种、折算规则dim_account:账户、账户类型、开户行dim_product:活期、定期、贷款、支付产品dim_counterparty:交易对手、客户类型dim_time_bucket:隔夜、7 天、30 天、90 天dim_snapshot_time:日间快照时点
事实表
| 事实表 | 粒度 | 典型字段 |
|---|---|---|
fact_eod_balance |
日 + 法人 + 账户 + 币种 | 账面余额、可用余额、透支额度 |
fact_intraday_balance |
快照时间 + 法人 + 账户 + 币种 | 可用余额、账面余额、待清算借记/贷记 |
fact_cash_transaction |
交易 ID | 金额、方向、交易类型、状态、起息日、入账日 |
fact_term_deposit |
存单 ID | 本金、利率、起息日、到期日、期限、自动续存标志 |
核心指标
- EOD 可用余额
- Intraday 峰值/谷值可用头寸
- 净交易流 = 流入 - 流出
- 定存到期金额(未来 7 天 / 30 天)
- 交易笔数与平均金额
五、实现例子:用 dbt 构建现金流 Data Mart
1. 项目结构
text
models/
staging/
stg_eod_balance.sql
stg_intraday_balance.sql
stg_cash_transaction.sql
stg_term_deposit.sql
intermediate/
int_cash_position_daily.sql
int_term_deposit_maturity.sql
marts/
cashflow/
mart_cash_position_daily.sql
mart_intraday_liquidity.sql
mart_cash_transaction_summary.sql
mart_term_deposit_maturity.sql
2. Staging 层:接入四类源数据
sql
-- models/staging/stg_eod_balance.sql
select
as_of_date,
entity_id,
account_id,
currency,
product_id,
closing_balance,
available_balance,
overdraft_limit
from {{ source('core_banking', 'account_balance_eod') }}
sql
-- models/staging/stg_intraday_balance.sql
select
snapshot_ts,
entity_id,
account_id,
currency,
available_balance,
ledger_balance,
pending_debits,
pending_credits
from {{ source('core_banking', 'account_balance_intraday') }}
sql
-- models/staging/stg_cash_transaction.sql
select
txn_id,
txn_ts,
value_date,
entity_id,
account_id,
currency,
amount,
direction, -- IN / OUT
txn_type, -- PAYMENT / RECEIPT / TRANSFER / FX
status, -- SETTLED / PENDING / REJECTED
counterparty_id
from {{ source('payments', 'cash_transaction') }}
sql
-- models/staging/stg_term_deposit.sql
select
deposit_id,
entity_id,
customer_id,
currency,
principal_amount,
interest_rate,
start_date,
maturity_date,
term_days,
auto_renewal_flag,
status
from {{ source('core_banking', 'term_deposit') }}
3. Mart 层:现金流日汇总
sql
-- models/marts/cashflow/mart_cash_position_daily.sql
{{ config(
materialized='table',
partition_by={'field': 'as_of_date', 'data_type': 'date'},
tags=['cashflow', 'eod']
) }}
with eod as (
select
as_of_date,
entity_id,
currency,
sum(closing_balance) as eod_closing_balance,
sum(available_balance) as eod_available_balance
from {{ ref('stg_eod_balance') }}
group by 1, 2, 3
),
txn as (
select
value_date as as_of_date,
entity_id,
currency,
sum(case when direction = 'IN' then amount else -amount end) as net_transaction_amount,
count(*) as txn_count
from {{ ref('stg_cash_transaction') }}
where status = 'SETTLED'
group by 1, 2, 3
),
td_mat as (
select
maturity_date as as_of_date,
entity_id,
currency,
sum(principal_amount) as term_deposit_maturing_amount,
count(*) as term_deposit_count
from {{ ref('stg_term_deposit') }}
where status = 'ACTIVE'
group by 1, 2, 3
)
select
coalesce(e.as_of_date, t.as_of_date, d.as_of_date) as as_of_date,
coalesce(e.entity_id, t.entity_id, d.entity_id) as entity_id,
coalesce(e.currency, t.currency, d.currency) as currency,
e.eod_closing_balance,
e.eod_available_balance,
t.net_transaction_amount,
t.txn_count,
d.term_deposit_maturing_amount,
d.term_deposit_count
from eod e
full outer join txn t
on e.as_of_date = t.as_of_date
and e.entity_id = t.entity_id
and e.currency = t.currency
full outer join td_mat d
on coalesce(e.as_of_date, t.as_of_date) = d.as_of_date
and coalesce(e.entity_id, t.entity_id) = d.entity_id
and coalesce(e.currency, t.currency) = d.currency
4. Intraday 流动性汇总
sql
-- models/marts/cashflow/mart_intraday_liquidity.sql
{{ config(materialized='table', tags=['cashflow', 'intraday']) }}
select
cast(snapshot_ts as date) as as_of_date,
entity_id,
currency,
max(available_balance) as intraday_peak_available,
min(available_balance) as intraday_trough_available,
avg(available_balance) as intraday_avg_available,
count(*) as snapshot_count
from {{ ref('stg_intraday_balance') }}
group by 1, 2, 3
5. 交易汇总
sql
-- models/marts/cashflow/mart_cash_transaction_summary.sql
{{ config(materialized='table', tags=['cashflow', 'transaction']) }}
select
value_date,
entity_id,
currency,
txn_type,
direction,
sum(amount) as total_amount,
count(*) as txn_count
from {{ ref('stg_cash_transaction') }}
where status = 'SETTLED'
group by 1, 2, 3, 4, 5
6. 定期存款到期视图
sql
-- models/marts/cashflow/mart_term_deposit_maturity.sql
{{ config(materialized='table', tags=['cashflow', 'term_deposit']) }}
select
entity_id,
currency,
maturity_date,
sum(principal_amount) as maturing_principal,
count(*) as deposit_count,
avg(interest_rate) as avg_interest_rate
from {{ ref('stg_term_deposit') }}
where status = 'ACTIVE'
group by 1, 2, 3
六、调度与数据质量
- EOD:每日日切后调度,T+0 或 T+1 产出。
- Intraday:每 5 分钟或每 15 分钟增量刷新,保留关键时点快照。
- Transaction :准实时或小时级增量,按
value_date分区。 - Term Deposit :每日全量或 CDC 增量,按
maturity_date分区。
质量检查示例:
- EOD 余额与总账勾稽;
- 交易净额与余额变动一致性;
- 定期存款到期日不为空、利率在合理区间;
- Intraday 快照时间连续、无缺失。
七、消费场景
| 场景 | 使用数据 |
|---|---|
| 司库每日头寸报表 | EOD 可用余额 + Intraday 峰值/谷值 |
| 日间流动性监控 | Intraday 快照 + Transaction 净流量 |
| 未来现金流预测 | Term Deposit 到期 + Transaction 趋势 |
| 监管或内部审计 | 历史快照 + 交易明细 + 定存状态 |
| 多币种、多法人合并 | 统一维度 + 折算规则 |
八、总结
现金流 Data Mart 不是数据仓库的替代品,而是数据供应链上的"最后一公里"。
Data Lake 存原水,Data Warehouse / Lakehouse 净化水,现金流 Data Mart 把 EOD、Intraday、Transaction、Term Deposit 四类水调到司库最方便饮用的温度。
它的核心价值是:
- 小:只做现金流主题;
- 专:面向司库、流动性、财务;
- 快:日间和日终都能及时消费;
- 准:统一口径、可追溯、可审计。
对于跨国银行而言,一个设计良好的现金流 Data Mart,能让司库团队从"手工拼 Excel"转向"打开报表就能决策"。