FX Integration API upgrade guide: v2 to v3

The document provides guidance on migrating from version 2 to version 3 of the FX Integration API.

Contents:

Requirements

The FX Integration API v3 requires Java 8.

Breaking changes

Breaking changes have been introduced in the following components:

Blotter API

The FX Integration API now uses the DataSource Blotter API, com.caplin.datasource.blotter, included in the Caplin Integration Suite. The old Blotter API, com.caplin.motif.fx.blotter, has been removed.

The DataSource Blotter API offers developers the following advantages over the old Blotter API:

For a detailed guide to using the DataSource Blotter API, see Blotter Integration API.

Trading API

The ESP and RFS trading API is now generated directly from the ESP and RFS trade model XML. The API is now more streamlined, consistent, and easier to use.

The packages com.caplin.motif.fx.trading.esp and com.caplin.motif.fx.trading.rfs have been replaced by com.caplin.generated.motif.fx.trading.esp and com.caplin.generated.motif.fx.trading.rfs respectively.

The Novo Adapter examples provide an overview of how to use the new API.

Most of the generated classes retain the same name as the classes they replace, but there are some significant differences:

Trade model XML

To enable the ESP and RFS trading API to be generated directly from trade model XML, the trade model XML specification has been expanded to include field definitions for transitions.

Field definitions are defined using the <field> element, a child of the <transition> element:

<tradeModels>
    <tradeModel name="ESP" initialState="Initial">
        <state name="Initial">
            <transition target="Submitted" trigger="Submit" source="client" utilities="ESPTradeUtilities.vm">
                <field name="CurrencyPair"
                    description="The currency pair for the trade..."/>
                <field name="DealtCurrency"
                    description="The dealt currency for the trade (what the amount is expressed in)..."/>
                ⋮
            </transition>
        </state>
        ⋮
    </tradeModel>
    ⋮
</tradeModels>

See the table below for the attributes of the new <field> element.

<field> attributes
Attribute Mandatory Default Value Description
name Yes   The name of the field.
isLegField No false Set to true to allow the field name to be prefixed by a leg prefix "Ln_", where n is a leg number.
required No true Fields are required by default. Set to false to define the field as optional.
description Yes   A description of the field.
isDeprecated No false Set to true to mark the field as deprecated.

Rates

Almost all classes and interfaces in the package com.caplin.motif.fx.rates have been replaced by classes in the new com.caplin.generated.motif.fx.rates package.

Quotes, such as com.caplin.generated.motif.fx.rates.QuoteTypesDef.SwapQuote, now implement the com.caplin.motif.fx.common.Message interface. Messages supply a map of fields (key-value pairs). Pricing events, such as com.caplin.generated.motif.fx.trading.rfs.events.server.PriceUpdateTradeEvent, accept a Message object as a constructor argument.

The quote builders have been re-designed to simplify the building of complex quotes. There is now one builder for swap quotes, removing the need for conditional branching to handle spot-forward swaps and forward-forward swaps. All quotes are built from smaller parts, each one of which implements the Message interface and supplies a subset of the final quote's fields. Each quote part has its own builder, with explicit setter methods for each field. Unlike in version 2, there are no calculated quote fields in version 3 — you must explicitly set each field.

Custom fields are now set on the pricing event object, as opposed to the quote builder.

To browse the different quotes and quote parts available in the FX Integration API, see com.caplin.generated.motif.fx.rates.

Code examples

The code examples in this section compare the old and the new API. For more detailed examples, see the Novo Adapter Examples in the FX Integration API Kit.

Building a swap quote

This section compares building a swap quote using version 2 and version 3 of the FX Integration API.

Building a swap quote (FX Integration API 2)

// The following two variables need to be passed into your method.
boolean firstQuote = null;
FXSwapType fxSwapType = null; 

// Declare the quote, and instantiate in one of the following blocks based on type
FXQuote quote = null;

SwapFields swapFields = SwapFieldsBuilder.create()
    .swapAskPips("askSwapPips")
    .swapRawAskPoints("rawAskSwapPips")
    .swapBidPips("bidPips")
    .swapRawBidPoints("rawBidSwapPips")
    .build();

if( FXSwapType.SPOTFWD == fxSwapType)
{
    SwapSpotQuote nearSpotQuote = SwapSpotQuoteBuilder.createNearLegBuilder()
        .bidRate("bidSpotRate")
        .askRate("askSpotRate")
        .build();
    
    SwapFwdQuote farFwdQuote = SwapFwdQuoteBuilder.createFarLegBuilder()
        .askRate("askSpotRate", "askAllInPrice", "farAskPips")
        .bidRate("bidSpotRate", "bidAllInPrice", "farBidPips")
        .build();
    
    quote = new SwapQuote("bidQuoteId", "askQuoteId", 
            nearSpotQuote, farFwdQuote, swapFields);
}
else if(FXSwapType.FWDFWD == fxSwapType)
{
    SwapFwdQuote nearFwdQuote = SwapFwdQuoteBuilder.createNearLegBuilder()
        .askRate("askSpotRate", "askAllInRate", "nearAskPips")
        .bidRate("bidSpotRate", "bidAllInRate", "nearBidPips")
        .build();
    
    SwapFwdQuote farFwdQuote = SwapFwdQuoteBuilder.createFarLegBuilder()
        .askRate("askSpotRate", "askAllInRate", "nearAskPips")
        .bidRate("bidSpotRate", "bidAllInRate", "nearBidPips")
        .build();
    
    quote = new SwapQuote("bidQuoteId", "askQuoteId", 
            nearFwdQuote, farFwdQuote, swapFields);
}

if (firstQuote)
{
    firstQuote = false;
    int timeout = 120;
    rfsTrade.getPickedUpResponder().sendPriceUpdate(quote, timeout);
}
else
{
    rfsTrade.getExecutableResponder().sendPriceUpdate(quote);
}

Building a swap quote (FX Integration API 3)

CommonFields commQuoteFields = CommonFields.newBuilder()
        .setOverallTimeOut("overallTimeout")
        .setBidQuoteID("bidQuoteID")
        .setAskQuoteID("quoteID")
        .setTimePriceReceived("timePriceRecieved")
        .setSpotRateDPS("spotRateDPS")
        .setSpotBidRate("bidSpotRate")
        .setSpotAskRate("askSpotRate")
        .setDigitsBeforePips("numberOfDigitsBeforePips")
        .setNumberOfPips("numberOfPips")
        .setSwapGFA("swapGFA")
        .setBidPips("bidPips")
        .setAskPips("askPips")
        .build();

LegFields nearLegFields = LegFields.newBuilder()
        .setTenor("nearTenor")
        .setSettlementDate("nearSettlementDate")
        .setAllInRateDPS("nearAlInRateDps")
        .setAllInAskRate("nearAllInAskRate")
        .setAllInBidRate("nearAllInBidRate")
        .setFwdAskPoints("nearFwdAskPoints")
        .setFwdBidPoints("nearFwdBidPoints")
        .build();

LegFields farLegFields = LegFields.newBuilder()
        .setTenor("farTenor")
        .setSettlementDate("farSettlementDate")
        .setAllInRateDPS("farAlInRateDps")
        .setAllInAskRate("farAllInAskRate")
        .setAllInBidRate("farAllInBidRate")
        .setFwdAskPoints("farFwdAskPoints")
        .setFwdBidPoints("farFwdBidPoints")
        .build();

SwapQuoteFields swapFields = SwapQuoteFields.newBuilder()
        .setSwapAskPoints("askSwapPoints")
        .setSwapBidPoints("bidSwapPoints")
        .build();

SwapQuote swapQuote = SwapQuote.newBuilder()
        .setCommonFields(commQuoteFields)
        .setNearLegFields(nearLegFields)
        .setFarLegFields(farLegFields)
        .setSwapFields(swapFields)
        .build();

PriceUpdateTradeEvent priceUpdateTradeEvent =
        new PriceUpdateTradeEvent(rfsTrade, swapQuote);

priceUpdateTradeEvent.addField("custom_field_name_a", "custom_field_value_a");
priceUpdateTradeEvent.addField("custom_field_name_b", "custom_field_value_b");

rfsTrade.sendPriceUpdateEvent(priceUpdateTradeEvent);

Building a sales swap-quote

This section compares building a sales swap-quote using version 2 and version 3 of the FX Integration API.

Building a sales swap quote (FX Integration API 2)

// The following two variables need to be passed into your method
Boolean firstQuote = null;
FXSwapType fxSwapType = null; 

// Declare the quote, and instantiate in one of the following blocks based on type
FXQuote quote = null;

SwapFields swapFields = SwapFieldsBuilder.create()
    .swapAskPips("askSwapPips")
    .swapRawAskPoints("rawAskSwapPips")
    .swapBidPips("bidPips")
    .swapRawBidPoints("rawBidSwapPips")
    .build();

SalesSwapFields salesSwapFields = SalesSwapFieldsBuilder.create()
        .defaultSwapAskMargin("defaultSwapAskMargin")
        .defaultSwapBidMargin("defaultSwapBidMargin")
        .swapFields(swapFields)
        .build();

