2020/04/27

OpenComponents: Advantages and Disadvantages

by Lucido Group

What is OpenComponents?

OpenComponents (OC) is Openlink’s advanced application programming interface (API) that allows users to customize and extend the functionality of the Openlink application. OC is available for both Java and .NET platforms. It supports plugins (similar to AVS and OpenJVS) and extensions, as well as external applications (replacing the old VB ToolKit and VB.NET ToolKit).

OC deliberately follows a business-oriented design, and uses object-oriented principles to allow developers to more easily learn the API. It also exposes meta-data for many of the objects, which helps allow code to be written in a very generic way.

Later on in this document, there is a side-by-side comparison of transaction handling that demonstrates how OC can be easier to design, develop and support, compared to OpenJVS.

How is OpenComponents Different to OpenJVS?

OpenJVS is based on the original AVS function library, which has been exposed to Java with some minor cleanup, although functionality has grown with each new release. A very limited object model covering classes like Table and Transaction has also been added. This design makes OpenJVS very easy to learn for ex-AVS developers and OpenLink actually has scripts which automatically translate most code from AVS to OpenJVS, with minimal editing required. While it is possible to make use of Java constructs in OpenJVS plugins, this is not very common in practice as the API does not make use of anything but the most basic Java functionality. 

OC uses more standard Java and .NET programming constructs, such as interfaces, abstract base classes, collections, exception handling, and event handling, which makes it much more intuitive for new developers to learn and use. While exception handling was added to OpenJVS, it is not consistently used across the whole API. For backwards compatibility, OpenJVS Table errors are not treated as exceptions unless you specify an optional attribute on your plugin class. In general, error checking and exception handling is much more consistent and memory management is better using OC.

OC is an alternative to Openlink’s OpenJVS for plugin development, but there are many things possible using OC that are not possible using OpenJVS. At the same time, there are also a number of APIs in OpenJVS which do not have any equivalent in OC. In this case, it is possible to call OpenJVS (or .NET ToolKit) code from within OC context to fill these gaps. It is not possible to use OC classes from an OpenJVS plugin.

Most OC development originated from within the Risk team at Openlink and this means that the front and middle office functionality are particularly strong. There are a number of the more advanced features in this area which have never been exposed to OpenJVS. In general terms, there are more gaps in OC amongst the CTRM/ETRM features and back office functionality, meaning that developers must still use some OpenJVS classes. 

Extensions are generally used to add functionality to the core system as if it was built in, mostly related to simulations, time series analysis, pricing, and curves. In addition, it is possible to to embed a .NET control in the Openlink Desktop using the OC Desktop Layout.

Who Uses OpenComponents

Clients: There are about 50 clients licensed to use OC. These clients represent a wide range of institutions including functionality that spans Findur and Endur all around the world.

Openlink Product Developers: Openlink uses OC to build several of their licensable products including RiskPak, Market Data Tools, Collateral Desktop, and more.

Openlink Professional Services: Openlink’s own professional service teams use OC inconsistently. Consultants that have more experience with OpenJVS typically favor that API over OC. Those consultants will use OC only when it is necessary (see later section about ‘When Is OpenComponents Required?‘).

Benefits of OpenComponents

Lower Development Costs

  • Business-oriented design is more intuitive 
  • Easier translation from business requirements to code

Deliver Higher Quality

  • Easier to build automated test suites 
  • Easier to reuse business component objects

Faster Time To Delivery

  • Well-designed programming interfaces reduce complexity and coupling to the Openlink data model
  • More easily integrated in the development environment for agile projects, rapid prototyping

Transaction Object Hierarchy

OC has implemented many business objects, but here we will illustrate how the Transaction object was designed.

Let’s assume the transaction in this context is a vanilla interest rate swap. We chose that instrument because it is very common, and it has enough simplicity to be understood, but enough complexity to clearly demonstrate some of the benefits of using OC.

