var cc = analytics.customcolumn;
var today = cc.yymmdd(cc.calcdate());
var numSimsPerPeriod = 100;
var guiMode = false; //set guiMode to true when testing your model in the editor
if (guiMode) {
var portname = "BillRainbow";
var port = positions.loadPortfolio(portname);
var hold = port.holdings[0];
var greeks = hold.callModelFunction(RainbowOptionModel);
}
function RainbowOptionModel(inputs) {
log(inputs);
let outputGreeks = {};
let spot = inputs.underlyingPrice;
let strike = inputs.strike;
let vol = inputs.volatility;
let t = inputs.interestDays / 365;
let r = inputs.domesticRate;
let expDate = inputs.expirationDate;
let asofDate = inputs.asofDate;
let monteSimGenerator = analytics.createMonteModelSimGenerator("LinearCongruentialShuf");
let numFactors = inputs.underlyingInputs.length;
let financeInputMain = inputs.domesticFinanceCurve || inputs.domesticRate;
//example of retrieving pricing inputs
let financeInput1 = inputs.underlyingInputs[0].financeCurve || inputs.underlyingInputs[0].domesticRate;
let divInput1 = inputs.underlyingInputs[0].dividendTable || inputs.underlyingInputs[0].dividendYield;
let undPrice1 = inputs.underlyingInputs[0]['underlyingPrice'];
//add the factors to the monteSimGenerator:
for (let i = 0; i < numFactors; ++i) {
let factorSym = inputs.underlyingInputs[i].refSymbol;
monteSimGenerator.addFactor(factorSym, "lognormal");
monteSimGenerator.setYieldCurve(factorSym, inputs.underlyingInputs[i].financeCurve); // finance curve
// monteSimGenerator.setBorrowCurve( factorSym, inputs.underlyingInputs[i].borrowCurve );
// we want a constant dividend yield so we will extract the yield first and set it directly to the sim generator
let divCurve = inputs.underlyingInputs[i].dividendTable;
let spot = inputs.underlyingInputs[i].underlyingPrice;
let divYield = divCurve.estimatedYield({
startDate: asofDate,
endDate: expDate,
price: spot,
yc: "USD"
});
//or set the div curve directly: divYield = inputs.underlyingInputs[i].dividendTable || inputs.underlyingInputs[i].dividendYield;
monteSimGenerator.setDividendCurve(factorSym, divYield);
volInput = (inputs.underlyingInputs[i].strikeVolCurve ? inputs.underlyingInputs[i].strikeVolCurve.getVol({ //if strikeVolCurve exists, determine the volitility using expiration date and strike values
expiry: expDate,
side: 'mid',
strike: spot // * strike/100
}) : inputs.underlyingInputs[i].volatility);
//when using 'local' vol lookup, point to strike vol surface instead of fixed vol... and update tools, preferences, data, market data to use a parametric interpolation setting
//volInput = (inputs.underlyingInputs[0].strikeVolCurve ? inputs.underlyingInputs[0].strikeVolCurve : inputs.underlyingInputs[0].volatility);
monteSimGenerator.setVolatilityCurve(factorSym, volInput);
monteSimGenerator.setVolatilityLookupType(factorSym, "atm"); // we can also use the 'local volatility' lookup
monteSimGenerator.setInitialValue(factorSym, spot);
}
monteSimGenerator.setPeriodEndDates([expDate]);
monteSimGenerator.setAsofDate([asofDate]);
monteSimGenerator.setAsofTime(inputs.asofTime);
monteSimGenerator.setNumberOfSimulationsPerPeriod(numSimsPerPeriod);
monteSimGenerator.setCorrelationFunction(getCorrelation);
//Setting the Grid Size allows us to generate sub-paths to be used for calculating the Greeks
monteSimGenerator.setFactorGridSize(3);
monteSimGenerator.setFactorGridSpacingPercent(1);
var simulations = monteSimGenerator.getSimulations();
// calculate payout
let payout = inputs.payout;
let simWeight = 1.0 / numSimsPerPeriod;
let totalPayout = [];
for (let i = 0; i < numFactors; ++i) {
totalPayout.push([0,0,0]);
}
for (let sim = 0; sim < numSimsPerPeriod; ++sim) {
let payoutOnSim = [];
for (let i = 0; i < numFactors; ++i) {
if (payout == "Best of Assets") {
payoutOnSim.push([-1.0e6,-1.0e6,-1.0e6]);
} else {
payoutOnSim.push([1.0e6,1.0e6,1.0e6]);
}
}
let periodIndex = 0; // only one period
//format of simulated prices is: simulations[factorSym][sim][subPath][periodIndex];
for (let idx = 0; idx < numFactors; ++idx) {
for (let factor = 0; factor < numFactors; ++factor) {
let factorSym = inputs.underlyingInputs[factor].refSymbol;
let endingPeriodValue = [];
for (let i = 0; i < numFactors; ++i) {
endingPeriodValue.push([0,0,0]);
}
for (let subpath = 0; subpath < 3; ++subpath) {
// only apply subpath to one asset for calculating delta
endingPeriodValue[idx][subpath] = (factor == idx) ? simulations[factorSym][sim][subpath][0] / inputs.underlyingInputs[factor].level : simulations[factorSym][sim][1][0] / inputs.underlyingInputs[factor].level;
if (payout == "Best of Assets") {
if (endingPeriodValue[idx][subpath] > payoutOnSim[idx][subpath]) payoutOnSim[idx][subpath] = endingPeriodValue[idx][subpath];
} else {
if (endingPeriodValue[idx][subpath] < payoutOnSim[idx][subpath]) payoutOnSim[idx][subpath] = endingPeriodValue[idx][subpath];
}
}
}
// add payoff of each simulation to total
for (let subpath = 0; subpath < 3; ++subpath) {
totalPayout[idx][subpath] += payoutOnSim[idx][subpath] * simWeight;
}
}
}
let discountFactorFromExpiry = inputs.domesticFinanceCurve.getDiscountFactor(asofDate, expDate);
for (let idx = 0; idx < numFactors; ++idx) {
for (let subpath = 0; subpath < 3; ++subpath) {
totalPayout[idx][subpath] = (inputs.putCall == "Call") ? Math.max(totalPayout[idx][subpath] - strike/100, 0.0) : Math.max(strike/100 - totalPayout[idx][subpath], 0.0);
}
}
let mydelta = [];
let mygamma = [];
for (let i = 0; i < numFactors; ++i) {
let tmpUPrice = inputs.underlyingInputs[0]['underlyingPrice'];
mydelta.push(discountFactorFromExpiry * (totalPayout[i][2] - totalPayout[i][0]) / (0.02 * tmpUPrice));
mygamma.push(discountFactorFromExpiry * (totalPayout[i][0] + totalPayout[i][2] - 2 * totalPayout[i][1]) / (0.0001 * Math.pow(tmpUPrice, 2)));
}
outputGreeks.fair = totalPayout[0][1] * discountFactorFromExpiry;
// focus on fair for now
outputGreeks.delta = mydelta;
outputGreeks.gamma = mygamma;
// outputGreeks.vega = 0;
// outputGreeks.theta = 0;
// outputGreeks.dv01 = 0;
log("########################## RESULTS ##########################");
log(outputGreeks);
return outputGreeks;
}
function getCorrelation(days, syma, symb) {
return analytics.customcolumn.corr(days, syma, symb);
}
function getCurrentTime() {
return new Date().getTime();
}
function log(msg) {
if (guiMode) {
system.out.println(JSON.stringify(msg, null, '\t'));
};
}
exports['RainbowOptionModel'] = RainbowOptionModel;
Like this:
Like Loading...