Adding a new objective to Calypso Forward Ladder

I’ve been spending the last 6 weeks configuring the Forward Ladder in Calypso 11 in order to get a real-time view into FX risk from Opics.  While I actually did some work on the Forward Ladder analysis when I was back at Calypso, they did a complete rewrite for version 11 and I must say that, while I did encounter a few issues, it is well thought out and quite extensible.  As such, I thought I’d share how easy it is to plug in a new objective in the forward ladder.

The request was to display the discount factor (df, for short) which is unfortunately not available in the new ForwardLadder analysis.   While it was a column in one of the earlier incantations of the analysis (i.e., FwdLadder), it seems to have disappeared in this latest version.   We could have of course asked for a P6 enhancement request, but that probably means we’d have had to roll this out next year as opposed to this year, so that was a no go.   Digging into the code, I came across the Forward Ladder Registry, a class that allows you to plug in and/or modify the objectives and flow generation extremely easily.

The ForwardLadderRegistry class actually reads the configuration from an XML file included in the resources.jar called com/calypso/tk/risk/ForwardLadderGeneratorMappings.xml.  Here’s a snippet from that file:

<registry>
    <global>
        <objectiveGenerators>
            <generator>
                <objectiveClass>com.calypso.tk.risk.forwardladder.objective.ForwardLadderObjectiveCore</objectiveClass>
                <generatorClass>com.calypso.tk.risk.forwardladder.generator.DefaultCoreGenerator</generatorClass>
            </generator>
            <generator>
                <objectiveClass>com.calypso.tk.risk.forwardladder.objective.ForwardLadderObjectiveCash</objectiveClass>
                <generatorClass>com.calypso.tk.risk.forwardladder.generator.DefaultCashFlowAmountCashGenerator</generatorClass>
            </generator>
            ...
        </objectiveGenerators>
    </global>
    ...
</registry>

I decided to create a new objective called MarketData in order to bring in the df, as requested by the users.   Thus, I added the following lines to the xml file:

            ...
            <generator>
                <objectiveClass>com.myco.tk.risk.forwardladder.objective.ForwardLadderObjectiveMarketData</objectiveClass>
                <generatorClass>com.myco.tk.risk.forwardladder.generator.DefaultMarketDataGenerator</generatorClass>
            </generator>
            ...

That’s easy enough, right?   The code for the ForwardLadderObjectiveMarketData is trivial enough and you can easily implement it based on one of the other objectives supplied by Calypso.   The meat & bones, however, resides in the DefaultMarketDataGenerator which actually implements the ForwardLadderObjectiveGeneratorI interface.  (Incidentally, I’m not quite sure why Calypso forces you to implement 2 interfaces here.   I think one interface could easily have described the contract for both the objective metadata and the actual implementation!  Go figure…)

Here’s what the code looks like to display the discount factor:

public class DefaultMarketDataGenerator implements ForwardLadderObjectiveGeneratorI {
...
public void populateObjectiveData(ForwardLadderObjectiveI objective, FlowGenerationContextI context,
List<ForwardLadderFlowItem> flows) { Trade trade = context.getTrade(); PricingEnvBasedFlowGenerationContext peContext = (PricingEnvBasedFlowGenerationContext)context; for (ForwardLadderFlowItem flow : flows) { for (ColumnMetaData metaData : objective.getObjectiveColumnMetaData(context.getParams())) { String dataName = metaData.getName(); if (ForwardLadderObjectiveMarketData.CURRENCY_DF.equals(dataName)) { CashFlow cf = flow.getCashFlow(); String ccy = cf.getCurrency(); CurveZero curve = peContext.getPricingEnv().getPricerConfig().getDiscountZeroCurve(ccy); double df = 1.; try { df = curve.getDF(trade.getSettleDate(), QuoteSet.MID); Amount dfDV = new Amount(df, ForwardLadderAnalysisUtil.DEFAULT_CONVERSION_RATE_ROUNDING); ForwardLadderObjectiveData data = new ForwardLadderObjectiveData(metaData, dfDV); flow.setObjectiveData(dataName, data); } catch (Throwable t) { Log.error(LOG_CATEGORY, t); } } } } }
}

That just about does it, believe it or not!   The only thing is you’ll have to tweak one more resource bundle file or the ParamViewer will choke when trying to add the new objective.   Look for a file called com/calypso/bundles/apps/forwardladder/ForwardLadderObjectives.properties in the resources.jar and add the following properties at the end of that file:

objective.displayname.MarketData=Market Data
objective.help.MarketData=

As long as your classes and modified resource files come before Calypso’s in your classpath, you’ll be able to add this new objective to your Forward Ladder.