Skip to content

Bank Statement Collection

About This Page

What: How each bank's statements reach the system, flow table structure and sharding strategy, collection cron jobs, and flow type codes Audience: Product managers who need to understand "where the matching engine's input comes from" Prerequisites: Deposit Methods OverviewReading time: 5 minutes Owner: Deposit Product Manager

Key Takeaways: Bank statement collection is the input source for the matching engine. Different banks have vastly different collection methods — from real-time push in seconds to batch pulls only 3 times daily — directly determining the user's deposit waiting time.


Quick Navigation — What you might want to do:

Why This Page Exists

The core prerequisite for Push mode (FPS, online banking, ATM, etc.) deposits: bank statements must first reach the system before the matching engine can work.

Different banks' statement arrival methods vary dramatically — from real-time push in seconds to batch pulls only 3 times daily. This directly determines the waiting time from user transfer to seeing "deposit successful." Understanding statement collection mechanisms is the foundation for diagnosing "money hasn't arrived" issues and evaluating bank onboarding proposals.

eDDA/BST Don't Go Through Statement Collection

Pull mode (eDDA) and Direct mode (BST) deposits do not rely on statement collection — the system initiates the debit/transfer itself and knows when it completes. This page only covers Push mode statement collection.


Statement Collection by Bank

Real-time Push

HSBC — MT910 Real-time Notification

DimensionDescription
ProtocolSWIFT MT910 format, transmitted via SFTP + GPG encryption
Arrival LatencySeconds — pushed immediately after bank credits
Collection Servicehsbc_bank_flow_service (Python)
TransType218 (HSBC)
DeduplicationTransaction Reference Number (:20: field) unique constraint

MT910 is the SWIFT standard "credit confirmation" message. The system periodically downloads GPG-encrypted files from SFTP, decrypts and parses the MT910 format, extracting transaction reference number, amount, currency, payer name, and other fields.

Key Parsing Fields:

  • :20: -> Transaction reference number (deduplication identifier)
  • :32A: -> Date + Currency + Amount (compound field: YYMMDD + CCY + Amount)
  • :50K: -> Payer name (used for name matching)
  • :72: -> Remarks (supplementary information)

SCB / CGB — FPS API Real-time

DimensionSCBCGB
ProtocolWebhook callback + REST APIREST API batch/single
Arrival LatencySecondsSeconds
Collection Servicescb_service (Go)cgb_fps_service (Go)
TransType219 (SC_SUBACC)FPS related
Queue MechanismDB Queue (9 Job Handlers)DB Queue (4 Job Handlers)

SCB actively pushes transaction events to the system via Webhook. The system persists the event first then enqueues for processing (ProcessWebhookEvent -> Save -> Enqueue). CGB submits batch or single payment tasks via REST API, and the system polls for results via query Jobs.

DimensionDescription
ProtocolBinary Socket bidirectional link, message-level encryption
Arrival LatencySeconds — event-driven, bank actively pushes
Collection Servicecmb_stock_trans / ms_stock_bank_transaction
TransType101 (MSB BST), 102 (CMB BST), 304 (Airstar BST)

BST (Bank-Securities Transfer) communicates via long-connection Socket. After the bank completes fund transfer, it actively pushes the result through the established Socket link. No system polling required.

Note the Distinction

BST statements are part of Direct mode and don't go through the matching engine. However, BST statements are still written to the flows table for reconciliation and monitoring purposes.

Scheduled Pull

BOCHK — B2E Batch Pull

DimensionDescription
ProtocolB2E (Business-to-Enterprise) XML-RPC
Arrival Latency3 pulls per day + ~2 hours conversion processing
Collection Servicebochk_flow_go (Go)
TransType301 (BOC)
DeduplicationPre-query DB to skip existing records

BOCHK B2E is the slowest statement source. The system actively pulls 3 times daily:

BatchTimeContent
TodayActivity~06:00Today's settled transactions
AcctStatement~07:00Previous day's account statement
AcctActivity~08:00Recent 2 days' transaction details (including counterparty info)

After pulling, ~2 hours of flow conversion (TrdRecordFlowConverter / TransactionRecordFlowConverter) is needed to standardize raw records into boc_bank_flow format before writing to the flows table.

