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