ConstrainedMeanVarianceOptimizer.java

  1. package org.drip.portfolioconstruction.allocator;

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

  77. /**
  78.  * <i>ConstrainedMeanVarianceOptimizer</i> builds an Optimal Portfolio Based on MPT Using the Asset Pool
  79.  * Statistical Properties with the Specified Lower/Upper Bounds on the Component Assets.
  80.  *
  81.  *  <br><br>
  82.  *  <ul>
  83.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/PortfolioCore.md">Portfolio Core Module</a></li>
  84.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/AssetAllocationAnalyticsLibrary.md">Asset Allocation Analytics</a></li>
  85.  *      <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>
  86.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/portfolioconstruction/allocator/README.md">MVO Based Portfolio Allocation Construction</a></li>
  87.  *  </ul>
  88.  *
  89.  * @author Lakshmi Krishnamurthy
  90.  */

  91. public class ConstrainedMeanVarianceOptimizer extends
  92.     org.drip.portfolioconstruction.allocator.MeanVarianceOptimizer
  93. {
  94.     private org.drip.function.rdtor1descent.LineStepEvolutionControl _lineStepEvolutionControl = null;
  95.     private org.drip.function.rdtor1solver.InteriorPointBarrierControl _interiorPointBarrierControl = null;

  96.     protected org.drip.portfolioconstruction.allocator.HoldingsAllocationControl constrainedPCP (
  97.         final org.drip.portfolioconstruction.allocator.HoldingsAllocationControl
  98.             designPortfolioConstructionParameters,
  99.         final double returnsConstraint)
  100.     {
  101.         java.lang.String[] assetIDArray = designPortfolioConstructionParameters.assetIDArray();

  102.         int assetCount = assetIDArray.length;
  103.         org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl
  104.             boundedPortfolioConstructionParametersIn =
  105.                 (org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl)
  106.                     designPortfolioConstructionParameters;

  107.         try
  108.         {
  109.             org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl
  110.                 boundedPortfolioConstructionParametersOut =
  111.                     new org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl (
  112.                         assetIDArray,
  113.                         designPortfolioConstructionParameters.customRiskUtilitySettings(),
  114.                         new org.drip.portfolioconstruction.allocator.EqualityConstraintSettings (
  115.                             designPortfolioConstructionParameters.equalityConstraintSettings().constraintType() |
  116.                                 org.drip.portfolioconstruction.allocator.EqualityConstraintSettings.RETURNS_CONSTRAINT,
  117.                             returnsConstraint
  118.                         )
  119.                     );

  120.             for (int assetIndex = 0; assetIndex < assetCount; ++assetIndex)
  121.             {
  122.                 if (!boundedPortfolioConstructionParametersOut.addBound (
  123.                     assetIDArray[assetIndex],
  124.                     boundedPortfolioConstructionParametersIn.lowerBound (assetIDArray[assetIndex]),
  125.                     boundedPortfolioConstructionParametersIn.upperBound (assetIDArray[assetIndex])
  126.                 ))
  127.                 {
  128.                     return null;
  129.                 }
  130.             }

  131.             return boundedPortfolioConstructionParametersOut;
  132.         }
  133.         catch (java.lang.Exception e)
  134.         {
  135.             e.printStackTrace();
  136.         }

  137.         return null;
  138.     }

  139.     /**
  140.      * ConstrainedMeanVarianceOptimizer Constructor
  141.      *
  142.      * @param interiorPointBarrierControl Interior Fixed Point Barrier Control Parameters
  143.      * @param lineStepEvolutionControl Line Step Evolution Control Parameters
  144.      */

  145.     public ConstrainedMeanVarianceOptimizer (
  146.         final org.drip.function.rdtor1solver.InteriorPointBarrierControl interiorPointBarrierControl,
  147.         final org.drip.function.rdtor1descent.LineStepEvolutionControl lineStepEvolutionControl)
  148.     {
  149.         if (null == (_interiorPointBarrierControl = interiorPointBarrierControl))
  150.         {
  151.             _interiorPointBarrierControl =
  152.                 org.drip.function.rdtor1solver.InteriorPointBarrierControl.Standard();
  153.         }

  154.         _lineStepEvolutionControl = lineStepEvolutionControl;
  155.     }

  156.     /**
  157.      * Retrieve the Line Step Evolution Control
  158.      *
  159.      * @return The Line Step Evolution Control
  160.      */

  161.     public org.drip.function.rdtor1descent.LineStepEvolutionControl lineStepEvolutionControl()
  162.     {
  163.         return _lineStepEvolutionControl;
  164.     }

  165.     /**
  166.      * Retrieve the Interior Point Barrier Control
  167.      *
  168.      * @return The Interior Point Barrier Control
  169.      */

  170.     public org.drip.function.rdtor1solver.InteriorPointBarrierControl interiorPointBarrierControl()
  171.     {
  172.         return _interiorPointBarrierControl;
  173.     }

  174.     @Override public org.drip.portfolioconstruction.allocator.HoldingsAllocation
  175.         longOnlyMaximumReturnsAllocate (
  176.             final org.drip.portfolioconstruction.allocator.HoldingsAllocationControl
  177.                 portfolioConstructionParameters,
  178.             final org.drip.portfolioconstruction.params.AssetUniverseStatisticalProperties
  179.                 assetUniverseStatisticalProperties)
  180.     {
  181.         if (null == portfolioConstructionParameters ||
  182.             !(portfolioConstructionParameters instanceof
  183.                 org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl) ||
  184.             null == assetUniverseStatisticalProperties)
  185.         {
  186.             return null;
  187.         }

  188.         java.lang.String[] assetIDArray = portfolioConstructionParameters.assetIDArray();

  189.         int portfolioAssetIndex = 0;
  190.         double cumulativeWeight = 0.;
  191.         int assetCount = assetIDArray.length;
  192.         org.drip.portfolioconstruction.asset.AssetComponent[] assetComponentArray = new
  193.             org.drip.portfolioconstruction.asset.AssetComponent[assetCount];
  194.         org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl
  195.             boundedPortfolioConstructionParameters =
  196.                 (org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl)
  197.                     portfolioConstructionParameters;

  198.         double[] expectedAssetReturnsArray = assetUniverseStatisticalProperties.expectedReturns (
  199.             assetIDArray
  200.         );

  201.         if (null == expectedAssetReturnsArray || assetCount != expectedAssetReturnsArray.length)
  202.         {
  203.             return null;
  204.         }

  205.         java.util.TreeMap<java.lang.Double, java.lang.String> assetReturnsMap =
  206.             new java.util.TreeMap<java.lang.Double, java.lang.String>();

  207.         for (int assetIndex = 0; assetIndex < assetCount; ++assetIndex)
  208.         {
  209.             assetReturnsMap.put (
  210.                 expectedAssetReturnsArray[assetIndex],
  211.                 assetIDArray[assetIndex]
  212.             );
  213.         }

  214.         java.util.Set<java.lang.Double> descendingAssetReturnsSet = assetReturnsMap.descendingKeySet();

  215.         for (double assetReturns : descendingAssetReturnsSet)
  216.         {
  217.             double assetWeight = 0.;

  218.             java.lang.String assetID = assetReturnsMap.get (assetReturns);

  219.             try
  220.             {
  221.                 if (1. > cumulativeWeight)
  222.                 {
  223.                     double assetWeightUpperBound = boundedPortfolioConstructionParameters.upperBound (
  224.                         assetID
  225.                     );

  226.                     double maximumAllowedAssetWeight = 1. - cumulativeWeight;

  227.                     if (!org.drip.numerical.common.NumberUtil.IsValid (assetWeightUpperBound))
  228.                     {
  229.                         assetWeightUpperBound = maximumAllowedAssetWeight;
  230.                     }

  231.                     assetWeight = assetWeightUpperBound < maximumAllowedAssetWeight ? assetWeightUpperBound :
  232.                         maximumAllowedAssetWeight;
  233.                     cumulativeWeight += assetWeight;
  234.                 }

  235.                 assetComponentArray[portfolioAssetIndex++] =
  236.                     new org.drip.portfolioconstruction.asset.AssetComponent (
  237.                         assetID,
  238.                         assetWeight
  239.                     );
  240.             }
  241.             catch (java.lang.Exception e)
  242.             {
  243.                 e.printStackTrace();

  244.                 return null;
  245.             }
  246.         }

  247.         return org.drip.portfolioconstruction.allocator.HoldingsAllocation.Create (
  248.             assetComponentArray,
  249.             assetUniverseStatisticalProperties
  250.         );
  251.     }

  252.     @Override public org.drip.portfolioconstruction.allocator.HoldingsAllocation
  253.         globalMinimumVarianceAllocate (
  254.             final org.drip.portfolioconstruction.allocator.HoldingsAllocationControl
  255.                 portfolioConstructionParameters,
  256.             final org.drip.portfolioconstruction.params.AssetUniverseStatisticalProperties
  257.                 assetUniverseStatisticalProperties)
  258.     {
  259.         if (null == portfolioConstructionParameters ||
  260.             !(portfolioConstructionParameters instanceof
  261.                 org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl) ||
  262.             null == assetUniverseStatisticalProperties)
  263.         {
  264.             return null;
  265.         }

  266.         java.lang.String[] assetIDArray = portfolioConstructionParameters.assetIDArray();

  267.         double[][] assetCovarianceMatrix = assetUniverseStatisticalProperties.covariance (assetIDArray);

  268.         if (null == assetCovarianceMatrix)
  269.         {
  270.             return null;
  271.         }

  272.         int assetCount = assetIDArray.length;
  273.         org.drip.portfolioconstruction.asset.AssetComponent[] assetComponentArray = new
  274.             org.drip.portfolioconstruction.asset.AssetComponent[assetCount];
  275.         org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl
  276.             boundedPortfolioConstructionParameters =
  277.                 (org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl)
  278.                     portfolioConstructionParameters;

  279.         try
  280.         {
  281.             org.drip.function.rdtor1.LagrangianMultivariate lagrangianMultivariate =
  282.                 new org.drip.function.rdtor1.LagrangianMultivariate (
  283.                     portfolioConstructionParameters.customRiskUtilitySettings().riskObjectiveUtility (
  284.                         assetIDArray,
  285.                         assetUniverseStatisticalProperties
  286.                     ),
  287.                     new org.drip.function.definition.RdToR1[]
  288.                     {
  289.                         boundedPortfolioConstructionParameters.fullyInvestedConstraint()
  290.                     }
  291.                 );

  292.             org.drip.function.rdtor1solver.VariateInequalityConstraintMultiplier
  293.                 variateInequalityConstraintMultiplier =
  294.                     new org.drip.function.rdtor1solver.BarrierFixedPointFinder (
  295.                         lagrangianMultivariate,
  296.                         boundedPortfolioConstructionParameters.boundingConstraintsArray (
  297.                             lagrangianMultivariate.constraintFunctionDimension()
  298.                         ),
  299.                         _interiorPointBarrierControl,
  300.                         _lineStepEvolutionControl
  301.                     ).solve (
  302.                         boundedPortfolioConstructionParameters.weightConstrainedFeasibleStart()
  303.                     );

  304.             if (null == variateInequalityConstraintMultiplier)
  305.             {
  306.                 return null;
  307.             }

  308.             double[] optimalWeightArray = variateInequalityConstraintMultiplier.variateArray();

  309.             for (int assetIndex = 0; assetIndex < assetCount; ++assetIndex)
  310.             {
  311.                 assetComponentArray[assetIndex] = new org.drip.portfolioconstruction.asset.AssetComponent (
  312.                     assetIDArray[assetIndex],
  313.                     optimalWeightArray[assetIndex]
  314.                 );
  315.             }

  316.             return org.drip.portfolioconstruction.allocator.HoldingsAllocation.Create (
  317.                 assetComponentArray,
  318.                 assetUniverseStatisticalProperties
  319.             );
  320.         }
  321.         catch (java.lang.Exception e)
  322.         {
  323.             e.printStackTrace();
  324.         }

  325.         return null;
  326.     }

  327.     @Override public org.drip.portfolioconstruction.allocator.HoldingsAllocation allocate (
  328.         final org.drip.portfolioconstruction.allocator.HoldingsAllocationControl
  329.             holdingsAllocationControl,
  330.         final org.drip.portfolioconstruction.params.AssetUniverseStatisticalProperties
  331.             assetUniverseStatisticalProperties)
  332.     {
  333.         if (null == holdingsAllocationControl ||
  334.             !(holdingsAllocationControl instanceof
  335.                 org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl) ||
  336.             null == assetUniverseStatisticalProperties)
  337.         {
  338.             return null;
  339.         }

  340.         java.lang.String[] assetIDArray = holdingsAllocationControl.assetIDArray();

  341.         double[][] aadblCovariance = assetUniverseStatisticalProperties.covariance (assetIDArray);

  342.         if (null == aadblCovariance)
  343.         {
  344.             return null;
  345.         }

  346.         int assetCount = assetIDArray.length;
  347.         org.drip.portfolioconstruction.asset.AssetComponent[] assetComponentArray = new
  348.             org.drip.portfolioconstruction.asset.AssetComponent[assetCount];
  349.         org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl
  350.             boundedHoldingsAllocationControl =
  351.                 (org.drip.portfolioconstruction.allocator.BoundedHoldingsAllocationControl)
  352.                     holdingsAllocationControl;

  353.         try
  354.         {
  355.             org.drip.function.rdtor1.LagrangianMultivariate lagrangianMultivariate =
  356.                 new org.drip.function.rdtor1.LagrangianMultivariate (
  357.                     holdingsAllocationControl.customRiskUtilitySettings().riskObjectiveUtility (
  358.                         assetIDArray,
  359.                         assetUniverseStatisticalProperties
  360.                     ),
  361.                     boundedHoldingsAllocationControl.equalityConstraintArray (
  362.                         assetUniverseStatisticalProperties
  363.                     )
  364.                 );

  365.             org.drip.function.rdtor1solver.VariateInequalityConstraintMultiplier
  366.                 variateInequalityConstraintMultiplier =
  367.                     new org.drip.function.rdtor1solver.BarrierFixedPointFinder (
  368.                         lagrangianMultivariate,
  369.                         boundedHoldingsAllocationControl.boundingConstraintsArray (
  370.                             lagrangianMultivariate.constraintFunctionDimension()
  371.                         ),
  372.                         _interiorPointBarrierControl,
  373.                         _lineStepEvolutionControl
  374.                     ).solve (
  375.                         boundedHoldingsAllocationControl.weightConstrainedFeasibleStart()
  376.                     );

  377.             if (null == variateInequalityConstraintMultiplier)
  378.             {
  379.                 return null;
  380.             }

  381.             double[] optimalWeightArray = variateInequalityConstraintMultiplier.variateArray();

  382.             for (int assetIndex = 0; assetIndex < assetCount; ++assetIndex)
  383.             {
  384.                 assetComponentArray[assetIndex] = new org.drip.portfolioconstruction.asset.AssetComponent (
  385.                     assetIDArray[assetIndex],
  386.                     optimalWeightArray[assetIndex]
  387.                 );
  388.             }

  389.             return org.drip.portfolioconstruction.allocator.HoldingsAllocation.Create (
  390.                 assetComponentArray,
  391.                 assetUniverseStatisticalProperties
  392.             );
  393.         }
  394.         catch (java.lang.Exception e)
  395.         {
  396.             e.printStackTrace();
  397.         }

  398.         return null;
  399.     }
  400. }