设计提案

设计 MT5 投资者门户、钱包与 IB 佣金:决定方案的五个问题

作者:曾祈荣 · · 阅读约 10 分钟

创始人描述这个平台时,讲的是一个个页面。投资者能看到自己的 MetaTrader 5 账户(交易历史、盈亏、余额、净值、保证金),还有一个钱包;介绍经纪商(IB)和他们的下级 IB 赚取佣金。听起来像是一个看板项目,外加一个支付页面。

页面是最便宜的部分。成本和风险由五个问题决定,它们都和页面无关,我会在报价之前先问清楚。这篇文章就是那场调研对话,写下来是为了让你自己也能回答这些问题。

问题一:你实际拥有什么样的 MT5 接入权限,对应哪些券商?

一个 Manager API 或 Web API 登录账号,只属于某一家券商的交易服务器。它能读取这家券商的账户,通常还仅限于券商开放的那些组别,除此之外什么都读不到。这个凭证只能由券商授予:我自己没有 MT5 服务器,也没有 Manager 授权。

如果你的投资者都在同一家券商交易,而且这家券商授予 Manager 权限,这部分很简单。如果他们分散在多家券商,每家券商就是一条独立的接入路线,路线有三种:

  • 合作方接入:券商给你开一个 Manager API 或 Web API 登录账号,权限限定在你的客户所在的组别。
  • 第三方云端桥接服务:用每个账户自己的登录凭证登录,再通过 API 把数据提供出来。
  • 只读的投资者密码:每个账户开一个终端会话,导出交易历史和余额。

这几条路线在速度、成本、可靠性以及各家券商条款是否允许上都不一样,所以我会从第一天起就设计一个券商适配器接口。系统的其余部分只向适配器要账户、成交记录和持仓,永远不知道背后走的是哪条路线。账户用(服务器,登录号)来标识,因为同一个登录号在两家券商就是两个不同的人。

报价之前,我会要求看一下凭证的类型、它所属的服务器、覆盖哪些组别,以及它能不能写(余额操作、交易权限),还是只能读。两条官方路线的比较,见 MT5 Manager API 还是 Web API。

问题二:账户由谁来交易?

常见的答案有三种:每个投资者自己交易自己的账户,由一位管理人代为交易,或者从一个主账户跟单复制。在数据库里,这三种看起来差不多。在监管机构眼里却不一样:在很多地方,代他人操作资金或收取业绩费属于需要牌照的业务,在你所在的地方是不是,要问你的律师。

这个答案也决定了看板要展示什么。自己交易的人要看持仓、保证金水平和交易历史。托管账户或跟单账户的投资者,要看扣除费用后的业绩,以及一份对账单,能和券商出的那份核对上。IB 要看客户的交易量和佣金,不需要比这更私人的信息。

问题三:这个钱包在法律上和功能上到底是什么?

“钱包”这个词涵盖三种不同的产品。预付费用额度:投资者充值,平台费用从中扣除。储值:可以提现、也可以转给其他用户的钱。交易本金:直接为 MT5 账户入金的钱。

提现和用户之间的转账,可能让钱包变成受监管的储值产品,随之而来的牌照要求和客户资金保障义务因国家而异。设计开始之前,先拿到律师的书面答复,因为它会改变数据模型、后台,以及哪些支付服务商愿意接你这个客户。

三种钱包我都会建在同一个基础上:一本复式记账、只追加的账本,投资者账户和 IB 账户分开。余额由分录推导出来,从不原地修改。

每一类资金事件(充值、费用、佣金、提现)在代码里只有一条记账路径:测试只看一处,审计也只看一处。我没有在生产环境运行过记有客户余额的账本,所以文章开头的说明才要求做独立评审。具体模式见金融科技初创公司的复式记账账本。

问题四:佣金或业绩费的公式到底是什么?

“利润的 20%”这样一句话不是公式。写任何代码之前,下面每一项都要有书面答案:

  • 费率是多少,是否因投资者、账户或 IB 层级而不同。
  • 是否采用高水位线(high-water mark),也就是亏损补回来之后才再次收费。
  • 交易账户上的入金和出金怎么处理。
  • 只算已平仓盈亏,还是连浮动盈亏也算。未平仓的盈利仍然可能消失。
  • 货币换算:用哪个汇率、取哪个时点的汇率,把账户货币换成钱包货币。
  • 钱包余额为零时怎么办:允许负余额、记一笔欠款、部分扣费,还是暂停访问。
  • 多级 IB 之间怎么分成,以及资格规则(最低交易量、活跃客户数、佣金追回)。