PM Focus: BOCHK deposit "slow crediting" mainly comes from statement collection delay, not the matching engine. This is why BOCHK's matching time window is -3~+4 days (2 days wider than the standard -3~+2).

ICBC Asia — Banking API Polling

DimensionDescription
ProtocolBank-enterprise direct REST API, RSA signature verification
Arrival LatencyMinutes
Collection Serviceicbc_be_relay (Python)
TransType202 (ICBCASIA)
ICBC Known System Limitations

ICBC is the second largest deposit source (about 12.3%), but has the most system limitations among all banks. PMs and operations should pay special attention to these known issues:

LimitationImpactMitigation
No unique transaction IDDeduplication can only rely on composite fields (amount+date+card number+remarks), higher duplicate risk than other banksMatching engine adds extra deduplication validation logic
T-1 late statementsSome statements arrive the day after the transaction date (not real-time)Matching time window extended by 1 extra day
Missing balance check for refund/reversalCannot automatically verify securities account balance sufficiency before reversalOperations must manually check balance before reversal
Unstable statement formatICBC occasionally adjusts statement message format without prior noticeStatement parser maintains compatibility redundancy

Extra Regression Required for ICBC Changes

Due to the above limitations, any changes involving matching rules or statement parsing require extra regression testing specifically for ICBC — particularly deduplication logic and T-1 statement scenarios. For ICBC-related troubleshooting -> Deposit Troubleshooting - ICBC Duplicate Statements

Other API Polling

BankCollection ServiceTransTypeArrival Latency
DBSdbs_service208Minutes
CCB AsiaAPI polling206Minutes
ZA BankAPI polling221Minutes
AirstarAPI callback304Seconds

Manual Upload

EWB — CSV + BAI2 Files

DimensionDescription
ProtocolOperations manually upload CSV / BAI2 files to OA backend
Arrival LatencyDepends on operations, typically 1-2 times daily
TransType217 (EWB_SUBACC)

CSV provides basic transaction information; BAI2 supplements payer name and other fields needed for matching. After upload, the system automatically parses, deduplicates, and writes to the flows table.

Summary Comparison Table

BankCollection MethodProtocolArrival Latency
HSBCReal-time pushMT910 via SFTPSeconds
SCBReal-time pushWebhook + APISeconds
CGBReal-time pushFPS REST APISeconds
CMB/MSBReal-time pushSocket bidirectional linkSeconds
AirstarAPI callbackREST APISeconds
ICBCScheduled pullBanking APIMinutes
DBSScheduled pullAPIMinutes
CCBScheduled pullAPIMinutes
ZA BankScheduled pullAPIMinutes
BOCHKBatch pullB2E XML-RPCHours
Hang SengSpecial interfaceMinutes~hours
EWBManual uploadCSV + BAI2Depends on operations

Bank Statement Arrival Latency Visualization

From user transfer to statement entering the system, the waiting experience varies dramatically:

Latency LevelBanksTypical WaitUser Perception
SecondsHSBC(MT910), SCB(Webhook), CGB(FPS API), Airstar(API)<1 minute"I just transferred and it's already showing"
MinutesICBC(Banking API), DBS(API), CCB(API), ZA(API)5~30 minutes"It arrived after a short while"
HoursBOCHK(B2E 3x daily)2~6 hours"Transferred in the morning, arrived in the afternoon"
UncertainHang Seng(special interface), EWB(manual upload)Hours~next day"Needs to wait for operations to process"

PM Focus: When a user complains "money hasn't arrived," first check which bank — if it's BOCHK, 2~6 hours of waiting is normal, not a system failure.

If Requirements Change: Statement Collection Related
ChangeLocationNotes
Add new bank statement collectionNew Go/Python service + crontab configRefer to Deposit Change Guide - Scenario 7
Modify B2E pull frequency (BOCHK)bochk_flow_go/conf/conf.tomlAdjust cron expression
Modify matching frequencydeposit/doc/crontab.sh -> corresponding match:*Refer to Deposit Change Guide - Scenario 6
Replace SFTP/API credentialsConfiguration file of corresponding bank collection serviceUsually requires ops deployment
Modify Flow Converter frequency (BOCHK)bochk_flow_go cron configCurrently every 2 hours

