参考文档:http://www.ojalgo.org/generated/org/ojalgo/finance/portfolio/MarkowitzModel.html
org.ojalgo.finance.portfolio.MarkowitzModel.setRiskAversion 方法
org.ojalgo.finance.portfolio.MarkowitzModel.getAssetWeights 方法
源码:
public final void setRiskAversion(final Number aFactor) { myMarketEquilibrium.setRiskAversion(aFactor); this.reset(); }
MarketEquilibrium.java源码:
/* * Copyright 2003-2011 Optimatika (www.optimatika.se) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.ojalgo.finance.portfolio; import java.math.BigDecimal; import org.ojalgo.ProgrammingError; import org.ojalgo.array.ArrayUtils; import org.ojalgo.constant.BigMath; import org.ojalgo.matrix.BasicMatrix; import org.ojalgo.scalar.BigScalar; import org.ojalgo.scalar.PrimitiveScalar; import org.ojalgo.scalar.Scalar; import org.ojalgo.type.TypeUtils; /** * MarketEquilibrium translates between the market portfolio weights * and the equilibrium excess returns. The only things needed to do * those translations are the covariance matrix and the risk aversion * factor - that's what you need to supply when you instantiate this * class. * * @see #calculateAssetReturns(BasicMatrix) * @see #calculateAssetWeights(BasicMatrix) * * @author apete */ public class MarketEquilibrium { private static final BigDecimal DEFAULT_RISK_AVERSION = BigMath.ONE; private static final String STRING_ZERO = "0"; private static final String SYMBOL = "Asset_"; /** * Calculates the portfolio return using the input instrument * weights and returns. */ public static Scalar> calculatePortfolioReturn(final BasicMatrix aWeightsVctr, final BasicMatrix aReturnsVctr) { return aWeightsVctr.multiplyVectors(aReturnsVctr); } private static String[] makeSymbols(final int aCount) { final String[] retVal = new String[aCount]; final int tmpMaxLength = Integer.toString(aCount - 1).length(); String tmpNumberString; for (int i = 0; i < aCount; i++) { tmpNumberString = Integer.toString(i); while (tmpNumberString.length() < tmpMaxLength) { tmpNumberString = STRING_ZERO + tmpNumberString; } retVal[i] = SYMBOL + tmpNumberString; } return retVal; } private final BasicMatrix myCovariances; private BigDecimal myRiskAversion; private final String[] mySymbols; public MarketEquilibrium(final BasicMatrix aCovarianceMatrix) { this(aCovarianceMatrix, DEFAULT_RISK_AVERSION); } public MarketEquilibrium(final BasicMatrix aCovarianceMatrix, final Number aRiskAversionFactor) { this(MarketEquilibrium.makeSymbols(aCovarianceMatrix.getRowDim()), aCovarianceMatrix, aRiskAversionFactor); } public MarketEquilibrium(final String[] instrumentNamesOrKeys, final BasicMatrix aCovarianceMatrix, final Number aRiskAversionFactor) { super(); mySymbols = ArrayUtils.copyOf(instrumentNamesOrKeys); myCovariances = aCovarianceMatrix; myRiskAversion = TypeUtils.toBigDecimal(aRiskAversionFactor); } @SuppressWarnings("unused") private MarketEquilibrium() { this(null, null, null); ProgrammingError.throwForIllegalInvocation(); } MarketEquilibrium(final MarketEquilibrium aMarket) { this(aMarket.getSymbols(), aMarket.getCovariances(), aMarket.getRiskAversion().getNumber()); } /** * If the input vector of asset weights are the weights of the market * portfolio, then the ouput is the equilibrium excess returns. */ public BasicMatrix calculateAssetReturns(final BasicMatrix aWeightsVctr) { final BasicMatrix tmpWeightsVctr = myRiskAversion.compareTo(DEFAULT_RISK_AVERSION) == 0 ? aWeightsVctr : aWeightsVctr.multiply(myRiskAversion); return myCovariances.multiplyRight(tmpWeightsVctr); } /** * If the input vector of returns are the equilibrium excess returns * then the output is the market portfolio weights. This is * unconstrained optimisation - there are no constraints on the * resulting instrument weights. */ public BasicMatrix calculateAssetWeights(final BasicMatrix aReturnsVctr) { final BasicMatrix tmpWeightsVctr = myCovariances.solve(aReturnsVctr); if (myRiskAversion.compareTo(DEFAULT_RISK_AVERSION) == 0) { return tmpWeightsVctr; } else { return tmpWeightsVctr.divide(myRiskAversion); } } /** * Calculates the portfolio variance using the input instrument * weights. */ public Scalar> calculatePortfolioVariance(final BasicMatrix aWeightsVctr) { BasicMatrix tmpLeft; BasicMatrix tmpRight; if (aWeightsVctr.getColDim() == 1) { tmpLeft = aWeightsVctr.transpose(); tmpRight = aWeightsVctr; } else { tmpLeft = aWeightsVctr; tmpRight = aWeightsVctr.transpose(); } return myCovariances.multiplyRight(tmpRight).multiplyLeft(tmpLeft).toScalar(0, 0); } /** * Will set the risk aversion factor to the best fit for an observed * pair of market portfolio asset weights and equilibrium/historical * excess returns. */ public void calibrate(final BasicMatrix aWeightsVctr, final BasicMatrix aReturnsVctr) { this.setRiskAversion(this.getImpliedRiskAversion(aWeightsVctr, aReturnsVctr).getNumber()); } public MarketEquilibrium copy() { return new MarketEquilibrium(this); } public BasicMatrix getCovariances() { return myCovariances; } /** * Will calculate the risk aversion factor that is the best fit for * an observed pair of market portfolio weights and equilibrium/historical * excess returns. */ public Scalar> getImpliedRiskAversion(final BasicMatrix aWeightsVctr, final BasicMatrix aReturnsVctr) { // Least-squares-solve [LHS: unscaled derived returns][X: risk aversion] = [RHS: observed returns] BasicMatrix tmpLHS = myCovariances.multiplyRight(aWeightsVctr); BasicMatrix tmpRHS = aReturnsVctr; final BasicMatrix tmpTranspose = tmpLHS.transpose(); tmpLHS = tmpLHS.multiplyLeft(tmpTranspose); tmpRHS = tmpRHS.multiplyLeft(tmpTranspose); return new PrimitiveScalar(tmpRHS.doubleValue(0, 0) / tmpLHS.doubleValue(0, 0)); } public Scalar> getRiskAversion() { return new BigScalar(myRiskAversion); } public String[] getSymbols() { return ArrayUtils.copyOf(mySymbols); } public void setRiskAversion(final Number aFactor) { myRiskAversion = TypeUtils.toBigDecimal(aFactor); } }
EquilibriumModel.java源码:
/* * Copyright 2003-2011 Optimatika (www.optimatika.se) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.ojalgo.finance.portfolio; import java.math.BigDecimal; import java.util.List; import org.ojalgo.ProgrammingError; import org.ojalgo.matrix.BasicMatrix; import org.ojalgo.matrix.MatrixFactory; import org.ojalgo.matrix.PrimitiveMatrix; abstract class EquilibriumModel extends FinancePortfolio { protected static final MatrixFactory> FACTORY = PrimitiveMatrix.FACTORY; private transient BasicMatrix myAssetReturns; private transient BasicMatrix myAssetWeights; private final MarketEquilibrium myMarketEquilibrium; private transient BigDecimal myMeanReturn; private transient BigDecimal myReturnVariance; @SuppressWarnings("unused") private EquilibriumModel() { this(null); ProgrammingError.throwForIllegalInvocation(); } protected EquilibriumModel(final MarketEquilibrium aMarketEquilibrium) { super(); myMarketEquilibrium = aMarketEquilibrium.copy(); } public final BasicMatrix getAssetReturns() { if (myAssetReturns == null) { myAssetReturns = this.calculateAssetReturns(); } return myAssetReturns; } public final BasicMatrix getAssetWeights() { if (myAssetWeights == null) { final BasicMatrix tmpAssetWeights = this.calculateAssetWeights(); if (tmpAssetWeights != null) { myAssetWeights = tmpAssetWeights.round(WEIGHT_CONTEXT); } } return myAssetWeights; } public final BasicMatrix getCovariances() { return myMarketEquilibrium.getCovariances(); } public final BigDecimal getImpliedRiskAversion(final BasicMatrix aWeightsVctr, final BasicMatrix aReturnsVctr) { return myMarketEquilibrium.getImpliedRiskAversion(aWeightsVctr, aReturnsVctr).toBigDecimal(); } @Override public final double getMeanReturn() { if (myMeanReturn == null) { final BasicMatrix tmpAssetWeights = this.getAssetWeights(); final BasicMatrix tmpAssetReturns = this.getAssetReturns(); if ((tmpAssetWeights != null) && (tmpAssetReturns != null)) { myMeanReturn = this.calculatePortfolioReturn(tmpAssetWeights, tmpAssetReturns); } } return myMeanReturn.doubleValue(); } @Override public final double getReturnVariance() { if (myReturnVariance == null) { myReturnVariance = this.calculatePortfolioVariance(this.getAssetWeights()); } return myReturnVariance.doubleValue(); } public final BigDecimal getRiskAversion() { return myMarketEquilibrium.getRiskAversion().toBigDecimal(); } public final String[] getSymbols() { return myMarketEquilibrium.getSymbols(); } @Override public final ListgetWeights() { final BasicMatrix tmpAssetWeights = this.getAssetWeights(); if (tmpAssetWeights != null) { return tmpAssetWeights.toBigStore().asList(); } else { return null; } } public final void setRiskAversion(final Number aFactor) { myMarketEquilibrium.setRiskAversion(aFactor); this.reset(); } protected final BasicMatrix buildColumnVector(final List aColumn) { return FACTORY.columns(aColumn); } protected abstract BasicMatrix calculateAssetReturns(); protected abstract BasicMatrix calculateAssetWeights(); protected final BasicMatrix calculateEquilibriumReturns(final BasicMatrix aWeightsVctr) { return myMarketEquilibrium.calculateAssetReturns(aWeightsVctr); } protected final BasicMatrix calculateEquilibriumWeights(final BasicMatrix aReturnsVctr) { return myMarketEquilibrium.calculateAssetWeights(aReturnsVctr); } protected final BigDecimal calculatePortfolioReturn(final BasicMatrix aWeightsVctr, final BasicMatrix aReturnsVctr) { return MarketEquilibrium.calculatePortfolioReturn(aWeightsVctr, aReturnsVctr).toBigDecimal(); } protected final BigDecimal calculatePortfolioVariance(final BasicMatrix aWeightsVctr) { return myMarketEquilibrium.calculatePortfolioVariance(aWeightsVctr).toBigDecimal(); } protected final void calibrate(final BasicMatrix aWeightsVctr, final BasicMatrix aReturnsVctr) { myMarketEquilibrium.calibrate(aWeightsVctr, aReturnsVctr); this.reset(); } @Override protected void reset() { myAssetWeights = null; myAssetReturns = null; myMeanReturn = null; myReturnVariance = null; } final MarketEquilibrium getMarketEquilibrium() { return myMarketEquilibrium; } }
FinancePortfolio.java源码:
/* * Copyright 2003-2011 Optimatika (www.optimatika.se) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.ojalgo.finance.portfolio; import static org.ojalgo.constant.PrimitiveMath.*; import java.math.BigDecimal; import java.util.List; import org.ojalgo.function.implementation.PrimitiveFunction; import org.ojalgo.random.RandomUtils; import org.ojalgo.random.process.GeometricBrownianMotion; import org.ojalgo.type.StandardType; import org.ojalgo.type.context.NumberContext; /** ** An asset is a financial instrument that can be bought and sold, and * put in a portfolio. Here, the term is primarily used to describe * something that can be put in a portfolio. When doing theoretical * calculations on model portfolios an asset may just as well be an * index. *
* A portfolio is a collection/combination of assets. *
* Any asset can be viewed as a portfolio containing only itself. *
* * @author apete */ public abstract class FinancePortfolio { protected static final NumberContext WEIGHT_CONTEXT = StandardType.PERCENT; protected static final boolean BOOLEAN_FALSE = false; protected FinancePortfolio() { super(); } public final GeometricBrownianMotion forecast() { final double tmpInitialValue = ONE; final double tmpExpectedValue = ONE + this.getMeanReturn(); final double tmpValueVariance = this.getReturnVariance(); final double tmpHorizon = ONE; return GeometricBrownianMotion.make(tmpInitialValue, tmpExpectedValue, tmpValueVariance, tmpHorizon); } /** * The mean/expected return of this instrument. * May return either the absolute or excess return of the instrument. * The context in which an instance is used should make it clear * which. Calling {@linkplain #shift(Number)} with an appropriate * argument will transform between absolute and excess return. */ public abstract double getMeanReturn(); /** * The instrument's return variance. * * Subclasses must override either {@linkplain #getReturnVariance()} or {@linkplain #getVolatility()}. */ public double getReturnVariance() { final double tmpVolatility = this.getVolatility(); return tmpVolatility * tmpVolatility; } public final double getSharpeRatio(final Number aRiskFreeReturn) { if (aRiskFreeReturn != null) { return (this.getMeanReturn() - aRiskFreeReturn.doubleValue()) / this.getVolatility(); } else { return this.getMeanReturn() / this.getVolatility(); } } /** * Value at Risk (VaR) is the maximum loss not exceeded with a * given probability defined as the confidence level, over a given * period of time. */ public final double getValueAtRisk(final Number aConfidenceLevel, final Number aTimePeriod) { final double aReturn = this.getMeanReturn(); final double aStdDev = this.getVolatility(); final double tmpConfidenceScale = SQRT_TWO * RandomUtils.erfi(ONE - (TWO * (ONE - aConfidenceLevel.doubleValue()))); final double tmpTimePeriod = aTimePeriod.doubleValue(); return Math.max(Math.sqrt(tmpTimePeriod) * aStdDev * tmpConfidenceScale - tmpTimePeriod * aReturn, ZERO); } /** * Volatility refers to the standard deviation of * the change in value of an asset with a specific * time horizon. It is often used to quantify the risk of the * asset over that time period. * * Subclasses must override either {@linkplain #getReturnVariance()} or {@linkplain #getVolatility()}. */ public double getVolatility() { return PrimitiveFunction.SQRT.invoke(this.getReturnVariance()); } /** * This method returns a list of the weights of the Portfolio's * contained assets. An asset weight is NOT restricted to being * a share/percentage - it can be anything. Most subclasses do * however assume that the list of asset weights are * shares/percentages that sum up to 100%. Calling * {@linkplain #normalise()} will transform any set of weights to * that form. */ public abstract ListgetWeights(); /** * Normalised weights Portfolio */ public final FinancePortfolio normalise() { return new NormalisedPortfolio(this); } /** * Will shift the portfolio mean return (all asset returns) * upp/down. Can be used to add/remove the risk-free return. */ public final FinancePortfolio shift(final Number aReturnShift) { return new ShiftedPortfolio(this, aReturnShift); } protected abstract void reset(); }