Skip to content

Question: Leveraging ORE-SWIG Python Bindings for SACCR Implementation #23

@vannarho-fas

Description

@vannarho-fas

Hello Community,

Actually, I cannot find a community for ORE so I am posting here. I tried to contact the forum on the ore webpage but there was no response. 😃

Please redirect me as needed. I am part of the Quantlib user group but don't see any threads there re ORE. Is there a group that I am not aware of?

I have a SACCR calculator using Python but it does not currently cover all instruments in ORE / QL so I'm looking into the option of refactoring the code to leverage ORE and its Python bindings via SWIG. An alternative is porting the code to C++ / ORE, but as I judge this to be more difficult (for me at least, though has a lot of other advantages), I want to explore the SWIG route first.

As a first step in this investigation, I want to populate a dictionary, such as the one below, using details from various trade objects in the portfolio.

Here's an example dictionary structure I'm looking to fill:

trade_dict = {
'TradeType': '', 'SubClass': '', 'Notional': '', 'Currency': '', 'Si': '', 'Ei': '',  'BuySell': '', 'Id': '', 'Counterparty': '', 'OptionType': '', 'UnderlyingPrice': '',  'StrikePrice': '', 'commodity_type': '', 'RefEntity': '', 'CcyPair': '', 'PayLegType': '', 'PayLegRef': '', 'PayLegTenor': '', 'RecLegType': '', 'RecLegRef': '', 'RecLegTenor': '',  'Vol_Strike': '', 'Traded_Price': '', 'Delivery_Type': '', 'Underlying_Instrument': '', 'Exotic_Type': '',  'ISIN': '', 'CouponType': '', 'Issuer': '', 'Maturity': '', 'PaymentFrequency': '',  'CreditRiskWeight': '', 'CdoAttachPoint': '', 'CdoDetachPoint': '', 'FxNearLegFields': '', 'CcyPaying': '', 'AmountPaying': '', 'CcyReceiving': '', 'AmountReceiving': ''
}

The concept was to iterate over the portfolio's trade IDs, extracting the relevant information from each trade:

for id in portfolio.ids():
    trade = portfolio.get(id)
    if trade.tradeType() == 'Swap':
        trade_dict['TradeType'] = trade.tradeType()
        trade_dict['Notional'] = trade.notional()
        trade_dict['Counterparty'] = trade.envelope().counterparty()
        # and so on...
        for leg in trade.legs() # this currently returns a cashflow as far as remember, not leg data
              if leg.legType = "Fixed". # made this up
                     # and so on...
    elif trade_type == 'Swaption':
       # handle swaption trades...

Using the "Input" files from Example_1 (/oreswig/OREAnalytics-SWIG/Python/Examples/Notebooks/Example_1), trade.legs() seems to be returning an empty tuple, even though the trade has fixed and floating legs. print(portfolioXML) shows that the data is fully populated...how to get access to it?

from ORE import *
import sys, time, math
sys.path.append('..')
import utilities
params = Parameters()
params.fromFile("Input/ore.xml")
ore = OREApp(params)
portfolio = ore.getInputs().portfolio()
print("asof date:",ore.getInputs().asof())
print("Number of trades:", portfolio.size())

for id in portfolio.ids():
    trade = portfolio.get(id)
    print("Trade class (trade variable): " , trade)
    print("Trade:  id=%s type=%s" % (id, trade.tradeType()))
    print("Counterparty:" , trade.envelope().counterparty())
    print("NettingSetId:" , trade.envelope().nettingSetId())
    print("additionalFields:" , trade.envelope().additionalFields())
    print("instrument:" , trade.instrument())
    print("notional:" , trade.notional())
    print("maturity:" , trade.maturity())
    print("legs:" , trade.legs())
    
# no binding available for the below
#     print("portfolioIds:" , trade.portfolioIds() 
#     print("tradeActions:" , trade.tradeActions())
#     print("legPayers:" , trade.legPayers())
#     print("npvCurrency:" , trade.npvCurrency()) 
#     print("notionalCurrency:" , trade.notionalCurrency()) 
#     print("issuer:" , trade.issuer() 

# throws the error "'NoneType' object has no attribute 'qlInstrument'"
#     print("qlInstrument:" , trade.instrument().qlInstrument()) 


portfolioXML = portfolio.toXMLString()
print()
print(portfolioXML)

Here is the console output.

asof date: February 5th, 2016
Number of trades: 1
Trade class (trade variable):  <ORE.ORE.Trade; proxy of <Swig Object of type 'std::vector< ext::shared_ptr< Trade > >::value_type *' at 0x10ee18120> >
Trade:  id=Swap type=Swap
Counterparty: CPTY_A
NettingSetId: CPTY_A
additionalFields: <ORE.ORE.StringStringMap; proxy of <Swig Object of type 'std::map< std::string,std::string,std::less< std::string >,std::allocator< std::pair< std::string const,std::string > > > *' at 0x10ee18ae0> >
instrument: None
notional: 3.4028234663852886e+38
maturity: null date
legs: ()
<Portfolio>
	<Trade id="Swap">
		<TradeType>Swap</TradeType>
		<Envelope>
			<CounterParty>CPTY_A</CounterParty>
			<NettingSetId>CPTY_A</NettingSetId>
			<PortfolioIds/>
			<AdditionalFields/>
		</Envelope>
		<SwapData>
			<LegData>
				<LegType>Fixed</LegType>
				<Payer>false</Payer>
				<Currency>EUR</Currency>
				<PaymentConvention>MF</PaymentConvention>
				<DayCounter>A360</DayCounter>
				<Notionals>
					<Notional>10000000.000000</Notional>
					<Exchanges>
						<NotionalInitialExchange>false</NotionalInitialExchange>
						<NotionalFinalExchange>false</NotionalFinalExchange>
						<NotionalAmortizingExchange>false</NotionalAmortizingExchange>
					</Exchanges>
				</Notionals>
				<ScheduleData>
					<Rules>
						<StartDate>20160209</StartDate>
						<EndDate>20360209</EndDate>
						<Tenor>1Y</Tenor>
						<Calendar>TARGET</Calendar>
						<Convention>MF</Convention>
						<TermConvention>MF</TermConvention>
						<Rule>Forward</Rule>
						<EndOfMonth/>
						<FirstDate/>
						<LastDate/>
					</Rules>
				</ScheduleData>
				<FixedLegData>
					<Rates>
						<Rate>0.021000</Rate>
					</Rates>
				</FixedLegData>
			</LegData>
			<LegData>
				<LegType>Floating</LegType>
				<Payer>true</Payer>
				<Currency>EUR</Currency>
				<PaymentConvention>MF</PaymentConvention>
				<DayCounter>A360</DayCounter>
				<Notionals>
					<Notional>10000000.000000</Notional>
					<Exchanges>
						<NotionalInitialExchange>false</NotionalInitialExchange>
						<NotionalFinalExchange>false</NotionalFinalExchange>
						<NotionalAmortizingExchange>false</NotionalAmortizingExchange>
					</Exchanges>
				</Notionals>
				<ScheduleData>
					<Rules>
						<StartDate>20160209</StartDate>
						<EndDate>20360209</EndDate>
						<Tenor>6M</Tenor>
						<Calendar>TARGET</Calendar>
						<Convention>MF</Convention>
						<TermConvention>MF</TermConvention>
						<Rule>Forward</Rule>
						<EndOfMonth/>
						<FirstDate/>
						<LastDate/>
					</Rules>
				</ScheduleData>
				<FloatingLegData>
					<Index>EUR-EURIBOR-6M</Index>
					<IsInArrears>false</IsInArrears>
					<IsAveraged>false</IsAveraged>
					<HasSubPeriods>false</HasSubPeriods>
					<IncludeSpread>false</IncludeSpread>
					<FixingDays>2</FixingDays>
					<Caps/>
					<Floors/>
					<Gearings/>
					<Spreads>
						<Spread>0.000000</Spread>
					</Spreads>
					<NakedOption>false</NakedOption>
				</FloatingLegData>
			</LegData>
		</SwapData>
	</Trade>
</Portfolio>

I also tried to load a new Portfolio directly with new data in case it had been processed (e.g. In a subsequent step, initiated by a call to the build member function, if the “raw” trade data is then translated into QuantLib/QuantExt objects up to the QuantLib/QuantExt instrument, linked to a QuantLib/QuantExt pricing engine, in turn linked to the relevant term structures provided by the Market class. e.g.

port = Portfolio()
port.fromFile("/home/vr/oreswig/OREAnalytics-SWIG/Python/Examples/Notebooks/Example_2/Input/portfolio.xml")
print("Number of trades:", port.size())
for id in port.ids():
    trade = port.get(id)
    print("id:",id)
    print("Counterparty:" , trade.envelope().counterparty())
    print("legs:" , trade.legs())

output:

Number of trades: 3
id: Swap_1
Counterparty: CPTY_A
legs: ()
id: Swap_2
Counterparty: CPTY_A
legs: ()
id: Swap_3
Counterparty: CPTY_A
legs: ()

In the swig interface file, the trade.legs() method seems to return a two-dimensional vector of shared_ptrs to CashFlow objects.

%shared_ptr(Trade)
class Trade {
  private:
    Trade();
  public:
    const std::string& id();
    const std::string& tradeType();
    const ext::shared_ptr<InstrumentWrapper>& instrument();
    std::vector<std::vector<ext::shared_ptr<QuantLib::CashFlow>>> legs();
    const Envelope& envelope() const;
    const QuantLib::Date& maturity();
    Real notional();
};

If I want to access the underlying leg and schedule data, I had two ideas, but I can't see the bindings for these / understand how to do this yet:

  1. Use the instrument (?does the Portfolio need to be loaded afresh and not built to have access to the raw XML inputs?)
  • Access the QuantLib::Instrument object from the InstrumentWrapper using the qlInstrument() method.
  • Cast the QuantLib::Instrument object to the appropriate derived class (QuantLib::Swap, QuantLib::Bond, etc.).
  • Call the appropriate methods of the derived class to access the leg and schedule data.

However in the above example trade.instrument().qlInstrument() = None and trade.instrument().qlInstrument() throws the error "'NoneType' object has no attribute 'qlInstrument'"

  1. Pass the trade to XML and then use utilities (e.g. using c++)
// Assuming 'trade' is your Trade object and 'doc' is your XMLDocument object
XMLNode* node = trade.toXML(doc);

//  use the xml utility functions to extract the data
string id = XMLUtils::getChildValue(node, "id");
Real notional = XMLUtils::getChildValueAsDouble(node, "notional");
bool payer = XMLUtils::getChildValueAsBool(node, "payer");
Period tenor = XMLUtils::getChildValueAsPeriod(node, "tenor");

trade.toXML(doc) and the xmlutils would need to be exposed via swig.

So, I am a bit stuck.

So, my question for the community is: Can I directly use the ORE-SWIG Python bindings "as is" to accomplish this task (e.g. how to access fixed / floating legdata)? Would I need to extend these SWIG bindings to access the necessary functions or objects? Or are there other better ways to do this?

I appreciate any insights or guidance you can provide.

Thanks in advance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions