股票连续投资历史收益计算

假设每月有几千块钱投资某股票,在每月第一个星期五按收盘价买入,购买一定时间后全部卖出,计算收益率


由于有除权这种事件存在,所以不能简单的按照历史价格进行计算。
后复权:以时间起点往后复权,分红送股向上平移,用于计算历史收益,时间起点是股票发行日
前复权:以时间终点往前复权,分红送股向下平移,用于观察涨跌行情?


计算历史上某一段时间的收益,算法如下。
股票买入价:获取不复权的股价数据,寻找当日的股价A。
股票卖出价:获取后复权的股价数据,寻找买入日和卖出日的股价X和Y,做比例缩放即可。A/X*Y,这样就可以将中间的除权事件包含在内了。


python环境anaconda 5.1.0 
股票接口使用tushare


完整计算器代码如下:
# 测试环境 anaconda 5.1.0
# tushare 安装 pip install tushare
import sys
import datetime
import tushare as ts


def get_stock_price(pricedata, buydate):
  # pricedate 股价数据
  # buydate 买入日期,字符串 例 2012-01-01
  # 返回收盘价 如果停牌返回0
  for index, row in pricedata.iterrows():
    if row.date == buydate:
      return row.close
  return 0


def get_max_buy_count(price, fund):
  count = 100
  while count * price < fund:
    count += 100
  return count - 100


def get_last_trade_date(pricedata, selldate_exp):
  # pricedate 股价数据
  # selldate_exp 期望的卖出日期,字符串 例 2012-01-01
  # 返回距离期望最近的交易日期
  dsell = datetime.datetime.strptime(selldate_exp,'%Y-%m-%d')
  dret = 0
  for index, row in pricedata.iterrows():
    drow = datetime.datetime.strptime(row.date,'%Y-%m-%d')
    if drow <= dsell:
      dret = drow
    else:
      break
  if dret == 0:
    return 0
  return dret.strftime("%Y-%m-%d")


def calc_stock(price, price_hfq, buydate, selldate, fund):
  # price 股价数据 不复权
  # price_hfq 股价数据 后复权
  # buydate 买入日期
  # selldate 卖出日期
  # fund 购买资金
  # 返回 买入单价,买入单价后复权,卖出单价,购买数量
  buyprice = get_stock_price(price, buydate)
  buyprice_hfq = get_stock_price(price_hfq, buydate)
  sellprice_hfq = get_stock_price(price_hfq, selldate)
  if buyprice == 0 or buyprice_hfq == 0 or sellprice_hfq == 0:
    return 0,0,0,0
  buycount = get_max_buy_count(buyprice, fund)
  sellprice = buyprice / buyprice_hfq * sellprice_hfq
  return buyprice, buyprice_hfq, sellprice, buycount


