交易费用架构设计
概述
交易费用模块负责管理券商的交易费用配置,并在订单成交时自动计算和扣除相应的交易费用。系统支持美股和港股的不同费用标准,费用配置与券商绑定,在交易会话启动时传递给相关模块使用。
费用处理模式
系统根据不同的交易模式采用不同的费用处理策略:
1. 模拟资产交易(实时交易 + 回测)
- 订单费用:在订单成交时实时计算费用,直接填入订单的
trading_fee
字段 - 费用扣除:成交后立即从账户现金中扣除费用
- 资产更新:
- 买入:扣除交易金额和费用,增加持仓
- 卖出:增加交易金额,扣除费用,减少持仓
- 费用来源:基于券商费用配置实时计算
2. 真实资产交易(实时交易)
- 订单费用:从券商API拉取的订单数据可能不包含费用明细
- 费用计算:系统模拟计算费用并填入订单的
trading_fee
字段(仅用于展示和统计) - 费用扣除:不扣除费用,真实资产以券商数据为准
- 资产更新:完全基于券商API返回的账户数据,不做本地计算
- 费用来源:基于券商费用配置模拟计算(用于参考)
关键设计原则
- 订单费用字段:所有订单都有
trading_fee
字段,存储费用明细 - 买卖差异:买入和卖出的费用计算规则不同(交易活动费仅在卖出时收取)
- 模式隔离:模拟资产和真实资产的费用处理逻辑完全隔离
- 真实数据优先:真实资产模式下,账户数据以券商API为准,不做本地修改
架构图
1. 费用配置数据流
graph TB
subgraph "前端层"
FE1[券商设置页面]
FE2[费用配置表单]
end
subgraph "API层"
API1[Broker API<br/>券商管理]
API2[Fee Config API<br/>费用配置]
end
subgraph "服务层"
SVC1[BrokerService<br/>券商服务]
SVC2[TradingService<br/>交易服务]
end
subgraph "仓储层"
REPO1[BrokerRepository<br/>券商仓储]
REPO2[Redis缓存]
end
subgraph "交易引擎层"
TSE[TradingSessionEngine<br/>交易会话引擎]
SE[StrategyEngine<br/>策略引擎]
TE[TradingEngine<br/>交易引擎]
SIM[SimulationEngine<br/>模拟交易引擎]
FEE[FeeCalculator<br/>费用计算器]
end
subgraph "数据存储"
DB[(PostgreSQL<br/>持久化存储)]
REDIS[(Redis<br/>缓存)]
end
%% 配置流程
FE2 --> |更新费用配置|API2
API2 --> SVC1
SVC1 --> REPO1
REPO1 --> DB
REPO1 --> REDIS
%% 启动流程
TSE --> |获取券商配置|SVC1
SVC1 --> REPO1
REPO1 --> |返回费用配置|SVC1
SVC1 --> |传递费用配置|TSE
TSE --> |初始化|SE
TSE --> |初始化|TE
TSE --> |初始化|SIM
%% 交易流程
SIM --> |计算费用|FEE
FEE --> |扣除现金|SIM
2. 费用计算时序图
sequenceDiagram
participant Strategy as StrategyEngine
participant Trading as TradingEngine
participant Simulation as SimulationEngine
participant FeeCalc as FeeCalculator
participant Account as AccountManager
Strategy->>Trading: 发送订单信号
Trading->>Simulation: 执行订单
Note over Simulation: 订单成交
Simulation->>FeeCalc: 计算费用(quantity, price, side, market)
alt 美股市场
FeeCalc->>FeeCalc: 使用US费用配置
FeeCalc->>FeeCalc: 计算平台费
FeeCalc->>FeeCalc: 计算交易活动费(仅卖出)
FeeCalc->>FeeCalc: 计算交收费
FeeCalc->>FeeCalc: 计算综合审计费
else 港股市场
FeeCalc->>FeeCalc: 使用HK费用配置
FeeCalc->>FeeCalc: 计算平台费
FeeCalc->>FeeCalc: 计算交易活动费(仅卖出)
FeeCalc->>FeeCalc: 计算交收费
FeeCalc->>FeeCalc: 计算综合审计费
end
FeeCalc-->>Simulation: 返回总费用
Simulation->>Account: 扣除交易费用
Account->>Account: 更新现金余额
Account-->>Simulation: 扣除成功
Simulation->>Simulation: 记录交易费用到订单
Simulation-->>Trading: 订单完成
Trading-->>Strategy: 交易完成通知
核心组件设计
1. 费用配置模型
FeeConfig(费用配置)
class FeeConfig(BaseModel):
"""交易费用配置"""
us_fees: USFeeConfig # 美股费用配置
hk_fees: HKFeeConfig # 港股费用配置
USFeeConfig(美股费用配置)
class USFeeConfig(BaseModel):
"""美股交易费用配置"""
# 平台费用
platform_fee_per_share: Decimal = Decimal('0.005') # 平台费 0.005美元/股
platform_fee_minimum: Decimal = Decimal('1.0') # 最低收取1美元
# 交易活动费用 (仅在卖出时收取)
activity_fee_per_share: Decimal = Decimal('0.000166') # 0.000166美元/股
activity_fee_maximum: Decimal = Decimal('8.3') # 最高8.3美元
# 交收费
clearing_fee_per_share: Decimal = Decimal('0.003') # 0.003美元/股
clearing_fee_max_pct: Decimal = Decimal('0.07') # 最高7%
# 综合审计费
audit_fee_per_share: Decimal = Decimal('0.000046') # 0.000046美元/股
audit_fee_minimum: Decimal = Decimal('0.01') # 最低0.01美元
HKFeeConfig(港股费用配置)
class HKFeeConfig(BaseModel):
"""港股交易费用配置(结构与美股相同)"""
# 平台费用
platform_fee_per_share: Decimal = Decimal('0.005')
platform_fee_minimum: Decimal = Decimal('1.0')
# 交易活动费用 (仅在卖出时收取)
activity_fee_per_share: Decimal = Decimal('0.000166')
activity_fee_maximum: Decimal = Decimal('8.3')
# 交收费
clearing_fee_per_share: Decimal = Decimal('0.003')
clearing_fee_max_pct: Decimal = Decimal('0.07')
# 综合审计费
audit_fee_per_share: Decimal = Decimal('0.000046')
audit_fee_minimum: Decimal = Decimal('0.01')
2. 费用计算器
FeeCalculator(费用计算器)
class FeeCalculator:
"""交易费用计算器"""
def __init__(self, fee_config: Optional[FeeConfig] = None):
"""
初始化费用计算器
Args:
fee_config: 费用配置(包含美股和港股配置),如果为None则使用默认配置
"""
if fee_config is None:
fee_config = FeeConfig()
self.us_fees = fee_config.us_fees
self.hk_fees = fee_config.hk_fees
def calculate_fee(
self,
quantity: Decimal,
price: Decimal,
side: str,
market: str
) -> TradingFee:
"""
计算交易费用
Args:
quantity: 成交数量
price: 成交价格
side: 买卖方向 ('buy' | 'sell')
market: 市场类型 ('US' | 'HK')
Returns:
TradingFee: 费用明细对象
"""
if market == 'US':
return self._calculate_us_fee(quantity, price, side)
elif market == 'HK':
return self._calculate_hk_fee(quantity, price, side)
else:
raise ValueError(f"Unsupported market: {market}")
def _calculate_us_fee(
self,
quantity: Decimal,
price: Decimal,
side: str
) -> TradingFee:
"""计算美股费用"""
trade_amount = quantity * price
fees = TradingFee()
# 1. 平台费(买入和卖出都收取)
fees.platform_fee = max(
quantity * self.us_fees.platform_fee_per_share,
self.us_fees.platform_fee_minimum
)
# 2. 交易活动费(仅卖出收取)
if side == 'sell':
fees.activity_fee = min(
quantity * self.us_fees.activity_fee_per_share,
self.us_fees.activity_fee_maximum
)
# 3. 交收费(买入和卖出都收取)
fees.clearing_fee = min(
quantity * self.us_fees.clearing_fee_per_share,
trade_amount * self.us_fees.clearing_fee_max_pct
)
# 4. 综合审计费(买入和卖出都收取)
fees.audit_fee = max(
quantity * self.us_fees.audit_fee_per_share,
self.us_fees.audit_fee_minimum
)
# 计算总费用
fees.total_fee = (
fees.platform_fee +
fees.activity_fee +
fees.clearing_fee +
fees.audit_fee
)
# ⭐ 精度控制:将所有费用四舍五入到2位小数
fees.platform_fee = fees.platform_fee.quantize(Decimal('0.01'))
fees.activity_fee = fees.activity_fee.quantize(Decimal('0.01'))
fees.clearing_fee = fees.clearing_fee.quantize(Decimal('0.01'))
fees.audit_fee = fees.audit_fee.quantize(Decimal('0.01'))
fees.total_fee = fees.total_fee.quantize(Decimal('0.01'))
# ⭐ 记录计算详情(用于调试和审计)
fees.calculation_details = {
'quantity': str(quantity),
'price': str(price),
'trade_amount': str(trade_amount),
'side': side,
'market': 'US',
'fee_breakdown': {
'platform_fee': {'applied': str(fees.platform_fee)},
'activity_fee': {'applied': str(fees.activity_fee)},
'clearing_fee': {'applied': str(fees.clearing_fee)},
'audit_fee': {'applied': str(fees.audit_fee)}
}
}
return fees
def _calculate_hk_fee(
self,
quantity: Decimal,
price: Decimal,
side: str
) -> TradingFee:
"""计算港股费用(逻辑与美股相同)"""
# 实现逻辑与 _calculate_us_fee 相同,使用 hk_fees 配置
pass
TradingFee(费用明细)
class TradingFee(BaseModel):
"""交易费用明细"""
platform_fee: Decimal = Decimal('0') # 平台费
activity_fee: Decimal = Decimal('0') # 交易活动费
clearing_fee: Decimal = Decimal('0') # 交收费
audit_fee: Decimal = Decimal('0') # 综合审计费
total_fee: Decimal = Decimal('0') # 总费用
currency: str = 'USD' # 币种
calculation_details: Dict[str, Any] = {} # 计算详情
3. 模拟交易引擎集成
class SimulationEngine:
"""模拟交易引擎"""
def __init__(
self,
user_id: str,
session_id: str,
fee_config: Optional[FeeConfig] = None
):
"""
初始化模拟交易引擎
Args:
user_id: 用户ID
session_id: 会话ID
fee_config: 费用配置(可选,默认使用长桥标准费率)
"""
self.user_id = user_id
self.session_id = session_id
# 初始化费用计算器
if fee_config is None:
fee_config = self._get_default_fee_config()
self.fee_calculator = FeeCalculator(fee_config)
async def execute_order(
self,
symbol: str,
side: str,
quantity: Decimal,
price: Decimal
) -> Order:
"""
执行订单
Args:
symbol: 股票代码 (格式: CODE.MARKET, 如 AAPL.US)
side: 买卖方向 ('buy' | 'sell')
quantity: 数量
price: 价格
Returns:
Order: 订单对象
"""
# 1. 解析市场类型
market = symbol.split('.')[-1] # US 或 HK
# 2. 计算交易费用
trading_fee = self.fee_calculator.calculate_fee(
quantity=quantity,
price=price,
side=side,
market=market
)
# 3. 检查账户余额
if side == 'buy':
required_cash = (quantity * price) + trading_fee.total_fee
if not self._has_sufficient_cash(required_cash, market):
raise InsufficientFundsError("现金余额不足")
# 4. 执行订单
order = self._execute_order_internal(
symbol=symbol,
side=side,
quantity=quantity,
price=price
)
# 5. 扣除交易费用
self._deduct_trading_fee(trading_fee, market)
# 6. 记录费用到订单
order.trading_fee = trading_fee
# 7. 持久化订单
await self._persist_order(order)
return order
def _deduct_trading_fee(self, trading_fee: TradingFee, market: str):
"""
扣除交易费用
Args:
trading_fee: 费用明细
market: 市场类型 (US | HK)
"""
currency = 'USD' if market == 'US' else 'HKD'
# 从账户现金中扣除费用
current_cash = self.account.get_cash(currency)
new_cash = current_cash - trading_fee.total_fee
self.account.set_cash(currency, new_cash)
# 记录费用日志
self._log_fee_deduction(trading_fee, currency)
@staticmethod
def _get_default_fee_config() -> FeeConfig:
"""获取默认费用配置(长桥标准费率)"""
return FeeConfig(
us_fees=USFeeConfig(),
hk_fees=HKFeeConfig()
)
数据存储设计
1. PostgreSQL存储
Broker表扩展
-- 券商表中的config字段存储费用配置
-- config JSONB字段结构:
{
"api_config": {
"app_key": "...",
"app_secret": "...",
"access_token": "..."
},
"fee_config": {
"us_fees": {
"platform_fee_per_share": "0.005",
"platform_fee_minimum": "1.0",
"activity_fee_per_share": "0.000166",
"activity_fee_maximum": "8.3",
"clearing_fee_per_share": "0.003",
"clearing_fee_max_pct": "0.07",
"audit_fee_per_share": "0.000046",
"audit_fee_minimum": "0.01"
},
"hk_fees": {
"platform_fee_per_share": "0.005",
"platform_fee_minimum": "1.0",
"activity_fee_per_share": "0.000166",
"activity_fee_maximum": "8.3",
"clearing_fee_per_share": "0.003",
"clearing_fee_max_pct": "0.07",
"audit_fee_per_share": "0.000046",
"audit_fee_minimum": "0.01"
}
}
}
Order表扩展
-- 订单表增加费用字段
ALTER TABLE orders ADD COLUMN trading_fee JSONB;
-- trading_fee JSONB字段结构:
{
"platform_fee": "1.50",
"activity_fee": "0.50",
"clearing_fee": "0.90",
"audit_fee": "0.14",
"total_fee": "3.04",
"currency": "USD",
"calculation_details": {
"quantity": 300,
"price": "150.25",
"side": "buy",
"market": "US"
}
}
2. Redis缓存
# 券商费用配置缓存
key: f"broker:fee_config:{broker_id}"
value: {
"us_fees": {...},
"hk_fees": {...}
}
ttl: 3600 # 1小时
# 交易会话费用配置缓存
key: f"trading:session:fee_config:{session_id}"
value: {
"us_fees": {...},
"hk_fees": {...}
}
ttl: 86400 # 24小时
前端配置界面
1. 费用配置表单
interface FeeConfigFormData {
us_fees: USFeeConfig;
hk_fees: HKFeeConfig;
}
interface USFeeConfig {
// 平台费用
platform_fee_per_share: number; // 平台费(美元/股)
platform_fee_minimum: number; // 最低收费(美元)
// 交易活动费用
activity_fee_per_share: number; // 交易活动费(美元/股)
activity_fee_maximum: number; // 最高收费(美元)
// 交收费
clearing_fee_per_share: number; // 交收费(美元/股)
clearing_fee_max_pct: number; // 最高收费百分比
// 综合审计费
audit_fee_per_share: number; // 综合审计费(美元/股)
audit_fee_minimum: number; // 最低收费(美元)
}
// HKFeeConfig 结构相同
2. 表单字段说明
字段 | 说明 | 默认值 | Tooltip |
---|---|---|---|
平台费(每股) | 每股交易平台费用,买入和卖出都收取 | 0.005 | 按成交股数计算,例如100股收取0.5美元 |
平台费(最低) | 每笔订单最低收取的平台费 | 1.0 | 即使按股计算不足1美元,也收取1美元 |
交易活动费(每股) | 每股交易活动费,仅卖出时收取 | 0.000166 | 按成交股数计算,仅适用于卖出订单 |
交易活动费(最高) | 每笔订单最高收取的交易活动费 | 8.3 | 即使按股计算超过8.3美元,也只收取8.3美元 |
交收费(每股) | 每股交收费用,买入和卖出都收取 | 0.003 | 按成交股数计算 |
交收费(最高百分比) | 交收费最高收取交易额的百分比 | 0.07 | 例如交易额1000美元,最高收取70美元 |
综合审计费(每股) | 每股综合审计费,买入和卖出都收取 | 0.000046 | 按成交股数计算 |
综合审计费(最低) | 每笔订单最低收取的综合审计费 | 0.01 | 即使按股计算不足0.01美元,也收取0.01美元 |
关键特性
1. 费用配置灵活性
- 支持券商级别的费用配置
- 美股和港股独立配置
- 默认值为长桥标准费率
- 支持动态修改和实时生效
2. 费用计算准确性
- 分项计算各类费用
- 遵循最低/最高收费规则
- 区分买入和卖出的费用差异
- 精确到小数点后2位(与系统价格和资产数据精度保持一致)
3. 费用扣除可靠性
- 订单成交时立即扣除费用
- 费用明细记录到订单
- 现金余额实时更新
- 支持多币种费用扣除
4. 费用透明度
- 费用明细完整记录
- 支持费用预估功能
- 前端展示费用详情
- 日志记录所有费用操作
安全与性能
1. 数据安全
- 费用配置加密存储
- 费用计算过程审计
- 防止费用计算错误
2. 性能优化
- 费用配置缓存(Redis)
- 批量费用计算支持
- 异步费用记录
3. 容错处理
- 费用计算失败降级
- 默认费用配置兜底
- 费用扣除事务保证
扩展性
1. 新市场支持
- 易于添加新市场费用配置(如A股、新加坡等)
- 统一的费用计算接口
2. 新费用类型
- 灵活扩展费用项目
- 支持自定义费用规则
3. 费用策略
- 支持VIP用户费用优惠
- 支持批量交易费用折扣
- 支持动态费用策略