持仓净额结算引擎
Position Netting
题目详情
多账户持仓净额结算是期货清算和风险管理中的核心操作。通过将同一产品不同账户的多头和空头头寸相互抵消,可以减少总持仓量、保证金占用和结算成本。
任务:实现一个持仓净额结算引擎,按账户和产品维度汇总并计算净持仓。
英文原题
A position netting engine aggregates a stream of individual trade executions into a consolidated view of net positions and average entry prices (AEP). Accurate and low-latency netting of these positions is essential for real-time risk management and precise Profit and Loss (PnL) calculations in quantitative trading systems.
Task
Implement a PositionNettingEngine class that processes a stream of trade executions (fills) and supports querying the current net position and average entry price for a
解析
问题分析
多账户持仓净额结算在期货清算中至关重要。通过将同一产品的多头和空头头寸相互抵消,可以减少总保证金占用和结算风险。核心是构建按产品+账户维度的头寸汇总表,识别可抵消的对冲头寸。
实现
struct Position { std::string account, product; int quantity; double price; };
struct NetPosition { std::string account, product; int net_qty; double avg_price; };
class PositionNettingEngine {
std::map<std::pair<std::string, std::string>, std::vector<Position>> positions_;
public:
void addPosition(const Position& pos) {
positions_[{pos.account, pos.product}].push_back(pos);
}
std::vector<NetPosition> computeNet() {
std::vector<NetPosition> result;
for (auto& [key, pos_list] : positions_) {
int total_qty = 0;
double total_cost = 0;
for (auto& p : pos_list) {
total_qty += p.quantity;
total_cost += p.quantity * p.price;
}
result.push_back({key.first, key.second, total_qty,
total_qty ? total_cost / total_qty : 0});
}
return result;
}
};复杂度与边界
- 时间复杂度:O(N) 遍历所有头寸一次完成汇总
- 空间复杂度:O(K) 其中 K 为不同 (账户, 产品) 的组合数
- 边界条件:(1) 净持仓为 0 时 avg_price 设为 0 (2) 空头寸列表返回空结果 (3) 大数量导致 int 溢出需考虑使用 int64
英文解析
Analysis
Multi-account position netting is essential in futures clearing. By offsetting long and short positions in the same product, total margin requirements and settlement risk are reduced. The core is building a position summary table by product+account dimension and identifying offsetting hedge positions.
Solution
struct Position { std::string account, product; int quantity; double price; };
struct NetPosition { std::string account, product; int net_qty; double avg_price; };
class PositionNettingEngine {
std::map<std::pair<std::string, std::string>, std::vector<Position>> positions_;
public:
void addPosition(const Position& pos) {
positions_[{pos.account, pos.product}].push_back(pos);
}
std::vector<NetPosition> computeNet() {
std::vector<NetPosition> result;
for (auto& [key, pos_list] : positions_) {
int total_qty = 0;
double total_cost = 0;
for (auto& p : pos_list) {
total_qty += p.quantity;
total_cost += p.quantity * p.price;
}
result.push_back({key.first, key.second, total_qty,
total_qty ? total_cost / total_qty : 0});
}
return result;
}
};Complexity & Edge Cases
- Time complexity: O(N) single traversal of all positions
- Space complexity: O(K) where K is distinct (account, product) combinations
- Edge cases: (1) net_qty=0 sets avg_price to 0 (2) empty position list returns empty result (3) large quantities may overflow int
Key Considerations
- Directionality matters: Netting long vs short at same price level is not the same as offsetting — regulatory regimes may prohibit cross-direction netting
- Partial fills: Each fill updates net position incrementally; must track per-fill netted quantities, not just final net
- Multi-currency: Positions in different currencies cannot be netted directly — convert to base currency first
- Audit trail: Every netting operation must be logged for compliance; regulators require full position reconstruction capability