ojAlgo v47.1.1, ojAlgo-finance v2.1 & Financial Time Series Data

ojAlgo v47.1.1

  • Primarily this release has improvements to the optimisation code:
    • Extensive work on tuning the solvers (primarily the ConvexSolver)
    • Major refactoring of test cases (mainly for LinearSolver and IntegerSolver).
    • The presolve functionality has been improved, affecting all solvers.
    • MPS file parser improved to handle more cases
    • A couple of bugs fixed…
  • Refactoring/restructuring of the org.ojalgo.function (sub)packages. You will most likely need to update some import statements.
  • Fixed a couple of minor bugs related to eigenvalue decompositions.
  • New functionality that enable data “transformations” via functional interfaces.

Check the ojAlgo change-log for a more complete list of what’s new!

ojAlgo-finance v2.1.0

  • Adjustments for ojAlgo v47.1
  • Improvements to code that fetches historical data from Yahoo, IEX Trading or Alpha Vantage. It is now very easy to fetch data from different sources and have it automatically coordinated – same start and end dates, same frequency – so that computing things like covariance matrices becomes straight forward.

Example Code – Historical Financial Data

FinancialData.java
import java.time.LocalDate;

import org.ojalgo.OjAlgoUtils;
import org.ojalgo.data.domain.finance.series.DataSource;
import org.ojalgo.data.domain.finance.series.YahooSession;
import org.ojalgo.netio.BasicLogger;
import org.ojalgo.random.SampleSet;
import org.ojalgo.random.process.GeometricBrownianMotion;
import org.ojalgo.random.process.RandomProcess.SimulationResults;
import org.ojalgo.series.BasicSeries;
import org.ojalgo.series.primitive.CoordinatedSet;
import org.ojalgo.series.primitive.PrimitiveSeries;
import org.ojalgo.type.CalendarDateUnit;
import org.ojalgo.type.PrimitiveNumber;

/**
 * An example demonstrating how to download historical financial time series data, and how you can continue
 * working with it.
 *
 * @see https://www.ojalgo.org/2019/04/ojalgo-v47-1-ojalgo-finance-v2-1-financial-time-series-data/
 * @see https://github.com/optimatika/ojAlgo/wiki/Financial-Data
 */
public abstract class FinancialData {