然后我会要三个书面算例,用真实的数字:一个普通的盈利月,一个既有入金又有出金的月份,以及一次先亏损后回本的情况。它们会成为第一批自动化测试。如果公司里两个人对同一个算例算出不同的答案,问题就在代价最低的时候被发现了。

// Amounts are integer minor units (cents) of the account currency.
type FeeInput = {
  hwm: bigint; // high-water mark carried in from the last charged period
  netDeposits: bigint; // balance deals in the period: deposits minus withdrawals
  endEquity: bigint; // or end balance, if the agreement says closed P/L only
  rateBps: bigint; // 2000n = 20%
};

type FeeResult = { fee: bigint; newHwm: bigint; gainAboveMark: bigint };

export function performanceFee(input: FeeInput): FeeResult {
  const { hwm, netDeposits, endEquity, rateBps } = input;
  if (rateBps < 0n || rateBps > 10_000n) throw new Error('rate out of range');

  // A deposit is not profit, a withdrawal is not a loss: the mark moves with the cash.
  const mark = hwm + netDeposits;
  const gainAboveMark = endEquity - mark;

  // At or below the mark: no fee. Losses never lower the mark.
  if (gainAboveMark <= 0n) return { fee: 0n, newHwm: mark, gainAboveMark };

  // bigint division truncates, so the fee rounds down. Agree that rule in writing.
  const fee = (gainAboveMark * rateBps) / 10_000n;

  // The fee is charged to the wallet, not taken from the trading account,
  // so the account's equity is unchanged and becomes the new mark.
  return { fee, newHwm: endEquity, gainAboveMark };
}

// Worked example (USD): carried mark 10,000.00, deposit 2,000.00,
// withdrawal 500.00, end equity 12,650.00, rate 20%.
//   mark = 1_000_000 + (200_000 - 50_000) = 1_150_000
//   gain = 1_265_000 - 1_150_000          =   115_000  (1,150.00)
//   fee  = 115_000 * 2000 / 10_000        =    23_000  (230.00)
//   new mark                              = 1_265_000  (12,650.00)
const result = performanceFee({
  hwm: 1_000_000n,
  netDeposits: 150_000n,
  endEquity: 1_265_000n,
  rateBps: 2000n,
}); // { fee: 23_000n, newHwm: 1_265_000n, gainAboveMark: 115_000n }
ts示意用的 TypeScript,不是生产代码。金额用整数表示最小货币单位,所以没有任何数字会经过浮点运算。

这个版本按出入金的金额平移水位线。有些协议则是在出金时按比例下调水位线,所以要查清楚你的合同写的是哪一种。

问题五:由哪个法律实体收款?

支付这一侧由四个事实决定:哪家公司收投资者的钱,在哪个国家,持有哪些牌照,以及有没有支付服务商书面认可过这个业务类别。对很多银行卡收单机构和支付网关来说,外汇和投资属于受限类别。如果服务商的风控团队拒绝开户,或者上线后把账户关掉,沙盒里跑通的对接什么也证明不了。

比较稳妥的上线顺序是:先做人工充值,由管理员确认后账本才记账;提现由人工打款,走双人复核(maker-checker),一个人准备付款,另一个人审批。支付网关、用户间转账和稳定币,等服务商和律师都点头之后再做。

牌照和客户资金方面的问题,归业务方和它的律师负责。我的职责是把系统设计好,让他们要求的控制措施(审批、限额、审计记录)不用重写就能满足。

我会搭建的架构

五个答案都有了之后,系统本身并不特别:一个模块化单体,只有 MT5 桥接服务单独拆出来。桥接服务之所以独立,是因为 Manager API 的 SDK 是 Windows 原生的,而且同一个连接上的调用必须串行化。我为自营交易公司做的对接也是这样拆分的:一个跑在 Windows 上的 .NET 服务,由主后端通过 HTTP 调用。

