标签:idx tday inp 各期 str rec 工具 收益率 def
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# Copyright © 2022, 飞麦 <fitmap@qq.com>, All rights reserved. # frozen_string_literal: true require 'clipboard' require 'xirr' # 根据剪贴板中的日期(可选)、交费与现金价值计算各期的内部收益率 module XirrGo module_function # 结构: 日期, 交费, 现金价值 RecEx = Struct.new(:tday, :fee, :curr) # 从匹配字符串中删除分隔千位数的逗号后获取数值 def positive_value(str) str && !str.empty? && str != '-' ? str.gsub(',', '').to_f : nil end # 从匹配字符串中删除分隔千位数的逗号后获取数值, 然后转换为负值 def negative_value(str) tmp = positive_value(str) tmp ? -tmp : nil end # 判断行的有效性(包含交费和/或现金价值) def valid(rec) rec.fee || rec.curr end # 获取计算内部收益率的输入数组 def deal(rec_a, o_idx) tday = Date.today inp_a = [] # 内部收益率输入数组 rec_a.each_with_index do |rec, i_idx| next unless valid(rec) tday = rec.tday if rec.tday inp_a << [tday, rec.fee] if rec.fee # 日期、发生金额(交费转换为负数, 现金价值保持为正数) if i_idx >= o_idx inp_a << [tday, rec.curr] if rec.curr break end tday >>= 12 # 下一保险年度 end inp_a end # 根据资金发生序列计算各年的内部收益率 def calc(rec_a) gain_a = [] # 收益率数组 rec_a.each_with_index do |rec, o_idx| if rec.curr inp_a = deal(rec_a, o_idx) # 获取计算内部收益率的输入数组 gain = (Xirr.xirc(inp_a)**365.2425) - 1.0 # 计算内部收益率 gain_a << "#{format('%.4f', gain * 100)}%" # 转换为百分数 else gain_a << '' # 标题行或空行 end end gain_a.join("\n") # 所有行合并转换为一段文本 end # 从字符串行中提取交费、现金价值等数据 def pick2(line) md = line.match(/^\s*((\d+(,\d+)*(\.\d+)?)|-?)\s*\t\s*((\d+(,\d+)*(\.\d+)?)|-?)\s*$/) if md RecEx.new(nil, negative_value(md[1]), positive_value(md[5])) # 交费、现金价值 else puts "\n#{line}: 本行没有日期[可选]、交费、现金价值等数据" RecEx.new # 不予处理 end end # 分析日期字符串 def date_parse(str) Date.parse(str) rescue Date::Error nil end # 从字符串行中提取日期、交费、现金价值等数据 def pick3(line) md = line.match(/^\s*(\d+-\d+-\d+)\s*\t\s*((\d+(,\d+)*(\.\d+)?)|-?)\s*\t\s*((\d+(,\d+)*(\.\d+)?)|-?)\s*$/) if md datey = date_parse(md[1]) if datey RecEx.new(datey, negative_value(md[2]), positive_value(md[6])) # 日期、交费、现金价值 else puts "\n#{line}: #{md[1]} 日期非法" RecEx.new # 不予处理 end else pick2(line) end end # 根据剪贴板的日期(可选)、交费与现金价值序列,计算内部收益率 def run text = Clipboard.paste # 从剪贴板获取日期列(可选)、交费列、现金价值列 rec_a = [] # 日期(可选)、交费、现金价值序列(若无日期,则假设每年一行) # 对剪贴板内容中的每一行 text.each_line { |line| rec_a << pick3(line) } Clipboard.copy(calc(rec_a)) # 将计算结果拷贝回剪贴板 puts "\n【内部收益率列已拷贝到剪贴板中】" end end # 用<Ctrl>-<鼠标左键>点选交费列、现金价值列后,拷贝到剪贴板 # 或用<Ctrl>-<鼠标左键>点选日期(YYYY-MM-DD)列、交费列、现金价值列后,拷贝到剪贴板 # 运行后剪贴板包含内部收益率列 $PROGRAM_NAME == __FILE__ && XirrGo.run |
标签:idx,tday,inp,各期,str,rec,工具,收益率,def 来源: https://www.cnblogs.com/fitmap/p/16593806.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。