参考文档: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 List getWeights() {
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(); }