Implementing Historic Search

This page provides a guide to the changes you need to make to your integration adapters to implement FX Sales' Historic Search feature.

Requirements

To provide a backend implementation of the Historic Search, you require the following:

  • Front end: Caplin FX Sales 2.13 or greater

  • Back end: A trading integration adapter based on the FX Integration API 3.49 or greater.

Implementation checklist

To enable the use of Historic Search in your instance of Caplin FX Sales, perform each of the tasks below:

  • Create an implementation of a search blotter listener

  • Create an implementation of a configuration provider

  • Grant user permissions

  • Enable Historic Search

For a working example of an adapter with a Historic Search implementation, see the Novo Trading Adapter example in the FX Integration API Kit (v3.50 or greater).

Implementing a search blotter provider

To implement a search blotter provider, follow the steps below:

  1. Create an implementation of the SearchBlotterListener interface:

    com.caplin.motif.fx.searchSearchBlotterListenerinitialise(BlotterConfiguration, BlotterItemFactory)searchChannelOpened(SearchBlotterChannel, SearchExpression)searchChannelClosed(SearchBlotterChannel)MySearchBlotterListenerinitialise(BlotterConfiguration, BlotterItemFactory)searchChannelOpened(SearchBlotterChannel, SearchExpression)searchChannelClosed(SearchBlotterChannel)
  2. In your implementation’s searchChannelOpened method, perform the following tasks:

    1. Refering to the SearchExpression parameter, build a query to a source of historical data (for example, a database). For more information see Search expression syntax and Parsing a search expression.

    2. For each trade returned by your query, create a blotter item using the BlotterItemFactory instance passed to your implementation in the initialise method. Publish each blotter item with the SearchBlotterChannel.sendBlotterItem method.

  3. Register your implementation of SearchBlotterListener with an instance of FXTradeBlotterAdapter:

    FXTradeBlotterAdapter blotterAdapter = new FXTradeBlotterAdapter(dataSource);
    blotterAdapter.registerSalesExecutionSearchBlotterListener(
        new MySearchBlotterListener());

Search expression syntax

The Historic Search subject takes the following format:

/PRIVATE/FX/SALES/BLOTTER/SEARCH/EXECUTION/searchFilter=search_expression

The search_expression is a string with the following format:

image/svg+xml ( field == != >= <= > < value ) & |
Boolean operators (in order of precedence)
Operator Description

&

Logical AND

|

Logical OR

Comparators
Comparator Description

==

Equals

!=

Not Equals

>=

Greater Than or Equal To

<=

Less Than or Equal To

>

Greater Than

<

Less Than

Example search subjects:

  • /PRIVATE/FX/SALES/BLOTTER/SEARCH/EXECUTION/searchFilter=Status==Completed

  • /PRIVATE/FX/SALES/BLOTTER/SEARCH/EXECUTION/searchFilter=Status==Completed&(Amount>1000&Amount<=2000)

Parsing a search expression

The FX Integration API parses the search expression and passes it to the SearchBlotterListener.searchChannelOpened method as a parse tree of SearchExpression objects.

com.caplin.motif.fx.searchSearchExpressionSearchExpression.Type getType()String getText()SearchOperator getOperator()SearchComparator getComparator()SearchExpression getLeft()SearchExpression getRight()SearchOperatorANDORSearchComparatorEQGTGTELTLTENESearchExpression.TypeCOMPARATOROPERATORTEXT
SearchExpression class and associated enumerators

Each node in the tree is one of three types:

  • SearchExpression.Type.OPERATOR: a boolean operator (AND, OR)

  • SearchExpression.Type.COMPARATOR: a comparator (==, !=, <, >, <=, >=)

  • SearchExpression.Type.TEXT: a string operand (a field name or a field value)

For example, the parse tree for the search expression Field1=ABCDE&Field2>=1000 would be as follows:

«SearchExpression»node1type = OPERATORoperator = AND«SearchExpression»node2type = COMPARATORcomparator = EQ«SearchExpression»node3type = COMPARATORcomparator = GTE«SearchExpression»node4type = TEXTtext = "Field1"«SearchExpression»node5type = TEXTtext = "ABCDE"«SearchExpression»node6type = TEXTtext = "Field2"«SearchExpression»node7type = TEXTtext = "1000"leftrightleftrightleftright
Parse tree for the search expression "Field1==ABCDE&Field2>=1000"

You can use the SearchExpression parse tree to build a query to a source of historical data. The example below shows a recursive method that builds a WHERE clause for a SQL query. To keep the example simple, the method makes the following assumptions:

  • Trading history is stored in one database table

  • Database column names are identical to FX Sales field names

  • All columns are string types (TEXT, VARCHAR, CHAR, …​)

Building a WHERE clause from a SearchExpression parse tree
private String buildWhereClause(SearchExpression se, String tableName)
{
    StringBuilder sb = new StringBuilder();
    switch (se.getType()) {
        case OPERATOR:
            switch (se.getOperator()) {
                case AND:
                    sb.append("(");
                    sb.append(buildWhereClause(se.getLeft(), tableName));
                    sb.append(" AND ");
                    sb.append(buildWhereClause(se.getRight(), tableName));
                    sb.append(")");
                    break;
                case OR:
                    sb.append("(");
                    sb.append(buildWhereClause(se.getLeft(), tableName));
                    sb.append(" OR ");
                    sb.append(buildWhereClause(se.getRight(), tableName));
                    sb.append(")");
                    break;
            }
            break;
        case COMPARATOR:
            String fieldName = se.getLeft().getText();
            String fieldValue = se.getRight().getText();
            sb.append(tableName).append(".").append(fieldName);
            switch (se.getComparator()) {
                case EQ:
                    sb.append("==");
                    break;
                case NE:
                    sb.append("!=");
                    break;
                case GTE:
                    sb.append(">=");
                    break;
                case LTE:
                    sb.append("<=");
                    break;
                case GT:
                    sb.append(">");
                    break;
                case LT:
                    sb.append("<");
                    break;
            }
            sb.append("'").append(fieldValue).append("'");
            break;
        case TEXT:
            break;
    }
    return sb.toString();
}

Implementing a search configuration provider

The Historic Search user interface includes a query builder panel above the search results blotter:

historic search overview
Historic Search user interface

The query builder is rendered automatically based on search field meta-data provided by the FX Integration API’s Configuration Service.

To provide search field meta-data to FX Sales, see Implementing the Configuration Service in the FX Integration API documentation.

Granting permissions

To allow a user to request Historic Search subjects, grant the user (or a group the user belongs to) the following permissions in the global namespace:

Historic Search permission
Field Description

Action

VIEW

Product

^/PRIVATE/%u/FX/SALES/BLOTTER/SEARCH/EXECUTION/.*

Namespace

Authorisation

ALLOW

Filtered Historic Search permission
Field Description

Action

VIEW

Product

^/FILTER/PRIVATE/%u/FX/SALES/BLOTTER/SEARCH/EXECUTION/.*

Namespace

Authorisation

ALLOW

For instructions on granting users permission to access the FX Integration API’s Configuration Service, see Implementing the Configuration Service.

Caplin FX Sales uses Caplin’s Permissioning Service to authenticate and authorise users. For more information on the Caplin Permissioning Service and the terms used in the tables above, see Caplin Platform Architecture > Permissioning.

By default, the Historic Search feature is disabled. To enable this feature in FX Sales, set the the configuration option HISTORIC_SEARCH.ENABLED to the boolean value true.


See also: