1515if TYPE_CHECKING :
1616 from rateslib .typing import (
1717 Any ,
18- Curves_ ,
18+ CurvesT_ ,
1919 DualTypes ,
2020 FXForwards_ ,
2121 FXVolOption_ ,
@@ -64,16 +64,54 @@ def _composit_fixings_table(df_result: DataFrame, df: DataFrame) -> DataFrame:
6464
6565class Fly (_BaseInstrument ):
6666 """
67- Create a butterfly of *Instruments*.
67+ A *Butterfly* of :class:`~rateslib.instruments.components.protocols._BaseInstrument`.
68+
69+ .. rubric:: Examples
70+
71+ The following initialises a *Butterfly* of *IRSs*.
72+
73+ .. ipython:: python
74+ :suppress:
75+
76+ from rateslib.instruments.components import Fly, IRS
77+ from datetime import datetime as dt
78+
79+ .. ipython:: python
80+
81+ fly = Fly(
82+ instrument1=IRS(dt(2000, 1, 1), "1y", notional=10e6, spec="eur_irs", curves=["estr"]),
83+ instrument2=IRS(dt(2000, 1, 1), "2y", notional=-5e6, spec="eur_irs", curves=["estr"]),
84+ instrument3=IRS(dt(2000, 1, 1), "3y", notional=1.75e6, spec="eur_irs", curves=["estr"]),
85+ )
86+ fly.cashflows()
87+
88+ .. rubric:: Pricing
89+
90+ Each :class:`~rateslib.instruments.components.protocols._BaseInstrument` should have
91+ its own ``curves`` and ``vol`` objects set at its initialisation, according to the
92+ documentation for that *Instrument*. For the pricing methods ``curves`` and ``vol`` objects,
93+ these can be universally passed to each *Instrument* but in many cases that would be
94+ technically impossible since each *Instrument* might require difference pricing objects, e.g.
95+ if the *Instruments* have difference currencies. For a *Fly*
96+ of three *IRS* in the same currency this would be possible, however.
6897
6998 Parameters
7099 ----------
71100 instrument1 : _BaseInstrument
72- An *Instrument* with the shortest maturity.
101+ The *Instrument* with the shortest maturity.
73102 instrument2 : _BaseInstrument
74- The *Instrument* of the body of the *Fly* .
103+ The *Instrument* with the intermediate maturity .
75104 instrument3 : _BaseInstrument
76- An *Instrument* with the longest maturity.
105+ The *Instrument* with the longest maturity.
106+
107+ Notes
108+ -----
109+ A *Fly* is just a container for three
110+ :class:`~rateslib.instruments.components.protocols._BaseInstrument`, with an overload
111+ for the :meth:`~rateslib.instruments.components.Spread.rate` method to calculate twice the
112+ belly rate minus the wings (whatever metric is in use for each *Instrument*), which allows
113+ it to offer a lot of flexibility in *pseudo Instrument* creation.
114+
77115 """
78116
79117 _instruments : Sequence [_BaseInstrument ]
@@ -94,7 +132,7 @@ def __init__(
94132 def npv (
95133 self ,
96134 * ,
97- curves : Curves_ = NoInput (0 ),
135+ curves : CurvesT_ = NoInput (0 ),
98136 solver : Solver_ = NoInput (0 ),
99137 fx : FXForwards_ = NoInput (0 ),
100138 fx_vol : FXVolOption_ = NoInput (0 ),
@@ -125,7 +163,7 @@ def npv(
125163 def local_analytic_rate_fixings (
126164 self ,
127165 * ,
128- curves : Curves_ = NoInput (0 ),
166+ curves : CurvesT_ = NoInput (0 ),
129167 solver : Solver_ = NoInput (0 ),
130168 fx : FXForwards_ = NoInput (0 ),
131169 fx_vol : FXVolOption_ = NoInput (0 ),
@@ -182,7 +220,7 @@ def local_analytic_rate_fixings(
182220 def cashflows (
183221 self ,
184222 * ,
185- curves : Curves_ = NoInput (0 ),
223+ curves : CurvesT_ = NoInput (0 ),
186224 solver : Solver_ = NoInput (0 ),
187225 fx : FXForwards_ = NoInput (0 ),
188226 fx_vol : FXVolOption_ = NoInput (0 ),
@@ -200,73 +238,10 @@ def cashflows(
200238 base = base ,
201239 )
202240
203- def delta (self , * args : Any , ** kwargs : Any ) -> DataFrame :
204- """
205- Calculate the delta of the *Instrument*.
206-
207- For arguments see :meth:`Sensitivities.delta()<rateslib.instruments.Sensitivities.delta>`.
208- """
209- return super ().delta (* args , ** kwargs )
210-
211- def gamma (self , * args : Any , ** kwargs : Any ) -> DataFrame :
212- """
213- Calculate the gamma of the *Instrument*.
214-
215- For arguments see :meth:`Sensitivities.gamma()<rateslib.instruments.Sensitivities.gamma>`.
216- """
217- return super ().gamma (* args , ** kwargs )
218-
219- def exo_delta (self , * args : Any , ** kwargs : Any ) -> DataFrame :
220- """
221- Calculate the delta of the *Instrument* measured
222- against user defined :class:`~rateslib.dual.Variable`.
223-
224- For arguments see
225- :meth:`Sensitivities.exo_delta()<rateslib.instruments.Sensitivities.exo_delta>`.
226- """
227- return super ().exo_delta (* args , ** kwargs )
228-
229- def fixings_table (
230- self ,
231- curves : Curves_ = NoInput (0 ),
232- solver : Solver_ = NoInput (0 ),
233- fx : FX_ = NoInput (0 ),
234- base : str_ = NoInput (0 ),
235- approximate : bool = False ,
236- right : datetime_ = NoInput (0 ),
237- ) -> DataFrame :
238- """
239- Return a DataFrame of fixing exposures on the *Instruments*.
240-
241- For arguments see :meth:`XCS.fixings_table()<rateslib.instruments.XCS.fixings_table>`,
242- and/or :meth:`IRS.fixings_table()<rateslib.instruments.IRS.fixings_table>`
243-
244- Returns
245- -------
246- DataFrame
247- """
248- df_result = DataFrame (
249- index = DatetimeIndex ([], name = "obs_dates" ),
250- )
251- for inst in self .instruments :
252- try :
253- df = inst .fixings_table ( # type: ignore[attr-defined]
254- curves = curves ,
255- solver = solver ,
256- fx = fx ,
257- base = base ,
258- approximate = approximate ,
259- right = right ,
260- )
261- except AttributeError :
262- continue
263- df_result = _composit_fixings_table (df_result , df )
264- return df_result
265-
266241 def rate (
267242 self ,
268243 * ,
269- curves : Curves_ = NoInput (0 ),
244+ curves : CurvesT_ = NoInput (0 ),
270245 solver : Solver_ = NoInput (0 ),
271246 fx : FXForwards_ = NoInput (0 ),
272247 fx_vol : FXVolOption_ = NoInput (0 ),
0 commit comments