The API can return the factor exposures, risk, and performance for a simulated portfolio, where the simulated portfolio can be passed-in as a positionSet. 

A position set for any one date or set of dates can be used to construct any hypothetical portfolios and emulate how these changes propagate forward as a backcast.

Learn more about Using Position Sets.

Coverage

Before getting started with modeled metrics, it is first important to understand which securities can be successfully mapped to a given risk model. Using the query.model.simulation.coverage node, a coverage report is generated that calculates the percentGMVAvailable for the securities in the position set. Additional nodes, such as missingEquities, missingSwaps , etc. also generates a list of securities that were not successfully mapped and its associated security ID. 

Using the security ID can help determine if the security ID included a typo, if the security ID exists on a particular date, if the security is a basket that has not yet been registered with the Omega Point platform, if the security was included in the wrong asset type, or if it is a security that is not covered by the risk model. 

Please note: since these are securities that are not mapped, the missingEquities, missingSwaps, etc. nodes will only return the information you provided in the first place.
Another note: Model data availability takes place on the following business day. For example, Looking at Aug 10 data is actually EOD Aug 9 data.

query ($modelId: String!, $positionSet: PositionSetInput!)
{
  model(id: $modelId) {
    simulation(positionSet: $positionSet) {    
      coverage (modelId: $modelId) {
        date
        summary {
          percentGmvAvailable
          percentGmvNotAvailable
        }
        missingEquities {
          id {
            ticker
            mic
            sedol
          }
          percentGmv
        }
      }
    }
  }
}

Exposure

Using a simple position set containing equal weights of Apple and Microsoft as an example, the below query demonstrates how to request exposures to Style factors on 2017-06-01 (the same date as the positionSet):

Query

query ($modelId: String!, $positionSet: PositionSetInput!)
{
  model(id: $modelId) {
    simulation(positionSet: $positionSet) {
      exposure {
        date
        factors(category: "Style") {
          id
          net
        }
      }
    }
  }
}

Variables

{
  "modelId": "xxxxx-xx",
  "positionSet": {
    "dates": [{
      "date": "2017-06-01",
      "equities": [
        {
          "id": {"ticker": "MSFT", "mic": "XNAS"},
          "economicExposure": 5000
        }, {
          "id": {"ticker": "AAPL", "mic": "XNAS"},
          "economicExposure": 5000
        }
      ]
    }]
  }
}

Running the above query should produce results similar to the following:

{
  "data": {
    "model": {
      "simulation": {
        "exposure": [
          {
            "date": "2017-06-01",
            "factors": [
              {
                "id": "DivYield",
                "net": 0.012956262
              },
...
              {
                "id": "Growth",
                "net": -0.08895331
              },
...
              {
                "id": "Size",
                "net": 0.9163455
              },
...
            ]
          }
        ]
      }
    }
  }
}


Exposure Backcast
Using the example from above and paired with simulation(to: $toDate) , a future date ahead of the position set can be used to obtain the backcasted exposure metrics -- and risk, performance. When using a future date, the position set is automatically propagated forward using data from the risk model.

Risk

