基于quantmod的股票实际PnL精准计算方案及代码实现
股票分红场景下的精准PnL计算问题
使用quantmod获取股票数据时,发现调整收盘价已预先扣除股票分红,但用于实际PnL(盈亏)计算时存在精度问题——若并非从IPO日买入股票,PnL不应包含调整收盘价中体现的全部分红。
希望统计2018-01-20至2022-10-01时间段内的所有分红总额,结合收盘价(而非调整收盘价),通过公式「买入价格 + 累计分红 - 最新收盘价」模拟计算PnL,具体该如何实现?
初始尝试的示例代码:
library(quantmod) getSymbols("TGT", from='2018-01-01', to='2022-10-01') # 第一笔分红发放日为2018-01-20 TGT_dividend <- getDividends("TGT", from='2018-01-20', to='2022-10-01') # 不含分红的收盘价 TGT$TGT.Close
最终实现代码
感谢@phiver的帮助,已完成如下代码实现:
# 含分红股票的PnL计算 library(quantmod) # 核心PnL计算函数 calc_pnl <- function(close, dividends, buy_price, buy_date){ names(close) <- "close" names(dividends) <- "div" # 合并买入日之后的收盘价与累计分红 out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")])) # 填充分红的空值(将最新累计分红向前填充) out$div <- na.locf(out$div) # 计算PnL:当前收盘价 - 买入价格 + 累计分红 out$pnl <- out$close - buy_price + out$div out } # 注:以下三个函数逻辑与calc_pnl完全一致,可合并为一个函数减少冗余 calc_pnl_max <- function(close, dividends, buy_price, buy_date){ names(close) <- "close" names(dividends) <- "div" out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")])) out$div <- na.locf(out$div) out$pnl <- out$close - buy_price + out$div out } calc_pnl_min <- function(close, dividends, buy_price, buy_date){ names(close) <- "close" names(dividends) <- "div" out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")])) out$div <- na.locf(out$div) out$pnl <- out$close - buy_price + out$div out } calc_pnl_avg <- function(close, dividends, buy_price, buy_date){ names(close) <- "close" names(dividends) <- "div" out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")])) out$div <- na.locf(out$div) out$pnl <- out$close - buy_price + out$div out } # 时间范围设置 start <- '2015-01-01' end <- '2022-10-21' # 目标股票代码 symbols <- '0386.HK' # 获取股票收盘价数据(自动去空值) ticker <- na.omit(getSymbols(symbols, from = start, to = end, auto.assign=FALSE)) # 获取分红数据并保留两位小数 ticker_dividend <- round(getDividends(symbols, from=start, to=end), 2) # 计算不同买入价格:区间最高价、最低价、均价 buy_max <- max(ticker[,4]) buy_min <- min(ticker[,4]) buy_avg <- mean(ticker[,4]) # 计算三种买入价格下的PnL pnl_max <- calc_pnl_max(ticker[,4], ticker_dividend, buy_price = buy_min , buy_date = start) pnl_min <- calc_pnl_max(ticker[,4], ticker_dividend, buy_price = buy_max , buy_date = start) pnl_avg <- calc_pnl_max(ticker[,4], ticker_dividend, buy_price = buy_avg , buy_date = start) # 提取最近8天的PnL数据并格式化 df <- round(tail(cbind(pnl_max$pnl, pnl_min$pnl, pnl_avg$pnl), 8), 2) colnames(df) <- c('maxPnL','minPnL','avgPnL')
内容的提问来源于stack exchange,提问作者Bubbles
相关产品推荐
相关产品推荐