def main(stock, start, end, fundpermonth):
  print('股票代码: ', stock)
  print('开始日期: ', start)
  print('卖出日期: ', end)
  print('每月资金: ', fundpermonth)


  # 获取不复权股价数据
  print('正在获取不复权股价数据')
  data_bfq = ts.get_k_data(stock,start,end,autype='none')
  print('正在获取后复权股价数据')
  data_hfq = ts.get_k_data(stock,start,end,autype='hfq')


  # 获取最后卖出日
  selldate = get_last_trade_date(data_bfq, end)
  if selldate == 0:
    print('卖出日期不存在')
    sys.exit(1)


  print('正在计算连续投资收益')
  # 遍历交易日 (每个月第一个星期五)
  dstart = datetime.datetime.strptime(start,'%Y-%m-%d')
  dend = datetime.datetime.strptime(end,'%Y-%m-%d')
  dtmp = dstart
  oneday = datetime.timedelta(days=1)
  month_buy = 0
  month_fund = 0
  total_buy = 0
  total_sell = 0
  total_stock = 0
  fund_pool = 0
  last_price_hfq = 0
  while dtmp <= dend:
    if dtmp.month != month_fund:
      # 新的月份,资金池累加
      fund_pool += int(fundpermonth)
      month_fund = dtmp.month
    if dtmp.month != month_buy:
      if dtmp.weekday() == 4:    #是个星期五
        # 检查是否可以购买
        print('=================================')
        buydate = dtmp.strftime("%Y-%m-%d")
        price = get_stock_price(data_bfq, buydate)
        if price > 0:
          # 可以购买 买入
          buyprice,buyprice_hfq,sellprice,buycount = calc_stock(data_bfq, data_hfq, buydate, selldate, fund_pool)
          if last_price_hfq > 0:
            gain = (buyprice_hfq - last_price_hfq) / last_price_hfq * 100
            print('同比增长: ', round(gain, 2), '%')
          print('买入日期: ', buydate)
          print('买入单价: ', round(buyprice, 2))
          print('卖出单价: ', round(sellprice, 2))
          print('买入数量: ', buycount)
          print('当月投资: ', round(buyprice * buycount, 2))
          total_buy += buyprice * buycount
          total_stock += buycount
          total_sell += sellprice * buycount
          fund_pool -= buyprice * buycount
          print('剩余资金: ', round(fund_pool, 2))
          print('当期总投资: ', round(total_buy, 2))
          print('当期总持股: ', total_stock)
          print('当期总收入: ', round(total_sell, 2))
          print('当期总收益: ', round((total_sell - total_buy) / total_buy * 100, 2), '%')
          last_price_hfq = buyprice_hfq
          month_buy = dtmp.month
        else:
          # 停牌 无法交易
          print('买入日期: ', buydate)
          print('停牌中,无法交易')
          
    dtmp += oneday
  
  rate = round((total_sell - total_buy) * 100 / total_buy, 2)
  print('=================================')
  print('总投资额: ', round(total_buy, 2))
  print('总持有量: ', total_stock)
  print('卖出金额: ', round(total_sell, 2))
  print('总收益率: ', rate, '%')


# 命令行参数
# 股票代码 买入起始日期 卖出日期 每月资金
if __name__ == "__main__":
  if len(sys.argv) < 5:  
    print('Usage: calc [stockcode] [startdate] [selldate] [fundpermonth]')
    print('Exam:  calc 000002 2012-01-01 2016-01-01 8000')
    sys.exit()
  main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])


测试输出结果


