Skip to content

Commit

Permalink
Big merge of master into yield curves.
Browse files Browse the repository at this point in the history
  • Loading branch information
Casey Clements committed Nov 26, 2017
2 parents 4c2de1a + 7b0d8cc commit b49efc2
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 10 deletions.
14 changes: 10 additions & 4 deletions .travis.yml
@@ -1,5 +1,4 @@
language: python
sudo: false

env:
matrix:
Expand All @@ -11,7 +10,8 @@ env:

install:
# Install conda
- wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh
- sudo apt-get update
- wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- conda config --set always_yes yes --set changeps1 no
Expand All @@ -28,10 +28,16 @@ install:
#- pip install --no-deps -e .

script:
- if [[ $COVERAGE == 'true' ]]; then py.test --cov --cov-report=html -vv -s --pyarg tests; fi
- if [[ $COVERAGE == 'true' ]]; then
py.test --cov --cov-report=html -vv -s tests;
else
py.test -vv -s tests;
fi

after_success:
- if [[ COVERAGE == 'true' ]]; then coverage report --show-missing; pip install coveralls ; coveralls ; fi
- coverage report --show-missing
- pip install coveralls
- coveralls

#notifications:
# email: false
1 change: 1 addition & 0 deletions pennies/calculators/assets.py
Expand Up @@ -150,3 +150,4 @@ def default_calculators():
str(assets.StirFuture): None,
str(assets.FRA): None,
str(assets.IborFixing): None}

57 changes: 57 additions & 0 deletions pennies/calculators/bonds.py
@@ -0,0 +1,57 @@
from __future__ import absolute_import, division, print_function

import math
import numbers
import pandas as pd
from datetime import date
from pennies.assets.core import CashFlow
from pennies.assets.bonds import Bond
from pennies.dispatch import dispatch
from pennies.time import date_range, freq_to_frac, to_offset


def _bond_cash_flows(b):
"""Generate a series of cash flows for a bond.
Parameters
----------
b: Bond
bond to compute cash flows
Returns
-------
pandas.Series
"""

# get payment dates
end_date = b.start_date + to_offset(b.maturity)
date_index = date_range(b.start_date, end_date, b.frequency)

# get coupon cash flows
if b.frequency is None:
b.frequency = 'A'
payments = [b.principal * b.coupon * freq_to_frac(b.frequency)] * len(date_index)
payments[-1] += b.principal

# create cash flow objects
cash_flows = []
for p, dt in zip(payments, date_index):
cash_flows.append(CashFlow(p, dt.to_datetime()))

# create series and remove cash flows that already occurred
return pd.Series(cash_flows, index=date_index)[date.today():]


@dispatch(Bond, numbers.Number)
def present_value(b, discount_factor):
"""Calculate the present value of a bond.
Calculates the value of simple bonds by taking the sum
of the discounted cash flows relative to the coupon, frequency,
and term to maturity.
"""
cash_flows = _bond_cash_flows(b)
pv_cash_flows = present_value(cash_flows, discount_factor)
return pv_cash_flows.sum()
2 changes: 1 addition & 1 deletion pennies/calculators/trades.py
@@ -1,6 +1,5 @@
from __future__ import absolute_import, division, print_function


from pennies.trading.trades import Trade, Portfolio
from pennies.market.market import RatesTermStructure
from pennies import dispatch
Expand Down Expand Up @@ -50,3 +49,4 @@ def present_value(self):
if self.settlement_ccr is not None:
pv += self.settlement_ccr.present_value()
return pv

73 changes: 68 additions & 5 deletions pennies/time.py
@@ -1,4 +1,9 @@
"""Daycount calculations, Schedule creation, and so on."""
"""Daycount calculations, Schedule creation, and so on.
Only a small number of required daycount conventions are included here.
For full list, see the following:
https://developers.opengamma.com/quantitative-research/Interest-Rate-Instruments-and-Market-Conventions.pdf
"""
from __future__ import absolute_import, division, print_function

import numpy as np
Expand Down Expand Up @@ -52,6 +57,68 @@ def daycounter(name=None):
"""Function to compute accrual, given name from daycount_conventions"""
return daycount_conventions.get(name, thirty360)

# TODO - What is the following used for?
FREQ_TO_YEAR_FRAC = {
'D': 1/365,
'W': 1/52,
'WS': 1/52,
'M': 1/12,
'MS': 1/12,
'Q': 1/4,
'QS': 1/4,
'A': 1,
'AS': 1
}


def freq_to_frac(freq):
return FREQ_TO_YEAR_FRAC[freq]


def date_range(start, end, freq):
"""
Generate range of dates.
Parameters
----------
start: str, date, datetime
start date of range (exclusive)
end: str, date, datetime
end date of range(inclusive)
freq: str
D, W, M, Q, A for end (WS, MS, QS, AS for start)
If None, return DatetimeIndex with end.
Returns
-------
`DatetimeIndex`
"""
if freq is None:
return pd.DatetimeIndex([end])

if isinstance(end, str):
end = dt.datetime.strptime(end, '%Y-%m-%d')

return pd.date_range(start, end, freq=freq)


def to_offset(s):
"""Pass in a string to get a date offset.
Arguments
---------
s: str
offset string which has format "<int> <freq>" where
frequency can be one of "days", "months", or "years".
"""
amount, freq = s.split(' ')
kwargs = {freq: int(amount)}
return pd.tseries.offsets.DateOffset(**kwargs)


if __name__ == '__main__':
# TODO Move this into tests
today = pd.to_datetime('today')
Expand All @@ -69,7 +136,3 @@ def daycounter(name=None):
print('Series - act365: {}'.format(act365_fixed(today, sched_end)))
print('Series - thirty360: {}'.format(thirty360(today, sched_end)))





5 changes: 5 additions & 0 deletions requirements.txt
@@ -0,0 +1,5 @@
pandas
multipledispatch
scipy
matplotlib

0 comments on commit b49efc2

Please sign in to comment.