ty-mozhesh-sravnit-2-excel-f/check-calculations.py

306 lines
14 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import openpyxl
from datetime import datetime
print("📊 ПРОВЕРКА КОРРЕКТНОСТИ РАСЧЕТОВ В ШАБЛОНЕ\n")
print("Файл:", "Шаблон БП_ БКВ 2027 с займами.xlsx")
wb = openpyxl.load_workbook("Шаблон БП_ БКВ 2027 с займами.xlsx", data_only=True)
sheets = wb.sheetnames
print(f"Листов: {len(sheets)}")
print("=" * 70)
errors = []
warnings = []
success_checks = []
# Проверка 1: Финансовые показатели (лист 10.Фин.пок-ли)
print("\n1️⃣ ПРОВЕРКА: Финансовые показатели (лист 10.Фин.пок-ли)")
if "10.Фин.пок-ли" in sheets:
sheet = wb["10.Фин.пок-ли"]
# T1 - ставка дисконтирования, T2 - WACC
discount_rate = sheet.cell(row=1, column=20).value # T1
wacc = sheet.cell(row=2, column=20).value # T2
print(f" Ставка дисконтирования: {discount_rate}")
print(f" WACC: {wacc}")
if discount_rate is None or discount_rate == 0:
errors.append("❌ Ставка дисконтирования не заполнена или равна 0")
elif discount_rate > 0.3:
warnings.append(f"⚠ Ставка дисконтирования {discount_rate*100:.1f}% выглядит завышенной")
else:
success_checks.append(f"✓ Ставка дисконтирования: {discount_rate*100:.2f}%")
if wacc and wacc > discount_rate:
warnings.append(f"⚠ WACC ({wacc*100:.2f}%) > ставки дисконтирования ({discount_rate*100:.2f}%)")
else:
errors.append("❌ Лист '10.Фин.пок-ли' отсутствует")
# Проверка 2: NPV, IRR, PI (лист 11.Заключение)
print("\n2️⃣ ПРОВЕРКА: Показатели эффективности (лист 11.Заключение)")
if "11.Заключение" in sheets:
sheet = wb["11.Заключение"]
npv = sheet.cell(row=6, column=20).value # T6
irr = sheet.cell(row=7, column=20).value # T7
pi = sheet.cell(row=8, column=20).value # T8
pbp = sheet.cell(row=9, column=20).value # T9
print(f" NPV: {npv} тыс. тг")
print(f" IRR: {irr}")
print(f" PI: {pi}")
print(f" PBP: {pbp} лет")
if npv is None:
errors.append("❌ NPV не заполнен")
elif npv < 0:
warnings.append(f"⚠ NPV отрицательный ({npv}) - проект неэффективен")
else:
success_checks.append(f"✓ NPV положительный: {npv} тыс. тг")
if irr is None:
errors.append("❌ IRR не заполнен")
elif discount_rate and irr < discount_rate:
errors.append(f"❌ IRR ({irr*100:.2f}%) < ставки дисконтирования ({discount_rate*100:.2f}%) - проект неэффективен")
else:
success_checks.append(f"✓ IRR: {irr*100:.2f}%")
if pi is None:
errors.append("❌ PI не заполнен")
elif pi < 1:
warnings.append(f"⚠ PI < 1 ({pi}) - проект неэффективен")
else:
success_checks.append(f"✓ PI: {pi:.3f}")
else:
errors.append("❌ Лист '11.Заключение' отсутствует")
# Проверка 3: Анализ чувствительности (лист 12.Анализ чувствительности)
print("\n3️⃣ ПРОВЕРКА: Анализ чувствительности")
if "12.Анализ чувствительности" in sheets:
sheet = wb["12.Анализ чувствительности"]
base_npv = sheet.cell(row=4, column=3).value # C4
down_10_rev = sheet.cell(row=5, column=3).value # C5 (-10% доходы)
up_10_exp = sheet.cell(row=5, column=5).value # E5 (+10% расходы)
up_10_capex = sheet.cell(row=5, column=7).value # G5 (+10% CAPEX)
print(f" Базовый NPV: {base_npv}")
print(f" NPV при -10% доходов: {down_10_rev}")
print(f" NPV при +10% расходов: {up_10_exp}")
print(f" NPV при +10% CAPEX: {up_10_capex}")
if base_npv and down_10_rev:
if down_10_rev >= base_npv:
errors.append(f"❌ Анализ чувствительности: NPV при -10% доходов ({down_10_rev}) >= базового NPV ({base_npv})")
else:
success_checks.append("✓ NPV корректно реагирует на снижение доходов")
if base_npv and base_npv > 0:
if down_10_rev and down_10_rev < 0:
success_checks.append("✓ При -10% доходов NPV становится отрицательным (высокая чувствительность)")
else:
errors.append("❌ Лист '12.Анализ чувствительности' отсутствует")
# Проверка 4: EBITDA и риск-аппетит (лист 13.1 Карта рисков)
print("\n4️⃣ ПРОВЕРКА: Расчет риск-аппетита (лист 13.1 Карта рисков)")
if "13.1 Карта рисков" in sheets:
sheet = wb["13.1 Карта рисков"]
ebitda = sheet.cell(row=1, column=18).value # R1
risk_appetite_pct = sheet.cell(row=1, column=19).value # S1
risk_appetite_val = sheet.cell(row=1, column=20).value # T1
print(f" EBITDA: {ebitda} тыс. тг")
print(f" Риск-аппетит: {risk_appetite_pct*100 if risk_appetite_pct else None}%")
print(f" Расчетное значение: {risk_appetite_val} млрд. тг")
if ebitda and risk_appetite_pct and risk_appetite_val:
calculated = (ebitda * risk_appetite_pct) / 1_000_000_000
diff = abs(calculated - risk_appetite_val)
if diff > 0.1:
errors.append(f"❌ Риск-аппетит: расчетное значение {calculated:.3f} млрд ≠ {risk_appetite_val} млрд")
else:
success_checks.append(f"✓ Риск-аппетит рассчитан верно: {risk_appetite_val:.3f} млрд. тг")
else:
errors.append("❌ Лист '13.1 Карта рисков' отсутствует")
# Проверка 5: Премия за специфичный риск (лист 13.2)
print("\n5️⃣ ПРОВЕРКА: Премия за специфичный риск (лист 13.2)")
if "13.2 Премия за специфич риск" in sheets:
sheet = wb["13.2 Премия за специфич риск"]
total_risk_premium = 0
risk_factors = 0
for row in range(7, 35):
cell_value = sheet.cell(row=row, column=5).value # E7:E34
if cell_value and isinstance(cell_value, (int, float)) and cell_value > 0:
total_risk_premium += cell_value
risk_factors += 1
print(f" Фактор {risk_factors}: {cell_value*100:.2f}%")
print(f" Итого премия за риск: {total_risk_premium*100:.2f}%")
if total_risk_premium == 0:
warnings.append("⚠ Премия за специфичный риск не рассчитана (все факторы = 0)")
elif total_risk_premium > 0.05:
warnings.append(f"⚠ Премия за специфичный риск {total_risk_premium*100:.2f}% превышает разумный предел (5%)")
else:
success_checks.append(f"✓ Премия за специфичный риск: {total_risk_premium*100:.2f}%")
else:
errors.append("❌ Лист '13.2 Премия за специфич риск' отсутствует")
# Проверка 6: Заявление о риск-аппетите (лист 13.3)
print("\n6️⃣ ПРОВЕРКА: Заявление о риск-аппетите (лист 13.3)")
if "13.3 Заявление о риск аппетите" in sheets:
sheet = wb["13.3 Заявление о риск аппетите"]
div_errors = 0
for row in range(6, 15):
for col in range(1, 10):
cell_value = sheet.cell(row=row, column=col).value
if cell_value == "#DIV/0!":
div_errors += 1
if div_errors > 0:
errors.append(f"❌ В листе '13.3 Заявление о риск аппетите' найдено {div_errors} ошибок #DIV/0!")
else:
success_checks.append("✓ Заявление о риск-аппетите: формулы рассчитаны")
else:
errors.append("❌ Лист '13.3 Заявление о риск аппетите' отсутствует")
# Проверка 7: Лизинг (лист Лизинг)
print("\n7️⃣ ПРОВЕРКА: Расчеты лизинга")
if "Лизинг" in sheets:
sheet = wb["Лизинг"]
total_amount = sheet.cell(row=8, column=6).value # F8
payments_sum = sheet.cell(row=53, column=5).value # E53 (Итого)
print(f" Общая сумма договора: {total_amount}")
print(f" Сумма платежей по графику: {payments_sum}")
if total_amount and total_amount > 0:
if not payments_sum or payments_sum == 0:
errors.append(f"❌ Лизинг: сумма платежей ({payments_sum}) не равна общей сумме ({total_amount})")
else:
success_checks.append("✓ Лизинг: график платежей заполнен")
else:
warnings.append("⚠ Лизинг: общая сумма договора не заполнена или равна 0")
zero_payments = 0
for row in range(11, 52):
payment = sheet.cell(row=row, column=5).value
if payment == 0:
zero_payments += 1
if zero_payments > 40:
warnings.append(f"⚠ Лизинг: {zero_payments} платежей равны 0 - формулы не настроены")
else:
errors.append("❌ Лист 'Лизинг' отсутствует")
# Проверка 8: Заполненность БКВ (лист 4.БКВ)
print("\n8️⃣ ПРОВЕРКА: Заполненность БКВ")
if "4.БКВ" in sheets:
sheet = wb["4.БКВ"]
empty_cells = 0
total_cells = 0
for row in range(1, min(21, sheet.max_row + 1)):
for col in range(1, min(21, sheet.max_column + 1)):
total_cells += 1
cell_value = sheet.cell(row=row, column=col).value
if cell_value is None or cell_value == "":
empty_cells += 1
empty_pct = (empty_cells / total_cells * 100) if total_cells > 0 else 0
print(f" Пустых ячеек в первых 20 строках: {empty_pct:.1f}%")
if empty_pct > 50:
warnings.append(f"⚠ Лист '4.БКВ': {empty_pct:.1f}% пустых ячеек")
else:
success_checks.append(f"✓ Лист '4.БКВ': заполненность {100-empty_pct:.1f}%")
else:
errors.append("❌ Лист '4.БКВ' отсутствует")
# Проверка 9: ОДДС (лист 8.ОДДС)
print("\n9️⃣ ПРОВЕРКА: Отчет о движении денежных средств (8.ОДДС)")
if "8.ОДДС" in sheets:
sheet = wb["8.ОДДС"]
# Проверяем наличие отрицательных накопленных потоков в начале проекта
negative_dcf = 0
for col in range(5, 20): # Квартальные столбцы
dcf = sheet.cell(row=10, column=col).value # Накопленный дисконтированный поток
if dcf and dcf < 0:
negative_dcf += 1
if negative_dcf > 0:
success_checks.append(f"✓ ОДДС: {negative_dcf} кварталов с отрицательным накопленным DCF (нормально для начала проекта)")
else:
errors.append("❌ Лист '8.ОДДС' отсутствует")
# ВЫВОД РЕЗУЛЬТАТОВ
print("\n" + "=" * 70)
print("📋 ИТОГОВЫЙ ОТЧЕТ")
print("=" * 70)
if errors:
print(f"\n❌ КРИТИЧЕСКИЕ ОШИБКИ ({len(errors)}):")
for i, e in enumerate(errors, 1):
print(f" {i}. {e}")
if warnings:
print(f"\n⚠ ПРЕДУПРЕЖДЕНИЯ ({len(warnings)}):")
for i, w in enumerate(warnings, 1):
print(f" {i}. {w}")
if success_checks:
print(f"\n✅ КОРРЕКТНЫЕ РАСЧЕТЫ ({len(success_checks)}):")
for i, s in enumerate(success_checks, 1):
print(f" {i}. {s}")
print("\n" + "=" * 70)
print("ВСЕГО НАЙДЕНО:")
print(f" Ошибки: {len(errors)}")
print(f" Предупреждения: {len(warnings)}")
print(f" Корректных расчетов: {len(success_checks)}")
print("=" * 70)
# Сохраняем отчет
report_wb = openpyxl.Workbook()
report_sheet = report_wb.active
report_sheet.title = "Отчет о проверке"
report_data = [
["ПРОВЕРКА КОРРЕКТНОСТИ РАСЧЕТОВ В ШАБЛОНЕ"],
["Файл", "Шаблон БП_ БКВ 2027 с займами.xlsx"],
["Дата проверки", datetime.now().strftime("%d.%m.%Y %H:%M")],
[],
["КРИТИЧЕСКИЕ ОШИБКИ"] + [len(errors)],
] + [[e] for e in errors] + [
[],
["ПРЕДУПРЕЖДЕНИЯ"] + [len(warnings)],
] + [[w] for w in warnings] + [
[],
["КОРРЕКТНЫЕ РАСЧЕТЫ"] + [len(success_checks)],
] + [[s] for s in success_checks]
for row_idx, row_data in enumerate(report_data, 1):
for col_idx, value in enumerate(row_data, 1):
report_sheet.cell(row=row_idx, column=col_idx, value=value)
report_file = "Отчет_о_проверке_расчетов.xlsx"
report_wb.save(report_file)
print(f"\n📁 Подробный отчет сохранен: {report_file}")
if errors:
exit(1)