Broker AMT5 serverBroker BMT5 serverBroker adaptersone per access routeidentity: server + loginSyncclassify dealsno data = failureDeals storeper accountCommission engineone key peraccount and periodLedgerdouble-entryinvestor and IB walletsDashboardsinvestors · IBsBack officeapproves runsposts once
每家券商各有一个 MT5 适配器,为同步任务提供数据;同步任务把成交记录分类后写入成交库,佣金引擎再据此向账本记账,投资者看板、IB 看板和管理后台都从账本读取。
  • MT5 适配器:每条券商接入路线一个,都在同一个接口后面。
  • 同步任务:按相互重叠的时间窗口拉取成交记录,并给每一条分类:是交易(DEAL_BUY、DEAL_SELL)还是余额操作(DEAL_BALANCE、DEAL_CREDIT);如果是交易,再看进出场方向(ENTRY_IN、ENTRY_OUT、ENTRY_INOUT、ENTRY_OUT_BY)。
  • 成交库:放在你自己的数据库里,以(服务器,登录号,成交单号)为唯一键,重复拉取同一个窗口不会改变任何数据。
  • 佣金引擎:只依据已入库的成交记录和当期规则做纯计算。
  • 账本:资金只在这里变动。
  • 投资者看板和 IB 看板,以及带双人复核审批的管理后台。

公式依赖这一步分类。已实现盈利记在平仓成交上(out、in-out、out-by),而入金和出金是以余额类成交的形式出现的。分类一旦出错,入金就会被算成利润。

对投资者看板来说,每隔几分钟同步一次就够了。逐 tick 的实时推送成本高得多,除了风控监控之外很少用得上。有一条来自实际项目的规则可以原样沿用:MT5 返回“没有数据”时,要当作失败处理,绝不能当作空结果。把账户标记为数据过期,显示最后一次成功读取的时间,并通知工作人员。

月末佣金结算与 IB 关系树

佣金结算是系统里风险最高的任务:它一次性给所有账户记账。我会让它具备四个特性:

  • 每个(账户,结算周期)一个唯一键,由数据库强制保证,重跑也不会重复记账。
  • 任务可以续跑:进度按账户记录,中途崩溃的任务会从停下的地方继续。
  • 先出预览:工作人员审核并批准之后,才有任何内容写入账本。
  • 给 IB 的对账单:列出每个客户账户、计算基数、费率和结果。

IB 的层级关系要用闭包表或物化路径来存,让一个客户的所有上级都能低成本地查出来,因为每一笔佣金都要沿着树向上走。还要按结算周期保存快照,因为 IB 会调动、会离开、会被重新分配。三月的佣金必须按三月的关系树来算,哪怕有人在六月重跑。

一页纸看完五个问题

问题为什么重要对范围或成本的影响
1. 有什么 MT5 接入权限,对应哪些券商一个登录账号只能读一家券商的服务器,别的都读不到一个适配器还是多个,第三方桥接服务的费用,只读还是可读可写
2. 账户由谁交易代客交易和跟单交易可能属于需要牌照的业务需要哪些看板和对账单,以及业绩费到底适不适用
3. 钱包是什么提现和转账可能让它成为受监管的储值产品费用额度只需要一本小账本。储值则要加上客户资金保障、限额和后台控制措施
4. 费用和佣金的公式含糊之处会变成与投资者和 IB 之间的纠纷佣金引擎、测试和对账单的规模
5. 由哪个实体收款对受限类别,服务商会拒绝开户或关闭账户上线时用人工充值,还是对接支付网关并走完它的审批流程
每一个答案对范围的影响,都比任何一个页面大。

稳定币入金,两句话说完

先接一家能分配充值地址并处理链上确认的支付服务商,把它的回调当作普通的支付 webhook 来处理。自己在链上监测入金是后面的事,工作量更大,还要有单独的对账,而且这一块我没有在生产环境运行过。

一次付费技术调研应该交付什么

我不会只凭一份功能清单就给整个项目报价。先做一次付费的技术调研或概念验证,它应该交付:

  • 通过适配器接通一家券商,用的是你实际拥有的凭证。
  • 真实的成交记录和账户数据进入成交库,已完成分类,并且能检测出过期数据。
  • 公式已经实现,并通过那三个算例。
  • 一份调研报告:这个接入权限能做什么,数据反映出什么,以及还没有答案的法律问题和服务商问题。
  • 一份里程碑计划,范围划分到可以分段报价。

这类工作我承接:可以只做 MT5 对接,也可以以金融科技技术合伙人的身份负责更大范围的构建。如果五个问题里你今天能回答两三个,把你手上的信息发给我,我会告诉你我会先核实什么。

相关服务MT5 Manager API 对接了解更多

更多笔记