A swap Transaction in OC has Legs. The Legs collection (using Java’s Collection interface, or the .NET equivalent) has one or more Leg objects. A developer can easily iterate over each of the legs of the transaction. This swap is a vanilla swap with one fixed rate leg and one floating rate leg. This illustration does not show the entire object hierarchy, but it is most of it.

OpenComponents' Transaction Object Hierarchy
OpenComponents’ Transaction Object Hierarchy

Each Leg has Profiles, which is a collection of Profile objects. Each Profile represents a payment. A developer can iterate over each of the payments to perform any necessary business processing.

Each Profile on the floating rate leg has a collection of Resets. For a vanilla swap, which has no compounding or averaging, the collection of Resets will have just one Reset. If the swap’s floating leg has compounding or averaging, the Resets collection can include more than one Reset.

We expect this Transaction object diagram is intuitive to most users, spanning business analysts through to developers, as long as they have worked in financial markets for at least a few months. Where we find it helpful is that a conversation between a developer and a business analyst is more easily able to articulate business requirements and to deliver a solution that is higher quality, in a shorter timeframe. The business user and developer ‘meet in the middle’ between a discussion of complex business requirements, and abstraction of the API.

For each of the objects described above, there are methods or properties available that speed up delivery of any customization.

Limited Reliance on Table Objects

OpenJVS plugins can be used to implement customizations at extension points as wide-ranging as User Defined Simulation Results, Operation Services, and Accounting Results. All of these solutions in OpenJVS implement the same IScript interface, which passes arguments in an OpenJVS Table. Each of the extension points passes a table with a different structure, requiring the developer to parse the table to retrieve the required business object, such as dependent simulation results, a transaction, a trade confirmation or accounting rule.

OC delivers interfaces and abstract base classes specific to many of the different script categories, that speed up development by coupling the solution more directly and more intuitively to the business requirements.

Many OpenJVS classes have methods that return a Table object. A developer working with a method that returns a table must know its structure before they can work with it (including column names, data types, and expected row count). For example, OpenJVS’s transaction.getTranEventTable()  method returns a table of transaction events, which are the transaction’s payments and other lifecycle events. The table probably contains a long for the event_num, and an integer for the event_type, and much more, but the developer is required to guess or to recall the information. Contrast that to OC, which has transaction.getDealEvents() that returns a collection of DealEvents, from which it is possible to easily iterate and retrieve the required details (including perhaps the event’s SettlementInstruction).

Memory Usage

Memory management is better in OC. OC implements standard interfaces (AutoCloseable in Java and IDisposable in .NET) which allows the use of built in constructs, try-with-resources in Java and using-statements in .NET, to free memory deterministically. Since OC also constructs hierarchies of objects, such as Transaction/Leg/Profile, it also automatically manages the memory of all members of the hierarchy.

Memory management can be an issue for OpenJVS and OC if there are bugs in the Openlink native code. Both OC and OpenJVS use garbage collection to free memory allocated to objects that have passed out of scope. The memory allocated to the object is mostly allocated by the operating system, rather than the Java/.NET virtual machine, so the garbage collector underestimates the memory allocation, which affects the timing of the garbage collection. In some circumstances, memory usage can become a problem.

OC provides debug methods which record a snapshot of all allocated objects and an approximation of the memory consumed. Along with the provided comparison method, this can be used to determine if objects are not being freed when expected, making it easier to find and fix memory leaks.

OpenComponents versus OpenJVS: A Sample Implementation Requirement

Let’s imagine there is a need to get a list of each of the payment amounts for a swap. Using OC, this task is easy to demonstrate and intuitive.

private static List<Double> getPaymentsUsingOC(Transaction transaction) {
    List<Double> paymentAmounts = new ArrayList<>();
    Legs legs = transaction.getLegs();
    for(Leg leg: legs) {
        Profiles profiles = leg.getProfiles();
        for(Profile profile: profiles) {
            paymentAmounts.add(profile.getValueAsDouble(EnumProfileFieldId.Payment));
        }
    }
    return paymentAmounts;
}

