AttributeJointFactor.java

  1. package org.drip.portfolioconstruction.risk;

  2. /*
  3.  * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  4.  */

  5. /*!
  6.  * Copyright (C) 2020 Lakshmi Krishnamurthy
  7.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  8.  * Copyright (C) 2018 Lakshmi Krishnamurthy
  9.  * Copyright (C) 2017 Lakshmi Krishnamurthy
  10.  *
  11.  *  This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
  12.  *      asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
  13.  *      analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
  14.  *      equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
  15.  *      numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
  16.  *      and computational support.
  17.  *  
  18.  *      https://lakshmidrip.github.io/DROP/
  19.  *  
  20.  *  DROP is composed of three modules:
  21.  *  
  22.  *  - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
  23.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  24.  *  - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
  25.  *
  26.  *  DROP Product Core implements libraries for the following:
  27.  *  - Fixed Income Analytics
  28.  *  - Loan Analytics
  29.  *  - Transaction Cost Analytics
  30.  *
  31.  *  DROP Portfolio Core implements libraries for the following:
  32.  *  - Asset Allocation Analytics
  33.  *  - Asset Liability Management Analytics
  34.  *  - Capital Estimation Analytics
  35.  *  - Exposure Analytics
  36.  *  - Margin Analytics
  37.  *  - XVA Analytics
  38.  *
  39.  *  DROP Computational Core implements libraries for the following:
  40.  *  - Algorithm Support
  41.  *  - Computation Support
  42.  *  - Function Analysis
  43.  *  - Model Validation
  44.  *  - Numerical Analysis
  45.  *  - Numerical Optimizer
  46.  *  - Spline Builder
  47.  *  - Statistical Learning
  48.  *
  49.  *  Documentation for DROP is Spread Over:
  50.  *
  51.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  52.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  53.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  54.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  55.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  56.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  57.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  58.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  59.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  60.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  61.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  62.  *
  63.  *  Licensed under the Apache License, Version 2.0 (the "License");
  64.  *      you may not use this file except in compliance with the License.
  65.  *  
  66.  *  You may obtain a copy of the License at
  67.  *      http://www.apache.org/licenses/LICENSE-2.0
  68.  *  
  69.  *  Unless required by applicable law or agreed to in writing, software
  70.  *      distributed under the License is distributed on an "AS IS" BASIS,
  71.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  72.  *  
  73.  *  See the License for the specific language governing permissions and
  74.  *      limitations under the License.
  75.  */

  76. /**
  77.  * <i>AttributeJointFactor</i> contains the Factor Based Loadings that determines the Joint Attributes
  78.  * between the Pair of Assets.
  79.  *
  80.  *  <br><br>
  81.  *  <ul>
  82.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/PortfolioCore.md">Portfolio Core Module</a></li>
  83.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/AssetAllocationAnalyticsLibrary.md">Asset Allocation Analytics</a></li>
  84.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/portfolioconstruction/README.md">Portfolio Construction under Allocation Constraints</a></li>
  85.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/portfolioconstruction/risk/README.md">Portfolio Construction Risk/Covariance Component</a></li>
  86.  *  </ul>
  87.  * <br><br>
  88.  *
  89.  * @author Lakshmi Krishnamurthy
  90.  */

  91. public class AttributeJointFactor
  92.     extends org.drip.portfolioconstruction.core.Block
  93. {
  94.     private java.util.Map<java.lang.String, java.lang.Double> _assetFactorLoadingMap =
  95.         new org.drip.analytics.support.CaseInsensitiveHashMap<java.lang.Double>();

  96.     private java.util.Map<java.lang.String, java.lang.Double> _factorAssetLoadingMap =
  97.         new org.drip.analytics.support.CaseInsensitiveHashMap<java.lang.Double>();

  98.     private java.util.Map<java.lang.String, java.lang.Double> _factorFactorAttributeMap =
  99.         new org.drip.analytics.support.CaseInsensitiveHashMap<java.lang.Double>();

  100.     private java.util.Map<java.lang.String, java.lang.Double> _mapAssetSpecificAttribute =
  101.         new org.drip.analytics.support.CaseInsensitiveHashMap<java.lang.Double>();

  102.     /**
  103.      * Generate a Standard Instance of AttributeJointFactor
  104.      *
  105.      * @param name AttributeJointFactor Instance Name
  106.      * @param id AttributeJointFactor Instance ID
  107.      * @param description AttributeJointFactor Description
  108.      * @param assetIDArray Array of Asset IDs
  109.      * @param factorIDArray Array of FactorIDs
  110.      * @param assetFactorLoadingGrid Matrix of Asset-Factor Loadings
  111.      * @param crossFactorAttributeGrid Matrix of Factor-Factor Attributes
  112.      * @param assetSpecificAttributeArray Array of Specific Attributes
  113.      *
  114.      * @return The Standard Instance of AttributeJointFactor
  115.      */

  116.     public static final AttributeJointFactor Standard (
  117.         final java.lang.String name,
  118.         final java.lang.String id,
  119.         final java.lang.String description,
  120.         final java.lang.String[] assetIDArray,
  121.         final java.lang.String[] factorIDArray,
  122.         final double[][] assetFactorLoadingGrid,
  123.         final double[][] crossFactorAttributeGrid,
  124.         final double[] assetSpecificAttributeArray)
  125.     {
  126.         if (null == assetIDArray ||
  127.             null == factorIDArray ||
  128.             null == assetFactorLoadingGrid ||
  129.             null == crossFactorAttributeGrid ||
  130.             null == assetSpecificAttributeArray)
  131.         {
  132.             return null;
  133.         }

  134.         int assetCount = assetIDArray.length;
  135.         int factorCount = factorIDArray.length;
  136.         AttributeJointFactor attributeJointFactor = null;

  137.         if (0 == assetCount ||
  138.             0 == factorCount ||
  139.             assetCount != assetFactorLoadingGrid.length ||
  140.             factorCount != crossFactorAttributeGrid.length ||
  141.             assetCount != assetSpecificAttributeArray.length)
  142.         {
  143.             return null;
  144.         }

  145.         try
  146.         {
  147.             attributeJointFactor = new AttributeJointFactor (
  148.                 name,
  149.                 id,
  150.                 description
  151.             );
  152.         }
  153.         catch (java.lang.Exception e)
  154.         {
  155.             e.printStackTrace();

  156.             return null;
  157.         }

  158.         for (int assetIndex = 0;
  159.             assetIndex < assetCount;
  160.             ++assetIndex)
  161.         {
  162.             for (int factorIndex = 0;
  163.                 factorIndex < factorCount;
  164.                 ++factorIndex)
  165.             {
  166.                 if (!attributeJointFactor.addAssetFactorLoading (
  167.                     assetIDArray[assetIndex],
  168.                     factorIDArray[factorIndex],
  169.                     assetFactorLoadingGrid[assetIndex][factorIndex]
  170.                 ))
  171.                 {
  172.                     return null;
  173.                 }
  174.             }

  175.             if (!attributeJointFactor.addSpecificAttribute (
  176.                 assetIDArray[assetIndex],
  177.                 assetSpecificAttributeArray[assetIndex]
  178.             ))
  179.             {
  180.                 return null;
  181.             }
  182.         }

  183.         for (int factorIndex1 = 0;
  184.             factorIndex1 < factorCount;
  185.             ++factorIndex1)
  186.         {
  187.             for (int factorIndex2 = 0;
  188.                 factorIndex2 < factorCount;
  189.                 ++factorIndex2)
  190.             {
  191.                 if (!attributeJointFactor.addFactorAttribute (
  192.                     factorIDArray[factorIndex1],
  193.                     factorIDArray[factorIndex2],
  194.                     crossFactorAttributeGrid[factorIndex1][factorIndex2]
  195.                 ))
  196.                 {
  197.                     return null;
  198.                 }
  199.             }
  200.         }

  201.         return attributeJointFactor;
  202.     }

  203.     /**
  204.      * AttributeJointFactor Constructor
  205.      *
  206.      * @param name The Name
  207.      * @param id The ID
  208.      * @param description The Description
  209.      *
  210.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  211.      */

  212.     public AttributeJointFactor (
  213.         final java.lang.String name,
  214.         final java.lang.String id,
  215.         final java.lang.String description)
  216.         throws java.lang.Exception
  217.     {
  218.         super (name, id, description);
  219.     }

  220.     /**
  221.      * Retrieve the Joint Asset-Factor Loading Map
  222.      *
  223.      * @return The Joint Asset-Factor Loading Map
  224.      */

  225.     public java.util.Map<java.lang.String, java.lang.Double> assetFactorLoading()
  226.     {
  227.         return _assetFactorLoadingMap;
  228.     }

  229.     /**
  230.      * Retrieve the Joint Factor-Asset Loading Map
  231.      *
  232.      * @return The Joint Factor-Asset Loading Map
  233.      */

  234.     public java.util.Map<java.lang.String, java.lang.Double> factorAssetLoading()
  235.     {
  236.         return _factorAssetLoadingMap;
  237.     }

  238.     /**
  239.      * Retrieve the Factor-to-Factor Attribute Map
  240.      *
  241.      * @return The Factor-to-Joint Attribute Map
  242.      */

  243.     public java.util.Map<java.lang.String, java.lang.Double> factorJointAttribute()
  244.     {
  245.         return _factorFactorAttributeMap;
  246.     }

  247.     /**
  248.      * Retrieve the Asset Specific Attribute
  249.      *
  250.      * @return The Asset Specific Attribute
  251.      */

  252.     public java.util.Map<java.lang.String, java.lang.Double> specificRisk()
  253.     {
  254.         return _mapAssetSpecificAttribute;
  255.     }

  256.     /**
  257.      * Add the Asset's Factor Loading Coefficient
  258.      *
  259.      * @param assetID The Asset ID
  260.      * @param factorID The Factor ID
  261.      * @param factorLoading The Factor Loading Coefficient
  262.      *
  263.      * @return TRUE - The Asset's Factor Loading Coefficient successfully added
  264.      */

  265.     public boolean addAssetFactorLoading (
  266.         final java.lang.String assetID,
  267.         final java.lang.String factorID,
  268.         final double factorLoading)
  269.     {
  270.         if (null == assetID || assetID.isEmpty() ||
  271.             null == factorID || factorID.isEmpty() ||
  272.             !org.drip.numerical.common.NumberUtil.IsValid (
  273.                 factorLoading
  274.             )
  275.         )
  276.         {
  277.             return false;
  278.         }

  279.         _assetFactorLoadingMap.put (
  280.             assetID + "::" + factorID,
  281.             factorLoading
  282.         );

  283.         _factorAssetLoadingMap.put (
  284.             factorID + "::" + assetID,
  285.             factorLoading
  286.         );

  287.         return true;
  288.     }

  289.     /**
  290.      * Add the Cross Factor Attribute
  291.      *
  292.      * @param factorID1 The Factor #1 ID
  293.      * @param factorID2 The Factor #2 ID
  294.      * @param crossFactorAttribute The Cross Factor Attribute
  295.      *
  296.      * @return TRUE - The Cross Factor Attribute successfully added
  297.      */

  298.     public boolean addFactorAttribute (
  299.         final java.lang.String factorID1,
  300.         final java.lang.String factorID2,
  301.         final double crossFactorAttribute)
  302.     {
  303.         if (null == factorID1 || factorID1.isEmpty() ||
  304.             null == factorID2 || factorID2.isEmpty() ||
  305.             !org.drip.numerical.common.NumberUtil.IsValid (
  306.                 crossFactorAttribute
  307.             )
  308.         )
  309.         {
  310.             return false;
  311.         }

  312.         _factorFactorAttributeMap.put (
  313.             factorID1 + "::" + factorID2,
  314.             crossFactorAttribute
  315.         );

  316.         _factorFactorAttributeMap.put (
  317.             factorID2 + "::" + factorID1,
  318.             crossFactorAttribute
  319.         );

  320.         return true;
  321.     }

  322.     /**
  323.      * Add the Asset's Specific Attribute
  324.      *
  325.      * @param assetID The Asset ID
  326.      * @param specificAttribute The Asset's Specific Attribute
  327.      *
  328.      * @return TRUE - The Asset's Specific Risk successfully added
  329.      */

  330.     public boolean addSpecificAttribute (
  331.         final java.lang.String assetID,
  332.         final double specificAttribute)
  333.     {
  334.         if (null == assetID || assetID.isEmpty() ||
  335.             !org.drip.numerical.common.NumberUtil.IsValid (
  336.                 specificAttribute
  337.             )
  338.         )
  339.         {
  340.             return false;
  341.         }

  342.         _mapAssetSpecificAttribute.put (
  343.             assetID,
  344.             specificAttribute
  345.         );

  346.         return true;
  347.     }

  348.     /**
  349.      * Check if the Asset is represented
  350.      *
  351.      * @param assetID The Asset ID
  352.      *
  353.      * @return TRUE - The Asset is represented
  354.      */

  355.     public boolean containsAsset (
  356.         final java.lang.String assetID)
  357.     {
  358.         return null != assetID && !assetID.isEmpty() &&
  359.             _assetFactorLoadingMap.containsKey (
  360.                 assetID
  361.             ) && _mapAssetSpecificAttribute.containsKey (
  362.                 assetID
  363.             );
  364.     }

  365.     /**
  366.      * Check if the Factor is available
  367.      *
  368.      * @param factorID The Factor ID
  369.      *
  370.      * @return TRUE - The Factor is available
  371.      */

  372.     public boolean containsFactor (
  373.         final java.lang.String factorID)
  374.     {
  375.         return null != factorID && !factorID.isEmpty() &&
  376.             _factorAssetLoadingMap.containsKey (
  377.                 factorID
  378.             ) && _factorFactorAttributeMap.containsKey (
  379.                 factorID
  380.             );
  381.     }

  382.     /**
  383.      * Retrieve the Factor Loading for the specified Asset
  384.      *
  385.      * @param assetID The Asset ID
  386.      *
  387.      * @return The Factor Loading for the specified Asset
  388.      */

  389.     public java.util.Map<java.lang.String, java.lang.Double> assetFactorLoading (
  390.         final java.lang.String assetID)
  391.     {
  392.         if (!containsAsset (
  393.             assetID
  394.         ))
  395.         {
  396.             return null;
  397.         }

  398.         java.util.Map<java.lang.String, java.lang.Double> assetFactorLoadingMap =
  399.             new org.drip.analytics.support.CaseInsensitiveHashMap<java.lang.Double>();

  400.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> assetFactorLoadingEntry :
  401.             _assetFactorLoadingMap.entrySet())
  402.         {
  403.             if (assetFactorLoadingEntry.getKey().startsWith (
  404.                 assetID
  405.             ))
  406.             {
  407.                 assetFactorLoadingMap.put (
  408.                     assetID,
  409.                     assetFactorLoadingEntry.getValue()
  410.                 );
  411.             }
  412.         }

  413.         return assetFactorLoadingMap;
  414.     }

  415.     /**
  416.      * Retrieve the Loadings for the specified Factor
  417.      *
  418.      * @param factorID The Factor ID
  419.      *
  420.      * @return The Loadings for the specified Factor
  421.      */

  422.     public java.util.Map<java.lang.String, java.lang.Double> factorAssetLoading (
  423.         final java.lang.String factorID)
  424.     {
  425.         if (!containsFactor (
  426.             factorID
  427.         ))
  428.         {
  429.             return null;
  430.         }

  431.         java.util.Map<java.lang.String, java.lang.Double> factorAssetLoadingMap = new
  432.             org.drip.analytics.support.CaseInsensitiveHashMap<java.lang.Double>();

  433.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> factorAssetLoadingEntry :
  434.             _factorAssetLoadingMap.entrySet())
  435.         {
  436.             if (factorAssetLoadingEntry.getKey().startsWith (
  437.                 factorID
  438.             ))
  439.             {
  440.                 factorAssetLoadingMap.put (
  441.                     factorID,
  442.                     factorAssetLoadingEntry.getValue()
  443.                 );
  444.             }
  445.         }

  446.         return factorAssetLoadingMap;
  447.     }

  448.     /**
  449.      * Retrieve the Cross Factor Attribute Entry
  450.      *
  451.      * @param factorID1 The Factor ID #1
  452.      * @param factorID2 The Factor ID #2
  453.      *
  454.      * @return The Cross Factor Attribute Entry
  455.      *
  456.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  457.      */

  458.     public double crossFactorAttribute (
  459.         final java.lang.String factorID1,
  460.         final java.lang.String factorID2)
  461.         throws java.lang.Exception
  462.     {
  463.         if (!containsFactor (
  464.                 factorID1
  465.             ) || !containsFactor (
  466.                 factorID2
  467.             )
  468.         )
  469.         {
  470.             throw new java.lang.Exception (
  471.                 "AttributeJointFactor::crossFactorAttribute => Invalid Inputs"
  472.             );
  473.         }

  474.         return _factorFactorAttributeMap.get (
  475.             factorID1 + "::" + factorID2
  476.         );
  477.     }

  478.     /**
  479.      * Retrieve the Asset Specific Attribute
  480.      *
  481.      * @param assetID The Asset ID
  482.      *
  483.      * @return The Asset Specific Attribute
  484.      *
  485.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  486.      */

  487.     public double assetSpecificAttribute (
  488.         final java.lang.String assetID)
  489.         throws java.lang.Exception
  490.     {
  491.         if (!containsFactor (
  492.             assetID
  493.         ))
  494.         {
  495.             throw new java.lang.Exception (
  496.                 "AttributeJointFactor::assetSpecificAttribute => Invalid Inputs"
  497.             );
  498.         }

  499.         return _mapAssetSpecificAttribute.get (
  500.             assetID
  501.         );
  502.     }

  503.     /**
  504.      * Compute the Cross Asset Attribute
  505.      *
  506.      * @param assetID1 Asset ID #1
  507.      * @param assetID2 Asset ID #2
  508.      *
  509.      * @return The Cross Asset Attribute
  510.      *
  511.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  512.      */

  513.     public double crossAssetAttribute (
  514.         final java.lang.String assetID1,
  515.         final java.lang.String assetID2)
  516.         throws java.lang.Exception
  517.     {
  518.         java.util.Map<java.lang.String, java.lang.Double> asset1FactorLoadingMap = assetFactorLoading (
  519.             assetID1
  520.         );

  521.         java.util.Map<java.lang.String, java.lang.Double> asset2FactorLoadingMap = assetFactorLoading (
  522.             assetID2
  523.         );

  524.         if (null == asset1FactorLoadingMap || null == asset2FactorLoadingMap)
  525.         {
  526.             throw new java.lang.Exception (
  527.                 "AttributeJointFactor::crossAssetAttribute => Invalid Factor Loadings"
  528.             );
  529.         }

  530.         double crossAssetAttribute = 0.;

  531.         for (java.util.Map.Entry<java.lang.String, java.lang.Double> asset1FactorLoadingEntry :
  532.             asset1FactorLoadingMap.entrySet())
  533.         {
  534.             java.lang.String factorID = asset1FactorLoadingEntry.getKey();

  535.             if (!asset2FactorLoadingMap.containsKey (
  536.                     factorID
  537.                 ) || !_factorFactorAttributeMap.containsKey (
  538.                     factorID
  539.                 )
  540.             )
  541.             {
  542.                 throw new java.lang.Exception (
  543.                     "AttributeJointFactor::crossAssetAttribute => Loading not available for " + assetID2 +
  544.                         " for factor " + factorID
  545.                 );
  546.             }

  547.             crossAssetAttribute += asset1FactorLoadingMap.get (
  548.                 factorID
  549.             ) * asset2FactorLoadingMap.get (
  550.                 factorID
  551.             ) * crossFactorAttribute (
  552.                 factorID,
  553.                 factorID
  554.             );
  555.         }

  556.         return crossAssetAttribute;
  557.     }
  558. }