鱼C论坛

 找回密码
 立即注册
查看: 163|回复: 3

[已解决]关于xlwings库读取Excel文件,进行计算的一个问题

[复制链接]
发表于 2024-10-24 18:49:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 shadowmage 于 2024-10-24 18:50 编辑

如题,我构建了一个函数,想要用Python帮助我计算一连串数据的XIRR值。这个在python里挺麻烦,需要不断试错,但是Excel本身就有xirr函数。但是运行结果总是不太对。我想知道错在哪
程序代码如下:
import xlwings as xw

def Excel_Xirr(file, sheet_name, date_col, cash_col, present_value_col, start_cell):
    wb = xw.Book(file)
    
    if '计算' in wb.sheet_names:
        sheet = wb.sheets['计算']
        sheet.api.Cells.Clear()
    else:
        sheet = wb.sheets.add('计算')
    
    data_sheet = wb.sheets[sheet_name]
    
    start_row = 2
    end_row = data_sheet.api.Cells(data_sheet.api.Rows.Count, date_col).End(xlUp).Row
    
    for i in range(start_row, end_row + 1):
        sheet.api.Cells.Clear()
        
        # 复制日期和现金流数据到'计算' sheet
        date_range = data_sheet.api.Range(f"{date_col}{i}:{date_col}{i}").Value
        cash_range = data_sheet.api.Range(f"{cash_col}{i}:{cash_col}{i}").Value
        present_value = data_sheet.api.Range(f"{present_value_col}{i}").Value
        
        # 复制第一笔现金流的数据
        sheet.api.Range('A1').Value = date_range
        sheet.api.Range('B1').Value = cash_range
        
        # 复制后续现金流的数据
        date_range_next = data_sheet.api.Range(f"{date_col}{i + 1}:{date_col}{end_row}").Value
        cash_range_next = data_sheet.api.Range(f"{cash_col}{i + 1}:{cash_col}{end_row}").Value
        for j, (date, cash) in enumerate(zip(date_range_next, cash_range_next), start=2):
            sheet.api.Range(f'A{j}').Value = date
            sheet.api.Range(f'B{j}').Value = cash
        
        if cash_range_next[-1] != 0:
            sheet.api.Range(f'B{j + 1}').Value = cash_range_next[-1] + present_value
        else:
            sheet.api.Range(f'B{j + 1}').Value = present_value
        
        sheet.api.Range(f'C{j}').Formula = '=XIRR(B1:B{j + 1}, A1:A{j + 1})'
        
        data_sheet.api.Range(f"{start_cell}{i}").Value = sheet.api.Range(f'C{j}').Value
    
    # 保存并关闭Excel文件
    wb.save(file)
    wb.close()

# 使用示例
Excel_Xirr('现金流示例2.xlsx', '006593', 'F', 'G', 'P', 'K3')

论坛没法上传xlsx,只能把截图发上来。
最佳答案
2024-10-24 18:54:21
你的代码有一些地方需要调整,以下是修正后的代码以及一些简化和优化:
import xlwings as xw

def Excel_Xirr(file, sheet_name, date_col, cash_col, present_value_col, start_cell):
    wb = xw.Book(file)
    
    # 检查并选择正确的 sheet
    if '计算' in wb.sheets:
        sheet = wb.sheets['计算']
        sheet.clear_contents()
    else:
        sheet = wb.sheets.add('计算')
    
    data_sheet = wb.sheets[sheet_name]
    
    start_row = 2
    end_row = data_sheet.range(f'{date_col}1').end('down').row
    
    for i in range(start_row, end_row + 1):
        sheet.clear_contents()
        
        # 复制日期和现金流数据到'计算' sheet
        date = data_sheet.range(f"{date_col}{i}").value
        cash = data_sheet.range(f"{cash_col}{i}").value
        present_value = data_sheet.range(f"{present_value_col}{i}").value
        
        sheet.range('A1').value = date
        sheet.range('B1').value = cash
        
        for j in range(i + 1, end_row + 1):
            next_date = data_sheet.range(f"{date_col}{j}").value
            next_cash = data_sheet.range(f"{cash_col}{j}").value
            sheet.range(f'A{j-i+1}').value = next_date
            sheet.range(f'B{j-i+1}').value = next_cash
        
        if cash != 0:
            sheet.range(f'B{end_row-i+2}').value = cash + present_value
        else:
            sheet.range(f'B{end_row-i+2}').value = present_value
        
        # 使用 Excel 公式 XIRR
        xirr_formula = f'=XIRR(B1:B{end_row-i+2}, A1:A{end_row-i+2})'
        sheet.range(f'C1').formula = xirr_formula
        
        # 将结果写回原始表
        data_sheet.range(f"{start_cell}{i}").value = sheet.range('C1').value
    
    # 保存并关闭Excel文件
    wb.save()
    wb.close()