(base) D:\stock>python main.py 000002 2012-01-01 2012-12-31 8000
股票代码:  000002
开始日期:  2012-01-01
卖出日期:  2012-12-31
每月资金:  8000
正在获取不复权股价数据
正在获取后复权股价数据
正在计算连续投资收益
=================================
买入日期:  2012-01-06
买入单价:  7.16
卖出单价:  10.27
买入数量:  1100
当月投资:  7876.0
剩余资金:  124.0
当期总投资:  7876.0
当期总持股:  1100
当期总收入:  11292.3
当期总收益:  43.38 %
=================================
同比增长:  8.8 %
买入日期:  2012-02-03
买入单价:  7.79
卖出单价:  10.27
买入数量:  1000
当月投资:  7790.0
剩余资金:  334.0
当期总投资:  15666.0
当期总持股:  2100
当期总收入:  21558.04
当期总收益:  37.61 %
=================================
同比增长:  10.78 %
买入日期:  2012-03-02
买入单价:  8.63
卖出单价:  10.27
买入数量:  900
当月投资:  7767.0
剩余资金:  567.0
当期总投资:  23433.0
当期总持股:  3000
当期总收入:  30797.2
当期总收益:  31.43 %
=================================
同比增长:  -2.9 %
买入日期:  2012-04-06
买入单价:  8.38
卖出单价:  10.27
买入数量:  1000
当月投资:  8380.0
剩余资金:  187.0
当期总投资:  31813.0
当期总持股:  4000
当期总收入:  41062.93
当期总收益:  29.08 %
=================================
同比增长:  10.02 %
买入日期:  2012-05-04
买入单价:  9.22
卖出单价:  10.27
买入数量:  800
当月投资:  7376.0
剩余资金:  811.0
当期总投资:  39189.0
当期总持股:  4800
当期总收入:  49275.52
当期总收益:  25.74 %
=================================
同比增长:  -0.76 %
买入日期:  2012-06-01
买入单价:  9.15
卖出单价:  10.27
买入数量:  900
当月投资:  8235.0
剩余资金:  576.0
当期总投资:  47424.0
当期总持股:  5700
当期总收入:  58514.68
当期总收益:  23.39 %
=================================
同比增长:  6.98 %
买入日期:  2012-07-06
买入单价:  9.65
卖出单价:  10.12
买入数量:  800
当月投资:  7720.0
剩余资金:  856.0
当期总投资:  55144.0
当期总持股:  6500
当期总收入:  66610.68
当期总收益:  20.79 %
=================================
同比增长:  -9.84 %
买入日期:  2012-08-03
买入单价:  8.7
卖出单价:  10.12
买入数量:  1000
当月投资:  8700.0
剩余资金:  156.0
当期总投资:  63844.0
当期总持股:  7500
当期总收入:  76730.68
当期总收益:  20.18 %
=================================
同比增长:  -1.15 %
买入日期:  2012-09-07
买入单价:  8.6
卖出单价:  10.12
买入数量:  900
当月投资:  7740.0
剩余资金:  416.0
当期总投资:  71584.0
当期总持股:  8400
当期总收入:  85838.68
当期总收益:  19.91 %
=================================
买入日期:  2012-10-05
停牌中,无法交易
=================================
同比增长:  -4.19 %
买入日期:  2012-10-12
买入单价:  8.24
卖出单价:  10.12
买入数量:  1000
当月投资:  8240.0
剩余资金:  176.0
当期总投资:  79824.0
当期总持股:  9400
当期总收入:  95958.68
当期总收益:  20.21 %
=================================
同比增长:  4.98 %
买入日期:  2012-11-02
买入单价:  8.65
卖出单价:  10.12
买入数量:  900
当月投资:  7785.0
剩余资金:  391.0
当期总投资:  87609.0
当期总持股:  10300
当期总收入:  105066.68
当期总收益:  19.93 %
=================================
同比增长:  6.36 %
买入日期:  2012-12-07
买入单价:  9.2
卖出单价:  10.12
买入数量:  900
当月投资:  8280.0
剩余资金:  111.0
当期总投资:  95889.0
当期总持股:  11200
当期总收入:  114174.69
当期总收益:  19.07 %
=================================
总投资额:  95889.0
总持有量:  11200
卖出金额:  114174.69
总收益率:  19.07 %