In OpenJVS, there are a few factors that make it more difficult to develop a solution to the same business requirement.

The values of fields on a transaction, on a leg, on a payment or on a reset are all retrieved from the OpenJVS Transaction object. This means that getting the trade date (a property of a transaction), or a maturity date (a property of a leg), or a payment amount (a property of a profile/payment record), or a reset date (a property of a reset) are all retrieved using a reference back to the parent transaction, with a complex reference to the appropriate leg ID, or profile ID, or reset ID.

In OpenJVS, this was implemented using a method such as transaction.getField(..) and passing in the leg ID, profile ID, and so on.

The getField(..) methods are poorly documented and the method signatures includes a lot of integers so it is not obvious which parameter on the method is intended for the leg ID, the payment ID, the reset ID, or something else. These methods, and the incomplete documentation leave the developer to guess and check during the development process.

The OpenJVS cycle of guess-and-check is time-consuming, frustrating, and ultimately leads to a brittle solution. For example, the OpenJVS plugin might work fine for this vanilla swap, but what if tomorrow the requirements include an OIS swap that has compounding resets? Using OC, it is easier to have greater confidence that the solution will work for the OIS swap. In fact, the conversation that took place between the business analyst and the developer was more likely to encounter scenarios with compounding swaps because a developer might ask about the size of the Resets collection, or a business analyst might be prompted, after seeing the code, to ask about handling of floating legs with compounding resets.

In OC, it is simple to identify how many legs are on a transaction, either using legs.size() or transaction.getLegCount(). It is simple to identify how many payments are on a single leg using leg.getProfiles().size(). OpenJVS has thousands of TRANF_FIELD enums, but we were not able to find one that appears to return the payment count for a given leg. Maybe there is an enum, but it has a name that it not obvious. The leg count is retrieved using the enum TRANF.TRANF_NUM_PARAM_REC, which is not obvious.

OC follows software engineering standards, in which all IDs count from 0 so the first leg of a transaction is leg number 0. In OpenJVS, this is not implemented consistently, requiring guess-and-check.

In the OpenJVS code, pay less attention to the length of the solution; it isn’t succinctness of the code that is the best measurement of code quality. Code quality is best when a solution was easy to develop, easy for other developers to understand, and easy to extend. Based on these criteria, the OC solution outperforms the OpenJVS solution.

private static List<Double> getPaymentsUsingOpenJVS(com.olf.openjvs.Transaction transaction) throws OException {
    List<Double> paymentAmounts = new ArrayList<>();
    int legCount = transaction.getFieldInt(TRANF_FIELD.TRANF_NUM_PARAM_REC.toInt());
    //The OpenJVS enums are not always well-named.     
    //Maybe TRANF_NUM_PARAM_REC is the number of legs. Can you be sure?
    //Some IDs in OpenJVS start at 0, some start at 1. We would need to test legs and payments.
    for(int legId = 0; legId < legCount; legId) {
        //There doesn't appear to be a OpenJVS enum for the number of payments, 
        double paymentCount = getPaymentCount(transaction);
        for(int paymentId = 0; paymentId < paymentCount; paymentId) {
            paymentAmounts.add(transaction.getFieldDouble(TRANF_FIELD.TRANF_PROFILE_PAYMENT.toInt(), legId, "", paymentId));
        }
    }
    return paymentAmounts;
}

private static double getPaymentCount(com.olf.openjvs.Transaction jvsTransaction) {
    //Either iterate through the payments until an exception is thrown,
    //or go to the database (assuming the trade exists in the database, 
    //which is not an option if this is a pre-trade context)
    return 2;
}

The chief problem with OpenJVS is that it is difficult for a developer to understand how to build a customization, even when that developer has a strong understanding of the business requirements. When the developer has a very limited understanding of the business requirements, the risk of the OpenJVS solution diverging far from the requirements is high.

When Is OpenComponents Required?

