出金生命週期
本頁說明
講什麼:跟著一筆錢走完出金全程——從用戶點擊"提交"到錢到銀行卡,中間每一步發生了什麼 適合誰:需要理解出金完整路徑的產品經理 前置閱讀:出金方式總覽預計閱讀:5 分鐘 負責人:出金產品經理
核心要點:一筆出金從提交到完成經歷六大階段:前置檢查→任務創建→風控檢測→三步審批→自動/人工執行→結果確認。大部分出金在 Confirm→Remittance 兩步內自動完成。
全程概覽
一筆出金從頭到尾經歷這些階段:
下面按時間順序,完整敘述每一步。
第一步:用戶提交 + 前置檢查
用戶在 App 點擊"提交出金"後,在出金任務創建之前,系統執行一系列前置檢查。檢查不通過的出金請求不會創建出金任務——用戶在 App 端直接看到錯誤提示。
最大可提金額
系統首先計算用戶最大可提金額:
最大可提金額 = min(實時淨資產, Min_ELV, 最大授信額)如果出金金額超過最大可提金額,直接拒絕。融資賬戶和現金賬戶的計算方式不同,融資賬戶還需扣除保證金要求。
前置檢查清單
| 順序 | 檢查項 | 不通過結果 | 觸發時機 |
|---|---|---|---|
| 1 | 出金限制標記(風控) | 直接拒絕("賬戶暫時無法出金") | 進入資金頁面 / 點擊確認 |
| 2 | 出金黑名單 | 直接拒絕("賬戶被限制提取資金") | 進入資金頁面 |
| 3 | 不動賬戶 / 休眠戶 | 直接拒絕("休眠戶不支持出金") | 進入資金頁面 / 點擊確認 |
| 4 | 證券帳戶狀態 | 拒絕("未開通證券帳戶/已銷戶") | 進入頁面 |
| 5 | 穿倉校驗 | 拒絕("賬戶存在欠款") | 點擊確認出金 |
| 6 | GDCA 認證 | 拒絕("未完成 GDCA") | 點擊確認出金 |
| 7 | NSS 問卷 | 拒絕("未完成 NSS 問卷") | 點擊確認出金 |
| 8 | 銀行卡有效性 | 提示重新綁卡 | 選擇收款賬戶 |
| 9 | 銀行賬戶認證狀態 | 拒絕("銀行賬戶未通過認證") | 選擇收款賬戶 |
| 10 | 在線開戶入金門檻 | 拒絕(綁卡須轉賬 ≥ 10,000 HKD 或 1,500 USD) | 選擇收款賬戶 / 點擊確認 |
| 11 | 可用出金方式 | 限制可選通道 | 選擇收款賬戶 |
| 12 | 幣種-市場一致性 | 拒絕 | 點擊確認 |
| 13 | 費用計算 | 展示給用戶確認(CHATS/RTGS 有彈窗) | 點擊確認 |
| 14 | 通道路由 | 確定 method 值 | 點擊確認 |
更多限制場景(低頻但需注意)
| 檢查項 | 不通過結果 | 說明 |
|---|---|---|
| 大陸銀行卡 | 拒絕("不支持提取到中國大陸銀行賬戶") | 系統直接攔截 |
| A 股通人民幣限制 | 拒絕("A 股通 CNH 僅支持提取到香港銀行") | 僅 CNH + 非港銀行 |
| Payoneer 賬戶 | 拒絕("Payoneer 賬戶不支持出金") | 業務限制 |
| 波多黎各地區 | 拒絕 | 地區限制 |
| 融資可提金額 | 拒絕("超出現金可提金額") | 融資賬戶專屬 |
| 銀行幣種不匹配 | 拒絕("銀行賬戶幣種與出金幣種不一致") | 如港元賬戶提美元 |
| 天星銀證未授權 | 拒絕("未授權銀證") | 僅銀行發起出金場景 |
| 機構賬戶未授權 | 拒絕 | 機構賬戶專屬 |
這些錯誤碼歸屬 140670xxx 系列,完整列表見 出金數據字典 § 前置校驗錯誤碼。
如果需求變更:修改前置檢查
- 新增檢查項 →
withdraw/src/app/Business/CreatorBase.php的check*()方法鏈中添加 - 調整黑名單 →
hk-withdraw-blacklist-go服務管理接口(數據庫配置,即時生效) - 修改通道路由邏輯 →
withdraw/src/app/Business/CreatorBase.php→calcMethod()方法 - 修改費用計算 →
CreatorBase.php→getFee()方法
第二步:任務創建 + 通道路由
檢查全部通過後,系統創建出金任務(寫入 tasks 表),同時確定出金通道。
通道路由由 calcMethod() 自動決定:
關鍵邊界:即使銀行卡支持 BST,如果是招行/民生 + 離岸人民幣 CNH,系統不選 BST,而是留給運營手動選擇。因為招行/民生的 BST 對 CNH 有額外限制。天星不受此影響。
當 method = null 時,運營在 Confirm 步驟從 9 種可選通道中手動選擇。
任務創建後狀態為 PENDING(0),同時入隊多個異步事件(風控檢測、銀行卡狀態更新等),開始後續處理。
第三步:風控檢測
任務創建後幾秒內,系統自動執行高風險檢測(HighRiskCheck),用 6 個因子判斷這筆出金是否異常。
6 個因子中只有 4 個會觸發額外審核(USER、AREA、FRAUDULENT、SWIFT),命中後任務模板從 default 升級為 unusual——審批從 2 步變成 3 步。
FREQUENCY 和 AMOUNT 只做記錄,不觸發額外審核——因為它們已有獨立的安全機制(每日 10 筆限制、三層限額)。
詳細的 6 因子說明和 bitmask 規則 → 出金規則手冊 § 高風險判定
第四步:審批三步
風控檢測完成後,任務狀態變為 PROCESSING(1),進入審批流程。最多三步:
Step 1: Audit(高危審核)— 僅 unusual 模板
只有被標記為異常的出金才需要。運營人員審核該出金是否存在風險——檢查用戶賬戶狀態、出金目的地、金額是否異常。
大部分正常出金跳過此步。
Step 2: Confirm(確認指示)— 所有出金
所有出金都經過此步。運營確認:
- 用戶銀行卡狀態正常
- 出金方式已正確設置
- 對於
method = null的任務,手動選擇出金通道
BST 額外校驗:Confirm 會驗證銀證授權(Mandate)狀態是否為 OPEN。如果不是 OPEN,出金無法推進——運營需要引導用戶先完成銀證授權。
重要:Confirm 不執行實際轉賬,這個動作保留給 Remittance。
Step 3: Remittance(匯出資金)— 所有出金
這是資金真正離開的一步。系統首先檢查自動出金條件(6 個條件詳見 規則手冊):
- 全部通過 → 自動調用
startTransfer(),進入下一節的自動執行路徑 - 任一不通過 → 降級為人工,運營確認後手動觸發轉賬
審批可以全自動
對於 BST 通道的普通出金(非 unusual),如果自動出金條件全部滿足,三步審批中 Confirm 和 Remittance 都是系統自動推進的。用戶感知上就是"提交後幾分鐘到賬"。
如果需求變更:修改審批流程
- 修改審批步驟 →
withdraw/src/app/Business/Task.php→$stepTemplates數組 - 新增審批步驟 → 新建 Step 類(實現
IFStep接口)+ 加到模板數組 - 修改自動出金條件 →
withdraw/src/app/Business/AutoSetting.php - 詳細變更指南 → 出金變更指南
第五步(A):BST 全自動執行
如果通道是 BST(auto_bs),Remittance 調用 startTransfer() 後,進入全自動路徑:
招行/民生:通過 Socket 雙向鏈路實時獲取結果,通常秒級完成。
天星:通過 REST API 分兩階段輪詢獲取結果——快速輪詢(AsbBstTransfer 每 5 秒,最多 10 次,~50 秒)和兜底同步(SyncAsbBstWithdraw 2 小時窗口內持續同步)。兜底同步後仍未完成則標記異常,需運營人工查詢天星 API 確認銀行側狀態。
餘額扣減注意:Remittance 執行時先從 auto_settings 扣減出金金額。如果餘額低於 alarm 閾值 → 發飛書告警;低於 stop 閾值 → 自動關閉該幣種的自動出金。這個扣減發生在銀行轉賬之前——即使銀行拒絕,餘額已扣減,需運營手動恢復。
通道技術細節 → 通道執行手冊 § BST
第五步(B):人工通道執行
所有非 BST 通道(網銀、FPS、傳統)都是運營驅動的:
關鍵區別:非 BST 通道的 startTransfer() 在 Confirm 步驟就調用了(不是 Remittance),因為是同步調用——SBA 立刻返回 transfer_manual。然後運營在銀行完成轉賬後,在 Remittance 步驟點擊確認。
部分通道在 Remittance 有前置要求:
| 通道 | 前置要求 |
|---|---|
| 廣發 FPS | FPS 批量提交完成 |
| CHATS/RTGS | 文件導出完成 |
| 中銀 FPS | FPS 提交完成 |
通道技術細節 → 通道執行手冊
第六步:結果處理
無論 BST 還是人工通道,最終結果只有三種:
| 結果 | 任務狀態 | 後續 |
|---|---|---|
| 成功 | DONE(2) | 通知用戶,出金完成 |
| 失敗 | 保持 PROCESSING(1) | 運營介入,可能換通道重試 |
| 超時 | 保持 PROCESSING(1) | 運營查詢銀行狀態,手動確認或重試 |
BST 回調碼參考:
- 0 = 成功 → Task DONE
- -5 = 超時 → 自動切換備用伺服器重試
- -6 = 銀行拒絕 → 標記失敗,需人工處理
異常場景的詳細排查 → 出金排障
其他觸發方式
上面描述的是"用戶在 moomoo App 發起出金"的標準路徑。還有幾種非標準觸發方式:
銀行發起出金
招行、民生、天星支持銀行端發起出金——用戶在銀行 App 操作轉出,moomoo 被動接收:
系統每分鐘通過隊列消費者拉取銀行流水,發現新的銀行端出金後自動創建任務,method 固定為 auto_bs,進入標準審批流程。
cmb_list / ms_list 記錄狀態:0=待處理 → 1=處理中 → 2=成功(任務已創建) / 3=失敗
如果需求變更:支持新銀行的銀行端發起
- 新建
xxx_list表(參考cmb_list結構) - 新建兩個隊列事件:
SyncXxxWithdraw(拉取流水)+XxxWithdrawCreate(創建任務) - 在
Queue.php的$_enableEvent中註冊 - 對接銀行側流水查詢 API
基金贖回出金
基金贖回不是用戶直接發起出金,而是贖回成功後系統自動創建出金任務:
基金贖回有獨立的 5 個事件組成等待鏈路:
| 事件 | 做什麼 |
|---|---|
| FundWithdrawCreate | 接收贖回完成通知 |
| FundWithdrawWait | 等待贖回資金到達證券帳戶 |
| FundWithdrawArrivalTime | 檢查預計到賬時間 |
| FundWithdrawSuccess | 資金到賬 → 創建 fund 模板的出金任務 |
| FundWithdrawFailed | 到賬失敗 → 需人工處理 |
這條鏈路可能需要 T+1 到 T+3 天,取決於基金贖回的到賬時間。
基金贖回 ≠ 用戶主動出金
觸發方式不同(系統自動 vs 用戶手動),前置流程不同(需等資金從基金賬戶轉入證券帳戶),但風控處理相同(都經過 HighRiskCheck)。
現金寶贖回出金
現金寶(活期理財)贖回與基金贖回類似,但回調方式不同——通過 SrvPush(服務推送)回調,而非隊列輪詢。
| 事件 | 做什麼 |
|---|---|
| CurrentDepositRedeemSuccess | 贖回成功 → 推進出金任務 |
| CurrentDepositRedeemRejected | 贖回被拒 → 出金任務標記失敗 |
| CurrentDepositRedeemSbaCreateRetry | SBA 創建失敗時重試 |
CRM 代發出金
運營可在 CRM 系統中直接幫用戶發起出金(無需用戶在 App 操作)。適用場景:
- 用戶無法登錄 App(如設備故障)
- 批量退款/補償操作
- 特殊情況下的運營協助
CRM 代發出金與用戶自發出金走相同的審批流程和風控檢測,但跳過部分 App 端前置檢查(如 GDCA)。
OM 賬戶出金
OM(Omnibus)賬戶是合併持倉賬戶,出金時 Remittance 步驟會先執行 OmWithdrawDeduct(OM 扣款),從 OM 子賬戶扣除資金。如果 OM 扣款失敗,出金任務卡在 Remittance 步驟,需人工處理。
OM 出金也支持 BST 自動出金,但前提是 OM 扣款已完成。
沖正
出金已完成(DONE)後需要把資金追回時,運營發起沖正(REVERSE):
- 運營在 CRM 發起沖正操作
- 系統檢查狀態——只有 DONE 的任務才能沖正
- 更新任務狀態為 REVERSE(5)
- SBA 執行反向資金操作
- 通知用戶出金已撤回
觸發原因:銀行退回、錯誤出金、風控事後攔截。
異步驅動:為什麼有時候要等
你可能注意到,出金流程中很多步驟之間有幾秒到幾分鐘的間隔。這是因為出金系統採用事件驅動隊列——每個異步操作是一個"事件",放入數據庫隊列表中,由後台進程逐個處理。
11 點截止規則與 8:30 批量處理
出金任務有一個關鍵的日切時間點:
| 時間 | 系統行為 |
|---|---|
| 每日 11:00 | 截止線——此時間之後提交的非自動出金,標記為"次日處理" |
| 次日 08:30 | 系統自動將前一天 11:00 後提交的任務從"次日處理"轉為"處理中",運營開始處理 |
這意味著用戶在 11:00 之後提交的非自動出金(非 BST 通道),實際要等到次日 08:30 才開始處理。BST 自動出金不受此規則影響(在服務時段內隨時處理)。
NSS 名單篩查
跨境電匯(tele_transfer)在執行前需通過 NSS(Name Screening Service) 檢查收款人姓名,確認不在制裁名單上。NSS 不通過的出金需人工審核,運營聯繫合規團隊判斷。
| 你觀察到的 | 實際發生了什麼 |
|---|---|
| "提交後幾秒才開始審批" | 風控檢測事件在排隊等待執行 |
| "BST 出金等了幾分鐘" | 系統正在輪詢銀行結果(每 5~60 秒一次) |
| "廣發 FPS 出金等了很久" | 廣發輪詢最多 1000 次(可達數小時) |
| "基金贖回出金等了好幾天" | 在等贖回資金從基金賬戶到證券帳戶 |
隊列消費者每分鐘由 cron 啟動,基於數據庫鎖避免重複消費。如果某類事件的專用消費者進程掛了,該類事件會卡住。
這不是 bug
間隔是異步設計的正常表現。如果出金異常地長時間不推進,排查方向是:對應的隊列消費者進程是否在運行。
常見誤解
| 誤解 | 事實 |
|---|---|
| "用戶點了提交,出金就開始了" | 還沒有。系統先執行 14 項前置檢查,任一不通過連出金任務都不會創建。用戶在 App 端直接看到錯誤提示 |
| "處理中 = 銀行正在轉錢" | 不一定。"處理中"包含了 Audit → Confirm → Remittance 三步審批,可能卡在運營確認環節,銀行還沒收到指令 |
| "BST 出金秒到" | 招行/民生通常秒級,但天星最長可能等 2 小時(快速輪詢 + 兜底同步)。即使招行,也需要 SBA 凍結/扣款/發指令的處理時間 |
| "11 點後不能出金" | 可以出金。BST 自動出金不受此限制。11 點截止規則只影響非 BST 通道——這些任務會推遲到次日 08:30 開始處理 |
| "CRM 代發出金跳過風控" | 不跳過。CRM 代發走相同的審批流程和風控檢測(HighRiskCheck),只是跳過部分 App 端前置檢查(如 GDCA) |
讀完之後
| 我想... | 去看 |
|---|---|
| 瞭解某條規則為什麼存在、能不能改 | 出金規則手冊 |
| 看某種通道從 Remittance 到銀行的技術細節 | 通道執行手冊 |
| 出金出了問題,按症狀排查 | 出金排障 |
| 推動一個出金相關的需求變更 | 出金變更指南 |
| 查某個狀態碼/欄位是什麼意思 | 出金數據字典 |