Compute the Portfolio Valuation
In this section you will work with Financial Model Builder and Microsoft Excel to do the following:
- Create the files required for the computation: the Java class, the box that will call the Java class, the workflow to price the portfolio, and the input file for the workflow.
- Execute the workflow and display the results in both Financial Model Builder and Microsoft Excel.
Create the files
Java Class
You build your application using a Financial Model Builder workflow based on a Java class that will manage the input and the post processing of the results. The class you are building accepts two types of input, containing:
- The path to the document file and the pricing data, when saved locally.
- The merged content of the document and pricing data file.
The indicator inputIncluded
identifies the type of input.
To create the Java Class
- In Financial Model Builder, create a Java class file in src > main > java > tutorial_package, and name it
Tutorial_portfolio
. - Open the newly created Java class file, and replace its content with the following code:
package tutorial_package;
import java.io.File;
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.trmsys.fpp.api.result.*;
import com.trmsys.fpp.api.document.*;
import com.trmsys.fpp.api.rest.ProcessingData;
import java.util.Map;
import java.util.List;
public class Tutorial_portfolio {
public static ObjectMapper mapper = new ObjectMapper();
public static ArrayNode tradeNode;
public static ArrayNode shifts;
public static ProcessingData pricingData;
public static Boolean inputIncluded;
public static Boolean shiftsIncluded;
public static void init(String value) throws IOException {
// Read value, put it in an valueNode node
final ObjectNode valueNode = (ObjectNode) mapper.readTree(value);
/*
// Check shifts information
shiftsIncluded = valueNode.get("shiftsIncluded").asBoolean();
if (shiftsIncluded){
shifts = (ArrayNode) valueNode.get("shifts");
}
*/
// Check Plugin
inputIncluded = valueNode.get("inputIncluded").asBoolean();
if (inputIncluded){
// Extract trades as ArrayNode
tradeNode = (ArrayNode) valueNode.get("documents");
// JSON converted to ProcessingData Java object
pricingData = mapper.readValue(valueNode.get("pricingData").toString(), ProcessingData.class);
}
else {
// Extract trades as ArrayNode
tradeNode = (ArrayNode) mapper.readTree(new File(valueNode.get("pathDoc").textValue()));
// JSON converted to ProcessingData Java object
pricingData = mapper.readValue(new File(valueNode.get("pathPricingData").textValue()),ProcessingData.class);
}
}
public static ArrayNode outputResults(Map<String, Result> res, List<JsonDocument> doc) throws IOException {
final ArrayNode results = mapper.createArrayNode();
for (final JsonDocument it : doc) {
ObjectNode docresults = mapper.createObjectNode();
docresults.put("dealStamp", it.getId());
docresults.put("typeOfDeals", it.getData().get("typeOfDeals").toString());
docresults.put("currency", it.getData().get("currency").toString());
docresults.put("counterparty", it.getData().get("counterparty").toString());
final Result result = res.get(it.getId());
docresults.set("NPV", mapper.readTree(result.toString()));
results.add(docresults);
}
return results;
}
}
Box and Workflow
The workflow is composed of one box that receives the input file and output the results.
To find out more about Financial Model Builder workflow, see Workflow Reference
To create the box
- In Financial Model Builder, create a box file in src > main > resources > library > boxes, and name it
tutorial_Portfolio
. - Open the newly created box file, and paste the following code:
import tutorial_package.Tutorial_portfolio;
// Inputs management
def request(value) {
Tutorial_portfolio.init(value)
}
def timeini = System.currentTimeMillis()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create the dataManager from the pricingData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DataManager dataManager = DataManagerRestUtils.create(Tutorial_portfolio.pricingData)
//Results Object mapper
def mapper = new ObjectMapper()
final ObjectNode resultsFinal = mapper.createObjectNode()
/*
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Scenario generation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
def aod = Tutorial_portfolio.pricingData.getDates()[0].toLocalDate().toEpochDay()
def toZC(value,aod,paydate){
if (aod == paydate) return 0
return -100 * Math.log(value) * 365 / (paydate-aod)
}
def toDF(value,aod,paydate){
return Math.exp(-(value / 100) * (paydate-aod) / 365)
}
def scenCount = 0
if (Tutorial_portfolio.shiftsIncluded) {
def shifts = Tutorial_portfolio.shifts
ArrayNode scenariiType = mapper.createArrayNode()
ArrayNode scenariiShift = mapper.createArrayNode()
shifts.each{
def scenariiList = []
def type = it.get("type").textValue()
def steps = it.get("steps").intValue()
def min = it.get("min").doubleValue()
def max = it.get("max").doubleValue()
def stepSize = (max - min) / steps
def param1 = it.get("param1").textValue()
def param2 = it.get("param2").textValue()
for (int j in 0 .. Tutorial_portfolio.pricingData.getScenarioData().size()-1) {
def scenarioData = Tutorial_portfolio.pricingData.getScenarioData()[j]
if (scenarioData.getId().getType()== "YIELD_CURVE" && scenarioData.getId().getParameters()[0] == param1 && scenarioData.getId().getParameters()[1] == param2) {
scenCount = steps + 2
scenarioData.getPoints().values().each {
for (final DataPoint s : it){
def value = new double [scenCount]
value[0] = s.values[0]
for (int i = 0; i < steps+1; i++){
value[i + 1] = toDF(toZC(s.values[0],aod,s.x) * (1 + (min + i * stepSize) / 100),aod,s.x)
}
scenariiList.add(new ScenarioValues(ScenarioIdentifier.create(type, [param1,param2]), Point.of(s.x), value))
}
scenariiType.add("YC_" + param1)
scenariiShift.add("0 % (base)")
for (int i = 0; i < steps+1; i++){
scenariiType.add("YC_" + param1)
scenariiShift.add((min + i * stepSize).round(6) + " %")
}
}
}
}
dataManager.addScenarios(scenariiList)
}
resultsFinal.put("type",scenariiType)
resultsFinal.put("shift",scenariiShift)
}
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Register the documents assigning them a script
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
documents = []
Tutorial_portfolio.tradeNode.each {
def id = it.get("dealStamp").asText()
documents.add(new JsonDocument(it.get("script").asText(), it, id))
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Run the execution (returns a non ordered map of results)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
resultById = engine().buildSession(dataManager)
.process(documents)
.collect()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Prepare output
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
def timefinal = System.currentTimeMillis()
if (Tutorial_portfolio.shiftsIncluded) {
double pvPerSecond = scenCount*documents.size()*1000.0/(timefinal-timeini)
resultsFinal.put("timeSpent", pvPerSecond.round() + " PVs per second")
}
*/
resultsFinal.put("results",Tutorial_portfolio.outputResults(resultById, documents))
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Output the result
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
output("results",mapper.writeValueAsString(resultsFinal))
close("results")
This box uses the Tutorial_portfolio
Java class to process the input, get the pricing data and output the results.
To create the workflow
- In Financial Model Builder, create a workflow file in src > main > resources > library > workflows, and name it
tutorial_Portfolio
. - Open the newly created workflow file, switch to the File tab, and paste the following code:
{
"links": [
{
"destinationBox": "tutorial_Portfolio",
"destinationEndPoint": "request"
},
{
"originBox": "tutorial_Portfolio",
"originEndPoint": "results"
}
]
}
Input File
Since the document and the pricing data files have been saved locally as explained in Prepare the Portfolio Data, this file contains only the path to these two files and the indicator inputIncluded
set to false
.
To create the input file
- In Financial Model Builder, create a document file in src > test > resources >documents, and name it
tutorial_PortfolioInput
. - Open the newly created document file, and paste the following code:
{
"inputIncluded": false,
"pathDoc": "/projects/<your_project>/src/test/resources/documents/tutorial_Portfolio.json",
"pathPricingData": "/projects/<your_project>/src/test/resources/pricingData/tutorial_Portfolio.scn"
}
- In the pasted code, replace
<your_project>
with the appropriate project name.
Execute the Workflow in the Financial Model Builder Editor
- In Financial Model Builder, click Run > Run Configuration to launch the FPP Launch Configuration window.
- Click New workflow to create a workflow configuration, with the following options:
- Configuration name:
tutorial_Portfolio
- Library:
fpp-library
- Workflow name:
tutorial_Portfolio
- tutorial_Portfolio request:
tutorial_PortfolioInput.json
- Configuration name:
- Click Save, and then click Run. The configuration runs and the results show the dealStamp, typeOfDeals, currency, counterparty and net present value for each document.
Execute the Workflow in REST mode
In this section you will do the following:
- Use the Microsoft Excel Valuation Plugin to call the
tutorial_Portfolio.workflow
in REST mode. - Switch the
inputIncluded
indicator to send either dynamic or stored input.
Execute the workflow in Microsoft Excel
- In Financial Model Builder deploy your libraries.
- Download the following Excel file: tutorial_PortfolioValuation_App.xlsm. This file contains
one sheet where you execute and see the results from the workflow and three sheets with information that you can send dynamically:
- Option Documents
- IRS Documents
- Pricing Data
- Set up your connection.
- Set inputIncluded to
false
, and then click on the Recompute All button located on the Valuation ribbon. The input is the same as in the Create the input file section, it only contains the paths to the files saved in Financial Model Builder.
- (Optional) Set inputIncluded to
true
, and then click Recompute All. The input is dynamically created based on the information from the worksheets and sent by Valuation Plugin.
- To see the results, select the results reference and either click
Open JSON in Editor
from the Valuation ribbon or right-click to use the contextual menu.
The results are the same as in the Execute the workflow and see the results section.