#!/usr/bin/env python """ Calculates return on investment over time. Usage: calc_roi [options] Options: -h, --help This message -u, --unit-cost Cost per panel (USD) [Default: 750] -i, --initial Initial investment cost (USD) [Default: 9000] -i, --units Initial units purchased [Default: 15] -d, --degradation Efficiency degradation per year % [Default: 0.007] -y, --years Years to calculate [Default: 25] -r, --return Annual return per unit (USD) [Default: 90] -p, --purchase Purchase new units with profit [Default: True] -s, --sunset When to sunset a panel [Default: 100] -m, --margin Percentage of revenue kept [Default: 80%] -c, --cease Year to cease purchasing new units [Default: 100] """ class Panel(object): """ Solar Panel used for calculating roi per unit """ @property def break_even(self): """ Year when this panel will break even """ investment_return = 0 for year in xrange(100): coeff = 1.0 - (self.degradation) margin = self.profit_margin revenue = self.annual_revenue investment_return += coeff * revenue * margin if investment_return >= self.investment: return year @property def age(self): """ age of panel """ return self.start + self.year @property def roi(self): """ return on investment (%) """ return self.investment / self.generated_revenue @property def degraded_revenue(self): """ degradation of panel in revenue """ value = 0 if self.age < self.sunset: coefficient = (1.0 - self.degradation * self.age) value = coefficient * self.annual_revenue * self.profit_margin return value def __init__(self, cost=750, year=0, revenue=2250 / 25, degradation=0.007, margin=0.8, sunset=100): """ Creates a unit which can be updated """ self.investment = cost self.start = year self.year = 0 self.profit_margin = 0.8 self.degradation = degradation self.annual_revenue = revenue self.generated_revenue = 0 self.sunset = sunset def update(self): """ Increments unit for this year """ self.generated_revenue += self.degraded_revenue self.year += 1 def __repr__(self): """ Panel at any point in time """ args = { "years": self.years, "capital": self.investment, "return": self.generated_revenue, "roi": self.roi, } string = "" return string.format(args) def calculate(args): unit_cost = args.get("--unit-cost") initial_cost = args.get("--initial") units_purchased = args.get("--units") degradation = args.get("--degradation") years = args.get("--years") annual_return = args.get("--return") purchase_new_units = args.get("--purchase", False) sunset = args.get("--sunset") margin = args.get("--margin") cease = args.get("--cease") cpu = initial_cost / units_purchased units = [Panel(cost=cpu, revenue=annual_return, degradation=degradation, margin=margin, sunset=sunset) for unit in xrange(units_purchased)] titles = ["year", "units", "monthly", "roi", "investment", "return"] print "{0:>4}: {1:>10} | {2:>16} | {3:<15} | ({4:>19}/{5:>19})".format(*titles) cumulative = 0 for year in xrange(years): profit = sum(u.degraded_revenue for u in units) cumulative += profit if purchase_new_units and year < cease: while cumulative > unit_cost: panel = Panel(cost=unit_cost, year=year, revenue=annual_return, degradation=degradation, margin=margin, sunset=sunset) units.append(panel) cumulative = cumulative - unit_cost data = { "units": sum(1 for u in units), "year": year, "cost": sum(u.investment for u in units), "profit": sum(u.generated_revenue for u in units), "monthly": sum(u.degraded_revenue/12.0 for u in units), } data["roi"] = data["profit"] / data["cost"] print("{year:>4}: {units:>10} | ${monthly:>15,} | {roi:<15} | (${cost:>18,}/${profit:>18,})".format(**data)) for unit in units: unit.update() if __name__ == "__main__": import docopt args = docopt.docopt(__doc__) for k, v in args.iteritems(): try: if "." not in v: v = int(v) args[k] = v else: v = float(v) args[k] = v except: pass calculate(args)