    public static void main(final String[] args) {

        BasicLogger.debug();
        BasicLogger.debug(FinancialData.class);
        BasicLogger.debug(OjAlgoUtils.getTitle());
        BasicLogger.debug(OjAlgoUtils.getDate());
        BasicLogger.debug();

        // First create the data sources

        DataSource sourceMSFT = DataSource.newAlphaVantage("MSFT", CalendarDateUnit.DAY, "demo");

        // Different Yahoo data sources should share a common session

        YahooSession yahooSession = new YahooSession();
        DataSource sourceAAPL = DataSource.newYahoo(yahooSession, "AAPL", CalendarDateUnit.DAY);
        DataSource sourceIBM = DataSource.newYahoo(yahooSession, "IBM", CalendarDateUnit.DAY);
        DataSource sourceORCL = DataSource.newYahoo(yahooSession, "ORCL", CalendarDateUnit.DAY);

        // Fetch the data

        BasicSeries<LocalDate, PrimitiveNumber> seriesIBM = sourceIBM.getLocalDateSeries(CalendarDateUnit.MONTH);
        BasicSeries<LocalDate, PrimitiveNumber> seriesORCL = sourceORCL.getLocalDateSeries(CalendarDateUnit.MONTH);

        BasicSeries<LocalDate, PrimitiveNumber> seriesMSFT = sourceMSFT.getLocalDateSeries(CalendarDateUnit.MONTH);
        BasicSeries<LocalDate, PrimitiveNumber> seriesAAPL = sourceAAPL.getLocalDateSeries(CalendarDateUnit.MONTH);

        BasicLogger.debug("Range for {} is from {} to {}", seriesMSFT.getName(), seriesMSFT.firstKey(), seriesMSFT.lastKey());
        BasicLogger.debug("Range for {} is from {} to {}", seriesAAPL.getName(), seriesAAPL.firstKey(), seriesAAPL.lastKey());
        BasicLogger.debug("Range for {} is from {} to {}", seriesIBM.getName(), seriesIBM.firstKey(), seriesIBM.lastKey());
        BasicLogger.debug("Range for {} is from {} to {}", seriesORCL.getName(), seriesORCL.firstKey(), seriesORCL.lastKey());

        // Coordinate the series - common start, end and frequency

        CoordinatedSet<LocalDate> coordinationSet = CoordinatedSet.from(seriesMSFT, seriesAAPL, seriesIBM, seriesORCL);

        BasicLogger.debug();
        BasicLogger.debug("Common range is from {} to {}", coordinationSet.getFirstKey(), coordinationSet.getLastKey());

        PrimitiveSeries primitiveMSFT = coordinationSet.getSeries(0);
        PrimitiveSeries primitiveAAPL = coordinationSet.getSeries(1);
        PrimitiveSeries primitiveIBM = coordinationSet.getSeries(2);
        PrimitiveSeries primitiveORCL = coordinationSet.getSeries(3);

        // Create sample sets of log differences

        SampleSet sampleSetMSFT = SampleSet.wrap(primitiveMSFT.log().differences());
        SampleSet sampleSetIBM = SampleSet.wrap(primitiveIBM.log().differences());

        BasicLogger.debug();
        BasicLogger.debug("Sample statistics (logarithmic differences on monthly data)");
        BasicLogger.debug("MSFT:  {}", sampleSetMSFT);
        BasicLogger.debug("IBM: {}", sampleSetIBM);
        BasicLogger.debug("Correlation: {}", sampleSetIBM.getCorrelation(sampleSetMSFT));

        // Estimate stochastic process parameters based on historical data

        GeometricBrownianMotion monthlyProcAAPL = GeometricBrownianMotion.estimate(primitiveAAPL, 1.0);
        GeometricBrownianMotion monthlyProcORCL = GeometricBrownianMotion.estimate(primitiveORCL, 1.0);
        monthlyProcAAPL.setValue(1.0); // To normalize the current value
        monthlyProcORCL.setValue(1.0);

        double yearsPerMonth = CalendarDateUnit.YEAR.convert(CalendarDateUnit.MONTH);

        // The same thing, but annualised

        GeometricBrownianMotion annualProcAAPL = GeometricBrownianMotion.estimate(primitiveAAPL, yearsPerMonth);
        GeometricBrownianMotion annualProcORCL = GeometricBrownianMotion.estimate(primitiveORCL, yearsPerMonth);
        annualProcAAPL.setValue(1.0); // To normalize the current value
        annualProcORCL.setValue(1.0);

        // Comparing the monthly and annual stochastic processes for AAPL

        BasicLogger.debug();
        BasicLogger.debug("    Apple    Monthly proc    Annual proc    (6 months from now)");
        BasicLogger.debug("Expected: {}    {}", monthlyProcAAPL.getDistribution(6.0).getExpected(), annualProcAAPL.getDistribution(0.5).getExpected());
        BasicLogger.debug("StdDev:   {}    {}", monthlyProcAAPL.getDistribution(6.0).getStandardDeviation(),
                annualProcAAPL.getDistribution(0.5).getStandardDeviation());
        BasicLogger.debug("Var:      {}    {}", monthlyProcAAPL.getDistribution(6.0).getVariance(), annualProcAAPL.getDistribution(0.5).getVariance());

        // Comparing the annualized stochastic processes for AAPL and ORCL

        BasicLogger.debug();
        BasicLogger.debug("    Apple    Oracle    (1 year from now)");
        BasicLogger.debug("Current:  {}    {}", annualProcAAPL.getValue(), annualProcORCL.getValue());
        // getExpected() is a shortcut to getDistribution(1.0).getExpected()
        BasicLogger.debug("Expected: {}    {}", annualProcAAPL.getExpected(), annualProcORCL.getExpected());
        // getStandardDeviation() is a shortcut to getDistribution(1.0).getStandardDeviation()
        BasicLogger.debug("StdDev:   {}    {}", annualProcAAPL.getStandardDeviation(), annualProcORCL.getStandardDeviation());
        // getVariance() is a shortcut to getDistribution(1.0).getVariance()
        BasicLogger.debug("Var:      {}    {}", annualProcAAPL.getVariance(), annualProcORCL.getVariance());

        // Simulate future scenarios for ORCL

        SimulationResults simulationResults = annualProcORCL.simulate(1000, 12, yearsPerMonth);
        BasicLogger.debug();
        BasicLogger.debug("Simulate future Oracle: 1000 scenarios, take 12 incremental steps of size 'yearsPerMonth' (1/12)");
        // There are 12 sample sets indexed 0 to 11
        BasicLogger.debug("Simulated sample set: {}", simulationResults.getSampleSet(11));
        // There are 1000 scenarios indexed 0 to 999
        BasicLogger.debug("Simulated scenario: {}", simulationResults.getScenario(999));

        // There is a shortcut to get a coordinated set

        DataSource.Coordinated coordinated = DataSource.coordinated(CalendarDateUnit.DAY);
        coordinated.addAlphaVantage("MSFT", "demo");
        coordinated.addYahoo("AAPL");
        coordinated.addYahoo("IBM");
        coordinated.addYahoo("ORCL");
        CoordinatedSet<LocalDate> coordinationSet2 = coordinated.get();

    }

}

Console Output

class FinancialData
ojAlgo
2019-04-11

Range for MSFT is from 2018-11-30 to 2019-04-30
Range for AAPL is from 2014-04-30 to 2019-04-30
Range for IBM is from 1989-04-30 to 2019-04-30
Range for ORCL is from 1989-04-30 to 2019-04-30

Common range is from 2018-11-30 to 2019-04-30

Sample statistics (logarithmic differences on monthly data)
	MSFT:  Sample set Size=5, Mean=0.016963754617290227, Var=0.003898700343476474, StdDev=0.0624395735369523, Min=-0.08779088268545898, Max=0.0745334981716903
	IBM: Sample set Size=5, Mean=0.030422355449287154, Var=0.008393992685262789, StdDev=0.09161873544893964, Min=-0.08915711966527695, Max=0.16766968378644798
Correlation: 0.6181368931750267

  Apple   Monthly proc 	         Annual proc (6 months from now)
Expected: 1.1810740629349612 	 1.1810740629349612
StdDev:   0.24837454053493682 	 0.24837454053493682
Var:      0.06168991238594097 	 0.06168991238594097

 	  Apple 		 Oracle (1 year from now)
Current:  1.0 			 1.0
Expected: 1.3949359421376966 	 1.337730471536396
StdDev:   0.4194193574444725 	 0.31584482401600694
Var:      0.17591259739913417 	 0.09975795285770238

Simulate future Oracle: 1000 scenarios, take 12 incremental steps of size 'yearsPerMonth' (1/12)
Simulated sample set:  Sample set Size=1000, Mean=1.3368173052144632, Var=0.09925845188383686, StdDev=0.3150530937537939, Min=0.504248921172877, Max=3.6405224252854183
Simulated scenario:  { 1.0, 0.987953283856134, 0.9803778218751452, 1.0275292151500863, 0.9806568759600218, 1.0407422677990135, 1.2023135797767084, 1.2971232117765163, 1.308873281212413, 1.3496369871350853, 1.3994778062888376, 1.3165433881275048, 1.3702583762345444 }