Until now, we have been comparing OC and OpenJVS for solutions when there is a choice of API to use. There are some implementations that require using OC extensions.

  • Attaching to a running instance of Findur/Endur: we wrote previously about attaching to a running instance of Findur/Endur. It is a great way to rapidly prototype a solution, as well as to implement automated testing
  • External pricing model: pricing model extensions, often abbreviated as EPMs, are common extension points for Openlink clients. The EPM interface is flexible and allows a developer to extend a native pricing model, and to override one or more features of a pricing model. For example, if you are satisfied with the native implementation of a Hull-White pricing model, but would like to override the volatility lookup, you can retain all of the normal logic, and only implement the volatility lookup feature. Of course, it is also possible to build a pricing model from scratch. 
  • Result calculator: native Openlink simulation results often require modifications. Most clients implement user-defined simulation results as results distinct from the standard results. If, however, the native Realized P&L result is correct for all instruments except for inflation-linked bonds, a better way to close the gap could be to use a result calculator to override the native Realized P&L result for only those instruments. The benefit here is that the dependent cumulative realized P&L results for month-to-date, year-to-date and life-to-date will benefit from the correction to the daily P&L result, and minimize the number of places where the customization must be implemented, including for accounting, APM, reporting, and other post-trade processing.
  • Payment calculator: OTC instruments have many out-of-the-box methods available to calculate payments, but sometimes clients discover gaps. Payment calculators are a great way to close gaps in the standard models. In old versions of Findur, clients resorted to payment formulas, but there are many reasons why they are not a good implementation. We wrote a paper comparing payment formulas to payment calculators, here.
  • Curve construction: OC has several interfaces available to fine-tune curve construction. Extension points include how the curve is bootstrapped and how points are interpolated.
  • Simulation extensions: OC has several interfaces available to customize the simulation engine including scenario targets, value-at-risk (VaR) model modifications, and time-series analysis data configuration.
  • Desktop panels: Openlink Desktops support many point-and-click features, but for some users, additional customizations are necessary. OC may be used to build custom panels that can be integrated directly into an Openlink Desktop. Note, however, that the OC desktop panel must be written using OC in .NET.

Disadvantages of OpenComponents

There are disadvantages to using OpenComponents, compared to using OpenJVS.

License Fees

OC exposes many licensable features, which can be confusing as well as expensive. Some clients with limited need for customization will not be able to justify the license fees. Clients with more complex requirements will evaluate OC and OpenJVS and quickly justify the license fee.

If a client identifies a need for OC, (e.g. to build a custom pricing model) instead of purchasing the OC license, Openlink’s professional services team can ‘sign’ the Java .jar file or .NET assembly to obviate the need for the OC license.

Project Risk

OpenJVS is tightly coupled to Openlink’s native C code base. OC is built with a C++ layer to the native C code. Bugs in the core code will generally affect both OpenJVS and OpenComponents. There are very occasionally bugs in the application that specifically affect OC implementations. Mitigating this project risk, in the past, we have experienced attentive response times from the OC development team to address bugs in the OC layer. There are fewer development staff supporting OC, so the response times are not as fast as they were in prior years.

Performance

This is not really a disadvantage of OC. There may be some circumstances when OpenJVS is more performant than OC but there are also cases where OC is faster, although in general, the time taken to execute the core code means the overhead of either OpenJVS or OC is negligible. OC allows multi-threading, which can improve performance in some circumstances, and the better abstractions generally make it much easier to optimize algorithms, which is where most significant performance improvements are generally found.

Documentation

The documentation for OpenJVS is usually thorough, with many examples of code snippets available in a .CHM help file. The OC development team manages a wiki that includes a lot of information, but there are limited examples of complete solutions. OC has an active user community forum with moderation from Openlink specialists.

Summary

While this has been a lengthy post, the scope of the OC API is broad, and we cannot cover all of its complexity. Contact us for additional information and we will be happy to discuss how OpenComponents and OpenJVS can be implemented effectively at your organization.