CMB (China Merchants Bank)
About This Page
What: CMB BST (Bank-Securities Transfer) channel-side Socket protocol specification + moomoo-side adaptation logic Audience: PMs understanding integration details / Developers locating code / Operations understanding bank characteristics Prerequisites: Bank Capability Matrix · BST OverviewReading time: 8 minutes Owner: Deposit & Withdrawal Product Team
Key Takeaway: CMB uses SM2-encrypted Socket bidirectional links for second-level BST, making it the most protocol-complex but fastest-responding of the three BST banks.
Capability Overview
| Capability | Supported | Protocol/Channel | Core Service |
|---|---|---|---|
| Deposit (BST) | ✅ | Binary Socket bidirectional link | cmb_stock_trans Entry Server |
| Withdrawal (BST Auto) | ✅ | Binary Socket bidirectional link | cmb_stock_trans Exit Server |
| SM2 National Crypto | ✅ | SM2 Signature + Encryption | Built-in crypto module |
| eDDA/eDDI | ❌ | — | — |
| FPS | ❌ | — | — |
CMB is one of moomoo's core BST channels, using dedicated Socket bidirectional persistent connections for real-time deposit notifications and withdrawal instruction delivery. Supports SM2 national cryptography to ensure fund instruction security.
Core Parameters Quick Reference
| Parameter | Value | Description |
|---|---|---|
| IMPORT_BANK_ID | 7 | System bank identifier (CMBCCHINA) |
| TransType | 102 (BST) / 205 (Regular) | BST / Regular deposit types |
| AUTO_SETTING_ID | 2 | Limit configuration ID in auto_settings table |
| Protocol Type | Binary Socket | Fixed byte-length message frames |
| Encryption | SM2 National Crypto | Optional, default 'N' (unencrypted) |
| Communication Mode | Bidirectional persistent connection | Entry Server + Exit Server |
Channel Interface Overview
Protocol Architecture
| Dimension | Description |
|---|---|
| Protocol Type | Binary Socket (fixed byte-length message frames) |
| Encryption | SM2 National Crypto (optional, default 'N' unencrypted) |
| Data Format | Binary (fixed-length fields, ASCII encoding) |
| Communication Mode | Bidirectional persistent connection (Entry Server receives + Exit Server sends) |
| Heartbeat | 0009/1009 and 0010/1010 bidirectional heartbeat keepalive |
| Connection Management | Auto-switch to backup Exit Server on disconnect |
Message Frame Structure
Each Socket message consists of a fixed-format header + variable-length business data:
| Part | Length | Format | Description |
|---|---|---|---|
| Encryption Type | 1 byte | char | 'N' = unencrypted, 'Y' = SM2 encrypted |
| Total Packet Length | 2 bytes | little-endian uint16 | Total message frame length |
| Signature | 64 bytes | binary | SM2 digital signature (blank-padded when unencrypted) |
| Command Code | 4 bytes | ASCII | e.g., "0001", "4001" |
| TX Packet Length | 2 bytes | little-endian uint16 | Business data length |
| Header Total | 73 bytes | ||
| Business Data | Variable | binary | Fixed-length fields concatenated |
Byte Order Note
Packet length fields use little-endian byte order. Pay attention to encoding/decoding direction during development.
Channel-Side Interface Details — Complete Command Code Table
Login & Authentication
| Command Code | Direction | Message Name | Purpose |
|---|---|---|---|
| 0001 | Broker→Bank | BrokerageLoginToBankReq | Broker logs into bank, establishes Entry link |
| 1001 | Bank→Broker | BrokerageLoginToBankRsp | Login response, returns auth result |
| 0002 | Bank→Broker | BankLoginToBrokerageReq | Bank logs into broker, establishes Exit link |
| 1002 | Broker→Bank | BankLoginToBrokerageRsp | Bank login response |
| 0003 | Broker→Bank | BrokerageLoginoutReq | Broker initiates logout |
| 1003 | Bank→Broker | BrokerageLoginoutRsp | Logout confirmation response |
Password & Configuration
| Command Code | Direction | Message Name | Purpose |
|---|---|---|---|
| 0004/1004 | Bidirectional | ModifyPwd | Modify communication password |
| 0005/1005 | Bidirectional | ChangeDate | Modify reconciliation date |
Heartbeat Keepalive
| Command Code | Direction | Message Name | Purpose |
|---|---|---|---|
| 0009/1009 | Broker→Bank | Keepalive | Broker-side heartbeat (moomoo initiated) |
| 0010/1010 | Bank→Broker | Keepalive | Bank-side heartbeat (CMB initiated) |
Bidirectional heartbeat ensures connection survival. If either side times out without receiving a heartbeat, the connection is deemed broken, triggering reconnection.
Customer Management
| Command Code | Direction | Message Name | Purpose |
|---|---|---|---|
| 2001/3001 | Bank→Broker | GetCustmorInfo | Bank queries customer info at broker |
| 2002/3002 | Broker→Bank | NotifyCustmorResult | Notify customer verification result (account opening/verification) |
| 2003/3003 | Bank→Broker | Cancel | Cancel customer's BST authorization |
Fund Transfer (Core)
| Command Code | Direction | Message Name | Purpose |
|---|---|---|---|
| 4001/5001 | Bank→Broker | BankMarginIn | Deposit notification — Bank informs broker that a customer transferred funds in |
| 4002/5002 | Broker→Bank | BrokerageMarginOut | Withdrawal instruction — Broker instructs bank to transfer funds out to customer |
| 4003/5003 | Bank→Broker | BankMarginOut | Withdrawal result notification — Bank informs withdrawal processing result |
| 4004/5004 | Broker→Bank | BankMarginOutReject | Reject withdrawal — Broker rejects bank-side initiated withdrawal request |
Reconciliation
| Command Code | Direction | Message Name | Purpose |
|---|---|---|---|
| 6001/7001 | Bidirectional | MarginCheck | Reconciliation request initiation |
| 6011/7011 | Bank→Broker | BankMarginInList | Deposit reconciliation list |
| 6013/7013 | Bank→Broker | BankNewCustmoerList | New customer list |
| 6014/7014 | Bank→Broker | BankCancelList | Cancelled authorization customer list |
| 6015/7015 | Bank→Broker | BankMarginOutList | Withdrawal reconciliation list |
| 6003/7003 | Broker→Bank | NewCustmoerCheck | New customer reconciliation confirmation |
| 6004/7004 | Broker→Bank | CancelCheck | Cancelled authorization reconciliation confirmation |
| 6005/7005 | Broker→Bank | MarginOutCheck | Withdrawal reconciliation confirmation |
Core Interface Field Details
4001 BankMarginInReq (Deposit Notification)
Bank notifies broker of a deposit credited — the core BST deposit message.
| Field | Length | Type | Description |
|---|---|---|---|
| m_brokerage_custmor_id | 20B | string | Broker customer ID. Value: moomoo UID |
| m_bank_custmor_id | 16B | string | Bank customer ID. Value: Bank card number |
| m_currency | 3B | string | Currency. Value: HKD / USD / CNH |
| m_amount | 20B | string | Amount. e.g., "50000.00" |
| m_tx_date | 8B | string | Transaction date. Format YYYYMMDD |
| m_tx_time | 6B | string | Transaction time. Format HHMMSS |
| m_tx_seq | 16B | string | Transaction sequence. Unique identifier (dedup key) |
| m_reconciliation_date | 8B | string | Reconciliation date. Format YYYYMMDD |
Field Encoding Notes
All fields are fixed-length ASCII strings, right-padded with spaces. Amount field includes decimal point, e.g., "50000.00" padded with spaces to 20 bytes. Currency is strictly 3 bytes: HKD, USD, CNH.
4002 BrokerageMarginOutReq (Withdrawal Instruction)
Broker sends withdrawal instruction to bank, transferring customer funds from securities account back to bank account.
| Field | Length | Type | Description |
|---|---|---|---|
| m_brokerage_custmor_id | 20B | string | Broker customer ID. moomoo UID |
| m_bank_custmor_id | 16B | string | Bank customer ID. Bank card number |
| m_bank_custmor_name | 20B | string | Bank customer name. Used for bank-side verification |
| m_currency | 3B | string | Currency. HKD / USD / CNH |
| m_amount | 20B | string | Amount. Withdrawal amount |
| m_tx_date | 8B | string | Transaction date. Format YYYYMMDD |
| m_tx_time | 6B | string | Transaction time. Format HHMMSS |
| m_tx_seq | 16B | string | Transaction sequence. Unique identifier |
| m_reconciliation_date | 8B | string | Reconciliation date. Format YYYYMMDD |
Common Response Fields
| Field | Length | Type | Description |
|---|---|---|---|
| m_rsp_code | 4B | string | Response code, "0000" = success |
moomoo-Side Adaptation
Entry/Exit Server Bidirectional Architecture
CMB BST uses a bidirectional persistent connection architecture. moomoo deploys two Servers to handle inbound and outbound messages respectively:
| Server | Process Name | Responsibility | Connection Direction |
|---|---|---|---|
| Entry Server | entrance_business | Receives messages from bank (deposit notifications, reconciliation lists etc.) -> forwards to CRM | Bank -> moomoo |
| Exit Server | exit_business | Receives CRM withdrawal instructions -> sends to bank | moomoo -> Bank |
Disconnect handling: Exit Server supports backup addresses. When the primary connection drops, it auto-switches to the backup exit_server address, ensuring withdrawal instructions are not interrupted.
SM2 National Crypto Encryption Flow
CMB BST supports SM2 national crypto for message signing and encryption, ensuring fund instruction security.
Encryption Configuration
- Encryption type field = 'Y' enables SM2
- Default is 'N' (unencrypted), can be enabled as needed
- Certificate files located in
cmb_stock_trans/conf/directory
Deposit: BST Real-time Deposit
Deposit Flow
The biggest advantage of BST deposits is real-time certainty: the bank directly provides customer ID and amount, eliminating the need for fuzzy matching like regular bank transfers.
Withdrawal: BST Auto Withdrawal (auto_bs)
Withdrawal Flow
Processing Hours
| Currency | Processing Hours | Notes |
|---|---|---|
| HKD / USD | Trading days 08:40 ~ 15:59 | Full trading day |
| CNH | Trading days 08:40 ~ 10:59 | Morning only, not available in afternoon |
| Margin withdrawal | Trading days 08:40 ~ 10:59 | Same window as CNH |
CNH Withdrawal Time Restriction
The CNH (offshore RMB) withdrawal window is only until 10:59 AM, much shorter than HKD/USD. Operations and users should note to initiate CNH withdrawals within this window; timeouts will be deferred to the next trading day.
CNH Withdrawal Restrictions
The calcMethod() method has additional restrictions for CNH:
- CNH + non-Hong Kong bank -> method = null (not supported)
- i.e., CNH withdrawal to Mainland bank card = not supported
- CNH only supports withdrawal to Hong Kong local CMB accounts
Withdrawal Cancellation Rules
| Scenario | Cancellable | Condition |
|---|---|---|
| Non-trading hours (< 08:20 or >= 16:00) | ✅ | Unconditionally cancellable |
| Trading day 08:20 ~ 16:00 | ✅ / ❌ | Cancellable if >= 10 minutes before scheduled execution |
| Non-trading day | ✅ | Unconditionally cancellable |
Why the 10-minute restriction during trading hours? Once a withdrawal instruction enters the bank's processing queue, it cannot be recalled. The 10-minute buffer ensures the cancellation request arrives before the bank actually executes.
Callback Result Codes
| result | Meaning | System Action | Manual Needed |
|---|---|---|---|
| 0 | Success | Task status -> DONE | ❌ |
| -5 | Timeout | Auto-switch to backup exit_server and retry | ❌ |
| -6 | Bank rejected | Task status -> Exception | ✅ Manual processing |
Timeout Retry Mechanism
When result = -5 (timeout) is received:
- Log timeout event for current exit_server
- Switch to backup exit_server address
- Resend withdrawal instruction using the same m_tx_seq
- If backup exit_server also times out, mark as exception and await manual processing
Withdrawal Limit Configuration
CMB BST withdrawal limits are configured via the auto_settings table (WHERE id = 2):
| Field | Meaning | Description |
|---|---|---|
| hk_max_amount | Per-transaction maximum | Rejected if exceeded |
| hk_alarm_amount | Alarm amount | Triggers alert but does not block |
| hk_stop_amount | Circuit breaker amount | Suspends auto-withdrawal if exceeded |
Three-tier threshold logic:
- Amount <= alarm_amount: Normal auto-processing
- alarm_amount < Amount <= max_amount: Auto-processing + triggers alert notification
- Amount > max_amount or cumulative > stop_amount: Suspend auto-withdrawal, route to manual approval
Exception Scenarios & Alerts
Socket Disconnection
| Alert Item | Severity | Response Time | Description |
|---|---|---|---|
| Entry Server disconnect | Critical | Within 15 min | Cannot receive deposit notifications |
| Exit Server disconnect | Critical | Within 15 min | Cannot send withdrawal instructions |
| Bidirectional heartbeat timeout | Warning | Within 30 min | May disconnect soon |
Socket disconnection is one of the most critical alerts — during disconnection, all BST deposit notifications and withdrawal instructions are interrupted. The system will auto-attempt reconnection, but if not recovered within 15 minutes, developer intervention is needed.
Common Exception Handling
| Exception Scenario | Symptom | Resolution |
|---|---|---|
| Socket disconnect | Deposit/Withdrawal interrupted | Auto-reconnect; manual intervention if not recovered in 15 min |
| SM2 signature verification failure | Message rejected | Check if certificate expired or replaced |
| Withdrawal timeout (result=-5) | Bank not responding | Auto-switch to backup exit_server |
| Bank rejected (result=-6) | Withdrawal failed | Manually verify reason then retry or refund |
| Reconciliation mismatch | Deposit/Withdrawal amounts inconsistent | Operations investigates discrepancy, contacts CMB for reconciliation |
| CNH out-of-window withdrawal | Withdrawal rejected | Defer to next trading day morning |
Bilateral Function Mapping Matrix
| Function | Channel-Side (CMB) | moomoo-Side | Description |
|---|---|---|---|
| Login Authentication | Bidirectional handshake | Entry/Exit Server | 0001-1003, establishes bidirectional link |
| Heartbeat Keepalive | Bidirectional heartbeat | Entry/Exit Server | 0009-1010, every 30s |
| Deposit Notification | 4001 BankMarginIn | Entry -> CRM | m_brokerage_custmor_id etc., real-time deposit |
| Withdrawal Instruction | 5002 receives and executes | CRM -> Exit -> Bank | m_amount / m_currency etc., auto withdrawal |
| Withdrawal Result | 4003 BankMarginOut | Entry -> CRM | result code, callback notification |
| Reconciliation | 6xxx series | Entry/Exit | Multiple lists, daily reconciliation |
| Encryption | SM2 verify and decrypt | SM2 sign and encrypt | 64B signature in message header, optional |
Cron Jobs
| Task | Frequency | Description |
|---|---|---|
| Heartbeat check | Every 30 seconds | Entry/Exit Server bidirectional heartbeat |
| Disconnect check | Every 5 minutes | Check Socket connection status, alert on anomaly |
| Reconciliation initiation | Daily after market close | Initiate 6001 reconciliation request |
| Reconciliation verification | Daily T+1 | Compare deposit/withdrawal/customer lists |
Change Guide
| Change Requirement | Location | Description |
|---|---|---|
| Modify withdrawal limits | auto_settings WHERE id = 2 | Adjust max/alarm/stop three-tier thresholds |
| Modify processing hours | exit_business -> time period config | Adjust processing windows per currency |
| Modify CNH restrictions | calcMethod() -> CNH judgment logic | Modify CNH withdrawal bank/region restrictions |
| Modify cancellation rules | Withdrawal cancellation logic -> time check | Adjust 10-minute buffer period |
| Replace SM2 certificate | cmb_stock_trans/conf/ | Replace public/private key files and restart service |
| Adjust heartbeat interval | cmb_stock_trans -> keepalive config | Modify heartbeat frequency |
| Add new command code | cmb_stock_trans/comm/pact.h | Protocol definition file |
| Modify Entry Server logic | cmb_stock_trans/entrance_business/ | Inbound message processing |
| Modify Exit Server logic | cmb_stock_trans/exit_business/ | Outbound message processing |
| Adjust backup exit_server | Exit Server config | Modify backup address list |
Code Location Quick Reference
| Module | Path | Description |
|---|---|---|
| Protocol definitions | cmb_stock_trans/comm/pact.h | All command codes and message structure definitions |
| Entry Server | cmb_stock_trans/entrance_business/ | Inbound message receiving and forwarding |
| Exit Server | cmb_stock_trans/exit_business/ | Outbound message sending (withdrawal instructions) |
| SM2 Encryption | cmb_stock_trans/ built-in module | Sign / Encrypt / Decrypt |
| Limit config | auto_settings table id = 2 | Database configuration |
| Withdrawal channel | withdraw/.../Method.php -> auto_bs | Withdrawal method registration |
Comparison with Other BST Banks
| Dimension | CMB | CMBC | Airstar |
|---|---|---|---|
| Protocol | Binary Socket | — | — |
| Encryption | SM2 National Crypto | — | — |
| Connection Mode | Bidirectional persistent | — | — |
| Deposit | ✅ Real-time notification | ✅ | ✅ |
| Withdrawal | ✅ auto_bs | ✅ | ✅ |
| CNH Support | ✅ (Morning only) | — | — |
| Reconciliation | Auto reconciliation | — | — |
BST Advantage
Compared to regular bank transfer deposits that require fuzzy matching, the biggest advantage of BST is certainty — the bank directly provides customer ID and amount, no matching engine involvement needed, deposits credited in real-time.
Top 3 Customer Complaints
| # | User Feedback | Cause | CS Response |
|---|---|---|---|
| 1 | "BST withdrawal timed out" | Socket connection jitter, callback code -5 | "Your withdrawal is being processed. The system has auto-retried, please check the result shortly." |
| 2 | "BST withdrawal rejected" | Callback code -6, bank-side rejection | "The bank was temporarily unable to process your withdrawal. Please try again later or contact support." |
| 3 | "Why can't I withdraw via CMB" | BST authorization not active or expired | "Please confirm your BST authorization status is active. If expired, please re-sign the agreement." |
After Reading
| I want to... | Go to |
|---|---|
| Understand the overall BST architecture | BST Overview |
| See CMB's position among all banks | Bank Capability Matrix |
| Understand withdrawal channel execution details | Channel Execution Manual |
| Understand withdrawal approval rules | Withdrawal Rules & Approval |
| Look up TransType and Bank ID mapping | Deposit Rules Quick Reference |
| Look up error codes and status codes | Unified Error Code Center |
| Understand other deposit matching logic | Matching & Auto-Deposit |