"""
The latest version of this package is available at:
<http://github.com/jantman/biweeklybudget>
################################################################################
Copyright 2016 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
This file is part of biweeklybudget, also known as biweeklybudget.
biweeklybudget is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
biweeklybudget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with biweeklybudget. If not, see <http://www.gnu.org/licenses/>.
The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/biweeklybudget> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
################################################################################
AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
################################################################################
"""
from decimal import Decimal
import json
from datetime import timedelta
import lxml.html
from lxml.etree import tostring
import requests
import logging
from biweeklybudget.models.dbsetting import DBSetting
from biweeklybudget.utils import dtnow, decode_json_datetime
from biweeklybudget.flaskapp.jsonencoder import MagicJSONEncoder
logger = logging.getLogger(__name__)
[docs]class PrimeRateCalculator(object):
def __init__(self, db_session):
"""
:param db_session: Database session
:type db_session: sqlalchemy.orm.session.Session
"""
self._db_sess = db_session
[docs] def _rate_from_marketwatch(self):
r = requests.get(
'http://www.marketwatch.com/investing/loanrate/usprime'
'?countrycode=mr'
)
doc = lxml.html.fromstring(r.text)
pr = doc.xpath('//meta[@name="price"]')[0]
pr_amt = pr.get('content')
logger.debug(
'Found "price" meta tag: %s amount=%s', tostring(pr), pr_amt
)
return pr_amt
[docs] def _get_prime_rate(self):
"""
Get the US Prime Rate from MarketWatch; update the DB and return the
value.
:return: current US Prime Rate
:rtype: decimal.Decimal
"""
rate = self._rate_from_marketwatch()
rate = Decimal(rate) * Decimal('0.01')
s = self._db_sess.query(DBSetting).get('prime_rate')
if s is None:
s = DBSetting(name='prime_rate')
logger.info('Got Prime Rate from MarketWatch: %s', rate)
s.value = json.dumps({
'value': '%s' % rate,
'date': dtnow()
}, cls=MagicJSONEncoder)
self._db_sess.add(s)
self._db_sess.flush()
self._db_sess.commit()
return rate
@property
def prime_rate(self):
"""
Return the current US Prime Rate
:return: current US Prime Rate
:rtype: decimal.Decimal
"""
pr = self._db_sess.query(DBSetting).get('prime_rate')
if pr is None:
return self._get_prime_rate()
j = json.loads(pr.value)
d = decode_json_datetime(j['date'])
if d >= (dtnow() - timedelta(hours=48)):
return Decimal(j['value'])
return self._get_prime_rate()
[docs] def calculate_apr(self, margin):
"""
Calculate an APR based on the prime rate.
:param margin: margin added to Prime Rate to get APR
:type margin: decimal.Decimal
:return: effective APR
:rtype: decimal.Decimal
"""
return self.prime_rate + margin