Skip to main content

ALM app: improving the front end

Now we can tidy up and improve some elements of the GUI to make things look a bit nicer.

The majority of this section will see changes made in the front-end folder, which is found under ALM/client.

Fixing capitalisation on front-end grids

Genesis Create saves with coding case, rather than visual case.

So, to start, let's do something very easy. We shall update some of the names in the front-end grid.

  1. Open the file ALM\client\src\routes\config.ts.

  2. Change the capitalisation of the tab names (titles) in the GUI:

        //Replace the following lines
title: 'Fx blotter',
title: 'Sourced trades',
//with
title: 'FX Blotter',
title: 'Sourced Trades',

Remove zero values from the position grid

info

OK, we are actually going to change the back-end code here - but don't tell anyone.

  1. Open the file ALM\server\ALM-app\src\main\genesis\scripts\ALM-reqrep.kts.

  2. Replace the POSITION request reply with the where clause, as below:

requestReply(POSITION) {
where { row, parameters ->
row.amount != 0.0
}
}

Formatting on positive/negative numbers

The code snippet below will make positive numbers green and negative numbers red.

  1. In the folder ALM\client\src\utils, create a new file called util-formatters.ts.

  2. Add the code below to the file. (We'll need to use this function in a few other files later on.):

export function cellStyle(params){
if(params.value > 0){
return {color: '#7ACC79'}
}else if (params.value < 0){
return {color: '#F9644D'}
} else {
return {color: '#FFFFFF'}
}
};

Format the columns

Now insert this function into some of the column selections.

  1. Open the file ALM\client\src\routes\sourced-trades\loans-manager\loans.column.defs.ts.

  2. To include this new function add the following import statement to the top of the file:

import { cellStyle } from '../../../utils/util-formatters';
  1. Under the PAYMENT_AMOUNT column description, add the below code snippet:
cellStyle: (params) => cellStyle(params),

The PAYMENT_AMOUNT section should now look like this:

  {
field: "PAYMENT_AMOUNT",
valueFormatter: getNumberFormatter("0,0.00", null),
cellStyle: (params) => cellStyle(params),
},
  1. Do the same for DRAW_DOWN_AMOUNT in the same resource file:
  {
field: "DRAWDOWN_AMOUNT",
valueFormatter: getNumberFormatter("0,0.00", null),
cellStyle: (params) => cellStyle(params),
},
  1. Make similar changes in the file ALM\client\src\routes\sourced-trades\c-ds-manager\c-ds.column.defs.ts.

Adjust the import statement and add the same line to DEPOSIT_AMOUNT and MATURITY_AMOUNT:

import { cellStyle } from '../../../utils/util-formatters';
...
{
field: "MATURITY_AMOUNT",
valueFormatter: getNumberFormatter("0,0.00", null),
cellStyle: (params) => cellStyle(params),
},
...
{
field: "DEPOSIT_AMOUNT",
valueFormatter: getNumberFormatter("0,0.00", null),
cellStyle: (params) => cellStyle(params),
},

Format the positions grid

We can also add this function to the positions grid.

  1. Open the file ALM\client\src\routes\fx-blotter\position-grid\position.gridOptions.ts.

  2. Add the import statement in the same way as you did before:

import { cellStyle } from '../../../utils/util-formatters';
  1. Within the AMOUNT column definition, add:
cellStyle: (params) => cellStyle(params)

The block should look like this:

  {
field: "AMOUNT",
valueFormatter: getNumberFormatter("0,0.00", null),
cellStyle: (params) => cellStyle(params),
},

Improving the Trade Entry/Modify pop ups

By default, the trade entry screens in our application are displayed in a vertical list. When we have many fields, this can be difficult to navigate. We can change this through the template.

  1. In the folder ALM\client\src\routes\fx-blotter\fx-trades-manager\, adjust the forms for creating and updating an FX Trade.

Edit both fx-trades.create.form.schema.ts and fx-trades.update.form.schema.ts, replacing "type": "VerticalLayout", with:

"type": "LayoutVertical2Columns",
tip

If you are replacing the whole line, make sure to keep the comma at the end of this line.

Pivot positions

Let’s create a consolidated view of your FX trades.

To do this, we need to create a new custom element and replace the existing grid pro. This new element will subscribe to a stream from the consolidator output table and transform the output.

This class will subscribe to the new ALL_POSITIONS stream. It will transform the array and group trades by date and create an aggregate daily amount for each currency.

It will also dynamically update the column definitions on the grid so that there is a column for each currency.

  1. Create your new custom element in a new file: client/src/components/positions-grid.ts. Add the content below.
import { customElement, FASTElement, html, ref } from '@microsoft/fast-element';
import { Connect } from '@genesislcap/foundation-comms';
import { getDateFormatter, getNumberFormatter } from '@genesislcap/foundation-utils';
import { GridPro } from '@genesislcap/rapid-grid-pro';
import { cellStyle } from '../utils/util-formatters';

@customElement({
name: 'positions-grid',
template: html<PositionsGrid>`
<rapid-grid-pro
${ref('grid')}
@onGridReady="${(x, e) => x.onGridReady(e)}"
>
</rapid-grid-pro>
`
})
export class PositionsGrid extends FASTElement {

@Connect connect!: Connect;

grid: GridPro;

connectedCallback() {
super.connectedCallback();
this.grid.gridOptions = {};
}

onGridReady(e): void {
this.connect.stream('ALL_POSITIONS', async () => {
const rows = await this.getPositionsData();
const currencies = this.getAllCurrenciesFromStream(rows);
const colDefs = this.createColDefs(rows, currencies);
const rowData = this.mapRowData(rows, currencies)
this.grid.gridApi.setColumnDefs(colDefs);
this.grid.gridApi.setRowData(rowData)
}, console.error);
}

async getPositionsData() {
const message = await this.connect.request('POSITION')
return message?.REPLY;
}

private mapRowData(message: any[], currencies: string[]): any[] {
if (!message) {
return [];
}

const rowMap: { [key: string] : any } = message.reduce((acc, row) => {

const { SETTLEMENT_DATE, AMOUNT, CURRENCY } = row;

if (!acc[SETTLEMENT_DATE]) {
acc[SETTLEMENT_DATE] = {
settlementDate: SETTLEMENT_DATE,
[CURRENCY]: AMOUNT
}
} else {
const existingValue = acc[SETTLEMENT_DATE][CURRENCY] !== undefined ? acc[SETTLEMENT_DATE][CURRENCY] : 0;
acc[SETTLEMENT_DATE][CURRENCY] = existingValue + AMOUNT
}

return acc;

}, {});

return Object.keys(rowMap).map(key => rowMap[key]).sort((a,b) => a.settlementDate > b.settlementDate ? 1 : -1);
}

private getAllCurrenciesFromStream(message: any[]): string[] {

if (!message) {
return [];
}

return message.reduce((currencies: string[], row) => {
const { CURRENCY } = row;
if (!currencies.includes(CURRENCY)) {
currencies.push(CURRENCY)
}

return currencies;
}, []);
}

private createColDefs(message: any[], currencies: string[]) {

const colDefs: any[] = [
{
field: "settlementDate",
headerName: "Settlement Date",
hide: false,
valueFormatter: getDateFormatter("en-GB", {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}
]

if (!message || message.length) {
currencies.forEach(c => {
colDefs.push({
field: c,
headerName: c,
hide: false,
type: 'rightAligned',
valueFormatter: getNumberFormatter("0,0.00", null),
cellStyle: (params) => cellStyle(params)
})
});

return colDefs;
}

}
}
  1. Add your new custom element to the client/src/components/components.ts.

This ensures that the browser knows how to render it. To do this, add two lines to the top of the file, as shown below:

import { EntityManagement } from '@genesislcap/foundation-entity-management';
import { Form } from '@genesislcap/foundation-forms';
import { foundationLayoutComponents } from '@genesislcap/foundation-layout';
import { getApp } from '@genesislcap/foundation-shell/app';
import { FoundationRouter } from '@genesislcap/foundation-ui';
import * as zeroDesignSystem from '@genesislcap/foundation-zero';
import { g2plotChartsComponents } from '@genesislcap/g2plot-chart';
import * as rapidDesignSystem from '@genesislcap/rapid-design-system';
import { rapidGridComponents } from '@genesislcap/rapid-grid-pro';
import { NotPermittedComponent } from './not-permitted-component';
import { PositionsGrid } from './positions-grid';

/**
* Ensure tree shaking doesn't remove these.
*/
FoundationRouter;
EntityManagement;
Form;
NotPermittedComponent;
PositionsGrid;

  1. Update your route template in client/src/routes/fx-blotter/fx-blotter.template.ts; find the rapid-layout-item for Position:
            <rapid-layout-item title="Position">
<fx-blotter-position-grid></fx-blotter-position-grid>
</rapid-layout-item>

... and replace it with the following code:

 <rapid-layout-item title="Positions">
<positions-grid></positions-grid>
</rapid-layout-item>
  1. Add the following to the imports:
import { PositionsGrid } from '../../components/positions-grid';
  1. Add PositionsGrid to the lines just below:
FxBlotterFxTradesManager;
FxBlotterPositionGrid;
FxBlotterRatesGrid;
PositionsGrid;

This will use the positions grid we added in the new positions-grid.ts file.

Adding a new chart

We won't be inputting loan data until we deal with data from external sources. However, it would be useful to set up currency conversion on the loan pie chart so that it displays all data in a single currency, in this case GBP.

We'll do this using the FX_RATE table that we created.

Update the back end

  1. Go to the back-end code, inside ALM/server. We need to add a new view to provide data for this chart.

  2. Open the file ALM\server\ALM-app\src\main\genesis\cfg\ALM-view-dictionary.kts.

  3. Add the code below, which defines a view joining LOAN_TRADE to the latest FX_RATE.

  view("LOAN_PAYMENTS_GBP", LOAN_TRADE) {
joins {
joining(FX_RATE) {
on(LOAN_TRADE.PAYMENT_CURRENCY to FX_RATE { SOURCE_CURRENCY })
.and(FX_RATE { TARGET_CURRENCY } to "GBP")
}
}

fields {
derivedField("PAYMENT_AMOUNT", DOUBLE) {
withInput(LOAN_TRADE.PAYMENT_AMOUNT, FX_RATE.RATE) { amount, rate ->
if (amount == null || rate == null) amount
else amount * rate
}
}
LOAN_TRADE.CLIENT_NAME
LOAN_TRADE.PAYMENT_CURRENCY
}
}
  1. In the file ALM\server\ALM-app\src\main\genesis\scripts\ALM-dataserver.kts, add a new query to towards the end of the file. This enables the front end to query this data.
  query("LOAN_PAYMENTS_GBP", LOAN_PAYMENTS_GBP) {
fields {
PAYMENT_AMOUNT
CLIENT_NAME
PAYMENT_CURRENCY
}
}

Update the front end

  1. Go to the front-end code inside ALM\client.

  2. Open the file ALM\client\src\routes\sourced-trades\sourced-trades.template.ts and find the following section:

             <rapid-layout-item title="Loans by Client">
  1. Modify this to the following to change the title in the front end:
             <rapid-layout-item title="Loans by Client - GBP">
  1. In the file ALM\client\src\routes\sourced-trades\loans-by-client-chart\loans-by-client.template.ts, adjust the chart-datasource to use the new data server and field:
                   <chart-datasource
resourceName="LOAN_PAYMENTS_GBP"
server-fields="CLIENT_NAME PAYMENT_AMOUNT"
></chart-datasource>
  1. In the file ALM\client\src\routes\sourced-trades\sourced-trades.template.ts, add a third chart, showing GBP Equivalent currency exposure from the loans. To do this, add this rapid layout item between the loan chart rapid layout item and the CD chart rapid layout item:
             <rapid-layout-item title="Loans by Currency - GBP Equivalent">
<rapid-g2plot-chart
type="bar"
:config="${(x) => ({
xField: 'value',
yField: 'groupBy',
seriesField: 'groupBy',
barWidthRatio: 0.8,
})}"
>
<chart-datasource
resourceName="LOAN_PAYMENTS_GBP"
server-fields="PAYMENT_CURRENCY PAYMENT_AMOUNT"
></chart-datasource>
</rapid-g2plot-chart>
</rapid-layout-item>

We can also make the FX Blotter look a bit neater by changing the layout slightly. In ALM\client\src\routes\fx-blotter\fx-blotter.template.ts, just before the position rapid layout item lines add:

         <rapid-layout-region type="vertical"> //LINE TO ADD
<rapid-layout-item title="Position">

Then close the region at the end of the Rates rapid-layout-item block:

         </rapid-layout-item>
</rapid-layout-region> //LINE TO ADD
</rapid-layout-region>
</rapid-layout>
Checking your work

You can view a final version of the code for the ALM app, including all the modifications outlined in this guide, in the ALM app repository.