Simulated risk can be requested by adding the risk field to the simulation. The example below outlines how to request the total risk, the breakdown of factor vs. specific risk, and the decomposition of each factor's risk contribution:

    simulation(positionSet: $positionSet) {
      ...
      risk {
        date
        total
        attribution {
          summary {
            factors
            specific
          }
          factors {
            name
            value
          }
        }
      }
      ...

Performance

Simulated performance can be requested by adding the performance field to the simulation.

Performance can be used to backcast any past positionSet to a specified date.  For example, passing in a positionSet  with one date can be paired with the to  input on a future date, and retrieving the performance metrics for the positionSet as an automatic position rollover  (i.e. backcast) to future dates.

The example below outlines how to request the total performance on a future to  date, and the breakdown of factor vs. specific performance, and the decomposition of each factor's performance contribution:

    simulation(positionSet: $positionSet, to: $toDate) {
      ...
      performance {
        date
        percentReturnCumulative {
          total
          attribution {
            summary {
              factors
              specific
            }
            factors {
              name
              value
            }
          }
        }
      }
      ...

Security Contributions

Security contributions to exposure, risk, and performance can all be requested as part of the simulation. The fields to be used are exposureContributors, riskContributors, and performanceContributors, respectively. The below example illustrates how to request the simulated security contributions to risk:

    simulation(positionSet: $positionSet) {
      ...
      riskContributors {
        id
        percentEquity
        total
        attribution {
          summary {
            factors
            specific
          }
          factors {
            id
            value
          }
        }
      }
      ...

Composition

The Composition API fuels portfolio position analysis, including powering all the position-level metrics made available in the composition screen. This position data can now be accessed via the query.model.portfolio.composition.positions endpoint.

This positions endpoint provides additional flexibility over the existing query.portfolio.positions endpoint. When used with the scaleFormat input, this allows you to specific how to calculate position sizing / concentration, as described below:

Scale Format

  • DEFAULT
    Returns position sizing in the default currency
  • PERCENT_GMV
    Returns position sizing as a percentage of GMV
  • PERCENT_MODELED_GMV
    Returns position sizing as a percentage of modeled GMV
  • PERCENT_EQUITY_GMV
    Returns position sizing as percentage of the provided equity, or as percentage of GMV if no equity provided
  • PERCENT_EQUITY_MODELED_GMV
    Returns position sizing as percentage of the provided equity, or as percentage of modeled GMV if no equity provided

Putting it all together, the below query would return daily position data — positions listed by SEDOL, and the respective economic exposure relative to GMV — for an entire month in a single call.

Query

{
model (id: "MODEL_ID") {
simulation(positionSet: { id: "PORTFOLIO_ID" type:PORTFOLIO }) {
# Composition API
composition (
from: "2019-06-01"
to: "2019-06-30"
scaleFormat: PERCENT_GMV
equityIdFormat: SEDOL
) {
positions{
id
economicExposure
}
summaryStats{
average{
marketCapitalization
}
}
}
}
}
}

This query can be used to capture large position deltas between dates, as well as, validate position ingestion into the Omega Point platform by comparing position size relative to GMV, Modeled GMV, or a provided Reference Equity.

This query also includes summary statistics, including returning the weighed market cap for any portfolio.

Also, when used in simulate, and in conjunction with a base benchmark (more details below) the API returns active position sizing in accordance to the scaleFormat set.

Query

{
model(id:"MODEL_ID"){
simulation(
positionSet:{
id:"PORTFOLIO_ID" type:PORTFOLIO
}
base:{
id:"BENCHMARK_ID" type:BENCHMARK
}
from:"2017-06-01" to:"2017-06-30"
){
composition(
scaleFormat:PERCENT_EQUITY_MODELED_GMV
){
date
concentration{
min
max
}
positions{
id
economicExposure
}
}
}
}
}

In this query, we return the position’s economic exposure, as well as the portfolio’s min / max concentration relative to the provided benchmark — as supplied by the base input. Since the scaleFormat parameter is set to PERCENT_EQUITY_MODELED_GMV, then each position’s active weight would be returned.

Base

You can run a simulation against a benchmark or other portfolio in order to request the active exposures, risk, and/or performance* (please see Benchmarks for more information on using benchmarks in the API).

*In the case for performance, the returned values can be understood as the difference of geometric sums over the selected time period. 

Taking our first query, we can modify it to use 50% S&P500 and 50% Russell 3000 as a custom benchmark, in order to return the active exposures:

Query

query(
  $modelId: String!,
  $positionSet: PositionSetInput!,
  $benchmark: [PositionSetInput!]
) {
  model(id: $modelId) {
    simulation(positionSet: $positionSet, base: $benchmark) {
      exposure {
        date
        factors(category: "Style") {
          id
          net
        }
      }
    }
  }
}

Variables

{
  "modelId": "xxxxx-xx",
  "positionSet": {
    "dates": [{
      "date": "2017-06-01",
      "equities": [
        {
          "id": {
            "ticker": "MSFT",
            "mic": "XNAS"
          },
          "economicExposure": 5000
        }, {
          "id": {
            "ticker": "AAPL",
            "mic": "XNAS"
          },
          "economicExposure": 5000
        }
      ]
    }]
  },
  "benchmark": [{
    "id":"SP500",
    "type":"BENCHMARK",
    "weight": 50
  }, {
    "id":"Russell3000",
    "type":"BENCHMARK",
    "weight": 50
  }]
}

We can see in the response that we are now receiving active exposures (as opposed to absolute exposures returned in the first example):

{
  "data": {
    "model": {
      "simulation": {
        "exposure": [
          {
            "date": "2017-06-01",
            "factors": [
              {
                "id": "DivYield",
                "net": -2.185651
              },
...
              {
                "id": "Growth",
                "net": 1.563076
              },
...
              {
                "id": "Size",
                "net": -16.589628
              },
...
            ]
          }
        ]
      }
    }
  }
}

Period Performance

The API returns total performance metrics that account for risk over for specified periods.

  • Annualized Volatility
    annualizedVolatility = stdDev(dailyPortfolioReturns) * sqRt(252) * 100
  • Max Drawdown
    The biggest decline from a peak to a trough for cumulative total returns in the selected date range, calculated as (cumulative return from trough - cumulative return from peak) / (1 + cumulative return from peak)
  • Information Ratio (Sharpe Ratio)
    informationRatio = avg(dailyPortfolioReturn - dailyRate) / stdDev(dailyPortfolioReturn - dailyRate)  

    Where dailyRate  is defined by the following three scenarios:

    1.  When the input parameter riskFreeRate is supplied with an annualized risk-free rate (rfr), then dailyRate = dailyRfr .
    2.  When simulation is used in conjunction with a base: $benchmark input, the dailyRate  is the dailyBenchmarkReturn (however, a rfr  will override this).
    3.  When no benchmark nor rfr is supplied, then the rfr -- and subsequently the dailyRate -- is assumed to be 0.
  • Sortino Ratio
    Defined as the downside information ratio, where when the stdDev(dailyReturns) > 0, then the positive value is replaced by 0.

These metrics are available under
query.model.portfolio.periodPerformance
query.model.simulation.periodPerformance
query.model.optimization.periodPerformance
 

Query

query(
  $modelId: String!,
  $positionSet: PositionSetInput!,
  $benchmark: [PositionSetInput!]
) {
  model(id: $modelId) {
    simulation(positionSet: $positionSet, base: $benchmark) {
      periodPerformance(riskFreeRate:0.10){
        annualizedVolatility
        maxDrawdown{
          drawdown
          from
          to
          daysBetween
        }
        informationRatio
        sortinoRatio
      }
    }
  }
}

*where periodPerformance(riskFreeRate)  takes in an annualized risk-free rate. When this input is used, it will override dailyBenchmarkReturn  as calculated by base: $benchmark .

Returns Correlation

The Pearson Correlation measuring the linear correlation between return samples x and y, where the lengths of samples x and y must be equal.

Correlation samples are set using the date range & date interval inputs, simulation(from, to, interval). Daily, weekly, or monthly return samples are used depending on the following:

  • Weekly return data interval: WEEKLY_START_DATES 
  • Monthly return data using interval: MONTHLY_START_DATES 
  • Daily return data is returned for date ranges less than 5 years old and using interval: AUTO

Correlations can be used in a two manners

  • Correlation with a benchmark
    simulation(portfolio: "x") { correlation(with: "y") }
    This is used to get the correlation from a portfolio to any other comparator, such as another portfolio or benchmark.
  • Correlation between 2 active portfolios
    simulation(portfolio: "x" base: "b") { correlation(with: "y") }
    This is most commonly used to compare to 2 active portfolios to a benchmark.
    This is (x - b) compared to (y - b) correlation.

Correlation with a Benchmark

Query

query(
  $modelId: String!,
  $positionSetX: PositionSetInput!,
  $benchmarkY: PositionSetInput!
) {
  model(id: $modelId) {
    simulation(positionSet: $positionSetX) {
      correlation(with: $benchmarkY)
    }
  }
}

Correlation Between 2 Active Portfolios 

Active portfolios are portfolios that already take the benchmark into account, using the simulation( base: $benchmark) input.

Query

query(
  $modelId: String!,
  $positionSetX: PositionSetInput!,
  $positionSetY: PositionSetInput!,
  $benchmarkB: [PositionSetInput!]
) {
  model(id: $modelId) {
    simulation(positionSet: $positionSetX base: $benchmarkB) {
      correlation(with: $positionSetY)
    }
  }
}

Did this answer your question?