if( FXSwapType.SPOTFWD == fxSwapType)
{
    SwapSpotQuote nearSpotQuote = SwapSpotQuoteBuilder.createNearLegBuilder()
        .bidRate("bidSpotRate")
        .askRate("askSpotRate")
        .build();
    
    SalesSwapLegQuote nearSalesSwapSpotQuote = SalesSwapSpotQuoteBuilder.create()
        .swapSpotQuote(nearSpotQuote)
        .defaultSpotAskMargin("defaultSpotAskMargin")
        .defaultSpotBidMargin("defaultSpotBidMargin")
        .build();
    
    SwapFwdQuote farFwdQuote = SwapFwdQuoteBuilder.createFarLegBuilder()
        .askRate("askSpotRate", "askAllInPrice", "farAskPips")
        .bidRate("bidSpotRate", "bidAllInPrice", "farBidPips")
        .build();
    
    SalesSwapLegQuote farSalesSalesSwapFwdQuote = SalesSwapFwdQuoteBuilder.create()
        .swapFwdQuote(farFwdQuote)
        .defaultSpotAskMargin("defaultSpotAskMargin")
        .defaultSpotBidMargin("defaultSpotBidMargin")
        .build();
    
    quote = new SalesSwapQuote("bidQuoteId", "askQuoteId", 
            nearSalesSwapSpotQuote, farSalesSalesSwapFwdQuote, salesSwapFields);
}
else if(FXSwapType.FWDFWD == fxSwapType)
{
    SwapFwdQuote nearFwdQuote = SwapFwdQuoteBuilder.createNearLegBuilder()
        .askRate("askSpotRate", "askAllInRate", "nearAskPips")
        .bidRate("bidSpotRate", "bidAllInRate", "nearBidPips")
        .build();
    
    SalesSwapLegQuote nearSalesSalesSwapFwdQuote = SalesSwapFwdQuoteBuilder.create()
        .swapFwdQuote(nearFwdQuote)
        .defaultSpotAskMargin("defaultSpotAskMargin")
        .defaultSpotBidMargin("defaultSpotBidMargin")
        .build();
    
    SwapFwdQuote farFwdQuote = SwapFwdQuoteBuilder.createFarLegBuilder()
        .askRate("askSpotRate", "askAllInRate", "nearAskPips")
        .bidRate("bidSpotRate", "bidAllInRate", "nearBidPips")
        .build();
    
    SalesSwapLegQuote farSalesSalesSwapFwdQuote = SalesSwapFwdQuoteBuilder.create()
        .swapFwdQuote(farFwdQuote)
        .defaultSpotAskMargin("defaultSpotAskMargin")
        .defaultSpotBidMargin("defaultSpotBidMargin")
        .build();

    quote = new SalesSwapQuote("bidQuoteId", "askQuoteId", 
            nearSalesSalesSwapFwdQuote, farSalesSalesSwapFwdQuote, salesSwapFields);

}

if (firstQuote)
{
    firstQuote = false;
    int timeout = 120;
    rfsTrade.getPickedUpResponder().sendPriceUpdate(quote, timeout);
}
else
{
    rfsTrade.getExecutableResponder().sendPriceUpdate(quote);
}

Building a sales swap-quote (FX Integration API 3)

The code sample below is dependent on the swapQuote object generated by the code in the Building a swap quote (FX Integration API 3) section above.

SalesCommonFields salesCommonFields = SalesCommonFields.newBuilder()
        .setDefaultSpotAskMargin("spotAskMargin")
        .setDefaultSpotBidMargin("spotBidMargin")
        .setTraderSpotAskRate("traderSpotAskRate")
        .setTraderSpotBidRate("traderSpotBidRate")
        .setProfitCurrency("profitCurrency")
        .setProfitAskRate("profitAskRate")
        .setProfitBidRate("profitBidRate")
        .setProfitCurrencyDPS("profitCurrencyDPS")
        .build();

SalesLegFields nearSalesLegFields = SalesLegFields.newBuilder()
        .setDefaultFwdAskMargin("nearLegFwdAskMargin")
        .setTraderAllInAskRate("nearLegTraderAllInAskRate")
        .setTraderFwdAskPoints("nearLegTraderFwdAskPoints")
        .setDefaultFwdBidMargin("nearLegFwdBidMargin")
        .setTraderAllInBidRate("nearLegTraderAllInBidRate")
        .setTraderFwdBidPoints("nearLegTraderFwdBidPoints")
        .build();

SalesLegFields farSalesLegFields = SalesLegFields.newBuilder()
        .setDefaultFwdAskMargin("farLegFwdAskMargin")
        .setTraderAllInAskRate("farLegTraderAllInAskRate")
        .setTraderFwdAskPoints("farLegTraderFwdAskPoints")
        .setDefaultFwdBidMargin("farLegFwdBidMargin")
        .setTraderAllInBidRate("farLegTraderAllInBidRate")
        .setTraderFwdBidPoints("farLegTraderFwdBidPoints")
        .build();

SalesSwapQuoteFields salesSwapFields = SalesSwapQuoteFields.newBuilder()
        .setDefaultSwapAskMargin("swapAskMargin")
        .setDefaultSwapBidMargin("swapBidMargin")
        .setTraderSwapBidPoints("traderSwapBidPoints")
        .setTraderSwapAskPoints("traderSwapAskPoints")
        .build();

SalesSwapQuote salesSwapQuote = SalesSwapQuote.newBuilder()
        .setSwapQuote(swapQuote)
        .setSalesCommonFields(salesCommonFields)
        .setNearSalesLegFields(nearSalesLegFields)
        .setFarSalesLegFields(farSalesLegFields)
        .setSalesSwapFields(salesSwapFields)
        .build();

PriceUpdateTradeEvent priceUpdateTradeEvent =
        new PriceUpdateTradeEvent(rfsTrade, salesSwapQuote);

priceUpdateTradeEvent.addField("custom_field_name_a", "custom_field_value_a");
priceUpdateTradeEvent.addField("custom_field_name_b", "custom_field_value_b");

rfsTrade.sendPriceUpdateEvent(priceUpdateTradeEvent);