You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:05:22