diff --git a/examples/american_option.py b/examples/american_option.py index 343b110e8..60a5aa8d4 100644 --- a/examples/american_option.py +++ b/examples/american_option.py @@ -7,15 +7,15 @@ FOR A PARTICULAR PURPOSE. See the license for more details. """ from quantlib.instruments.api import AmericanExercise, VanillaOption, OptionType -from quantlib.instruments.payoffs import PlainVanillaPayoff +from quantlib.payoffs import PlainVanillaPayoff from quantlib.pricingengines.api import BaroneAdesiWhaleyApproximationEngine from quantlib.pricingengines.api import FdBlackScholesVanillaEngine from quantlib.processes.black_scholes_process import BlackScholesMertonProcess from quantlib.quotes import SimpleQuote from quantlib.settings import Settings from quantlib.time.api import Actual365Fixed, Date, May, TARGET -from quantlib.termstructures.volatility.api import BlackConstantVol -from quantlib.termstructures.yields.api import HandleYieldTermStructure, FlatForward +from quantlib.termstructures.volatility.api import BlackConstantVol, HandleBlackVolTermStructure +from quantlib.termstructures.yields.api import RelinkableHandleYieldTermStructure, FlatForward from quantlib.methods.finitedifferences.solvers.fdmbackwardsolver \ import FdmSchemeDesc @@ -25,7 +25,7 @@ def main(): Settings.instance().evaluation_date = todays_date settlement_date = Date(17, May, 1998) - risk_free_rate = HandleYieldTermStructure() + risk_free_rate = RelinkableHandleYieldTermStructure() risk_free_rate.link_to( FlatForward( reference_date=settlement_date, @@ -43,9 +43,11 @@ def main(): # market data underlying = SimpleQuote(36.0) - volatility = BlackConstantVol(todays_date, TARGET(), 0.20, + volatility = HandleBlackVolTermStructure( + BlackConstantVol(todays_date, TARGET(), 0.20, Actual365Fixed()) - dividend_yield = HandleYieldTermStructure() + ) + dividend_yield = RelinkableHandleYieldTermStructure() dividend_yield.link_to( FlatForward( reference_date=settlement_date, diff --git a/examples/basic_example.py b/examples/basic_example.py index 82d2cbbd8..35329c290 100644 --- a/examples/basic_example.py +++ b/examples/basic_example.py @@ -9,7 +9,7 @@ from quantlib.quotes import SimpleQuote from quantlib.settings import Settings from quantlib.time.api import TARGET, Actual365Fixed, today -from quantlib.termstructures.yields.api import FlatForward, HandleYieldTermStructure +from quantlib.termstructures.yields.api import FlatForward, RelinkableHandleYieldTermStructure from quantlib.termstructures.volatility.api import BlackConstantVol @@ -36,8 +36,8 @@ underlyingH = SimpleQuote(underlying) # bootstrap the yield/dividend/vol curves -flat_term_structure = HandleYieldTermStructure() -flat_dividend_ts = HandleYieldTermStructure() +flat_term_structure = RelinkableHandleYieldTermStructure() +flat_dividend_ts = RelinkableHandleYieldTermStructure() flat_term_structure.link_to( FlatForward( diff --git a/examples/data/df_SPX_24jan2011.pkl b/examples/data/df_SPX_24jan2011.pkl index c3e7682e2..fe81e3ee2 100644 Binary files a/examples/data/df_SPX_24jan2011.pkl and b/examples/data/df_SPX_24jan2011.pkl differ diff --git a/examples/option_valuation.py b/examples/option_valuation.py index 62d316469..2f28c63b7 100644 --- a/examples/option_valuation.py +++ b/examples/option_valuation.py @@ -44,7 +44,7 @@ from quantlib.termstructures.yields.api import ( PiecewiseYieldCurve, DepositRateHelper, BootstrapTrait, HandleYieldTermStructure ) -from quantlib.termstructures.volatility.api import BlackConstantVol +from quantlib.termstructures.volatility.api import BlackConstantVol, HandleBlackVolTermStructure from quantlib.termstructures.yields.api import SwapRateHelper def dividendOption(): @@ -169,7 +169,7 @@ def dividendOption(): print('Creating process') - bsProcess = BlackScholesProcess(underlying_priceH, HandleYieldTermStructure(riskFreeTS), flatVolTS) + bsProcess = BlackScholesProcess(underlying_priceH, HandleYieldTermStructure(riskFreeTS), HandleBlackVolTermStructure(flatVolTS)) # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/examples/scripts/SPX_Options.py b/examples/scripts/SPX_Options.py index 41fd8458b..3b5f9aad4 100644 --- a/examples/scripts/SPX_Options.py +++ b/examples/scripts/SPX_Options.py @@ -1,4 +1,3 @@ -from __future__ import print_function # -*- coding: utf-8 -*- # 3 @@ -6,11 +5,11 @@ # Standardized Option Quotes Data Format # ====================================== -# +# # To facilitate model calibration, a standard input format has been defined, which contains all the # necessary data. The data is held in a [Panda](http://pandas.pydata.org) table, with one row per quote and # 8 columns, as follows: -# +# # * dtTrade: Quote date, or time stamp # * Strike: Ditto # * dtExpiry: Option expiry date @@ -19,23 +18,23 @@ # * Type: European/American # * PBid: Bid price # * PAsk: Ask price -# -# Note that we do not include the dividend yield nor the risk-free rate in the data set: The +# +# Note that we do not include the dividend yield nor the risk-free rate in the data set: The # implied forward price and risk-free rate are estimated from the call/put parity. -# +# # SPX Option Data Processing # -------------------------- -# +# # As an illustration, we provide below the procedure for converting raw SPX option data, as published by the [CBOE](http://www.cboe.com/DelayedQuote/QuoteTableDownload.aspx), into the standard input format. -# +# # ### SPX Utility functions -# +# # These functions parse the SPX option names, and extract expiry date and strike. # -import pandas -import dateutil, datetime +import pandas as pd +import dateutil import re def ExpiryMonth(s): @@ -58,26 +57,26 @@ def parseSPX(s): """ Parse an SPX quote string, return expiry date and strike """ - tokens = spx_symbol.split(s) + tokens = spx_symbol.split(s.iloc[0]) if len(tokens) == 1: - return {'dtExpiry': None, 'strike': -1} + return {'Strike': -1, 'dtExpiry': None} year = 2000 + int(tokens[1]) day = int(tokens[2]) month = ExpiryMonth(tokens[3]) strike = float(tokens[4]) - dtExpiry = datetime.date(year, month, day) + dtExpiry = pd.Timestamp(year=year, month=month, day=day) - return ({'dtExpiry': dtExpiry, 'strike': strike}) + return {'Strike': strike, 'dtExpiry': dtExpiry} # # ### Reading the SPX raw data file -# -# The csv file downloaded from the CBOE site can be converted into a standard panda table by the following function. +# +# The csv file downloaded from the CBOE site can be converted into a standard panda table by the following function. # @@ -93,12 +92,12 @@ def read_SPX_file(option_data_file): lineTwo = fid.readline() dt = lineTwo.split('@')[0] - dtTrade = dateutil.parser.parse(dt).date() + dtTrade = pd.to_datetime(dt) print('Dt Calc: %s Spot: %f' % (dtTrade, spot)) # read all option price records as a data frame - df = pandas.io.parsers.read_csv(option_data_file, header=0, sep=',', skiprows=[0,1]) + df = pd.read_csv(option_data_file, header=0, sep=',', skiprows=[0,1]) # split and stack calls and puts call_df = df[['Calls', 'Bid', 'Ask']] @@ -109,16 +108,13 @@ def read_SPX_file(option_data_file): put_df = put_df.rename(columns = {'Puts':'Spec', 'Bid.1':'PBid', 'Ask.1':'PAsk'}) put_df['Type'] = 'P' - - df_all = call_df.append(put_df, ignore_index=True) + df_all = pd.concat([call_df, put_df], ignore_index=True) # parse Calls and Puts columns for strike and contract month # insert into data frame - - cp = [parseSPX(s) for s in df_all['Spec']] - df_all['Strike'] = [x['strike'] for x in cp] - df_all['dtExpiry'] = [x['dtExpiry'] for x in cp] - + df_all = pd.concat([df_all, + df_all[["Spec"]].apply(parseSPX, axis="columns", result_type="expand")], + axis=1) del df_all['Spec'] df_all = df_all[(df_all['Strike'] > 0) & (df_all['PBid']>0) \ @@ -126,18 +122,14 @@ def read_SPX_file(option_data_file): df_all['dtTrade'] = dtTrade df_all['Spot'] = spot - return df_all -option_data_file = \ - '../data/SPX-Options-24jan2011.csv' - if __name__ == '__main__': + option_data_file = '../data/SPX-Options-24jan2011.csv' df_SPX = read_SPX_file(option_data_file) print('%d records processed' % len(df_SPX)) # save a csv file and pickled data frame df_SPX.to_csv('../data/df_SPX_24jan2011.csv', index=False) - df_SPX.to_pickle('../data/df_SPX_24jan2011.pkl', protocol=4) + df_SPX.to_pickle('../data/df_SPX_24jan2011.pkl') print('File saved') - diff --git a/examples/traits_example.py b/examples/traits_example.py index 06b136204..d8e117064 100644 --- a/examples/traits_example.py +++ b/examples/traits_example.py @@ -13,9 +13,8 @@ from quantlib.quotes import SimpleQuote from quantlib.settings import Settings from quantlib.time.api import TARGET, Actual365Fixed, today, Date as QlDate -from quantlib.termstructures.yields.api import FlatForward -from quantlib.termstructures.volatility.equityfx.black_vol_term_structure \ - import BlackConstantVol +from quantlib.termstructures.yields.api import FlatForward, HandleYieldTermStructure +from quantlib.termstructures.volatility.api import BlackConstantVol settings = Settings.instance() @@ -32,7 +31,7 @@ class OptionValuation(HasTraits): # options parameters - option_type = Enum(Put, Call) + option_type = Enum(OptionType.Put, OptionType.Call) underlying = Float(36) strike = Float(40) dividend_yield = Range(0.0, 0.5) @@ -50,12 +49,6 @@ class OptionValuation(HasTraits): ### Traits view ########################################################## - traits_view = View( - Item('option_type', editor=EnumEditor(values={Put:'Put', Call:'Call'})), - 'underlying', 'strike', 'dividend_yield', 'risk_free_rate', - 'volatility', 'maturity', - HGroup( Item('option_npv', label='Option value')) - ) ### Private protocol ##################################################### @@ -73,16 +66,20 @@ def _get_option_npv(self): underlyingH = SimpleQuote(self.underlying) # bootstrap the yield/dividend/vol curves - flat_term_structure = FlatForward( - reference_date = settlement_date, - forward = self.risk_free_rate, - daycounter = self.daycounter + flat_term_structure = HandleYieldTermStructure( + FlatForward( + reference_date = settlement_date, + forward = self.risk_free_rate, + daycounter = self.daycounter + ) ) - flat_dividend_ts = FlatForward( - reference_date = settlement_date, - forward = self.dividend_yield, - daycounter = self.daycounter + flat_dividend_ts = HandleYieldTermStructure( + FlatForward( + reference_date = settlement_date, + forward = self.dividend_yield, + daycounter = self.daycounter + ) ) flat_vol_ts = BlackConstantVol( @@ -105,10 +102,17 @@ def _get_option_npv(self): return european_option.net_present_value +traits_view = View( + Item('option_type', editor=EnumEditor(values={OptionType.Put:'Put', OptionType.Call:'Call'})), + 'underlying', 'strike', 'dividend_yield', 'risk_free_rate', + 'volatility', 'maturity', + HGroup( Item('option_npv', label='Option value')) +) + if __name__ == '__main__': model = OptionValuation() - model.configure_traits() + model.configure_traits(view=traits_view) ### EOF ####################################################################### diff --git a/quantlib/indexes/ibor_index.pyx b/quantlib/indexes/ibor_index.pyx index 5aad7c8d9..9f63a63ba 100644 --- a/quantlib/indexes/ibor_index.pyx +++ b/quantlib/indexes/ibor_index.pyx @@ -22,6 +22,29 @@ from quantlib.market.conventions.swap import params as swap_params from quantlib.indexes.interest_rate_index cimport InterestRateIndex cdef class IborIndex(InterestRateIndex): + """Base class for Inter-Bank-Offered-Rate indexes (e.g. Libor, etc.). + + Parameters + ---------- + family_name : str + The family name of the index. + tenor : :class:`~quantlib.time.date.Period` + The tenor of the index. + settlement_days : int + The number of settlement days. + currency : :class:`~quantlib.currency.currency.Currency` + The currency of the index. + fixing_calendar : :class:`~quantlib.time.calendar.Calendar` + The calendar used for fixing dates. + convention : int + The business day convention. + end_of_month : bool + Whether the end-of-month rule applies. + day_counter : :class:`~quantlib.time.daycounter.DayCounter` + The day counter for the index. + yts : :class:`~quantlib.termstructures.yield_term_structure.HandleYieldTermStructure`, optional + The yield term structure handle. + """ def __init__(self, str family_name, Period tenor not None, Natural settlement_days, Currency currency, Calendar fixing_calendar, int convention, @@ -40,17 +63,20 @@ cdef class IborIndex(InterestRateIndex): ) property business_day_convention: + """The business day convention.""" def __get__(self): cdef _ib.IborIndex* ref = <_ib.IborIndex*>self._thisptr.get() return ref.businessDayConvention() property end_of_month: + """Whether the end-of-month rule applies.""" def __get__(self): cdef _ib.IborIndex* ref = <_ib.IborIndex*>self._thisptr.get() return ref.endOfMonth() @property def forwarding_term_structure(self): + """The curve used to forecast fixings.""" cdef: _ib.IborIndex* ref = <_ib.IborIndex*>self._thisptr.get() HandleYieldTermStructure yts = HandleYieldTermStructure.__new__(HandleYieldTermStructure) @@ -59,8 +85,16 @@ cdef class IborIndex(InterestRateIndex): @staticmethod def from_name(market, term_structure=HandleYieldTermStructure(), **kwargs): - """ - Create default IBOR for the market, modify attributes if provided + """Create a default IBOR index for the given market. + + Parameters + ---------- + market : str + The market name (e.g., 'USDLibor', 'Euribor'). + term_structure : :class:`~quantlib.termstructures.yield_term_structure.HandleYieldTermStructure`, optional + The yield term structure handle. + **kwargs : + Additional keyword arguments to override default parameters. """ row = swap_params(market) @@ -84,6 +118,23 @@ cdef class IborIndex(InterestRateIndex): cdef class OvernightIndex(IborIndex): + """Base class for overnight indexes. + + Parameters + ---------- + family_name : str + The family name of the index. + settlement_days : int + The number of settlement days. + currency : :class:`~quantlib.currency.currency.Currency` + The currency of the index. + fixing_calendar : :class:`~quantlib.time.calendar.Calendar` + The calendar used for fixing dates. + day_counter : :class:`~quantlib.time.daycounter.DayCounter` + The day counter for the index. + yts : :class:`~quantlib.termstructures.yield_term_structure.HandleYieldTermStructure`, optional + The yield term structure handle. + """ def __init__(self, str family_name, Natural settlement_days, Currency currency, Calendar fixing_calendar, DayCounter day_counter not None, diff --git a/quantlib/indexes/inflation_index.pyx b/quantlib/indexes/inflation_index.pyx index 58bdc8163..413851117 100644 --- a/quantlib/indexes/inflation_index.pyx +++ b/quantlib/indexes/inflation_index.pyx @@ -32,27 +32,37 @@ cimport quantlib.indexes._region as _region from quantlib.termstructures._inflation_term_structure cimport ZeroInflationTermStructure, YoYInflationTermStructure cdef class InflationIndex(Index): + """Base class for inflation-rate indexes.""" def __cinit__(self): pass property family_name: + """The family name of the inflation index.""" def __get__(self): cdef _ii.InflationIndex* ref = <_ii.InflationIndex*>self._thisptr.get() return ref.familyName() property frequency: + """The publication frequency of the inflation index.""" def __get__(self): cdef _ii.InflationIndex* ref = <_ii.InflationIndex*>self._thisptr.get() return ref.frequency() property availability_lag: + """The availability lag of the index. + + The availability lag describes when the index might be + available; for instance, the inflation value for January + may only be available in April. + """ def __get__(self): cdef _ii.InflationIndex* ref = <_ii.InflationIndex*>self._thisptr.get() return period_from_qlperiod(ref.availabilityLag()) property currency: + """The currency of the inflation index.""" def __get__(self): cdef _ii.InflationIndex* ref = <_ii.InflationIndex*>self._thisptr.get() cdef Currency c = Currency.__new__(Currency) @@ -61,12 +71,32 @@ cdef class InflationIndex(Index): @property def region(self): + """The region of the index.""" cdef _ii.InflationIndex* ref = <_ii.InflationIndex*>self._thisptr.get() cdef Region region = Region.__new__(Region) region._thisptr = new _region.Region(ref.region()) return region cdef class ZeroInflationIndex(InflationIndex): + """Base class for zero-inflation indexes. + + Parameters + ---------- + family_name : str + The family name of the index. + region : :class:`~quantlib.indexes.region.Region` + The region of the index. + revised : bool + Whether the index is revised. + frequency : :class:`~quantlib.time.frequency.Frequency` + The frequency of the index. + availabilityLag : :class:`~quantlib.time.date.Period` + The availability lag of the index. + currency : :class:`~quantlib.currency.currency.Currency` + The currency of the index. + ts : :class:`~quantlib.termstructures.inflation_term_structure.ZeroInflationTermStructure`, optional + The zero-inflation term structure. + """ def __init__(self, str family_name, Region region, bool revised, @@ -74,7 +104,6 @@ cdef class ZeroInflationIndex(InflationIndex): Period availabilityLag, Currency currency, HandleZeroInflationTermStructure ts=HandleZeroInflationTermStructure()): - # convert the Python str to C++ string cdef string c_family_name = family_name.encode('utf-8') @@ -91,6 +120,7 @@ cdef class ZeroInflationIndex(InflationIndex): @property def zero_inflation_term_structure(self): + """Returns the zero-inflation term structure associated with the index.""" cdef HandleZeroInflationTermStructure r = \ HandleZeroInflationTermStructure.__new__(HandleZeroInflationTermStructure) r._handle = new Handle[ZeroInflationTermStructure]( @@ -100,17 +130,39 @@ cdef class ZeroInflationIndex(InflationIndex): @property def last_fixing_date(self): + """Returns the last date for which a fixing was provided.""" return date_from_qldate( (<_ii.ZeroInflationIndex*>(self._thisptr.get())).lastFixingDate() ) cdef class YoYInflationIndex(ZeroInflationIndex): + """Base class for year-on-year inflation indexes. + + These may be quoted indices published on, say, Bloomberg, or can be + defined as the ratio of an index at different time points. + + Parameters + ---------- + family_name : str + The family name of the index. + region : :class:`~quantlib.indexes.region.Region` + The region of the index. + revised : bool + Whether the index is revised. + frequency : :class:`~quantlib.time.frequency.Frequency` + The frequency of the index. + availability_lag : :class:`~quantlib.time.date.Period` + The availability lag of the index. + currency : :class:`~quantlib.currency.currency.Currency` + The currency of the index. + ts : :class:`~quantlib.termstructures.inflation_term_structure.YoYInflationTermStructure`, optional + The year-on-year inflation term structure. + """ def __init__(self, family_name, Region region, bool revised, Frequency frequency, Period availability_lag, Currency currency, HandleYoYInflationTermStructure ts=HandleYoYInflationTermStructure()): - cdef string c_family_name = family_name.encode('utf-8') self._thisptr.reset( diff --git a/quantlib/instrument.pyx b/quantlib/instrument.pyx index 456fb2757..7da931c5e 100644 --- a/quantlib/instrument.pyx +++ b/quantlib/instrument.pyx @@ -5,47 +5,51 @@ from quantlib.ext cimport static_pointer_cast from quantlib._observable cimport Observable as QlObservable cdef class Instrument(Observable): - """Abstract instrument class + """Abstract instrument class. This class is purely abstract and defines the interface of concrete instruments which will be derived from this one. """ def set_pricing_engine(self, PricingEngine engine not None): - '''Sets the pricing engine. + """Sets the pricing engine to be used. - ''' + .. warning:: + + Calling this method will have no effects in case the + `performCalculation` method was overridden in a derived class. + + Parameters + ---------- + engine : :class:`~quantlib.pricingengines.engine.PricingEngine` + The pricing engine to be used. + """ self._thisptr.get().setPricingEngine(engine._thisptr) cdef shared_ptr[QlObservable] as_observable(self) noexcept nogil: return static_pointer_cast[QlObservable](self._thisptr) property net_present_value: - """ Instrument net present value. """ + """The net present value of the instrument.""" def __get__(self): return self._thisptr.get().NPV() @property - def error_estimate(self) -> Real: - """error estimate on the NPV when available""" + def error_estimate(self): + """:obj:`Real`: error estimate on the NPV when available""" return self._thisptr.get().errorEstimate() property npv: - """ Shortcut to the net_present_value property. """ + """A shortcut to the net_present_value property.""" def __get__(self): return self._thisptr.get().NPV() @property - def is_expired(self) -> bool: - """whether the instrument might ave value greater than zero.""" + def is_expired(self): + """:obj:`bool`: whether the instrument might have value greater than zero.""" return self._thisptr.get().isExpired() @property def valuation_date(self): - """the date the net present value refers to. - - Returns - ------- - valuation_date: :class:`~quantlib.time.date.Date` - """ + """:class:`~quantlib.time.date.Date`: the date the net present value refers to.""" return date_from_qldate(self._thisptr.get().valuationDate()) diff --git a/quantlib/instruments/bond.pyx b/quantlib/instruments/bond.pyx index 4e678c6d5..ecbd1b5a2 100644 --- a/quantlib/instruments/bond.pyx +++ b/quantlib/instruments/bond.pyx @@ -47,32 +47,43 @@ cdef class Bond(Instrument): @property def settlement_days(self): + """:obj:`int`""" return self.as_ptr().settlementDays() @property def calendar(self): + """:class:`quantlib.time.date.calendar.Calendar`""" cdef Calendar c = Calendar.__new__(Calendar) c._thisptr = self.as_ptr().calendar() return c @property def start_date(self): - """ Bond start date""" + """:class:`~quantlib.time.date.Date`: Bond start date""" return date_from_qldate(self.as_ptr().startDate()) @property def maturity_date(self): - """ Bond maturity date""" + """:class:`~quantlib.time.date.Date`: Bond maturity date""" return date_from_qldate(self.as_ptr().maturityDate()) @property def issue_date(self): - """ Bond issue date""" + """:class:`~quantlib.time.date.Date`: Bond issue date""" return date_from_qldate(self.as_ptr().issueDate()) def settlement_date(self, Date from_date=Date()): - """ Returns the bond settlement date after the given date.""" + """Returns the bond settlement date after the given date. + + Parameters + ---------- + from_date : :class:`quantlib.time.date.Date` + + Returns + ------- + :class:`quantlib.time.date.Date` + """ return date_from_qldate(self.as_ptr().settlementDate(from_date._thisptr)) def clean_price(self, *args): @@ -122,7 +133,7 @@ cdef class Bond(Instrument): @property def cashflows(self): - """ cash flow stream as a :class:`~quantlib.cashflow.Leg`.""" + """:class:`~quantlib.cashflow.Leg`: cash flow stream""" cdef Leg leg = Leg.__new__(Leg) leg._thisptr = self.as_ptr().cashflows() return leg diff --git a/quantlib/instruments/europeanoption.pyx b/quantlib/instruments/europeanoption.pyx index 6a08c0a3e..8689235a9 100644 --- a/quantlib/instruments/europeanoption.pyx +++ b/quantlib/instruments/europeanoption.pyx @@ -6,7 +6,15 @@ from .. cimport _payoffs from quantlib.ext cimport shared_ptr, static_pointer_cast cdef class EuropeanOption(VanillaOption): - """European option on a single asset""" + """European option on a single asset. + + Parameters + ---------- + payoff : :class:`~quantlib.payoffs.StrikedTypePayoff` + The option payoff. + exercise : :class:`~quantlib.exercise.Exercise` + The option exercise. + """ def __init__(self, StrikedTypePayoff payoff not None, Exercise exercise not None): cdef shared_ptr[_payoffs.StrikedTypePayoff] payoff_ptr = \ diff --git a/quantlib/instruments/forward.pyx b/quantlib/instruments/forward.pyx index 1c1becada..d4d491e4f 100644 --- a/quantlib/instruments/forward.pyx +++ b/quantlib/instruments/forward.pyx @@ -10,26 +10,47 @@ from quantlib cimport _interest_rate as _ir from . cimport _forward cdef class Forward(Instrument): + """Abstract base forward class.""" @property def spot_value(self): - """spot value/price of an underlying financial instrument""" + """The spot value/price of the underlying financial instrument.""" return (<_forward.Forward*>self._thisptr.get()).spotValue() @property def forward_value(self): - """forward value/price of underlying, discounting income/dividends""" + """The forward value/price of the underlying, discounting income/dividends.""" return (<_forward.Forward*>self._thisptr.get()).forwardValue() def spot_income(self, HandleYieldTermStructure income_discount_curve): - """NPV of income/dividends/storate-cossts etc. of underlying instrument""" - return (<_forward.Forward*>self._thisptr.get()).spotIncome(income_discount_curve.handle()) + """The NPV of income/dividends/storage-costs etc. of the underlying instrument. + Parameters + ---------- + income_discount_curve : :class:`~quantlib.termstructures.yield_term_structure.HandleYieldTermStructure` + The yield term structure handle for discounting the income. + """ + return (<_forward.Forward*>self._thisptr.get()).spotIncome(income_discount_curve.handle()) def implied_yield(self, Real underlying_spot_value, Real forward_value, Date settlement_date, Compounding convention, DayCounter day_counter): - """implied yield + """Calculates the implied yield of the forward contract. + + This is a simple yield calculation based on underlying spot and forward + values, taking into account underlying income. - Simple yield calculation based on underlying spot and forward values, taking into account underlying income.""" + Parameters + ---------- + underlying_spot_value : float + The spot value of the underlying. + forward_value : float + The forward value. + settlement_date : :class:`~quantlib.time.date.Date` + The settlement date. + convention : :class:`~quantlib.compounding.Compounding` + The compounding convention. + day_counter : :class:`~quantlib.time.daycounter.DayCounter` + The day counter. + """ cdef InterestRate ir = InterestRate.__new__(InterestRate) ir._thisptr = move[_ir.InterestRate]( (<_forward.Forward*>self._thisptr.get()).impliedYield(underlying_spot_value, forward_value, settlement_date._thisptr, convention, deref(day_counter._thisptr))) diff --git a/quantlib/instruments/swap.pyx b/quantlib/instruments/swap.pyx index 3d2eaa2aa..1905984de 100644 --- a/quantlib/instruments/swap.pyx +++ b/quantlib/instruments/swap.pyx @@ -23,44 +23,92 @@ cdef inline _swap.Swap* get_swap(Swap swap) noexcept: cdef class Swap(Instrument): - """ - Base swap class + """Interest rate swap. + + The cash flows belonging to the first leg are paid; the ones belonging to + the second leg are received. + + Parameters + ---------- + first_leg : :class:`~quantlib.cashflow.Leg` + The first leg of the swap. + second_leg : :class:`~quantlib.cashflow.Leg` + The second leg of the swap. """ Payer = Type.Payer Receiver = Type.Receiver def __init__(self, Leg first_leg, Leg second_leg): - """ The cash flows belonging to the first leg are paid; - the ones belonging to the second leg are received""" - + """ + The cash flows belonging to the first leg are paid; the ones belonging + to the second leg are received. + """ self._thisptr.reset(new _swap.Swap(first_leg._thisptr, second_leg._thisptr)) property start_date: + """The start date of the swap.""" def __get__(self): cdef _date.Date dt = get_swap(self).startDate() return date_from_qldate(dt) property maturity_date: + """The maturity date of the swap.""" def __get__(self): cdef _date.Date dt = get_swap(self).maturityDate() return date_from_qldate(dt) def leg_BPS(self, Size j): + """The basis-point sensitivity of the j-th leg of the swap. + + Parameters + ---------- + j : int + The index of the leg. + """ return get_swap(self).legBPS(j) def leg_NPV(self, Size j): + """The net present value of the j-th leg of the swap. + + Parameters + ---------- + j : int + The index of the leg. + """ return get_swap(self).legNPV(j) def startDiscounts(self, Size j): + """The discount factor at the start of the j-th leg of the swap. + + Parameters + ---------- + j : int + The index of the leg. + """ return get_swap(self).startDiscounts(j) def endDiscounts(self, Size j): + """The discount factor at the end of the j-th leg of the swap. + + Parameters + ---------- + j : int + The index of the leg. + """ return get_swap(self).endDiscounts(j) def npv_date_discount(self): + """The discount factor at the NPV date.""" return get_swap(self).npvDateDiscount() def leg(self, int i): + """The i-th leg of the swap. + + Parameters + ---------- + i : int + The index of the leg. + """ cdef Leg leg = Leg.__new__(Leg) cdef _swap.Swap* swap = <_swap.Swap*>self._thisptr.get() if 0 <= i < swap.numberOfLegs(): @@ -70,6 +118,7 @@ cdef class Swap(Instrument): return leg def __getitem__(self, int i): + """The i-th leg of the swap.""" cdef Leg leg = Leg.__new__(Leg) cdef _swap.Swap* swap = <_swap.Swap*>self._thisptr.get() if 0 <= i < swap.numberOfLegs(): diff --git a/quantlib/instruments/vanillaswap.pyx b/quantlib/instruments/vanillaswap.pyx index 846a6902f..71eccfd1a 100644 --- a/quantlib/instruments/vanillaswap.pyx +++ b/quantlib/instruments/vanillaswap.pyx @@ -17,8 +17,30 @@ cdef inline _vanillaswap.VanillaSwap* get_vanillaswap(VanillaSwap swap): return <_vanillaswap.VanillaSwap*>swap._thisptr.get() cdef class VanillaSwap(FixedVsFloatingSwap): - """ - Vanilla swap class + """Plain-vanilla swap: fix vs ibor leg. + + Parameters + ---------- + type : :class:`~quantlib.instruments.swap.Type` + The swap type, either `Payer` or `Receiver`. + nominal : float + The swap nominal. + fixed_schedule : :class:`~quantlib.time.schedule.Schedule` + The schedule for the fixed leg. + fixed_rate : float + The fixed rate. + fixed_daycount : :class:`~quantlib.time.daycounter.DayCounter` + The day counter for the fixed leg. + float_schedule : :class:`~quantlib.time.schedule.Schedule` + The schedule for the floating leg. + ibor_index : :class:`~quantlib.indexes.ibor_index.IborIndex` + The IBOR index for the floating leg. + spread : float + The spread over the IBOR index. + floating_daycount : :class:`~quantlib.time.daycounter.DayCounter` + The day counter for the floating leg. + payment_convention : int, optional + The business day convention for payment dates. """ def __init__(self, Type type, diff --git a/quantlib/math/array.pyx b/quantlib/math/array.pyx index 4783b3191..b0b3805a0 100644 --- a/quantlib/math/array.pyx +++ b/quantlib/math/array.pyx @@ -15,8 +15,17 @@ cimport numpy as np np.import_array() cdef class Array: - """ - 1D array for linear algebra + """1D array for linear algebra. + + This class implements the concept of a vector as used in linear algebra. + + Parameters + ---------- + size : int, optional + The size of the array. + value : float, optional + The value to fill the array with. + """ def __init__(self, Size size=0, value=None): @@ -39,6 +48,7 @@ cdef class Array: return self._thisptr.size() def to_ndarray(self): + """Returns a view of the array as a numpy array.""" cdef np.npy_intp[1] dims dims[0] = self._thisptr.size() cdef arr = np.PyArray_SimpleNewFromData(1, &dims[0], np.NPY_DOUBLE, (self._thisptr.begin())) @@ -47,10 +57,12 @@ cdef class Array: return arr cpdef qlarray_from_pyarray(p): + """Create a QuantLib Array from a Python array.""" cdef Array x = Array(len(p)) for i in range(len(p)): x._thisptr[i] = p[i] return x cpdef pyarray_from_qlarray(a): + """Create a Python array from a QuantLib Array.""" return [a[i] for i in range(a.size)] diff --git a/quantlib/models/equity/heston_model.pyx b/quantlib/models/equity/heston_model.pyx index f657710dd..c0fda9f2f 100644 --- a/quantlib/models/equity/heston_model.pyx +++ b/quantlib/models/equity/heston_model.pyx @@ -73,8 +73,9 @@ cdef class HestonModel: process._thisptr)) ) + @property def process(self): - """underlying process""" + """:class:`~quantlib.processes.heston_process.HestonProcess: unnderlying process""" cdef HestonProcess process = HestonProcess.__new__(HestonProcess) process._thisptr = static_pointer_cast[_sp.StochasticProcess]( self._thisptr.get().process()) diff --git a/quantlib/models/shortrate/onefactor_model.pyx b/quantlib/models/shortrate/onefactor_model.pyx index c5202bf12..36e3fabbb 100644 --- a/quantlib/models/shortrate/onefactor_model.pyx +++ b/quantlib/models/shortrate/onefactor_model.pyx @@ -32,7 +32,7 @@ cdef class ShortRateDynamics: return self._thisptr.get().shortRate(t, variable) cdef class OneFactorModel(ShortRateModel): - + """Single-factor short-rate model abstract class""" @property def dynamics(self): """short-rate dynamics diff --git a/quantlib/models/shortrate/twofactor_model.pyx b/quantlib/models/shortrate/twofactor_model.pyx index 027b7277c..110b5fe54 100644 --- a/quantlib/models/shortrate/twofactor_model.pyx +++ b/quantlib/models/shortrate/twofactor_model.pyx @@ -6,15 +6,36 @@ cimport quantlib._stochastic_process as _sp from quantlib.stochastic_process cimport StochasticProcess1D cdef class ShortRateDynamics: + r"""Class describing the dynamics of the two state variables + + We assume here that the short-rate is a function of two state + variables :math:`x` and :math:`y`. + + .. math:: + r_t = f(t, x_t, y_t) + of two state variables :math:`x_t` and :math:`y_t`. These stochastic + processes satisfy + + .. math:: + x_t = \mu_x(t, x_t)dt + \sigma_x(t, x_t) dW_t^x\\ + y_t = \mu_y(t,y_t)dt + \sigma_y(t, y_t) dW_t^y + + where :math:`W^x` and :math:`W^y` are two brownian motions satisfying + + .. math:: + dW^x_t dW^y_t = \rho dt + """ @property - def process_x(self): + def x_process(self): + """Risk-neutral dynamics of the first state variable x""" cdef StochasticProcess1D sp = StochasticProcess1D.__new__(StochasticProcess1D) sp._thisptr = static_pointer_cast[_sp.StochasticProcess](self._thisptr.get().xProcess()) return sp @property - def process_x(self): + def y_process(self): + """Risk-neutral dynamics of the second state variable y""" cdef StochasticProcess1D sp = StochasticProcess1D.__new__(StochasticProcess1D) sp._thisptr = static_pointer_cast[_sp.StochasticProcess](self._thisptr.get().yProcess()) return sp @@ -24,13 +45,19 @@ cdef class ShortRateDynamics: @property def correlation(self): - """Correlation :math:`rho` between the two brownian motions""" + """Correlation :math:`\\rho` between the two brownian motions""" return self._thisptr.get().correlation() cdef class TwoFactorModel(ShortRateModel): @property def dynamics(self): + """short-rate dynamics + + Returns + ------- + dynamics : :class:`~quantlib.models.shortrate.twofactor_model.ShortRateDynamics` + """ cdef ShortRateDynamics dyn = ShortRateDynamics.__new__(ShortRateDynamics) dyn._thisptr = (<_tfm.TwoFactorModel*>self._thisptr.get()).dynamics() return dyn diff --git a/quantlib/models/shortrate/twofactormodels/g2.pyx b/quantlib/models/shortrate/twofactormodels/g2.pyx index bdaae62dc..17ae4b2fd 100644 --- a/quantlib/models/shortrate/twofactormodels/g2.pyx +++ b/quantlib/models/shortrate/twofactormodels/g2.pyx @@ -1,8 +1,24 @@ +"""Two-factor additive Gaussian Model G2++""" from quantlib.types cimport Real from quantlib.handle cimport HandleYieldTermStructure from . cimport _g2 cdef class G2(TwoFactorModel): + r"""Two-factor additive gaussian model class. + + This class implements a two-additive-factor model defined by + + .. math:: + dr_t = \varphi(t) + x_t + y_t + + where :math:`x_t` and :math:`y_t` are defined by + + .. math:: + dx_t = -a x_t dt + \sigma dW^1_t, x_0 = 0\\ + dy_t = -b y_t dt + \sigma dW^2_t, y_0 = 0 + + and :math:`dW^1_t dW^2_t = \rho dt`. + """ def __init(self, HandleYieldTermStructure h, Real a=0.1, diff --git a/quantlib/option.pyx b/quantlib/option.pyx index 64584082e..1599e7c8b 100644 --- a/quantlib/option.pyx +++ b/quantlib/option.pyx @@ -20,13 +20,15 @@ cdef class Option(Instrument): ) @property - def exercise(self) -> Exercise: + def exercise(self): + """:class:`~quantlib.exercise.Exercise`""" cdef Exercise ex = Exercise.__new__(Exercise) ex._thisptr = (<_option.Option*>self._thisptr.get()).exercise() return ex @property - def payoff(self) -> Payoff: + def payoff(self): + """:class:`~quantlib.payoffs.Payoff`""" cdef Payoff po = Payoff.__new__(Payoff) po._thisptr = (<_option.Option*>self._thisptr.get()).payoff() return po diff --git a/quantlib/payoffs.pyx b/quantlib/payoffs.pyx index e4594a699..cd76fc146 100644 --- a/quantlib/payoffs.pyx +++ b/quantlib/payoffs.pyx @@ -29,10 +29,9 @@ cdef class PlainVanillaPayoff(StrikedTypePayoff): Parameters ---------- - - option_type: :class:`~quantlib.option.OptionType` + option_type : :class:`~quantlib.option.OptionType` The type of option, can be either `Call` or `Put` - strike: double + strike : double The strike value """ @@ -45,14 +44,10 @@ cdef class PlainVanillaPayoff(StrikedTypePayoff): ) ) - property option_type: - """ Exposes the internal option type. - - The type can be converted to str using the OptionType enum. - - """ - def __get__(self): - return _get_payoff(self).optionType() + @property + def option_type(self): + """:class:`~quantlib.option.OptionType`""" + return _get_payoff(self).optionType() property strike: def __get__(self): diff --git a/quantlib/quotes/futuresconvadjustmentquote.pyx b/quantlib/quotes/futuresconvadjustmentquote.pyx index fe76b1287..97894185f 100644 --- a/quantlib/quotes/futuresconvadjustmentquote.pyx +++ b/quantlib/quotes/futuresconvadjustmentquote.pyx @@ -6,6 +6,21 @@ from quantlib.indexes.ibor_index cimport IborIndex cimport quantlib.indexes._ibor_index as _ii cdef class FuturesConvAdjustmentQuote(Quote): + """Quote for the futures-convexity adjustment of an index. + + Parameters + ---------- + index : :class:`~quantlib.indexes.ibor_index.IborIndex` + The underlying IBOR index. + futures_date_or_code : :class:`~quantlib.time.date.Date` or str + The futures date or IMM code. + futures_quote : :class:`~quantlib.quote.Quote` + The quote for the futures contract. + volatility : :class:`~quantlib.quote.Quote` + The volatility quote. + mean_reversion : :class:`~quantlib.quote.Quote` + The mean-reversion quote. + """ def __init__(self, IborIndex index, futures_date_or_code, Quote futures_quote, Quote volatility, @@ -36,16 +51,20 @@ cdef class FuturesConvAdjustmentQuote(Quote): @property def futures_value(self): + """The value of the futures quote.""" return self.as_ptr().futuresValue() @property def volatility(self): + """The volatility of the quote.""" return self.as_ptr().volatility() @property def mean_reversion(self): + """The mean reversion of the quote.""" return self.as_ptr().meanReversion() @property def imm_date(self): + """The IMM date of the futures contract.""" return _pydate_from_qldate(self.as_ptr().immDate()) diff --git a/quantlib/quotes/simplequote.pyx b/quantlib/quotes/simplequote.pyx index 6db85aebb..2422dcdad 100644 --- a/quantlib/quotes/simplequote.pyx +++ b/quantlib/quotes/simplequote.pyx @@ -4,8 +4,14 @@ from quantlib.utilities.null cimport Null from . cimport _simplequote as _sq cdef class SimpleQuote(Quote): + """Market element returning a stored value. + + Parameters + ---------- + value : float, optional + The value of the quote. Defaults to a null value. + """ def __init__(self, Real value=Null[Real]()): - """ Market element returning a stored value""" self._thisptr.reset(new _sq.SimpleQuote(value)) def __str__(self): @@ -21,6 +27,7 @@ cdef class SimpleQuote(Quote): return "SimpleQuote()" property value: + """The value of the quote.""" def __get__(self): return self._thisptr.get().value() @@ -28,4 +35,5 @@ cdef class SimpleQuote(Quote): (<_sq.SimpleQuote*>self._thisptr.get()).setValue(value) def reset(self): + """Resets the quote to a null value.""" (<_sq.SimpleQuote*>self._thisptr.get()).reset() diff --git a/quantlib/termstructure.pyx b/quantlib/termstructure.pyx index 66362a4a7..cccce8660 100644 --- a/quantlib/termstructure.pyx +++ b/quantlib/termstructure.pyx @@ -6,6 +6,7 @@ from quantlib.time.calendar cimport Calendar cimport quantlib.time._daycounter as _dc cdef class TermStructure(Observable): + """Basic term-structure functionality""" def __init__(self): raise NotImplementedError("Abstract Class") @@ -19,39 +20,48 @@ cdef class TermStructure(Observable): return static_pointer_cast[QlObservable](self._thisptr) def time_from_reference(self, Date dt): - """date/time conversion""" + """date/time conversion + + Returns + ------- + :obj:`Time` + + """ return self.as_ptr().timeFromReference(dt._thisptr) @property def reference_date(self): - """ the date at which discount = 1.0 and/or variance = 0.0""" + """:class:`~quantlib.time.date.Date`: the date at which discount = 1.0 and/or variance = 0.0 + """ cdef QlDate ref_date = self.as_ptr().referenceDate() return date_from_qldate(ref_date) @property def max_date(self): - """the latest date for which the curve can return values""" + """:class:`~quantlib.time.date.Date`: the latest date for which the curve can return values""" cdef QlDate max_date = self.as_ptr().maxDate() return date_from_qldate(max_date) @property def max_time(self): - """the latest time for which the curve can return values""" + """:obj:`Time`: the latest time for which the curve can return values""" return self.as_ptr().maxTime() @property def day_counter(self): + """:class:`~quantlib.time.daycounter.DayCounter`: day counter""" cdef DayCounter dc = DayCounter.__new__(DayCounter) dc._thisptr = new _dc.DayCounter(self.as_ptr().dayCounter()) return dc @property def settlement_days(self): - """ number of settlement days used for reference date calculation""" + """:obj:`int`: number of settlement days used for reference date calculation""" return self.as_ptr().settlementDays() @property def calendar(self): + """:class:`~quantlib.time.calendar.Calendar`: calendar""" cdef Calendar instance = Calendar.__new__(Calendar) instance._thisptr = self.as_ptr().calendar() return instance diff --git a/quantlib/termstructures/credit/flat_hazard_rate.pyx b/quantlib/termstructures/credit/flat_hazard_rate.pyx index dee766e52..60d245202 100644 --- a/quantlib/termstructures/credit/flat_hazard_rate.pyx +++ b/quantlib/termstructures/credit/flat_hazard_rate.pyx @@ -14,16 +14,15 @@ from quantlib.quote cimport Quote cdef class FlatHazardRate(DefaultProbabilityTermStructure): """Flat hazard rate curve - Parameters - ---------- - - settlement_days : int - number of days from evaluation date - calendar: :class:`~quantlib.time.calendar.Calendar` - calendar used to compute the reference date - hazard_rate: float or :class:`~quantlib.quote.Quote` - the flat hazard rate - day_counter: :class:`~quantlib.time.daycounter.DayCounter` + Parameters + ---------- + settlement_days : int + number of days from evaluation date + calendar : :class:`~quantlib.time.calendar.Calendar` + calendar used to compute the reference date + hazard_rate : float or :class:`~quantlib.quote.Quote` + the flat hazard rate + day_counter : :class:`~quantlib.time.daycounter.DayCounter` DayCounter for the curve """ diff --git a/quantlib/termstructures/credit/interpolated_hazardrate_curve.pyx b/quantlib/termstructures/credit/interpolated_hazardrate_curve.pyx index b59793fab..8a476dda8 100644 --- a/quantlib/termstructures/credit/interpolated_hazardrate_curve.pyx +++ b/quantlib/termstructures/credit/interpolated_hazardrate_curve.pyx @@ -17,16 +17,16 @@ cimport quantlib.time._calendar as _calendar cdef class InterpolatedHazardRateCurve(DefaultProbabilityTermStructure): """DefaultProbabilityTermStructure based on interpolation of hazard rates - Parameters - ---------- - interpolator : int {Linear, LogLinear, BackwardFlat} - can be one of Linear, LogLinear, BackwardFlat - dates : :obj:`list` of :class:`~quantlib.time.date.Date` - list of dates - hazard_rates: :obj:`list` of float - corresponding list of hazard rates - day_counter: :class:`~quantlib.time.daycounter.DayCounter` - cal: :class:`~quantlib.time.calendar.Calendar` + Parameters + ---------- + interpolator : int {Linear, LogLinear, BackwardFlat} + can be one of Linear, LogLinear, BackwardFlat + dates : :obj:`list` of :class:`~quantlib.time.date.Date` + list of dates + hazard_rates : :obj:`list` of float + corresponding list of hazard rates + day_counter : :class:`~quantlib.time.daycounter.DayCounter` + cal : :class:`~quantlib.time.calendar.Calendar` """ def __init__(self, Interpolator interpolator, list dates, vector[Rate] hazard_rates, diff --git a/quantlib/termstructures/default_term_structure.pyx b/quantlib/termstructures/default_term_structure.pyx index d0bbd010b..b0e1b59c8 100644 --- a/quantlib/termstructures/default_term_structure.pyx +++ b/quantlib/termstructures/default_term_structure.pyx @@ -11,22 +11,49 @@ cdef class DefaultProbabilityTermStructure(TermStructure): return <_dts.DefaultProbabilityTermStructure*>self._thisptr.get() def survival_probability(self, d, bool extrapolate = False): + """Survival probability + + This returns the survival probability from the reference + date until a given date or time. In the former case, the time + is calculated as a fraction of year from the reference date. + + Parameters + ---------- + d : :class:`~quantlib.time.date.Date` or float + extrapolate : bool + + """ + if isinstance(d, Date): return self.as_dts_ptr().survivalProbability( (d)._thisptr, extrapolate) elif isinstance(d, float) or isinstance(d, int): return self.as_dts_ptr().survivalProbability(