Skip to content

About

Chronological financial ML research with purged evaluation, baselines and transparent model risk

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ChronosResearch

A financial forecast must earn its complexity on observations it has never seen.

ChronosResearch investigates whether lagged returns, momentum and volatility improve future-return forecasts over a zero-return forecast and the historical mean. Its answer can be “no”—and that is a useful research result.

Research workbench

The financial question

Price histories contain persistent scales and transient relationships. Regressing today’s price on today’s moving average can look impressive while answering no tradable forecasting question. ChronosResearch instead asks: does information known strictly before a decision date reduce error on subsequent returns?

The purpose is to investigate weak market signals with reproducible engineering. Random train/test splitting is generally inappropriate here: it mixes future regimes into training, allows nearby overlapping labels to cross the evaluation boundary, and can fit preprocessing on information unavailable at the forecast date. Chronological ordering alone is insufficient when labels span multiple observations; their end dates must also be purged.

What the system analyzes

  1. Import your own daily price CSV, declare its source, units, adjustment convention and as-of date, or run the explicitly synthetic DEMO DATA fixture.
  2. Construct five prior-only signals and a forward simple-return target over 1–10 observations.
  3. Select Ridge regularization on a purged validation period, then score the untouched fixed test segment against two simple baselines.
  4. Expand training through four walk-forward blocks with a frozen alpha and strictly prior label cutoffs.
  5. Inspect regime errors, signed standardized coefficients, interactive forecasts, and the complete timeline.
  6. For one-period market-close inputs, inspect a deliberately delayed long/cash illustration with turnover costs. Reference rates and overlapping multi-period labels do not generate a strategy.
  7. Export the experiment JSON, including the exact input CSV, metadata, configuration, forecasts and data hash.

The engine is stateless; calculations come from the supplied input, not hardcoded dashboard values. Missing or unavailable data returns an error. Network access and credentials are unnecessary for the browser workflow and saved experiments.

An actual out-of-sample result

The included ECB EUR/USD reference series contains 2,048 observations from 2018–2025. The predeclared five-observation experiment reserves 405 forecast decisions from 2024-05-27 to 2025-12-22, with final labels ending 2025-12-31.

Forecast Fixed test RMSE Walk-forward RMSE
Zero return 0.9876% 0.9876%
Historical mean 0.9922% 0.9914%
Scaled Ridge 0.9992% 0.9970%

These are percentage points of five-observation return, computed by python -m scripts.run_experiments; see full results. Ridge did not outperform the simpler zero-return forecast. A plausible feature and a fitted coefficient do not establish predictive usefulness. Small error differences require further investigation, not a profitability claim. Overlapping five-observation labels are correlated; 405 forecasts are not 405 independent trials.

Source: European Central Bank reference rates. These rates are published for information, and the ECB discourages transaction use. The application therefore suppresses strategy simulation for price_basis="reference-rate". USD values are unchanged; selecting the period, normalizing column names and calculating returns are this project’s transformations. Retrieval record and source hashes and ECB reuse terms accompany the snapshot. The MIT software license does not replace the source’s data terms.

The synthetic example is a separate mechanics demonstration, never market evidence. Its fixed-test Ridge RMSE is 0.8068%, versus 0.8054% for the historical mean. Its observed simulated net return is also not evidence of an investment opportunity.

Financial framework

At decision index t, all predictors use prices through t−1. The target is:

y[t] = close[t+h] / close[t] − 1

The five features are the last observed one-period return, 5- and 20-observation momentum, 20-return sample volatility, and the mean of the last five observed returns. Ridge minimizes squared residuals plus alpha × sum(coefficients²) after training-only standardization. Shrinkage limits coefficient sensitivity; it does not create signal.

Training label end dates must be strictly earlier than the next partition’s first decision date. The 60/20/20 split is taken after warm-up and unavailable-label removal. The validation grid is fixed at [0.1, 1, 10, 100]; the test period never chooses alpha. Walk-forward retraining may use prior test outcomes only after their labels have matured. Full derivation.

Run locally

Python 3.12 and Node 24 are the release-tested runtimes. Node is used only for JavaScript syntax checks; the application has no npm dependencies.

python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m uvicorn chronos.api:app --host 127.0.0.1 --port 8077

Open the workbench. The initial experiment clearly loads DEMO DATA. For the real snapshot, upload examples/ecb_eurusd.csv, set source to European Central Bank, symbol EURUSD, currency USD, price basis Reference rate, adjustments Unadjusted, as-of 2026-09-08 and horizon 5. No API key is needed.

CSV header must be exactly date,close. Use strict YYYY-MM-DD dates and positive finite decimal prices. Supply 160–10,000 daily observations and at most 2 MB. Rows are sorted with a notice; duplicates, missing prices, malformed dates and extra columns are rejected. Horizons count observations, not calendar days. See the data dictionary.

# Offline reproduction of both committed experiments
python -m scripts.run_experiments
# Optional explicit refresh from ECB; failure raises an error
python -m scripts.fetch_ecb

The API exposes GET /api/health, GET /api/demo, POST /api/research and the OpenAPI schema. The UI and scripts use the same research service.

Validation and architecture

python -m pytest -q
ruff check .
mypy
node --check chronos/static/app.js
node --check chronos/static/charts.js
python -m build
python -m playwright install chromium
# With the local server running:
python scripts/browser_smoke.py

Tests cover hand-calculated returns, Ridge shrinkage and trading costs; future-data perturbations; label-horizon purging; constant series; malformed and oversized inputs; API integration; and a real Chromium journey with CSV import, interactive charts, JSON export and mobile layout checks. Architecture explains the small Python / FastAPI / static-browser boundary. CI runs lint, types, tests, package build and Chromium.

Assumptions and limitations

  • Historical relationships and volatility regimes change. Neither backtests nor coefficient signs are guarantees.
  • The API trusts declared adjustment and provenance conventions. A current adjusted-price history is not a complete point-in-time archive of corporate actions or data revisions.
  • This v1 studies one series at a time. It does not solve survivorship bias, cross-asset universe selection, macro release lags or feature mining.
  • Repeatedly choosing experiments after observing test results contaminates the holdout. Save a research log and reserve a new future period for confirmation.
  • Regime labels are descriptive, with their cutoff frozen on initial training volatility. Small subgroups are unstable.
  • The trading illustration ignores taxes, liquidity, borrow, interest on cash, financing, slippage variation and execution uncertainty. It uses market closes as simplified fills and an additional observation lag.
  • Local operation is the intended deployment. Public hosting requires authentication and resource controls; see security.

Model card · Limitations · Delivery evidence

Relationship to earlier work and future research

StockMarketPredictions remains an unchanged historical exploratory precursor. ChronosResearch is a distinct, complete research engine: it does not reuse that exploration’s random regression evaluation or missing-target treatment, and imports no claimed results from it.

Useful next research asks whether predeclared signals survive a genuinely new time period, whether volatility forecasts are more stable than return forecasts, and how robust comparisons change under block-bootstrap uncertainty estimates. Further model complexity should follow evidence that simple baselines leave something predictable.

About

Chronological financial ML research with purged evaluation, baselines and transparent model risk

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages