如何用dplyr的accumulate函数及rowwise复现R中的数据框/tibble?
用dplyr复现《期权与衍生品》中的保证金账户表格
核心逻辑梳理
首先明确赫尔书中期货保证金账户的结算规则:
- 初始存入初始保证金($12000),维持保证金为$9000(对应你代码中的
contract_value) - 每日盈亏 = (当日收盘价 - 前一日收盘价) × 合约乘数(200)
- 保证金余额 = 前一日余额 + 当日盈亏;若余额低于维持保证金,需追加资金至初始保证金水平
- 变动保证金 = 初始保证金 - 结算后未追加的余额(仅当余额低于维持保证金时产生)
- 追加通知(margin_call)为前一日需补缴的变动保证金
正确的accumulate实现(推荐)
这是最高效的矢量化实现,符合dplyr的风格:
library(tidyverse) initial_deposit <- 12000 maintenance_margin <- 9000 multiplier <- 200 closing_stock_indices <- c(1250,1241,1238.3,1244.6,1241.3,1240.1, 1236.2, 1229.9, 1230.8,1225.4,1228.1,1211,1211,1214.3,1216.1,1223,1226.9) # 构建基础数据 df <- tibble(Day = 0:(length(closing_stock_indices)-1), Closing_SI = closing_stock_indices) %>% mutate(Daily_change = c(0, diff(Closing_SI) * multiplier)) # 计算保证金账户各项指标 df <- df %>% mutate( # 递推计算保证金余额 Margin_balance = accumulate(Daily_change, .init = initial_deposit, ~ { new_bal <- .x + .y if (new_bal < maintenance_margin) initial_deposit else new_bal })[-1], # 计算变动保证金 Variation_Margin = ifelse(Margin_balance == initial_deposit, initial_deposit - (lag(Margin_balance) + Daily_change), 0), Variation_Margin = replace_na(Variation_Margin, 0), # 计算追加通知 margin_call = lag(Variation_Margin, default = 0) ) %>% # 修正Day0的保证金余额 mutate(Margin_balance = ifelse(Day == 0, initial_deposit, Margin_balance)) # 查看结果 print(df, n = Inf)
rowwise()替代实现(效率较低)
如果一定要用rowwise(),可以通过逐行重新计算累积序列的方式实现(不推荐用于大数据量):
df_rowwise <- df %>% select(Day, Closing_SI, Daily_change) %>% rowwise() %>% mutate( # 逐行计算从初始到当前日的保证金余额,取对应行结果 Margin_balance = accumulate(c(initial_deposit, Daily_change[Day:(n()-1)]), ~ { new_bal <- .x + .y if (new_bal < maintenance_margin) initial_deposit else new_bal })[row_number()] ) %>% ungroup() %>% mutate( Variation_Margin = ifelse(Margin_balance == initial_deposit & Day > 0, initial_deposit - (lag(Margin_balance) + Daily_change), 0), margin_call = lag(Variation_Margin, default = 0) ) # 查看结果 print(df_rowwise, n = Inf)
内容的提问来源于stack exchange,提问作者Homer Jay Simpson
相关产品推荐
相关产品推荐

