Sample formulas
Name - descriptive name.
Category - general category as to which the number relates to, for example Performance, Risk, Basic.
Description - short description of what the result is saying and its use-case.
Formula - the full code of the working formula.
Name | Category | Description | Formula |
---|---|---|---|
Recovery Rate | Performance | Days until next highest peak in period after a Maximum Drawdown. Return value represented in days. | import com.fasolutions.data.dto.analytics.IndexedReturnDataDTO; import java.time.* def orig = new IndexedReturnDataDTO() orig.setIndexValueLowest(100d); orig.setIndexValueHighest(100d); orig.setMaxDrawdown(0d); double previousIndexedValue = 0.0 double highAfterMdd = 0.0 LocalDate mddTroughDate = LocalDate.now() LocalDate recoveryDate = LocalDate.now() int daysAfterMdd = 0 if(data){ data.each{ date,ird -> if(mddTroughDate == null) mddTroughDate = date if(recoveryDate == null) recoveryDate = date if( ird.getIndexedValue() != 0 ) { if( ird.getIndexedValue() < orig.getIndexValueLowest() ) { orig.setIndexValueLowest( ird.getIndexedValue()); } if( ird.getIndexedValue() > orig.getIndexValueHighest() ) { orig.setIndexValueHighest( ird.getIndexedValue()); } orig.setDrawdown(ird.getIndexedValue() / orig.getIndexValueHighest() - 1 ); if( orig.getDrawdown() < orig.getMaxDrawdown() ){ orig.setMaxDrawdown(orig.getDrawdown()); mddTroughDate = date daysAfterMdd = 0 highAfterMdd = ird.getIndexedValue() } else { if(ird.getIndexedValue() > previousIndexedValue ){ highAfterMdd = ird.getIndexedValue() daysAfterMdd += 1 recoveryDate = date } } } previousIndexedValue = ird.getIndexedValue() } } return daysAfterMdd |
Monthly Volatility | Risk | Monthly volatility as defined by the standard deviation of monthly observations. | import com.fasolutions.analytics.* import com.fasolutions.data.analytics.* def monthlyData = AnalyticsUtil.monthlyData(data) def monthlyIndexedValueChanges = [] def prev double monthlyVolatility = 0.0 monthlyData.each { k,v -> if( prev != null ) { monthlyIndexedValueChanges << v.indexedValue / prev.indexedValue - 1 } prev = v } if(!monthlyIndexedValueChanges?.isEmpty()) monthlyVolatility = AnalyticsUtil.stats(monthlyIndexedValueChanges as double[]).standardDeviation * Math.sqrt(12) return monthlyVolatility |
Key Figure | Utility | Showcase of how to retrieve any key figure from the security object in the context. In this case the “CO2” key figure on date 2018-01-01 Can be used in other formulas by replacing the key and date. | import java.time.LocalDate import com.fasolutions.data.dto.analytics.CustomColumnValueDTO String returnString = "" if(security){ CustomColumnValueDTO customColumnValue = security.getKeyFigureValue("CO2",LocalDate.of(2018,1,1)) if(customColumnValue != null) returnString = customColumnValue.getDefaultValue() } return returnString |
Market Value (sec) | Basic | Market value of position/group in its local currency. | double marketValueSec = 0.0d; if(Double.compare( analytics.marketFxRate, 0.0d ) == 0) marketValueSec = analytics.marketValue else marketValueSec = analytics.marketFxRate * analytics.marketValue return marketValueSec |
Custom Total Profit | Example | For illustrative/example purposes. Example how to get total profits from the subtree attached to every GrouppedAnalytics with a formula. Note that since the formula sums up values from its children, it only works on group levels! Therefore you need to use the Apply formula also on group level aggregation setting. | import com.fasolutions.analytics.GrouppedAnalytics import com.fasolutions.data.dto.analytics.IndexedReturnDataDTO; import java.time.LocalDate import java.util.NavigableMap double profitFromSubtree = 0.0d //value to return = total profits (realized+unrealized+other) //Sub-tree of underlying GrouppedAnalytics levels wrt current level Map<String,GrouppedAnalytics> subGrouppedAnalyticsTree = ga?.subGrouppedAnalyticsTree //Navigate all underlying groups (e.g. securities) subGrouppedAnalyticsTree?.each{ orderedCode, subGrouppedAnalytics -> //Get underlying data for current group and navigate the daily positions NavigableMap<LocalDate,IndexedReturnDataDTO> dataFromGA = subGrouppedAnalytics?.getData() dataFromGA?.each{ date,ird -> profitFromSubtree += ird.dSoldProfit + ird.dValueChange + ird.dProfit //realized+unrealized+other } } return profitFromSubtree |
TWR Gross | Testing / Reconciliation | For testing purposes when changes are done to TWR. Can be modified and used in future changes to TWR calculation | import com.fasolutions.data.dto.analytics.IndexedReturnDataDTO import java.util.NavigableMap import com.fasolutions.math.var.Tools import java.lang.Math double twrGross = 0.0d; if (data) { IndexedReturnDataDTO sIrd = ((NavigableMap)data).firstEntry()?.getValue() IndexedReturnDataDTO eIrd = ((NavigableMap)data).lastEntry()?.getValue() double previousIndexedValue = 100.0d; double previousGrossIndexedValue = 100.0d; double previousCostIndexedValue = 100.0d; double grossMarketValueStart = sIrd.getMarketValueStart(); data?.each{ date, ird -> double startMarketValue = ird.getMarketValueStart() + ird.getPosNetCashflow(); double baseMarketValue = Math.abs(startMarketValue); double grossIndexedValueChangeDaily = 0; double dailyCosts = 0d; if( baseMarketValue != 0 ) { dailyCosts = ird.getdCost() + ird.getdOtherCost() + ird.getdImplicitCost(); grossIndexedValueChangeDaily = Tools.change2logYield(dailyCosts, baseMarketValue); if (Double.isInfinite(grossIndexedValueChangeDaily )) { grossIndexedValueChangeDaily = 0; } } double grossMarketValue = grossMarketValueStart + ird.getdMarketValue() + ird.getdCost() + ird.getdOtherCost() + ird.getdImplicitCost() // replace implicit with ird.getdTotalExPostSecCosts() to get previous method double dGrossMarketValue = grossMarketValue - grossMarketValueStart double costIndexedValue = previousCostIndexedValue + Tools.logYield2perYield(grossIndexedValueChangeDaily) * previousIndexedValue; //replace previousIndexedValue with 100.0d to get previous method (as of 2020-04-15) double grossIndexedValue = ird.getIndexedValue() + costIndexedValue - 100d ; previousIndexedValue = ird.getIndexedValue(); previousGrossIndexedValue = grossIndexedValue previousCostIndexedValue = costIndexedValue grossMarketValueStart = grossMarketValue } twrGross = previousGrossIndexedValue / 100.0d - 1; } return twrGross |
Options Call Delta | Options/Template | Template for calcuating Black-Scholes Option Greeks using Normal distribution from stats library. Can be configured and extended to fetch strike price, rate and/or price of underlying via other components such as key figures | import com.fasolutions.math.stat.Normal import java.time.LocalDate; import java.time.temporal.ChronoUnit //Components double price_underlying, strike, time, volatility, rate //input double d1, d2, p1, p2, pdf1, pdf2 //calcs double deltac, deltap, gamma, vega //output //Vars needed strike = 100.0 //could be retrieved with security?.maturityPrice price_underlying = analytics?.marketUnitPrice volatility = analytics?.volAnn rate = 0.01 //1 % //Date range - also needed LocalDate fromDate = analytics?.startDate //analytics?.marketUnitPriceDate or endDate LocalDate toDate = analytics?.endDate //security?.callDate if(fromDate && toDate) { //Calculate time float years = fromDate?.until(toDate, ChronoUnit.DAYS) / 365.2425f time = (double)years //Main params calculation double priceOverStrike = strike != 0.0 ? price_underlying.div(strike) : price_underlying d1 = ( Math.log(priceOverStrike) + time * (rate + Math.pow(volatility,2))?.div(2) )?.div(volatility*Math.sqrt(time)) d2 = d1 - volatility*Math.sqrt(time); p1 = Normal.cdf(d1); p2 = Normal.cdf(d2); pdf1 = Normal.pdf(d1); pdf2 = Normal.pdf(d2); //Call/Put price callprice = price_underlying*Math.exp(time*(rate))*p1 - strike*Math.exp(-rate*time)*p2; //putprice = strike*Math.exp(-rate*time)*Normal.cdf(-d2) - price_underlying*Math.exp(time*(rate))*Normal.cdf(-d1); //Greeks calculation deltac = Math.exp(time*(rate))*p1; //deltap = Math.exp(time*(rate))*(p1-1); //gamma = pdf1*Math.exp(time*(rate))/(price_underlying*volatility*Math.sqrt(time)); //vega = price_underlying*Math.exp(time*(rate))*pdf1*Math.sqrt(time); } return deltac |
Key Figure | Utility | Showcase of using a key figure in calculation | import java.time.LocalDate import com.fasolutions.data.dto.analytics.CustomColumnValueDTO double delta = 0.0 //value to return double marketValue = analytics?.marketValue //value to use in calculation //Assume Delta is some value stored on security level CustomColumnValueDTO customColumnValue = security?.getKeyFigureValue("Delta") if(customColumnValue != null){ delta = customColumnValue.getDoubleValue() * marketValue //use in calc } return delta |
TWR (pre 3.8) | Reconciliation | Showcase of how TWR is calculated for non-future instruments in version before FA 3.8 Can be used to test and reconcile TWR (and was in FA 3.8 testing when method changed) | import com.fasolutions.data.dto.analytics.IndexedReturnDataDTO import java.util.NavigableMap import com.fasolutions.math.var.Tools import java.lang.Math double twrOrig = 0.0d; if (data) { IndexedReturnDataDTO sIrd = ((NavigableMap)data).firstEntry()?.getValue() IndexedReturnDataDTO eIrd = ((NavigableMap)data).lastEntry()?.getValue() double previousIndexedValue = 100.0d; double marketValueStart = sIrd.getMarketValueStart(); data?.each{ date, ird -> double startMarketValue = ird.getMarketValueStart() + ird.getPosNetCashflow(); double baseMarketValue = Math.abs(startMarketValue); double indexedValueChangeDaily = ird.getIndexedValueChange(); double dailyTotalProfitAndLoss = ird.getdMarketValue() -ird.getNegNetCashflow() - ird.getPosNetCashflow(); if( baseMarketValue != 0 ) { indexedValueChangeDaily = Tools.change2logYield(dailyTotalProfitAndLoss,baseMarketValue); } else { indexedValueChangeDaily = 0; } if (Double.isInfinite(indexedValueChangeDaily)) { indexedValueChangeDaily = 0; } double indexedValue = Tools.logYield2value(indexedValueChangeDaily, previousIndexedValue); previousIndexedValue = indexedValue } twrOrig = previousIndexedValue / 100.0d - 1; } return twrOrig |
Money Weighted Return | Performance | Money weighted return retrieved from Internal Rate of Return (IRR) and scaled to the holding period. Note that IRR is only calculated when the column is selected or when using | import java.time.LocalDate; import java.time.temporal.ChronoUnit; double mwr = 0.0d double investmentPeriod = 0.0d; double daysInYear = 365.0d; //Start/End by default position-based LocalDate startDate = analytics.startDate LocalDate endDate = analytics.endDate if(startDate && endDate) investmentPeriod = ChronoUnit.DAYS.between(startDate, endDate) / daysInYear if(investmentPeriod > 0) mwr = Math.pow(1+analytics.irr, investmentPeriod) - 1 //(1+IRR)^(t/365) -1 return mwr |