参考:http://tushare.org/
参考:https://xueqiu.com/3488649239/62074848
<think>我们被要求计算市场日平均收益率。根据引用[2],年化收益率的计算中提到了日收益率的平均值。因此,市场日平均收益率就是市场日收益率的算术平均值。###计算公式市场日平均收益率的计算公式为:$$\bar{r}=\frac{1}{N}\sum_{t=1}^{N}r_t$$其中:-$\bar{r}$表示日平均收益率-$r_t$表示第$t$个交易日的收益率-$N$表示总交易日数###计算方法步骤1.**收集数据**:获取市场指数(如沪深300指数、标普500指数)的每日收盘价。2.**计算收益率**:通常使用对数收益率(更常用)或简单收益率。-对数收益率:$r_t=\ln\left(\frac{P_t}{P_{t-1}}\right)$-简单收益率:$R_t=\frac{P_t-P_{t-1}}{P_{t-1}}$3.**计算日平均收益率**:将每个交易日的收益率相加,然后除以交易日总数$N$。###Python实现示例引用[2]中提到了计算每日对数收益率,我们可以在此基础上计算平均值。```pythonimportpandasaspdimportnumpyasnp#示例数据:假设有一个包含日期和收盘价的DataFramedata=pd.DataFrame({"Date":pd.date_range(start="2023-01-01",periods=5),"Close":[100,102,105,103,106]})#计算对数日收益率data['Log_Return']=np.log(data['Close']/data['Close'].shift(1))#计算日平均收益率(对数收益率的算术平均)daily_avg_return=data['Log_Return'].mean()print(f"市场日平均收益率(对数):{daily_avg_return:.6f}")```###注意事项1.**收益率选择**:在金融分析中,对数收益率具有时间可加性,更适用于时间序列分析[^2]。但简单收益率在解释上更直观。两种方法计算的平均收益率会有细微差别。2.**数据清洗**:需要处理缺失值(如第一行因移位产生的NaN)和异常值。3.**时间区间**:选择足够长的时间段以反映市场平均表现,避免短期波动影响。###与年化收益率的关系引用[2]中提到,年化收益率可以通过日平均收益率来估算(假设收益按日复利):$$\text{年化收益率}=(1+\bar{r})^{\text{交易天数}}-1$$但更精确的复利计算是:$$\text{年化收益率}=e^{252\cdot\bar{r}}-1\quad\text{(对数收益连续复利)}$$其中252是一年约252个交易日。###Excel实现方法1.**数据列**:-A列:日期-B列:收盘价2.**收益率列**(以对数收益率为例):-C2单元格:`=LN(B2/B1)`,并向下填充3.**日平均收益率**:```excel=AVERAGE(C2:C100)```###金融应用-**业绩评估**:比较投资组合日平均收益率与市场日平均收益率。-**风险溢价计算**:市场日平均收益率减去无风险利率得到市场风险溢价[^1]。§§相关问题§§1.对数收益率与简单收益率在计算平均收益率时有何差异?2.如何用日平均收益率估算年化收益率?3.市场日平均收益率在CAPM模型中起什么作用?</think>### 计算市场日平均收益率的公式与方法 #### 核心公式 市场日平均收益率的计算公式为: $$ \bar{r} = \frac{1}{N} \sum_{t=1}^{N} r_t $$ 其中: - $\bar{r}$:市场日平均收益率 - $r_t$:第 $t$ 日的收益率 - $N$:总交易日数量 #### 计算步骤 1. **数据准备**: - 获取市场指数每日收盘价序列 $P_1, P_2, ..., P_N$ - 确保数据连续(排除非交易日) 2. **计算收益率**(推荐对数收益率): $$ r_t = \ln\left(\frac{P_t}{P_{t-1}}\right) $$ *注:也可使用简单收益率 $R_t = \frac{P_t - P_{t-1}}{P_{t-1}}$,但对数收益率具有时间可加性优势[^2]* 3. **求算术平均值**: $$ \bar{r} = \frac{\sum_{t=1}^{N} r_t}{N} $$ #### Python实现 ```python import pandas as pd import numpy as np # 示例数据(沪深300指数收盘价) data = pd.DataFrame({ "Date": ["2023-01-03", "2023-01-04", "2023-01-05", "2023-01-06"], "Close": [3888.60, 3893.22, 3901.35, 3895.98] }) # 计算对数日收益率 data['Return'] = np.log(data['Close'] / data['Close'].shift(1)) # 计算日平均收益率 daily_avg_return = data['Return'].mean() print(f"市场日平均收益率: {daily_avg_return:.6f} ({daily_avg_return*100:.4f}%)") ``` #### Excel实现 1. A列输入日期,B列输入收盘价 2. C2输入收益率公式:`=LN(B2/B1)` 3. 计算平均值:`=AVERAGE(C2:C100)` #### 注意事项 1. **时间周期选择**: - 短期分析:20-60个交易日 - 长期分析:1年以上数据(建议250+交易日) 2. **收益率类型选择**: | 收益率类型 | 公式 | 特点 | |------------|------|------| | 对数收益率 | $\ln(P_t/P_{t-1})$ | 时间可加,更适合理财分析[^3] | | 简单收益率 | $(P_t - P_{t-1})/P_{t-1}$ | 更直观,但不可加 | 3. **实际应用场景**: - 组合业绩基准比较 - CAPM模型中的市场收益率输入[^1] - 计算夏普比率的分母项[^2] #### 金融意义解读 市场日平均收益率反映: - 长期市场回报水平(如A股历史日均收益≈0.03%) - 风险溢价估计:$\text{市场收益} - \text{无风险收益}$ - 投资者预期回报基准[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值