Pricing a Bond Portfolio from a Pandas Table with QuantLib
Summary
The document explains a practical way to price several fixed-rate bonds described in a pandas table. A row-wise function converts each bond’s dates and coupon into a QuantLib bond object. The bonds are assigned a shared discounting engine built from a flat yield curve, and their net present values are summed. The example also shows wrapping these operations in a DataFrame subclass with methods for bond creation, engine assignment, and portfolio valuation.
This illustrates how to process a collection of instruments even though QuantLib does not provide a general portfolio object in the described workflow. The example is schematic: it uses a particular calendar, day-count convention, schedule frequency, and curve setup. It does not discuss market-data calibration, handling differing conventions, notional treatment, or validation against independent prices, so users should adapt those assumptions to their bond data and valuation requirements.
Key ideas
- A pandas row function can turn bond records into QuantLib fixed-rate bond objects.
- A shared discounting engine can be assigned across the constructed bonds.
- Individual bond NPVs can be aggregated to obtain a portfolio value.
- A DataFrame subclass can organize construction, engine assignment, and valuation steps.
- The example's conventions and curve assumptions may need adaptation.
Tags
Full text
# Bond portfolio valuation in Quantlib python
# Bond portfolio valuation in Quantlib python
I have a table of bonds which I imported into python using pandas.
Is there a way I can simultaneously price all of them in python using the Quantlib library. I know how to price one bond but not in a table.
## Answer by David Duarte (score 6)
https://quant.stackexchange.com/a/57334
QuantLib doesn't really have the concept of portfolio but since you're using pandas, you can play around with that to price your bonds at once. Here is an example:
```
data = [
[ "15-06-2018", "15-06-2022", 4.75, 500 ],
[ "21-07-2017", "21-07-2027", 0.25, 100 ],
[ "17-02-2015", "17-02-2045", 1.50, 250 ],
]
bonds = pd.DataFrame(data, columns=["start", "maturity", "coupon", "notional"])
def makeBond(row):
start, maturity, coupon, notional = row
startDate = ql.Date(start, "%d-%m-%Y")
maturityDate = ql.Date(maturity, "%d-%m-%Y")
return ql.FixedRateBond(2, ql.TARGET(), 100, startDate, maturityDate, ql.Period("1Y"), [coupon], ql.ActualActual())
yts = ql.YieldTermStructureHandle(
ql.FlatForward(2, ql.TARGET(), 0.05, ql.Actual360())
)
engine = ql.DiscountingBondEngine(yts)
bonds['bond'] = bonds.apply(makeBond, axis=1)
bonds['bond'].apply(lambda x: x.setPricingEngine(engine))
bonds['bond'].apply(lambda x: x.NPV()).sum()
```
#### 3347.2767053215985
Or you could even make a bond portfolio object from a pandas DataFrame:
```
class BondPortfolio(pd.DataFrame):
def makeBond(self, row):
start, maturity, coupon, notional = row
startDate = ql.Date(start, "%d-%m-%Y")
maturityDate = ql.Date(maturity, "%d-%m-%Y")
return ql.FixedRateBond(2, ql.TARGET(), 100, startDate, maturityDate, ql.Period("1Y"), [coupon], ql.ActualActual())
def makeBonds(self):
self['bond'] = self.apply(self.makeBond, axis=1)
def setPricingEngine(self, engine):
self['bond'].apply(lambda x: x.setPricingEngine(engine))
def NPV(self):
return self['bond'].apply(lambda x: x.NPV()).sum()
portfolio = BondPortfolio(data, columns=["start", "maturity", "coupon", "notional"])
portfolio.makeBonds()
portfolio.setPricingEngine(engine)
portfolio.NPV()
```
#### 3347.2767053215985Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.