Workflow Files

Workflow Input

In the input file tutorial_MCOptions, you provide the request that contains the number of paths to be simulated, the deal information about your option and the pricing data needed to compute the price.

{
  "documents": [
    {
      "paths": 10000,
      "type": "call",
      "strike": 43,
      "maturity_date": "2019-04-25",
      "value_date": "2017-04-13",
      "dealStamp": "COCA_COLA",
      "stockdata": {
        "name": "COCA_COLA",
        "instrument": "EQUITY",
        "currency": "USD"
      },
      "curve": "projection_Libor_3M"
    }
  ],
  "pricingData": {
    "dates": [
      "2017-04-13"
    ],
    "scenarioData": [
      {
        "id": {
          "type": "Volatility",
          "parameters": [
            "COCA_COLA"
          ]
        },
        "points": {
          "2017-04-13": [
            {
              "values": [
                0.0221
              ]
            }
          ]
        },
        "metaData": {}
      },
      {
        "id": {
          "type": "DIVIDEND",
          "parameters": [
            "COCA_COLA",
            "CONTINUOUS"
          ]
        },
        "points": {
          "2017-04-13": [
            {
              "values": [
                0.01
              ]
            }
          ]
        },
        "metaData": {}
      },
      {
        "id": {
          "type": "EQUITY",
          "parameters": [
            "COCA_COLA"
          ]
        },
        "points": {
          "2017-04-13": [
            {
              "values": [
                46
              ]
            }
          ]
        }
      },
      {
        "id": {
          "parameters": [
            "projection_Libor_3M",
            "discountFactor"
          ],
          "type": "YIELD_CURVE"
        },
        "metaData": {
          "currency": "USD",
          "interpolationMethods": [
            "flat"
          ],
          "interpolationVariables": [
            "discountFactor"
          ],
          "switchDates": [],
          "zeroCouponBasis": "ACT/365.FIXED",
          "zeroCouponFormula": "exponential"
        },
        "points": {
          "2017-04-13": [
            {
              "values": [
                1
              ],
              "x": 17269
            },
            {
              "values": [
                0.99943
              ],
              "x": 17294
            },
            {
              "values": [
                0.99886
              ],
              "x": 17319
            },
            {
              "values": [
                0.99829
              ],
              "x": 17344
            },
            {
              "values": [
                0.99772
              ],
              "x": 17369
            },
            {
              "values": [
                0.99715
              ],
              "x": 17394
            },
            {
              "values": [
                0.99658
              ],
              "x": 17419
            },
            {
              "values": [
                0.99629
              ],
              "x": 17444
            },
            {
              "values": [
                0.99601
              ],
              "x": 17469
            },
            {
              "values": [
                0.99572
              ],
              "x": 17494
            },
            {
              "values": [
                0.99544
              ],
              "x": 17519
            },
            {
              "values": [
                0.99515
              ],
              "x": 17544
            },
            {
              "values": [
                0.99486
              ],
              "x": 17569
            },
            {
              "values": [
                0.99458
              ],
              "x": 17594
            },
            {
              "values": [
                0.99403
              ],
              "x": 17619
            },
            {
              "values": [
                0.99347
              ],
              "x": 17644
            },
            {
              "values": [
                0.99292
              ],
              "x": 17669
            },
            {
              "values": [
                0.99236
              ],
              "x": 17694
            },
            {
              "values": [
                0.99181
              ],
              "x": 17719
            },
            {
              "values": [
                0.99125
              ],
              "x": 17787
            }
          ]
        }
      }
    ]
  }
}

Workflow and Box

In the workflow, the tutorial_MCOptions box is called with the input request and three outputs: closedFormula, sequential, parallel.

Fig. 91: The tutorial_MCOptions workflow.

Fig. 91: The tutorial_MCOptions workflow.

The content of the tutorial_MCOptions box is given below. This box calls 3 different workflows.

Several functions from the FPP Javadoc are leveraged.

// Input management
def request(input){
    // Create a jackson Object mapper
    mapper = new ObjectMapper();
    // Read the input, put it in valueNode
    valueNode = mapper.readTree(input);
    // Extract the document part from node
    docNode = valueNode["documents"][0]
    // Extract the pricing data part from node
    pricingDataNode = valueNode["pricingData"]
    // JSON converted to ProcessingData Java object
    pricingData = mapper.readValue(pricingDataNode.toString(), ProcessingData.class)
    // Extract the dates part from node   
    dates = pricingData.getDates()
}

////////////////////////////////////////////////////////////////////////// 
//////      closedFormula: Using the tutorial_EUadvanced script     //////
////////////////////////////////////////////////////////////////////////// 

// Create the dataManager from the pricingData
DataManager dataManager = DataManagerRestUtils.create(pricingData) 

// Run the script on the deal named "tutorial_EUadvanced"
def closedFormula = engine().buildSession(dataManager).process("tutorial_EUadvanced",  docNode.toString(),"tutorial_EUadvanced").collect()

// Check no error occured
if (closedFormula["tutorial_EUadvanced"].hasError())   
    output("closedFormula",closedFormula["tutorial_EUadvanced"].errors().toString());
else
    // Output results
    output("closedFormula", closedFormula["tutorial_EUadvanced"].get(0,0))
    close("closedFormula")

////////////////////////////////////////////////////////////////////////// 
//////      sequential: Using the tutorial_MCSequential script      //////
////////////////////////////////////////////////////////////////////////// 

// Run the script on the deal named "tutorial_MCSequential"
def sequential = engine().buildSession(dataManager).process("tutorial_MCSequential",  docNode.toString(),"tutorial_MCSequential").collect()
// Check no error occured
if (sequential["tutorial_MCSequential"].hasError())   
    output("sequential",sequential["tutorial_MCSequential"].errors().toString());
else
    // Output results
    output("sequential", sequential["tutorial_MCSequential"].get(0,0))
    close("sequential")

////////////////////////////////////////////////////////////////////////// 
//////      parallel: Using the tutorial_MCParallel script          //////
////////////////////////////////////////////////////////////////////////// 

// Retrieve number of paths
def paths = docNode.get("paths").intValue()

// Generate random numbers
def mt = new MersenneTwister(engine().configuration().seed())
def randoms = new double[paths]
for (int i = 0; i < randoms.length; ++i)
    randoms[i] = mt.nextGaussian()

// Create the ID to access the data. An ID has a type and a list of scenario identifiers
def id = ScenarioIdentifier.create("RANDOM", [])

// Create a ScenarioValues object that holds parallel data
def parallelValues = new ScenarioValues(id, Point.of(), randoms)

// Create the dataManager 
def dataManagerExtended = new DataManager(paths, dates)

// Populate the dataManager with the pricingData and automatically extend it to paths
DataManagerRestUtils.populate(dataManagerExtended, pricingData)  

// Add the randoms values
dataManagerExtended.addScenarios([parallelValues])

// Run the script on the deal named "tutorial_MCParallel"
def parallel = engine().buildSession(dataManagerExtended).process("tutorial_MCParallel",  docNode.toString(), "tutorial_MCParallel").collect()

// Check no error occured
if (parallel["tutorial_MCParallel"].hasError())   
    output("parallel",parallel["tutorial_MCParallel"].errors().toString())
else{
    // Compute the mean of the results and send it to next box
    def sum = 0
    def scalarRes = parallel["tutorial_MCParallel"]
    for(i = 0; i < scalarRes.scenarioCount(); ++i)
        sum += scalarRes.get(i, 0)
    
    // Output the result
    output("parallel", sum / parallel["tutorial_MCParallel"].scenarioCount())
    close("parallel")
    }

Monte-Carlo Simulations Scripts

tutorial_EUadvanced script

The tutorial_EUadvanced script is the same used in European Options Advanced Tutorial. In this case, no simulations are performed to compute the price of the option because the script uses a closed form formula.

tutorial_MCSequential script

The content of the tutorial_MCSequential script is given below. The loop for the simulated paths is defined into the script.

By default, the number of loops can reach 50 000. This is made on purpose to encourage the use of the parallelization aproach.

// time to expiry as a fraction of a year with basis 365
def tau = yearFraction(value_date, maturity_date, "ACT/365.FIXED", YearFractionParameters()) 
// spot price
def S = getEquitySpot(stockdata.name, calculationDate())
// continuously compounded dividend yield
def D = data0D("DIVIDEND", [stockdata.name, "CONTINUOUS"], calculationDate())
// risk-free interest rate
def r = forwardRate(calculationDate(), maturity_date, metaData("YIELD_CURVE", [curve, "discountFactor"], "zeroCouponBasis"), YearFractionParameters(), curve)
// volatility
def vol = data0D("Volatility", [stockdata.name], calculationDate())

// retrieve the number of paths
def n = paths
def sum = 0
// retrieve the type of option
def CP = getOptionType(type)
// create the loop for the Montecarlo values
for(def i = 0; i < n; i++){
    // define the normally distributed (0,1) variable
    def brownian = gaussianRand()
    // compute the payoff of the option using antithetic variables
    def payoff1 = max(0,(CP * S * exp((r - D - vol * vol / 2) * tau + brownian * vol * sqrt(tau)))- CP * strike)
    def payoff2 = max(0,(CP * S * exp((r - D - vol * vol / 2) * tau - brownian * vol * sqrt(tau)))- CP * strike)
    sum +=  (payoff1 + payoff2) / 2     
}
// compute the mean of the simulated prices
def mean = sum / n
// return the present value of the option 
return exp(-r * tau) * mean   

tutorial_MCParallel script

The content of the tutorial_MCParallel script is given below. It corresponds to the simulation along one path. Recall that all paths are called in parallel.

// time to expiry as a fraction of a year with basis 365
def tau = yearFraction(value_date, maturity_date, "ACT/365.FIXED", YearFractionParameters()) 
// spot price
def S = getEquitySpot(stockdata.name, calculationDate())
// continuously compounded dividend yield
def D = data0D("DIVIDEND", [stockdata.name, "CONTINUOUS"], calculationDate())
// risk-free interest rate
def r = forwardRate(calculationDate(), maturity_date, metaData("YIELD_CURVE", [curve, "discountFactor"], "zeroCouponBasis"), YearFractionParameters(), curve)
// volatility
def vol = data0D("Volatility", [stockdata.name], calculationDate())

// get the normally distributed (0,1) variable
def brownian = data0D("RANDOM", [], calculationDate())

// compute the payoff of the option using antithetic variables
def CP = getOptionType(type)
def payoff1 = max(0,(CP * S * exp((r - D - vol * vol / 2) * tau + brownian * vol * sqrt(tau))) - CP * strike)
def payoff2 = max(0,(CP * S * exp((r - D - vol * vol / 2) * tau - brownian * vol * sqrt(tau))) - CP * strike)
def totalpayoff = (payoff1 + payoff2) / 2 

// return the present value of the option 
return exp(-r * tau) * totalpayoff