Statement Collection Exception Troubleshooting

When statements are not coming in or processing abnormally, follow this path.

Quick Diagnosis: Why Statements Haven't Arrived

Step-by-Step Runbook: Received "Bank Statement Not Coming In" Alert

Minute 1 — Assess impact scope

  1. Review alert content: which bank? How many pending statements are queued?
  2. In OA statement list, filter by that bank, check the arrival time of the most recent statement
  3. If most recent statement was a few minutes ago -> possible false alarm (statements coming in normally, just matching delayed)
  4. If most recent statement was hours ago -> confirm collection is interrupted

Minutes 2~5 — Locate collection service 5. Check if the corresponding collection service process is alive:

  • HSBC: hsbc_bank_flow_service (Python)
  • SCB: scb_service (Go)
  • CGB: cgb_fps_service (Go)
  • BOCHK: bochk_flow_go (Go)
  • ICBC: icbc_be_relay (Python)
  1. Check recent service logs -> any connection timeouts, auth failures, parse exceptions

Minutes 5~10 — Attempt recovery 7. If service is down -> restart service, observe 1~2 cycles for new statements 8. If auth/certificate expired -> need to update credentials (contact bank relationship team for new credentials) 9. If bank side didn't push data -> not a system failure, record and contact bank relationship team

Minutes 10~15 — Compensation processing 10. After service recovery, check if any statements were missed during interruption (compare with bank reconciliation statement) 11. If missed -> BOCHK can manually trigger a supplemental pull; other banks need to contact the bank to re-push

Not recovered after 15 minutes -> Escalate to technical operations on-call

Step-by-Step Runbook: Matching Cron Job Not Executing

Minute 1 — Confirm the issue

  1. Check if the corresponding match:{bank} Cron is running
  2. Check the execution time and result of the most recent matching job

Minutes 2~5 — Investigate cause 3. Is the Cron process alive? If the Cron scheduler itself is down -> all banks' matching will stop 4. Check if a matching job is running too long (over 3 minutes), causing the next round to be skipped 5. Check if DB connection is normal — matching jobs need simultaneous access to flows and applys tables

Minutes 5~10 — Recovery 6. Restart Cron scheduler 7. Manually trigger one matching job, confirm successful execution 8. Observe whether the next cycle automatically recovers

Not recovered after 10 minutes -> Escalate to technical operations


Flow Table Structure & Sharding

Sharding Strategy

Flow tables are sharded by bank type + month:

flows_{trans_type}_{YYYYMM}

Example: flows_218_202604 = April 2026 HSBC MT910 statements.

Why shard this way:

  • By trans_type: Different banks have very different flow fields; separating allows independent index optimization per bank
  • By month: High volume of statements; monthly archiving allows historical months to be progressively frozen
Configuration Location

Sharding logic: deposit/src/app/Business/Flow.php:80 Auto-create when table doesn't exist: CREATE_WHEN_TABLE_NOT_FOUND config

Flow Status Lifecycle

Status CodeMeaningDescription
0PendingStatement stored, awaiting matching engine processing
1ProcessedSuccessfully matched and deposit task created
2ErrorProblem statement requiring manual intervention
3LockedOperations locked, temporarily excluded from matching (e.g., waiting for user supplementary info)
4In-transitTransfer confirmed but statement info incomplete, awaiting completion
9Soft deletedMarked as deleted (not physically deleted)

Flow Disposition Results

When a statement is processed, the system records the disposition method:

Result CodeMeaningTrigger Scenario
0System matchedMatching engine auto-matched successfully
1Manually addedOperations manually associated in OA backend
2Deposit initiatedOperations directly initiated deposit from statement
3RefundFunds corresponding to the statement need to be returned (see Refund & Reversal)
4OtherNon-deposit statements (e.g., interest, fees)
5Emergency processedProcessed through abnormal deposit flow
6Auto-depositedMatching engine auto-matched + auto-credited
Configuration Location

