2021/05/31

How to Create an Automated Findur Trade Extract

by Lucido Group Admin

Summary

Generating a trade extract as soon as a trade is executed is a frequent requirement. The extract could be bound for another department to review the trade details, for a counterparty, a customer, or even another downstream application.

Recently we had a question about the latter: how can we automatically generate a CSV file every time we book a deal. In this case, the question also included how easy it would be to use a ReportBuilder definition to generate the CSV file.

In this post, we demonstrate one way to create a trade extract automatically. We include snippets of code intentionally because not all customizations necessitate complicated Byzantine solutions.

We often wrap the OpenJVS API in simple Java classes to make it easier for our clients to understand the code we deliver, and to facilitate fast and reliable test automation.

The solution you see here relies on no additional vendor license requirements.

Operation Service

An operation service is a fancy name for a solution that is listening for an event in the system, such as a new trade. We created a new operation service to listen for trade activity. The operation service uses a plugin called CreateTradeExtract.

The plugin’s code is short and uses a fluent style to make it easier to read. This is all the code required to trigger the creation of this trade extract!

public class CreateTradeExtract extends AbstractPostProcessTradingScript {
   @Override
   protected void execute(List<Transaction> transactions) {
      String reportName = "Simple MTM IRS Extract";
		
      for(Transaction transaction: transactions) {
         int dealNum = transaction.getValueFromTransactionAsInt(OlfTransactionField.DealNum);
         getLogger().info("Generating CSV file for DealNum: " + dealNum);
			
         Definition.of(reportName)
            .withParameter(QueryParameter.of("ab_tran.deal_tracking_num").withValue(dealNum))
            .withOutputType(OutputType.CSV)
            .execute();
      }
   }
}

Let’s walk through each line of code to explain how this works.

Execute Method

All Openlink clients need trading operation services. There is a surprising amount of boilerplate code required to execute one of these services. We implement that code once in an abstract base class, and then solutions like this inherit the commonly required behavior. This is not unusual or complicated, but you many Openlink users will probably find their existing operation services involved a lot of copied-and-pasted code.

All this execute method is doing is delivering a collection of transactions to our new plugin. It might deliver just one transaction, or it could be a portfolio of transactions. But we will support extracting one or more than one transaction as part of this solution.

@Override
protected void execute(List<Transaction> transactions) {
  ...
}

For Loop

We will iterate over each transaction in this for loop. Our requirements state we should create a separate extract for each transaction, not one extract for a portfolio of transactions.

for(Transaction transaction: transactions) {
  ...
}

DealNum

Testing the Openlink system is not easy. We use various popular methods to ensure we have high test automation coverage. One method we use is to have an interface between our code and Findur.

This next line just gets the deal number from the transaction. While it might look more complicated than necessary, since we have automated tests supporting this solution, we already knew before we sat down to create this new solution, that this method is bulletproof.

int dealNum = transaction.getValueFromTransactionAsInt(OlfTransactionField.DealNum);

ReportBuilder Definition

This section is a little more involved.

Definition.of(reportName)
	.withParameter(QueryParameter.of("ab_tran.deal_tracking_num").withValue(dealNum))
	.withOutputType(OutputType.CSV)
	.execute();

Line 1 loads a ReportBuilder (RB) definition with a name of reportName. If the report does not exist, it will immediately throw an exception. As a rule, code should fail fast.

Line 2 controls the transaction that will be extracted.

The ReportBuilder definition was created with a transaction query and more importantly, a Query Parameter. There is a detailed description of the Query Parameter configuration later on. For now, just know that the definition is expected to be told which deal number should be included in the extract.

The way to read line 2 is like this: ‘with a ReportBuilder parameter, that is a QueryParameter type, that filters ab_tran.deal_tracking_num, with a value equal to my dealNum…’ The result of that admittedly long-winded translation into English is to know that we have a query parameter that should match the deal number to our new transaction.

Line 3 tells Findur to output to CSV file. This Output Type was configured on the ReportBuilder definition. The definition also knows the right file path and file name to use. Our extract will inherit those settings from ReportBuilder.

Line 4 says that we are all done staging the runtime properties to use, and just go ahead and generate the CSV file.

The Results

As soon as the user (or another automated operation) processed the transaction, Findur triggered our operation service. Our code ran the ReportBuilder definition, queried for the new transaction, and extracted the results to the CSV file as shown in the screenshot.

This is a simple example, so the trade extract includes only a subset of the fields typically required to send to a downstream system. But in this demonstration, we have seen how quickly we can create a new low-risk solution to automate an otherwise tedious manual task.

Automated Tests

We have 48 automated tests supporting just the solution you see here, and we are adding more all the time. The tests perform a variety of positive and negative tests to confirm expected behavior on happy and unhappy code execution paths. These tests take about 400ms to complete.

We are happy to talk (and at length!) about how great test automation is to produce solutions of high quality that are easy to understand and pleasant to use.

ReportBuilder Definition

Query Parameter

A Query Parameter allows the user to filter the business objects passed returned by the report. In this case, the ‘business object’ is a transaction, and we want to return only one transaction.

Our operation service knows the transaction’s deal tracking number, so we setup a new Query Parameter to filter on the Deal Tracking Num.

In the RB definition’s Advanced tab, select the Parameters tab.

Right-click in the empty grid and select Add Query Parameter.

There is a long list of fields available. Select ab_tran.deal_tracking_num.

Now, when a user runs the report, they will be asked to enter the deal tracking number. The same parameter will be available when the RB definition is execute via code.

When the user (or the operation service code) selects a deal number, the results will include only that transaction. If the user leaves the deal number field blank, all transactions that satisfy the report’s query will be extracted.