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
  1. In Financial Model Builder, create a Java class file in src > main > java > tutorial_package, and name it Tutorial_portfolio.
  2. 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
  1. In Financial Model Builder, create a box file in src > main > resources > library > boxes, and name it tutorial_Portfolio.
  2. 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
  1. In Financial Model Builder, create a workflow file in src > main > resources > library > workflows, and name it tutorial_Portfolio.
  2. 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
  1. In Financial Model Builder, create a document file in src > test > resources >documents, and name it tutorial_PortfolioInput.
  2. 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"  
}
  1. In the pasted code, replace <your_project> with the appropriate project name.

Execute the Workflow in the Financial Model Builder Editor

  1. In Financial Model Builder, click Run > Run Configuration to launch the FPP Launch Configuration window.
  2. 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
Fig. 94: Workflow configuration.

Fig. 94: Workflow configuration.

  1. 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.
Fig. 95: Workflow results.

Fig. 95: Workflow results.

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

  1. In Financial Model Builder deploy your libraries.
  2. 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
  3. Set up your connection.
  4. 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.
Fig. 96: Execute the workflow tab with inputIncluded set to false.

Fig. 96: Execute the workflow tab with inputIncluded set to false.

  1. (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.
Fig. 97: Execute the workflow tab with inputIncluded set to true.

Fig. 97: Execute the workflow tab with inputIncluded set to true.

  1. 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.
Fig. 98: Workflow results in editor.

Fig. 98: Workflow results in editor.

The results are the same as in the Execute the workflow and see the results section.