diff --git a/quantlib/_index.pxd b/quantlib/_index.pxd index 0c4f6a76e..e4e1b161a 100644 --- a/quantlib/_index.pxd +++ b/quantlib/_index.pxd @@ -19,7 +19,7 @@ from quantlib.time._calendar cimport Calendar from quantlib.time._date cimport Date -cdef extern from 'ql/index.hpp' namespace 'QuantLib': +cdef extern from 'ql/index.hpp' namespace 'QuantLib' nogil: cdef cppclass Index(Observable): string name() diff --git a/quantlib/_interest_rate.pxd b/quantlib/_interest_rate.pxd index 95e6e278c..aff1c187e 100644 --- a/quantlib/_interest_rate.pxd +++ b/quantlib/_interest_rate.pxd @@ -14,7 +14,7 @@ from quantlib.time._daycounter cimport DayCounter from quantlib.time._period cimport Frequency from quantlib.compounding cimport Compounding -cdef extern from 'ql/interestrate.hpp' namespace 'QuantLib': +cdef extern from 'ql/interestrate.hpp' namespace 'QuantLib' nogil: cppclass InterestRate: InterestRate() diff --git a/quantlib/_observable.pxd b/quantlib/_observable.pxd index f516ac3da..b1481fb18 100644 --- a/quantlib/_observable.pxd +++ b/quantlib/_observable.pxd @@ -1,5 +1,5 @@ -include 'types.pxi' from .handle cimport shared_ptr +from .types cimport Size cdef extern from 'ql/patterns/observable.hpp' namespace 'QuantLib' nogil: cdef cppclass Observable: diff --git a/quantlib/cashflows/_coupon_pricer.pxd b/quantlib/cashflows/_coupon_pricer.pxd index 108df9544..9a0106b6a 100644 --- a/quantlib/cashflows/_coupon_pricer.pxd +++ b/quantlib/cashflows/_coupon_pricer.pxd @@ -1,4 +1,4 @@ -include '../types.pxi' +from quantlib.types cimport Rate, Real from quantlib.handle cimport shared_ptr, Handle from quantlib.termstructures.volatility.optionlet._optionlet_volatility_structure cimport OptionletVolatilityStructure @@ -7,7 +7,7 @@ from quantlib._cashflow cimport Leg from quantlib.cashflows._floating_rate_coupon cimport FloatingRateCoupon from quantlib._quote cimport Quote -cdef extern from 'ql/cashflows/couponpricer.hpp' namespace 'QuantLib': +cdef extern from 'ql/cashflows/couponpricer.hpp' namespace 'QuantLib' nogil: cdef cppclass FloatingRateCouponPricer: FloatingRateCouponPricer() except + diff --git a/quantlib/cashflows/_overnight_indexed_coupon.pxd b/quantlib/cashflows/_overnight_indexed_coupon.pxd index 3c7382062..dc9a5c14b 100644 --- a/quantlib/cashflows/_overnight_indexed_coupon.pxd +++ b/quantlib/cashflows/_overnight_indexed_coupon.pxd @@ -1,4 +1,4 @@ -from quantlib.types cimport Rate, Real, Spread, Time +from quantlib.types cimport Natural, Rate, Real, Spread, Time from libcpp cimport bool from libcpp.vector cimport vector @@ -22,10 +22,15 @@ cdef extern from 'ql/cashflows/overnightindexedcoupon.hpp' namespace 'QuantLib': const Date& refPeriodEnd, #= Date(), const DayCounter& dayCounter, #= DayCounter(), bool telescopicValueDates, #=False, - RateAveraging averagingMethod) # = RateAveraging::Compound + RateAveraging averagingMethod, # = RateAveraging::Compound + Natural lookback_days, + Natural lockout_days, + bool apply_observation_shift) vector[Date]& fixingDates() vector[Time]& dt() vector[Rate]& indexFixings() except + vector[Date]& valueDates() RateAveraging averagingMethod() + Natural lockoutDays() + bool applyObservationShift() diff --git a/quantlib/cashflows/_overnight_indexed_coupon_pricer.pxd b/quantlib/cashflows/_overnight_indexed_coupon_pricer.pxd new file mode 100644 index 000000000..b79c368dc --- /dev/null +++ b/quantlib/cashflows/_overnight_indexed_coupon_pricer.pxd @@ -0,0 +1,13 @@ +from quantlib.types cimport Rate, Real +from libcpp cimport bool +from ._coupon_pricer cimport FloatingRateCouponPricer + +cdef extern from 'ql/cashflows/overnightindexedcouponpricer.hpp' namespace 'QuantLib' nogil: + cdef cppclass CompoundingOvernightIndexedCouponPricer(FloatingRateCouponPricer): + pass + cdef cppclass ArithmeticAveragedOvernightIndexedCouponPricer(FloatingRateCouponPricer): + ArithmeticAveragedOvernightIndexedCouponPricer( + Real meanReversion, # = 0.03 + Real volatility, # = 0.00 No convexity adjustment by default + bool byApprox # = false, True to use Katsumi Takada approximation + ) diff --git a/quantlib/cashflows/coupon_pricer.pyx b/quantlib/cashflows/coupon_pricer.pyx index cefeb626c..4c456de9c 100644 --- a/quantlib/cashflows/coupon_pricer.pyx +++ b/quantlib/cashflows/coupon_pricer.pyx @@ -1,5 +1,4 @@ -include '../types.pxi' - +from quantlib.types cimport Rate from cython.operator cimport dereference as deref from quantlib.cashflow cimport Leg from quantlib.termstructures.volatility.optionlet.optionlet_volatility_structure cimport OptionletVolatilityStructure @@ -15,14 +14,18 @@ from quantlib.time.daycounter cimport DayCounter from quantlib.quote cimport Quote from quantlib.quotes.simplequote cimport SimpleQuote from .coupon_pricer cimport FloatingRateCouponPricer +from .floating_rate_coupon cimport FloatingRateCoupon +from . cimport _floating_rate_coupon as _frc cimport quantlib._cashflow as _cf cdef class FloatingRateCouponPricer: - def __init__(self): - raise ValueError( - 'CouponPricer cannot be directly instantiated!' - ) + def __cinit__(self): + if type(self) in (FloatingRateCouponPricer, IborCouponPricer): + raise ValueError(f"'{type(self).__name__}' cannot be directly instantiated!") + + def initialize(self, FloatingRateCoupon coupon not None): + self._thisptr.get().initialize(deref(<_frc.FloatingRateCoupon*>coupon._thisptr.get())) def swaplet_price(self): return self._thisptr.get().swapletPrice() @@ -43,14 +46,6 @@ cdef class FloatingRateCouponPricer: return self._thisptr.get().floorletRate(effective_floor) -cdef class IborCouponPricer(FloatingRateCouponPricer): - - def __init__(self): - raise ValueError( - 'IborCouponPricer cannot be directly instantiated!' - ) - - cpdef enum TimingAdjustment: Black76 = _cp.Black76 BivariateLognormal = _cp.BivariateLognormal diff --git a/quantlib/cashflows/overnight_indexed_coupon.pyx b/quantlib/cashflows/overnight_indexed_coupon.pyx index 833205db6..858f06c7c 100644 --- a/quantlib/cashflows/overnight_indexed_coupon.pyx +++ b/quantlib/cashflows/overnight_indexed_coupon.pyx @@ -1,4 +1,4 @@ -from quantlib.types cimport Real, Spread +from quantlib.types cimport Natural, Real, Spread from libcpp cimport bool from libcpp.vector cimport vector @@ -8,6 +8,7 @@ from quantlib.time.date cimport Date, date_from_qldate from quantlib.time._date cimport Date as QlDate from quantlib.time.daycounter cimport DayCounter from quantlib.indexes.ibor_index cimport OvernightIndex +from quantlib.utilities.null cimport Null cimport quantlib.indexes._ibor_index as _ii cimport quantlib._cashflow as _cf from .rateaveraging cimport RateAveraging @@ -20,14 +21,18 @@ cdef class OvernightIndexedCoupon(FloatingRateCoupon): OvernightIndex index not None, Real gearing=1., Spread spread=0., Date ref_period_start=Date(), Date ref_period_end=Date(), DayCounter day_counter=DayCounter(), bool telescopic_values= False, - RateAveraging averaging_method=RateAveraging.Compound): + RateAveraging averaging_method=RateAveraging.Compound, + Natural lookback_days=Null[Natural](), + Natural lockout_days=0, + bool apply_observation_shift=False): self._thisptr = make_shared[_oic.OvernightIndexedCoupon]( payment_date._thisptr, nominal, start_date._thisptr, end_date._thisptr, static_pointer_cast[_ii.OvernightIndex](index._thisptr), gearing, spread, ref_period_start._thisptr, ref_period_end._thisptr, - deref(day_counter._thisptr), telescopic_values, averaging_method + deref(day_counter._thisptr), telescopic_values, averaging_method, + lookback_days, lockout_days, apply_observation_shift ) def fixing_dates(self): @@ -61,8 +66,19 @@ cdef class OvernightIndexedCoupon(FloatingRateCoupon): l.append(date) preinc(it) return l - - + + @property + def lockout_days(self): + return (<_oic.OvernightIndexedCoupon*>self._thisptr.get()).lockoutDays() + + @property + def averaging_method(self): + return (<_oic.OvernightIndexedCoupon*>self._thisptr.get()).averagingMethod() + + @property + def apply_observation_shift(self): + return (<_oic.OvernightIndexedCoupon*>self._thisptr.get()).applyObservationShift() + cdef class OvernightLeg(Leg): def __iter__(self): diff --git a/quantlib/cashflows/overnight_indexed_coupon_pricer.pxd b/quantlib/cashflows/overnight_indexed_coupon_pricer.pxd new file mode 100644 index 000000000..42e14a891 --- /dev/null +++ b/quantlib/cashflows/overnight_indexed_coupon_pricer.pxd @@ -0,0 +1,8 @@ +from .coupon_pricer cimport FloatingRateCouponPricer + +cdef class CompoundingOvernightIndexedCouponPricer(FloatingRateCouponPricer): + pass + + +cdef class ArithmeticAveragedOvernightIndexedCouponPricer(FloatingRateCouponPricer): + pass diff --git a/quantlib/cashflows/overnight_indexed_coupon_pricer.pyx b/quantlib/cashflows/overnight_indexed_coupon_pricer.pyx new file mode 100644 index 000000000..e359b9996 --- /dev/null +++ b/quantlib/cashflows/overnight_indexed_coupon_pricer.pyx @@ -0,0 +1,16 @@ +from quantlib.types cimport Real +from libcpp cimport bool +from . cimport _overnight_indexed_coupon_pricer as _oicp + +cdef class CompoundingOvernightIndexedCouponPricer(FloatingRateCouponPricer): + def __init__(self): + self._thisptr.reset(new _oicp.CompoundingOvernightIndexedCouponPricer()) + +cdef class ArithmeticAveragedOvernightIndexedCouponPricer(FloatingRateCouponPricer): + def __init__(self, Real mean_reversion = 0.03, Real volatility=0.0, bool by_approx=False): + """ pricer for arithmetically averaged overnight indexed coupons + + Reference: Katsumi Takada 2011, Valuation of Arithmetically Average of + Fed Funds Rates and Construction of the US Dollar Swap Yield Curve""" + + self._thisptr.reset(new _oicp.ArithmeticAveragedOvernightIndexedCouponPricer(mean_reversion, volatility, by_approx)) diff --git a/quantlib/indexes/_ibor_index.pxd b/quantlib/indexes/_ibor_index.pxd index a88e84935..805ce511b 100644 --- a/quantlib/indexes/_ibor_index.pxd +++ b/quantlib/indexes/_ibor_index.pxd @@ -22,7 +22,7 @@ cimport quantlib.termstructures.yields._flat_forward as _ff from quantlib.indexes._interest_rate_index cimport InterestRateIndex -cdef extern from 'ql/indexes/iborindex.hpp' namespace 'QuantLib': +cdef extern from 'ql/indexes/iborindex.hpp' namespace 'QuantLib' nogil: # base class for Inter-Bank-Offered-Rate indexes (e.g. %Libor, etc.) cdef cppclass IborIndex(InterestRateIndex): diff --git a/quantlib/indexes/_interest_rate_index.pxd b/quantlib/indexes/_interest_rate_index.pxd index 9d62b68e4..40b77b6b5 100644 --- a/quantlib/indexes/_interest_rate_index.pxd +++ b/quantlib/indexes/_interest_rate_index.pxd @@ -19,10 +19,9 @@ from quantlib.time._daycounter cimport DayCounter from quantlib.currency._currency cimport Currency -cdef extern from 'ql/indexes/interestrateindex.hpp' namespace 'QuantLib': +cdef extern from 'ql/indexes/interestrateindex.hpp' namespace 'QuantLib' nogil: cdef cppclass InterestRateIndex(Index): - InterestRateIndex() InterestRateIndex(string& familyName, Period& tenor, Natural settlementDays, diff --git a/quantlib/instruments/_make_ois.pxd b/quantlib/instruments/_make_ois.pxd index d1ebc5bf7..cc979a5bc 100644 --- a/quantlib/instruments/_make_ois.pxd +++ b/quantlib/instruments/_make_ois.pxd @@ -49,5 +49,8 @@ cdef extern from 'ql/instruments/makeois.hpp' namespace 'QuantLib': MakeOIS &withTelescopicValueDates(bool telescopicValueDates) MakeOIS& withAveragingMethod(RateAveraging averagingMethod) + MakeOIS& withLookbackDays(Natural lookbackDays) + MakeOIS& withLockoutDays(Natural lockoutDays) + MakeOIS& withObservationShift(bool ObservationShift) MakeOIS& withPricingEngine(shared_ptr[PricingEngine]& engine) diff --git a/quantlib/instruments/_overnightindexedswap.pxd b/quantlib/instruments/_overnightindexedswap.pxd index ca32b92cd..9f6be1ffa 100644 --- a/quantlib/instruments/_overnightindexedswap.pxd +++ b/quantlib/instruments/_overnightindexedswap.pxd @@ -1,5 +1,5 @@ -from quantlib.types cimport Natural, Rate, Real, Spread +from quantlib.types cimport Integer, Natural, Rate, Real, Spread from quantlib.cashflows.rateaveraging cimport RateAveraging from libcpp cimport bool from libcpp.vector cimport vector @@ -18,35 +18,47 @@ cdef extern from 'ql/instruments/overnightindexedswap.hpp' namespace 'QuantLib': cdef cppclass OvernightIndexedSwap(FixedVsFloatingSwap): OvernightIndexedSwap(Type type, Real nominal, - const Schedule& schedule, + const Schedule& fixedSchedule, Rate fixedRate, DayCounter fixedDC, + const Schedule overnightSchedule, shared_ptr[OvernightIndex] overnightIndex, Spread spread, # = 0.0, - Natural paymentLag, # = 0, + Integer paymentLag, # = 0, BusinessDayConvention paymentAdjustment, # = Following, const Calendar& paymentCalendar, # = Calendar(), bool telescopicValueDates, # = false, - RateAveraging averagingMethod) # = RateAveraging::Compound); + RateAveraging averagingMethod, # = RateAveraging::Compound); + Natural lookbackDays, # = Null(), + Natural lockoutDays, # = 0, + bool applyObservationShift) # = False OvernightIndexedSwap(Type type, - vector[Real] nominals, - const Schedule& schedule, + vector[Real] fixed_nominals, + const Schedule& fixedSchedule, Rate fixedRate, DayCounter fixedDC, + vector[Real] overnight_nominals, + const Schedule overnightSchedule, shared_ptr[OvernightIndex] overnightIndex, Spread spread, # = 0.0, - Natural paymentLag, # = 0, + Integer paymentLag, # = 0, BusinessDayConvention paymentAdjustment, # = Following, const Calendar& paymentCalendar, # = Calendar(), bool telescopicValueDates, # = false, - RateAveraging averagingMethod) # = RateAveraging::Compound); + RateAveraging averagingMethod, # = RateAveraging::Compound); + Natural lookbackDays, # = Null(), + Natural lockoutDays, # = 0, + bool applyObservationShift) # = False Frequency paymentFrequency() const shared_ptr[OvernightIndex]& overnightIndex() const Leg& overnightLeg() const RateAveraging averagingMethod() const + Natural lookbackDays() const + Natural lockoutDays() const + bool applyObservationShift() const Real overnightLegBPS() const Real overnightLegNPV() const diff --git a/quantlib/instruments/make_ois.pyx b/quantlib/instruments/make_ois.pyx index 1c3133bed..9fbc461fe 100644 --- a/quantlib/instruments/make_ois.pyx +++ b/quantlib/instruments/make_ois.pyx @@ -110,6 +110,18 @@ cdef class MakeOIS: self._thisptr.withAveragingMethod(averagingMethod) return self + def with_lookback_days(self, Natural lookback_days): + self._thisptr.withLookbackDays(lookback_days) + return self + + def with_lockout_days(self, Natural lockout_days): + self._thisptr.withLockoutDays(lockout_days) + return self + + def with_apply_observation_shift(self, bool observation_shift): + self._thisptr.withObservationShift(observation_shift) + return self + def with_pricing_engine(self, PricingEngine engine): self._thisptr.withPricingEngine(engine._thisptr) return self diff --git a/quantlib/instruments/overnightindexedswap.pyx b/quantlib/instruments/overnightindexedswap.pyx index 861e72b53..3a7c18e4b 100644 --- a/quantlib/instruments/overnightindexedswap.pyx +++ b/quantlib/instruments/overnightindexedswap.pyx @@ -1,5 +1,5 @@ """Overnight index swap paying compounded overnight vs. fixed""" -from quantlib.types cimport Real +from quantlib.types cimport Real, Integer, Natural from cython.operator cimport dereference as deref from libcpp cimport bool from libcpp.vector cimport vector @@ -13,6 +13,7 @@ from quantlib.time.calendar cimport Calendar from quantlib.time.daycounter cimport DayCounter from quantlib.time.schedule cimport Schedule from quantlib.handle cimport make_shared, static_pointer_cast +from quantlib.utilities.null cimport Null from .swap cimport Type from . cimport _overnightindexedswap as _ois from quantlib._instrument cimport Instrument @@ -25,12 +26,16 @@ cdef inline _ois.OvernightIndexedSwap* get_OIS(OvernightIndexedSwap self): cdef class OvernightIndexedSwap(FixedVsFloatingSwap): """Overnight indexed swap: fix vs compounded overnight rate""" - def __init__(self, Type swap_type, nominal, Schedule schedule, - Rate fixed_rate, DayCounter fixed_dc, OvernightIndex overnight_index, - Spread spread=0.0, Natural payment_lag=0, + def __init__(self, Type swap_type, nominal, Schedule fixed_schedule, + Rate fixed_rate, DayCounter fixed_dc, Schedule overnight_schedule, + OvernightIndex overnight_index, + Spread spread=0.0, Integer payment_lag=0, BusinessDayConvention payment_adjustment=Following, Calendar payment_calendar=Calendar(), bool telescopic_value_dates=False, - RateAveraging averaging_method=RateAveraging.Compound): + RateAveraging averaging_method=RateAveraging.Compound, + Natural lookback_days=Null[Natural](), + Natural lockout_days=0, + bool apply_observation_shift=False): cdef vector[double] nominals cdef double n @@ -38,10 +43,12 @@ cdef class OvernightIndexedSwap(FixedVsFloatingSwap): if isinstance(nominal, float): self._thisptr = static_pointer_cast[Instrument]( make_shared[_ois.OvernightIndexedSwap]( - swap_type, nominal, schedule._thisptr, fixed_rate, - deref(fixed_dc._thisptr), static_pointer_cast[_ii.OvernightIndex](overnight_index._thisptr), + swap_type, nominal, fixed_schedule._thisptr, fixed_rate, + deref(fixed_dc._thisptr), overnight_schedule._thisptr, + static_pointer_cast[_ii.OvernightIndex](overnight_index._thisptr), spread, payment_lag, payment_adjustment, payment_calendar._thisptr, - telescopic_value_dates, averaging_method + telescopic_value_dates, averaging_method, lookback_days, lockout_days, + apply_observation_shift ) ) elif isinstance(nominal, list): @@ -49,10 +56,12 @@ cdef class OvernightIndexedSwap(FixedVsFloatingSwap): nominals.push_back(n) self._thisptr = static_pointer_cast[Instrument]( make_shared[_ois.OvernightIndexedSwap]( - swap_type, nominals, schedule._thisptr, fixed_rate, - deref(fixed_dc._thisptr), static_pointer_cast[_ii.OvernightIndex](overnight_index._thisptr), + swap_type, nominals, fixed_schedule._thisptr, fixed_rate, + deref(fixed_dc._thisptr), nominals, overnight_schedule._thisptr, + static_pointer_cast[_ii.OvernightIndex](overnight_index._thisptr), spread, payment_lag, payment_adjustment, payment_calendar._thisptr, - telescopic_value_dates, averaging_method + telescopic_value_dates, averaging_method, lookback_days, lockout_days, + apply_observation_shift ) ) diff --git a/quantlib/termstructures/_helpers.pxd b/quantlib/termstructures/_helpers.pxd index 9b498f632..0acbed1b9 100644 --- a/quantlib/termstructures/_helpers.pxd +++ b/quantlib/termstructures/_helpers.pxd @@ -13,7 +13,7 @@ from quantlib.handle cimport Handle from quantlib._quote cimport Quote from quantlib.time._date cimport Date -cdef extern from 'ql/termstructures/bootstraphelper.hpp' namespace 'QuantLib': +cdef extern from 'ql/termstructures/bootstraphelper.hpp' namespace 'QuantLib' nogil: cdef cppclass BootstrapHelper[T]: BootstrapHelper(Handle[Quote]& quote) BootstrapHelper(Real quote) diff --git a/quantlib/termstructures/volatility/equityfx/_local_vol_surface.pxd b/quantlib/termstructures/volatility/equityfx/_local_vol_surface.pxd index 6e803105b..fe720a76b 100644 --- a/quantlib/termstructures/volatility/equityfx/_local_vol_surface.pxd +++ b/quantlib/termstructures/volatility/equityfx/_local_vol_surface.pxd @@ -25,9 +25,3 @@ cdef extern from 'ql/termstructures/volatility/equityfx/localvolsurface.hpp' nam Handle[YieldTermStructure] riskFreeTS, Handle[YieldTermStructure] dividendTS, Real underlying) - Volatility localVol(const Date& d, - Real underlyingLevel, - bool extrapolate) const # = false - Volatility localVol_ "localVol" (Time t, - Real underlyingLevel, - bool extrapolate) const # = false diff --git a/quantlib/termstructures/volatility/equityfx/_local_vol_term_structure.pxd b/quantlib/termstructures/volatility/equityfx/_local_vol_term_structure.pxd index b92518d71..f7163441c 100644 --- a/quantlib/termstructures/volatility/equityfx/_local_vol_term_structure.pxd +++ b/quantlib/termstructures/volatility/equityfx/_local_vol_term_structure.pxd @@ -32,7 +32,7 @@ cdef extern from 'ql/termstructures/volatility/equityfx/localvoltermstructure.hp Volatility localVol(const Date& d, Real underlyingLevel, - bool extrapolate = false) const + bool extrapolate) const # = false) const Volatility localVol(Time t, Real underlyingLevel, - bool extrapolate = false) const + bool extrapolate) # = false) const diff --git a/quantlib/termstructures/volatility/equityfx/local_vol_surface.pyx b/quantlib/termstructures/volatility/equityfx/local_vol_surface.pyx index a76ba54b0..df91f643d 100644 --- a/quantlib/termstructures/volatility/equityfx/local_vol_surface.pyx +++ b/quantlib/termstructures/volatility/equityfx/local_vol_surface.pyx @@ -36,7 +36,7 @@ cdef class LocalVolSurface(LocalVolTermStructure): def localVol(self, d, Real underlying_level, bool extrapolate=False): cdef _lvs.LocalVolSurface* surf = <_lvs.LocalVolSurface*>self._thisptr.get() if isinstance(d, float): - return surf.localVol_(