mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Initialize git repository - Add comprehensive .gitignore for Go projects - Install golangci-lint v2.6.0 (latest v2) globally - Configure .golangci.yml with appropriate linters and formatters - Fix all formatting issues (gofmt) - Fix all errcheck issues (unchecked errors) - Adjust complexity threshold for validation functions - All checks passing: build, test, vet, lint
124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
package profitability
|
|
|
|
import (
|
|
"math"
|
|
)
|
|
|
|
// ProfitabilityMetrics contains IRR and NPV calculations for the project.
|
|
type ProfitabilityMetrics struct {
|
|
NPV float64 `json:"npv"` // Net Present Value
|
|
IRR float64 `json:"irr"` // Internal Rate of Return (as percentage)
|
|
PaybackPeriod float64 `json:"payback_period"` // Payback period in years
|
|
NPVBreakEven float64 `json:"npv_break_even"` // NPV at break-even discount rate
|
|
}
|
|
|
|
// CalculateProfitability computes IRR, NPV, and payback period for cash flows.
|
|
func CalculateProfitability(cashFlows []float64, discountRate float64) ProfitabilityMetrics {
|
|
// Calculate NPV
|
|
npv := calculateNPV(cashFlows, discountRate)
|
|
|
|
// Calculate IRR (find rate where NPV = 0)
|
|
irr := calculateIRR(cashFlows)
|
|
|
|
// Calculate payback period
|
|
paybackPeriod := calculatePaybackPeriod(cashFlows)
|
|
|
|
// Calculate NPV at break-even (NPV = 0)
|
|
npvBreakEven := 0.0 // This would be the IRR rate itself
|
|
|
|
return ProfitabilityMetrics{
|
|
NPV: npv,
|
|
IRR: irr * 100, // Convert to percentage
|
|
PaybackPeriod: paybackPeriod,
|
|
NPVBreakEven: npvBreakEven,
|
|
}
|
|
}
|
|
|
|
// calculateNPV computes Net Present Value for a series of cash flows.
|
|
func calculateNPV(cashFlows []float64, discountRate float64) float64 {
|
|
npv := 0.0
|
|
for i, cf := range cashFlows {
|
|
if i == 0 {
|
|
// Year 0 cash flow is not discounted
|
|
npv += cf
|
|
} else {
|
|
npv += cf / math.Pow(1+discountRate, float64(i))
|
|
}
|
|
}
|
|
return npv
|
|
}
|
|
|
|
// calculateIRR finds the Internal Rate of Return using numerical approximation.
|
|
// This uses a simple iterative approach to find the rate where NPV = 0.
|
|
func calculateIRR(cashFlows []float64) float64 {
|
|
// Simple IRR calculation using Newton-Raphson approximation
|
|
// Start with initial guess of 10%
|
|
rate := 0.10
|
|
|
|
// Maximum iterations
|
|
maxIter := 100
|
|
tolerance := 0.0001
|
|
|
|
for i := 0; i < maxIter; i++ {
|
|
npv := calculateNPV(cashFlows, rate)
|
|
npvDerivative := calculateNPVDerivative(cashFlows, rate)
|
|
|
|
if math.Abs(npvDerivative) < tolerance {
|
|
break // Avoid division by zero
|
|
}
|
|
|
|
newRate := rate - npv/npvDerivative
|
|
|
|
if math.Abs(newRate-rate) < tolerance {
|
|
return newRate
|
|
}
|
|
|
|
rate = newRate
|
|
|
|
// Bound the rate between -50% and 100% to prevent extreme values
|
|
if rate < -0.5 {
|
|
rate = -0.5
|
|
} else if rate > 1.0 {
|
|
rate = 1.0
|
|
}
|
|
}
|
|
|
|
return rate
|
|
}
|
|
|
|
// calculateNPVDerivative calculates the derivative of NPV with respect to discount rate.
|
|
// Used in Newton-Raphson method for IRR calculation.
|
|
func calculateNPVDerivative(cashFlows []float64, discountRate float64) float64 {
|
|
derivative := 0.0
|
|
for i, cf := range cashFlows {
|
|
if i > 0 {
|
|
derivative -= float64(i) * cf / math.Pow(1+discountRate, float64(i+1))
|
|
}
|
|
}
|
|
return derivative
|
|
}
|
|
|
|
// calculatePaybackPeriod calculates how many years it takes to recover initial investment.
|
|
func calculatePaybackPeriod(cashFlows []float64) float64 {
|
|
cumulative := 0.0
|
|
|
|
for i, cf := range cashFlows {
|
|
cumulative += cf
|
|
if cumulative >= 0 {
|
|
if i == 0 {
|
|
return 0 // Already profitable in year 0
|
|
}
|
|
// Linear interpolation for partial year
|
|
previousCumulative := cumulative - cf
|
|
if previousCumulative < 0 {
|
|
fraction := math.Abs(previousCumulative) / cf
|
|
return float64(i-1) + fraction
|
|
}
|
|
return float64(i)
|
|
}
|
|
}
|
|
|
|
// If never reaches break-even, return a large number
|
|
return 999.0
|
|
}
|