-1
$\begingroup$

I am trying to use the QuantLib library with Python.

In the example below, I create a pandas dataframe with some dates and some cashflows, convert the dates from pandas' format to QuantLib's, and use QuantLib to calculate the daycount (which is banal for act/365, but QuantLib comes in handy for other cases like 30/360). There is probably room to make it more efficient (vectorise it somehow?) but it works.

I then tried to make a function that converts pandas datetime to QuantLib's dates, but it doesn't work, even if the code is the very same!

TypeError: Wrong number or type of arguments for overloaded function 'new_Date'.

It's the same dataframe apply statement. If, however, I pass int(x['day']) instead of just x['day'] , then it works.

Why would this be? pd.DatetimeIndex returns an integer, not a float. Why does the apply statement not require conversion of the inputs to integer if run outside of a function, but requires it if run within a function? I don't get it!

import QuantLib as ql
import pandas as pd
from datetime import date
import numpy as np

# I create a dataframe with
# investment in which we pay 100 in the first month, then get 2 each month for the next 59 months

d0 = pd.to_datetime(date(2010,1,1))
df = pd.DataFrame()

df['month #'] = np.arange(0,60)
df['dates'] = df.apply( lambda x: d0 + pd.DateOffset(months = x['month #']) , axis = 1 )
df['cf'] = 0
df.iloc[0,2] = -100
df.iloc[1:,2] = 2

df['year'] = pd.DatetimeIndex(df['dates']).year
df['month'] = pd.DatetimeIndex(df['dates']).month
df['day'] = pd.DatetimeIndex(df['dates']).day

# Now I use pandas apply to add a column which contains the same dates, but in qlib format
df['qldate'] = df.apply( lambda x:   ql.Date(x['day'], x['month'], x['year'] )       , axis = 1)

#now I use qlib to calculate the day count
# NB: actual 365 is easy to calculate manually, but qlib comes in handy for other daycount conventions
# so we don't reinvent the wheel
df['dayc act 365'] = df.apply( lambda x: ql.Actual365Fixed().dayCount(df['qldate'][0], x['qldate'])   , axis =1 )


def date_pd_to_ql(pdate):
    df = pd.DataFrame()
    df['year'] = pd.DatetimeIndex(pdate).year
    df['month'] = pd.DatetimeIndex(pdate).month
    df['day'] = pd.DatetimeIndex(pdate).day
    
    # this works:
    out = df.apply( lambda x: ql.Date(int(x['day']), int(x['month']), int(x['year']) )     , axis = 1  )
    
    # but this doesn't:
    out = df.apply( lambda x: ql.Date(x['day'], x['month'], x['year'] )     , axis = 1  )
    
    return out

out = date_pd_to_ql(df['dates'])
$\endgroup$
4
$\begingroup$

You could just use the ql.Date().from_date method.

Example:

d0 = pd.to_datetime(date(2010,1,1))
df = pd.DataFrame()

df['month #'] = np.arange(0,60)
df['dates'] = df.apply( lambda x: d0 + pd.DateOffset(months = x['month #']) , axis = 1 )
df['cf'] = 0
df.iloc[0,2] = -100
df.iloc[1:,2] = 2

df['qldate'] = df.dates.apply(ql.Date().from_date)
df['dayc act 365'] = df.apply( lambda x: ql.Actual365Fixed().dayCount(df['qldate'][0], x['qldate'])   , axis =1 )

df.head()

enter image description here

$\endgroup$
1
  • $\begingroup$ Obrigado! The curiosity of why my code didn't work remains, but yours is of course a much better solution. Do you know if QuantLib for pandas can use numpy arrays or pandas dataframes as inputs? Maybe that's faster than running apply? Finally, if I may make an observation, I find it is generally better to write df['column'] rather than df.column : the latter causes trouble if the column has the same name as a property of the dataframe, e.g. shape, columns, etc. $\endgroup$ Feb 6 at 21:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.