# 使用示例
Excel_Xirr('现金流示例2.xlsx', '006593', 'F', 'G', 'P', 'K3')

注意事项:

1. 确保 `xlwings` 和 Excel 都安装正确。
2. 确保 Excel 的计算功能正常。
3. 使用 `range` 而不是 `api`,代码更简洁。
4. 检查数据是否按照预期在 Excel 中。
5. 避免频繁清空 sheet 内容,直接使用新的起始位置。
   
请根据具体需求调整代码。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
现金流示例2.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-10-24 18:54:21 | 显示全部楼层    本楼为最佳答案   
你的代码有一些地方需要调整,以下是修正后的代码以及一些简化和优化:
import xlwings as xw

def Excel_Xirr(file, sheet_name, date_col, cash_col, present_value_col, start_cell):
    wb = xw.Book(file)
    
    # 检查并选择正确的 sheet
    if '计算' in wb.sheets:
        sheet = wb.sheets['计算']
        sheet.clear_contents()
    else:
        sheet = wb.sheets.add('计算')
    
    data_sheet = wb.sheets[sheet_name]
    
    start_row = 2
    end_row = data_sheet.range(f'{date_col}1').end('down').row
    
    for i in range(start_row, end_row + 1):
        sheet.clear_contents()
        
        # 复制日期和现金流数据到'计算' sheet
        date = data_sheet.range(f"{date_col}{i}").value
        cash = data_sheet.range(f"{cash_col}{i}").value
        present_value = data_sheet.range(f"{present_value_col}{i}").value
        
        sheet.range('A1').value = date
        sheet.range('B1').value = cash
        
        for j in range(i + 1, end_row + 1):
            next_date = data_sheet.range(f"{date_col}{j}").value
            next_cash = data_sheet.range(f"{cash_col}{j}").value
            sheet.range(f'A{j-i+1}').value = next_date
            sheet.range(f'B{j-i+1}').value = next_cash
        
        if cash != 0:
            sheet.range(f'B{end_row-i+2}').value = cash + present_value
        else:
            sheet.range(f'B{end_row-i+2}').value = present_value
        
        # 使用 Excel 公式 XIRR
        xirr_formula = f'=XIRR(B1:B{end_row-i+2}, A1:A{end_row-i+2})'
        sheet.range(f'C1').formula = xirr_formula
        
        # 将结果写回原始表
        data_sheet.range(f"{start_cell}{i}").value = sheet.range('C1').value
    
    # 保存并关闭Excel文件
    wb.save()
    wb.close()

# 使用示例
Excel_Xirr('现金流示例2.xlsx', '006593', 'F', 'G', 'P', 'K3')

注意事项:

1. 确保 `xlwings` 和 Excel 都安装正确。
2. 确保 Excel 的计算功能正常。
3. 使用 `range` 而不是 `api`,代码更简洁。
4. 检查数据是否按照预期在 Excel 中。
5. 避免频繁清空 sheet 内容,直接使用新的起始位置。
   
请根据具体需求调整代码。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-1 23:48:42 | 显示全部楼层
FishC 发表于 2024-10-24 18:54
你的代码有一些地方需要调整,以下是修正后的代码以及一些简化和优化:

实际上,刚刚发现,这个计算xirr的功能,还是用VBA实现更靠谱一点
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-2 00:11:17 | 显示全部楼层
shadowmage 发表于 2024-11-01 23:48
实际上,刚刚发现,这个计算xirr的功能,还是用VBA实 ...


确实,使用VBA来计算XIRR可能会更直接和高效。以下是一个简单的VBA代码示例,可以帮助你在Excel中计算XIRR:

1. 打开Excel,按 `Alt + F11` 打开VBA编辑器。
2. 在VBA编辑器中,选择 `Insert` > `Module`,然后在模块中粘贴以下代码:
Function CalculateXIRR(dates As Range, cashFlows As Range) As Double
    On Error GoTo ErrorHandler
    CalculateXIRR = Application.WorksheetFunction.Xirr(cashFlows, dates)
    Exit Function
ErrorHandler:
    CalculateXIRR = CVErr(xlErrValue)
End Function

3. 返回Excel工作表,在单元格中输入公式 `=CalculateXIRR(A1:A10, B1:B10)`,其中 `A1:A10` 是日期范围,`B1:B10` 是现金流范围。

这个VBA函数会调用Excel内置的XIRR函数来计算结果,并且在遇到错误时返回一个错误值。这样可以避免在Python中处理复杂的Excel操作,同时利用Excel的内置功能来简化计算过程。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-21 18:56

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表