Future/Promise 定价
Future Promise Pricing
题目详情
定价复杂衍生品计算成本高昂,可能阻塞主线程处理实时行情。为维持低延迟,量化交易系统通常使用底层并发原语将计算卸载到后台线程,确保关键路径不被阻塞而定价结果异步计算。
任务:实现 AsyncPricer 类,使用 std::promise 和 std::future 实现异步定价。submit() 方法接收定价请求并返回 future,后台线程计算定价结果并通过 promise 设置值,主线程在需要时通过 future.get() 获取结果。
英文原题
Pricing complex derivatives can be computationally expensive and may block the main thread from processing real-time market data. To maintain low latency, quantitative trading systems often offload these calculations to background threads using lower-level concurrency primitives. This ensures the critical path remains unblocked while the pricing result is computed asynchronously.
Task
Implement an AsyncPricer class that offloads a pricing calculation to a background thread. You must implement t
解析
问题分析
std::future/std::promise 用于跨线程传递一次性结果。在期权定价中,可将不同的蒙特卡洛路径批次分发给线程池,通过 future 收集各批次结果后汇总。
实现
double monteCarloBatch(int paths, double S, double K, double r, double sigma, double T) {
std::mt19937 rng(std::random_device{}());
double sum = 0;
for (int i = 0; i < paths; ++i) {
double ST = S * std::exp((r - sigma*sigma/2)*T + sigma*std::sqrt(T)*std::normal_distribution<>(0,1)(rng));
sum += std::max(ST - K, 0.0);
}
return std::exp(-r * T) * sum / paths;
}
double parallelPrice(int total_paths, int batches) {
std::vector<std::future<double>> futures;
for (int i = 0; i < batches; ++i)
futures.push_back(std::async(std::launch::async, monteCarloBatch, total_paths/batches, 100.0, 100.0, 0.05, 0.2, 1.0));
return std::accumulate(futures.begin(), futures.end(), 0.0, [] (\1) { return s + f.get(); }) / batches;
}复杂度与边界
- 时间复杂度:每个 batch O(路径数),并行后 O(路径数/批次数)
- 空间复杂度:O(批次数 * sizeof(future))
- 边界条件:(1) f.get() 阻塞直到该批次完成 (2) 批次抛异常时通过 get() 传播 (3) async 使用 std::launch::async 确保异步执行
英文解析
Analysis
std::future/std::promise are used to pass one-shot results across threads. In option pricing, different Monte Carlo path batches can be dispatched to a thread pool, with futures collecting each batch result for final aggregation.
Solution
double monteCarloBatch(int paths, double S, double K, double r, double sigma, double T) {
std::mt19937 rng(std::random_device{}());
double sum = 0;
for (int i = 0; i < paths; ++i) {
double ST = S * std::exp((r - sigma*sigma/2)*T + sigma*std::sqrt(T)*std::normal_distribution<>(0,1)(rng));
sum += std::max(ST - K, 0.0);
}
return std::exp(-r * T) * sum / paths;
}
double parallelPrice(int total_paths, int batches) {
std::vector<std::future<double>> futures;
for (int i = 0; i < batches; ++i)
futures.push_back(std::async(std::launch::async, monteCarloBatch, total_paths/batches, 100.0, 100.0, 0.05, 0.2, 1.0));
double sum = 0;
for (auto& f : futures) sum += f.get();
return sum / batches;
}Complexity & Edge Cases
- Time complexity: Each batch O(paths), parallelized to O(paths/batches)
- Space complexity: O(batches x sizeof(future))
- Edge cases: (1) f.get() blocks until that batch completes (2) Exceptions thrown in a batch propagate through get() (3) std::launch::async ensures truly asynchronous execution
Verification
Run parallel pricing with known parameters, benchmark against serial Monte Carlo result. Verify error decreases as total_paths increases. Confirm exception propagation works correctly.
Key Considerations
Future/promise decouples computation from result collection. In quantitative pricing, partitioning Monte Carlo paths across threads and aggregating via futures is the standard parallelization pattern. The blocking get() is acceptable here since all batches must complete before pricing is meaningful.