Repository navigation
Model MultiPeriodKagiMRStrategyDemo
All quantitative model results · Pinned source · Javadoc
Alexandre d’Aspremont, Identifying Small Mean Reverting Portfolios (2008 author preprint; published 2011) asks how to build a mean-reverting basket using only a few assets. A dense basket may look attractive statistically but be expensive and difficult to trade.
The paper uses a vector autoregressive representation and a Box–Tiao predictability ratio as a proxy for mean reversion. Minimizing this ratio seeks combinations whose current variation is less explained by lagged variation. A cardinality restriction limits the number of nonzero holdings. Greedy search and semidefinite relaxations address the resulting sparse optimization problem; regularized estimation can help stabilize its inputs.
Its central tradeoff is between sparsity and the strength of the mean-reversion proxy. Finding a basket does not specify a complete trading strategy or guarantee a profit. Kagi signals, entry and exit policies, sizing and the S&P 500 universe in these demos are separate choices. Sections 2–3 of the author preprint were reviewed.
MultiPeriodKagiMRStrategySim repeatedly combines selection and trading according to MRSimParamSP500, then exposes a PerformanceReport and basket diagnostics. Basket renewal, Kagi execution and the chosen universe are application settings; compare estimation windows with trade dates to avoid future information.
Using this example. Runs MultiPeriodKagiMRStrategySim using MRSimParamSP500 and inspects the resulting basket analysis and performance report. Basket construction and subsequent trading are separate stages; review their data windows before adapting the example.
Model and publication. Sparse mean-reverting portfolio construction motivates the basket search. The paper’s predictability criterion is not itself a trading return.
Implementation in this tutorial. MultiPeriodKagiMRStrategySim repeatedly combines selection and trading according to MRSimParamSP500, then exposes a PerformanceReport and basket diagnostics. Basket renewal, Kagi execution and the chosen universe are application settings; compare estimation windows with trade dates to avoid future information.
| Item | Value |
|---|---|
| Status | timeout |
| Run | 39114360151 |
| UTC publication | 2026-10-18 09:18 UTC |
| Source commit | 355aa9242fc2a247b256aecc8406cbb409aa5ff3 |
| Data mode | original main defaults |
| Exit code | -15 |
| Elapsed seconds | 180.16 |
| Time limit seconds | 180 |
| Maximum Java heap | 1200m |
The original main exceeded the configured execution limit; partial outputs are not a completed result.
Follow the repository setup for JDK 8, Maven credentials and an external NM license. From the repository root:
mvn -U -Dmaven.test.skip=true clean package
mvn exec:java -Dexec.mainClass=tech.nmfin.algoquant.demo.model.daspremont2008.MultiPeriodKagiMRStrategyDemoThe automated run uses scripts/ModelDemoRunner.java to initialize the external license before the unchanged main, save JFreeChart windows as PNGs, and exit after main returns. It uses an isolated working directory with the repository datasets/configuration linked in. Running directly may leave desktop windows open.
This is an incomplete or blocked run. Output below is diagnostic or partial, not a verified strategy result.
09:12:34.191 [main] INFO t.n.a.m.m.d.s.MultiPeriodKagiMRStrategySim,246 - there are 4 periods (period = P6M) in the interval [2013-01-01T00:00,2015-01-01T00:00): [2013-01-01T00:00, 2013-07-01T00:00, 2014-01-01T00:00, 2014-07-01T00:00]
09:12:34.219 [basket-precompute-1-thread-3] INFO t.n.a.m.m.d.s.SimpleMRBasketProvider,197 - computing baskets at time 2013-07-01T00:00 (covPenalty=1.5E-4; inSamplePeriodForClustering=P10Y; inSamplePeriodForBasketSelection=P5Y; nBaskets=1; basketSize=5)
09:12:34.219 [basket-precompute-1-thread-1] INFO t.n.a.m.m.d.s.SimpleMRBasketProvider,197 - computing baskets at time 2013-01-01T00:00 (covPenalty=1.5E-4; inSamplePeriodForClustering=P10Y; inSamplePeriodForBasketSelection=P5Y; nBaskets=1; basketSize=5)
09:12:34.219 [basket-precompute-1-thread-2] INFO t.n.a.m.m.d.s.SimpleMRBasketProvider,197 - computing baskets at time 2014-01-01T00:00 (covPenalty=1.5E-4; inSamplePeriodForClustering=P10Y; inSamplePeriodForBasketSelection=P5Y; nBaskets=1; basketSize=5)
09:12:34.219 [basket-precompute-1-thread-4] INFO t.n.a.m.m.d.s.SimpleMRBasketProvider,197 - computing baskets at time 2014-07-01T00:00 (covPenalty=1.5E-4; inSamplePeriodForClustering=P10Y; inSamplePeriodForBasketSelection=P5Y; nBaskets=1; basketSize=5)
09:12:34.236 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,194 - looking up configuration file: config.default.xml
09:12:34.236 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,194 - looking up configuration file: config/config.default.xml
09:12:34.236 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,209 - loading config file: file:/home/runner/work/algoquant-examples/algoquant-examples/target/model-results/MultiPeriodKagiMRStrategyDemo/work/config/config.default.xml
09:12:34.559 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,95 - current directory: /home/runner/work/algoquant-examples/algoquant-examples/target/model-results/MultiPeriodKagiMRStrategyDemo/work
09:12:34.559 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,169 - current config:
09:12:34.567 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - nm.license: /home/runner/work/algoquant-examples/algoquant-examples/license/nm.lic
09:12:34.568 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_FOLDER: ./test-data
09:12:34.568 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_GAINCAPITAL: ${DATA_FOLDER}/processed/gaincapital/extracted-from-raw-arrange-by-dates
09:12:34.568 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_BLOOMBERG: ${DATA_FOLDER}/processed/bloomberg
09:12:34.568 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_YAHOO: ${DATA_FOLDER}/yahoo
09:12:34.568 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_SGX: ${DATA_FOLDER}/raw/sgx
09:12:34.568 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_HOLIDAYS: ./log/holidays
09:12:34.569 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - DATA_COMPUSTAT_HK: ${DATA_FOLDER}/[database configuration redacted]/hk
09:12:34.569 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - PDF_OUTPUT_FOLDER: ./log/
09:12:34.569 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - PDF_PLOT_WIDTH: 800
09:12:34.569 [basket-precompute-1-thread-2] INFO t.n.algoquant.util.config.AQConfig,11 - PDF_PLOT_HEIGHT: 600
09:12:36.068 [basket-precompute-1-thread-2] INFO t.n.a.d.h.yahoo.YahooEODCacheFactory,237 - failed to load from file, reason: no data read from file; load from web
09:12:36.068 [basket-precompute-1-thread-2] INFO t.n.a.d.h.yahoo.YahooEODCacheFactory,196 - reading Yahoo! data for MMM from the Internet from 2003-01-01T00:00 to 2015-01-01T16:00
09:12:36.258 [basket-precompute-1-thread-2] INFO t.n.a.d.h.y.YahooEODCsvZipFileWriter,30 - writing csv.zip file ./log/yahoo/pricematrix/MMM.csv.zip
09:12:36.307 [basket-precompute-1-thread-2] INFO t.n.a.d.h.y.YahooEODCsvZipFileWriter,81 - finished writing ./log/yahoo/pricematrix/MMM.csv.zip
09:12:36.316 [basket-precompute-1-thread-2] INFO t.n.a.d.h.yahoo.YahooEODCacheFactory,237 - failed to load from file, reason: no data read from file; load from web
09:12:36.316 [basket-precompute-1-thread-2] INFO t.n.a.d.h.yahoo.YahooEODCacheFactory,196 - reading Yahoo! data for AOS from the Internet from 2003-01-01T00:00 to 2015-01-01T16:00
... excerpt shortened; complete stdout is in the release archive ...
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at dev.nm.misc.parallel.ParallelExecutor.executeAll(bwb:217)
at dev.nm.misc.parallel.ParallelExecutor.forEach(bwb:323)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.s(eh:153)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.preComputeBaskets(eh:96)
at tech.nmfin.algoquant.demo.model.daspremont2008.MultiPeriodKagiMRStrategyDemo.main(MultiPeriodKagiMRStrategyDemo.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at ModelDemoRunner.main(ModelDemoRunner.java:38)
Caused by: java.lang.IllegalArgumentException: List length = -1
at java.util.Collections.nCopies(Collections.java:4986)
at dev.nm.algebra.linear.matrix.doubles.operation.MatrixUtils.deColumnMean(pfc:101)
at dev.nm.stat.descriptive.covariance.SampleCovariance.b(jlb:30)
at dev.nm.stat.descriptive.covariance.SampleCovariance.<init>(jlb:168)
at dev.nm.stat.descriptive.covariance.SampleCovariance.<init>(jlb:3)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.ClusterFinder.s(uo:204)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.ClusterFinder.findClusters(uo:130)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.ClusterFinder.findLargestCluster(uo:205)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.MRMultiBasketFinder.findBaskets(ul:28)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.SimpleMRBasketProvider.s(mf:91)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.SimpleMRBasketProvider.basketsAtTime(mf:92)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.MRBasketProviderCachedFactory.preComputeBasket(gl:72)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.s(eh:102)
at dev.nm.misc.parallel.ParallelExecutor$2.call(bwb:385)
at dev.nm.misc.parallel.ParallelExecutor$2.call(bwb:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: List length = -1
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at dev.nm.misc.parallel.ParallelExecutor.executeAll(bwb:217)
at dev.nm.misc.parallel.ParallelExecutor.forEach(bwb:323)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.s(eh:153)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.preComputeBaskets(eh:96)
at tech.nmfin.algoquant.demo.model.daspremont2008.MultiPeriodKagiMRStrategyDemo.main(MultiPeriodKagiMRStrategyDemo.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at ModelDemoRunner.main(ModelDemoRunner.java:38)
Caused by: java.lang.IllegalArgumentException: List length = -1
at java.util.Collections.nCopies(Collections.java:4986)
at dev.nm.algebra.linear.matrix.doubles.operation.MatrixUtils.deColumnMean(pfc:101)
at dev.nm.stat.descriptive.covariance.SampleCovariance.b(jlb:30)
at dev.nm.stat.descriptive.covariance.SampleCovariance.<init>(jlb:168)
at dev.nm.stat.descriptive.covariance.SampleCovariance.<init>(jlb:3)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.ClusterFinder.s(uo:204)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.ClusterFinder.findClusters(uo:130)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.ClusterFinder.findLargestCluster(uo:205)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.MRMultiBasketFinder.findBaskets(ul:28)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.SimpleMRBasketProvider.s(mf:91)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.SimpleMRBasketProvider.basketsAtTime(mf:92)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.strategy.MRBasketProviderCachedFactory.preComputeBasket(gl:72)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.s(eh:102)
at dev.nm.misc.parallel.ParallelExecutor$2.call(bwb:385)
at dev.nm.misc.parallel.ParallelExecutor$2.call(bwb:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
at dev.nm.misc.parallel.ParallelExecutor.executeAll(bwb:95)
at dev.nm.misc.parallel.ParallelExecutor.forEach(bwb:323)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.s(eh:153)
at tech.nmfin.algoquant.model.meanreversion.daspremont2008.simulation.MultiPeriodKagiMRStrategySim.preComputeBaskets(eh:96)
at tech.nmfin.algoquant.demo.model.daspremont2008.MultiPeriodKagiMRStrategyDemo.main(MultiPeriodKagiMRStrategyDemo.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at ModelDemoRunner.main(ModelDemoRunner.java:38)
09:14:54.362 [main] INFO t.n.a.m.m.d.s.MultiPeriodKagiMRStrategySim,68 - pre-computed baskets:
dev.nm.misc.parallel.MultipleExecutionException: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: List length = -1
Caused by: java.lang.IllegalArgumentException: List length = -1
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: List length = -1
Caused by: java.lang.IllegalArgumentException: List length = -1
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: List length = -1
Caused by: java.lang.IllegalArgumentException: List length = -1
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: List length = -1
Caused by: java.lang.IllegalArgumentException: List length = -1
Download MultiPeriodKagiMRStrategyDemo.zip contains stdout, stderr, the execution record, checksums and any exported CSV/chart files.
| Export | Bytes |
|---|---|
files/log/basket.series.20261018091454/basket.series.combined.csv |
0 |
files/log/basket.series.20261018091454/basket.series.in.sample.csv |
0 |
files/log/basket.series.20261018091454/basket.series.out.of.sample.csv |
0 |
Use the first relevant exception and the source configuration to resolve the prerequisite or code issue, then rerun. A missing dataset requires the correct original schema and period; substituting synthetic values would be a different experiment. A timeout establishes only that this bounded attempt did not finish.
For model assumptions, original publications and adaptation limits, use the literature guide.