Status codes: deposit/src/app/Business/BankFlow.php:59-64 Result codes: deposit/src/app/Business/BankFlow.php:80-87


Collection Cron Jobs

Matching Crons

The matching engine scans each bank's pending statements every 3 minutes:

Job NameFrequencyBankDescription
match:ccbasiaEvery 3 minCCB AsiaCCB statement matching
match:ewbEvery 3 minEWBEast West Bank matching
match:bocEvery 3 minBOCHKBOCHK B2E matching
match:hangsengEvery 3 minHang SengHang Seng direct connection matching
match:hsbcEvery 3 minHSBCHSBC MT910 matching
match:main icbc-newEvery 3 minICBCICBC new version matching
match:main za-sub-accountEvery 3 minZA BankZA sub-account matching

Monitoring Crons

Job NameFrequencyDescription
monitor:flow-monitorEvery 30 min (07:00~23:00)Detect statement backlog — alert when pending statements exceed threshold
abnormal-deposit:searchEvery 30 minScan for unmatched orphan statements
abnormal-deposit:update-statusEvery 3 minUpdate abnormal deposit status

Reconciliation Crons

Job NameFrequencyDescription
bank_reconciliation:generate16:15 dailyGenerate today's reconciliation report (CNH/HKD/USD)
bank_reconciliation:generate --date=yesterday USD09:05 dailyGenerate yesterday's USD reconciliation (due to USD T+1 settlement)
crmbos_reconciliation:generateHourly on the hourCRM-BOS inter-system reconciliation
Configuration Location

All Cron definitions: deposit/doc/crontab.sh


Bank Statement Type Codes

Different banks' statements carry different type fields identifying the transfer method. The matching engine selects different matching rules based on type:

BOCHK

TypeRemarks KeywordMeaningMatching Rule
TransferFPSFPS transferReal-time matching window
TransferE-BANKING TRANSFEROnline banking transferStandard matching window
TransferCHATSCHATS clearing transferStandard matching window
TransferREMIT INInward remittanceCross-region tolerance
TransferCBS TRANSFERCBS system transferStandard matching window
Clearing ChequeCheque clearingStandard matching window

Hang Seng

Type CodeMeaningMatching Rule
ATMATM deposit/transferStandard matching
GTCounter transferStandard matching
WYOnline banking transferStandard matching
ZPChequeStandard matching
BPBill PaymentStandard matching

ICBC

Type KeywordMeaning
匯款存入Remittance deposit
FPS 轉賬FPS transfer
網上轉賬存款Online banking deposit
櫃員機跨行轉賬存款ATM interbank transfer deposit
支票Cheque deposit

Connection to the Matching Engine

Once a statement is written to the flows table with status = 0 (PROCESSING), it will be scanned in the next 3-minute matching cycle.

Detailed matching engine logic -> Matching & Auto-crediting


Common Misconceptions

MisconceptionFact
"Statements arriving means immediate crediting"Statement arrival is just the first step. Still need to wait for the matching engine's next 3-minute cycle to scan, and then match successfully before crediting. Minimum one matching cycle wait
"BOCHK slow deposits are the matching engine's fault"No. BOCHK is slow because B2E only pulls 3 times daily + 2 hours conversion time. Statements haven't even entered the system; the matching engine has nothing to match
"EWB statements are automatically collected"No. EWB requires operations to manually upload CSV/BAI2 files. If operations hasn't uploaded, there are no statements in the system
"BST and eDDA also need statement collection"No. BST and eDDA are system-initiated debits; the system knows the results itself. Statement collection on this page only covers Push mode
"All banks have the same statement format"Completely different. Every bank has different fields, encoding, and time formats, so each bank has independent collection services and parsing logic

After Reading

I want to...Go to
Understand matching logic after statement arrivalMatching & Auto-crediting
Troubleshoot "statement not in system"Deposit Troubleshooting
Look up TransType and flow status codesDeposit Quick Reference
See detailed integration rules for a specific bankBank Capability Matrix
Understand the collection service's position in the architectureSystem Architecture & Data Flow
Was this page helpful?

内部业务文档 · 仅限 moomoo 团队使用