point-in-time backtesting lab
Starting up…
PREVIEW MODE — no engine attached. Data shown is illustrative. Start the app with python main.py for real functionality.

Before you start

Midas is research software, not investment advice. Everything it produces is a hypothetical backtest — a simulation built with hindsight, not the record of real trading.

Please read the Terms of Use and the Privacy Policy.

Vault

permanent copies of runs you choose — unaffected by the 20-run history limit

Run history

one row per run — click a row for every experiment's breakdown; the last 20 are kept across restarts

Balance Lab

TEMPORARY — rank every experiment on the six locked axes, see which one is holding the score down, and promote search candidates into studies

Strategy

reusable scoring strategies — build once, link from any System

Companies

company lists & reusable universes

Company lists will live here — build a universe once (like the Universe step in an experiment) and reuse it across experiments. This page is a placeholder for now; the full company-list builder is coming in a later pass.

Guide

how Midas works, how to use it, and the math underneath

What is Midas?

Midas is a point-in-time backtesting lab. You design an Experiment — a reproducible recipe for an investing approach — and Midas replays it against history using only the data that was actually public at each moment, so a result can never peek at the future. It is deliberately philosophy-neutral: growth, value, quality, momentum, dividend, or fixed-basket ideas all run on the same engine, scored the same honest way.

The workflow

1. Experiments page → choose Create a System or Choose Stocks+ New. 2. Walk the steps: TimelineCashflowsUniverseReliability check. For a System, link a Strategy from your library using the donut in its Strategy column (strategies are built on the Strategy page). 3. Hit Run ▶ and pick everything to compare. 4. Read the results (chart, summary, portfolio-through-time, scorecard, rebalancing, taxes, observations). Every run is also saved to History.

Why "reproducible"?

An Experiment is a saved document: the same inputs produce the same result (a saved run in History is frozen exactly as it was). The Reliability check tells you how much of the data the experiment needs actually existed, so you know whether to believe the headline number. The only thing that legitimately moves a re-run is the passage of time (backtests end today) or your data provider revising history.

Use the tabs above to dig into each area. Midas is research software, not investment advice — see the Disclaimer.

Experiments & modes

An Experiment is one backtest recipe. It has a mode:

Create a System — a scoring Strategy re-ranks your universe on each Timeline date and deploys capital to the top names. This is the research workhorse (e.g. "own the 10 highest-quality stocks, re-checked quarterly").
Choose Stocks — you fix the tickers and (optionally) their target weights once; no scoring. Good for testing a specific basket or a model portfolio.
Benchmark — holds a single ETF (e.g. SPY/QQQ) and mirrors the first experiment's cashflows 1:1, so the comparison is apples-to-apples. Add them in the Run dialog to compare against your experiments.

Comparing & viewing

When you hit Run ▶, the table itself becomes the picker: tick the experiments to chart together (a checkbox appears beside each name), toggle any benchmark chips under the toolbar, then hit Run (N) ▶. On the results page a frozen strip lets you switch which one you're viewing at any time — its line is drawn on top, gets the headline number, and the portfolio-through-time, strategy, rebalancing and taxes panels reflect it.

Organizing

Click the crown to favourite an experiment (only favourites show gold names). Make named categories per group and drag rows between them; picking a row up turns off column-sort so your manual order sticks. Sort any column by clicking its header. Categories, favourites and manual order all persist across restarts.

Editing safely

Everything auto-saves. Use ↶ Undo / ↷ Redo in the editor to walk changes back and forth. Duplicate clones an experiment (and keeps you on the same tab). A trust re-audit only runs when you change something that affects the data needed — not when you tweak a weight.

Strategies (Create a System mode)

A Strategy decides what deserves capital. It is a set of metrics drawn from the library (revenue growth, ROIC, FCF yield, P/E, debt/equity, momentum, …), each tagged with a group (Income statement, Valuation, Profitability, Health, …) from the library's own taxonomy.

Weights & groups

Each metric has a direction (higher- or lower-is-better — flip it with the LOWER/HIGHER toggle) and a metric weight. Each group has a group multiplier (×). A metric's effective weight = metric weight × its group's multiplier; the score bar/donut shows each group's resulting share. (If you remove a group's last metric, its multiplier resets to 1× so it doesn't silently carry over.)

Reuse & visuals

Strategies are built on the Strategy page (each is a reusable card) and linked into Systems — click the donut in an experiment's Strategy column for a blown-up view of its make-up (metrics, groups, and a Swap Strategy button), or the + to link one. Editing a strategy updates every experiment that links it (resolved at run time); a saved run in History stays frozen. The make-up always shows as a donut; colours come from a fixed group→colour map, so a given group is always the same colour.

Gotcha: why weight tweaks sometimes don't move results

The basket rule + DCA method (next tab) decide the actual portfolio. If you hold an Equal-weighted Top-N and a weight tweak only re-orders names within that same top-N set, the portfolio — and the result — won't change. To make weights bite, use a rank/blend DCA, tighten the Top-N, or change which metrics are selected.

Universe — who's eligible

The Universe is the pool of companies an experiment may hold. On each re-score date, every eligible ticker is scored; any ticker missing a required metric is dropped from that date's ranking entirely — never silently scored as an average, which is how lookalike tools quietly corrupt results. A ticker also needs at least a year of filed quarterly statements (4 quarters) on that date to be scored at all, so a barely-public company can't rank top-N on one quarter of noisy data (a real failure mode on deep-history backtests with thin early fundamentals).

Point-in-time correctness

Financial statements are sliced by filing date, so a backtest only ever uses what was public on the as-of date. Index membership is reconstructed point-in-time (the members as of that date, not today's list) to avoid survivorship bias — from a built-in S&P 500 history (1996–present) that needs no data provider, so companies that were in the index then but have since delisted are still in the past universe.

Data providers

Sharadar (via Nasdaq Data Link) — the point-in-time core: prices from 1998 and fundamentals from 1990, covering delisted companies as well as live ones. That last part is what makes a survivorship-free backtest possible at all; it is why Midas uses this source rather than a free one. SEC EDGAR — free and public-domain: filing dates, SIC sectors, fund holdings, and bankruptcy detection, merged on top. Enable sources in Settings → Data providers; the Strategy metrics on offer are limited to what your enabled providers can actually supply, so the Reliability check never fails on data that never existed. The Missing-data policy (drop vs fill) also lives there.

Cashflows

Set a one-time lump and/or recurring deposits and withdrawals (each with a from/to window and cadence). The earliest cashflow date anchors where the backtest actually begins.

Basket rule + DCA method

For Systems, the basket rule (e.g. Top 10) selects which ranked names are eligible at each deposit. The DCA method then sizes them:

Equal — every selected name gets the same weight.
Linear · rank / Quad · rank — more capital to higher-ranked names (quad is steeper).
Linear · discount / Quad · discount — more to names trading further below their 2-year high.
Blend — rank × discount combined.
Momentum — weights by 12-month return.
Set allocations (Choose Stocks mode) — your fixed weights.

Capital-gains tax

Enable tax modeling to tax realized gains from sales/rebalancing. You choose short- vs long-term rates and a lot-selection method: FIFO, LIFO, highest-/lowest-cost (and their LT/ST variants), tax-sensitive, intraday-FIFO, or the Tax-Lot Optimizer (Schwab-style: short-term losses first, then long-term losses, then no-gain lots, then long-term gains, then short-term gains). Dividend income is also taxed (qualified at the long-term rate by default), settled each Dec 31 alongside capital gains.

Rebalancing

Without rebalancing an experiment is buy & hold: deposits only direct new money, and winners grow into ever-larger shares (allocation drift). Turn rebalancing on to periodically pull positions back toward their targets. It's organized in three parts:

WHEN — which Timeline dates trigger a rebalance, plus a minimum-months throttle so it can't fire too often.
HOW FAR — rebalance all the way to target, or only back to the edge of a drift band (partial / band-edge rebalancing — positions inside the band are left alone).
LIMITS — a ±drift band (pp), a max per holding (%), and a top-N cap.

Costs

Rebalancing realizes gains, which are taxed per the Cashflows tax panel (using your chosen lot method) and add turnover. The Rebalancing card on the results page shows each event's turnover, realized gain, and what was sold/bought, so you can see exactly what the discipline cost.

The Reliability check — can you believe the result?

A backtest is only as good as the data behind it. The Reliability grade = the percentage of (ticker × date × metric) cells that have real, filed data — not gap-filled, not assumed. A high grade means the experiment ran on data that genuinely existed point-in-time.

What it audits

Look-ahead: statements sliced by filing date. Survivorship & corporate events: a bankruptcy forces a held position to $0 on its filing date, while an acquisition / delisting is sold at its last price (the deal payout, redeployed as cash) — never $0. Both are applied automatically from a curated historical record plus live SEC EDGAR detection, with no per-user confirmation (see Settings → Corporate events). Universe basis: point-in-time vs today's membership. Dropped tickers: which names lacked a required metric on which dates.

Coverage by date → move start

The Coverage by date heat strip shows how complete the data was over time. Early years are often sparse. Click a cell to move your experiment's start date there — Midas trims earlier Timeline dates and clamps earlier cashflows so the backtest truly starts later. (Re-run to refresh the chart/portfolio.) The same "move start" appears as a nudge when coverage is below 90% and a later start would clear it.

When it re-runs

The audit re-runs only when you change something data-relevant (selected metrics, tickers, dates, mode) — not when you tweak weights, groups, basket, or cashflows. While it's running you'll see a calm blue spinner, never a stale FAIL.

Scoring

On each as-of date, for each selected metric, every eligible ticker's raw value is converted to a percentile (0–100) against the rest of the universe (the percentile is flipped for "lower is better" metrics). A ticker's Score is the weighted average of its percentiles:

Score = Σ ( percentileₘ × effective_weightₘ ) ÷ Σ effective_weightₘ

where effective_weightₘ = metric_weightₘ × group_multiplier(group of m). Tickers missing any selected metric are excluded from that date's ranking.

Returns

Total return % = final value ÷ total invested − 1.

CAGR — the headline number — is time-weighted. It is the per-year growth rate of the strategy with the effect of deposit timing removed: money flowing in or out is netted out on the day it moves, so an experiment is credited only with what its holdings actually did. That matters because you are drip-feeding cash — without it, a system that happened to receive a big deposit just before a rally would look better than one that didn't, even if its picks were worse. This is the figure on the Experiments table, the Balance card's Return axis, the Results summary and History.

Simple CAGR = (final ÷ invested)(365 ÷ days) − 1, where days is each experiment's own holding period (from its first investment to today). It treats every dollar you ever deposited as though it had been there since day one, so on a long drip-fed run it understates badly — E1-Champ 1 reads 14.8% simple against 22.9% time-weighted. That is why it is not the headline. Hover any CAGR to see both figures.

Money-weighted (MWR, an IRR) = what your actual dollars earned, deposit timing very much included. Shown beside the time-weighted column in the Return card. Time-weighted answers “how good is this strategy?”; money-weighted answers “how did my money do?”.

Max drawdown = the largest peak-to-trough decline of the value series.

Fees

The optional advisory fee %/yr is applied as a daily drag (compounded) to the value series, to either all experiments or the viewed experiment only — so you can see the long-run cost of fees.

Why a re-run can differ

Backtests end at today, so re-running on a later day lengthens the period and adds fresh prices, legitimately shifting the final value and CAGR; a provider revising its history does the same. A run saved in History is a frozen snapshot. Within a day, the result cache makes identical re-runs instant and bit-identical.

What these numbers are not

Every figure on this page is computed from a simulation. However carefully the arithmetic is done — and this page exists because it is done carefully — the result is still a hypothetical constructed with the benefit of hindsight, on a strategy no real account traded, without the effect your own orders would have had on prices. A precise number is not a reliable one. Past performance does not guarantee future results, and none of this is investment advice. See the Disclaimer.

Experiment creation

Checking…
Hypothetical These results are simulated with hindsight, not the record of real trading, and are not investment advice. Read the disclaimer →

Chart

View the price performance of each experiment. Switch the timeframe to drag the viewing window.

Consistency

See how each experiment performs across overfitting-robust consistency windows.

How the consistency windows work

The backtest is cut into contiguous calendar windows — one per year, quarter or month, whichever coarsest unit gives at least 8 windows (automatic, from the test length; nothing is adjustable, so the score can't be shopped).

Each window is scored by its annualised return on a soft-clip ruler (a flat window sits at 50; the ruler bends at ±25%/yr and approaches but never reaches 0 or 100), so how much a window made counts — a +45% year reads above a +28% year, and a −60% crash below a −25% dip, where the old ±25 clamp tied each pair. The consistency score is the mean of the window scores minus their spread: performance spread evenly across the calendar scores high, while a late-only run-up scores high in one window and low in the rest, so its spread drags the score down.

This value feeds the Risk card and the Balance card.

Portfolio

Drag the needle to any month-end and see exactly what the portfolio held.

Balance

Analyze how well each experiment performs across six dimensions of analysis. The score is the plain average of how far every axis reaches.

Balance is Midas's own composite, built from thresholds this author chose — not an industry standard, a credit rating, or a recommendation. It compares experiments to each other on the same yardstick; a high score says a backtest looked well-rounded on past data, and nothing about the future.

Strategy

Scorecard

What was held on each date, and why.

How the scorecard works

On each as-of date, every ticker in the experiment's universe is measured on your selected metrics using only data that was publicly filed by that date (statements are sliced by filing date, so the backtest cannot peek at the future). For each metric, tickers are ranked against each other and converted to a percentile (0–100); if you marked a metric "lower is better," the percentile is flipped.

The Score is the weighted average of those percentiles using your metric weights. Tickers missing any selected metric are dropped from that date's ranking entirely (listed below the table) — they are never silently given an average score, which is how lookalike tools quietly corrupt results. "Data through" shows the most recent quarter that was actually available on the as-of date, and when it was filed.

The top-ranked tickers receive capital per your basket rule (e.g., Top 10 equal-weight) at the next deposit.

Details

the full metric tables and per-section breakdowns behind the summary above

Risk

Drawdowns, volatility, and how robust — or fragile — the source of the return was.

Return

Growth rates and risk-adjusted performance.

Rebalancing

What each rebalance sold, and what it cost.

Special Conditions

rule triggers, reentries and warnings from the engine's event log

Taxes

Report

Detail

Disclaimer

Midas is research software, not investment advice. Nothing in this application — results, scores, trust checks, observations, nudges, or any other output — is a recommendation to buy, sell, or hold any security, or an offer of advisory services. Midas and its author are not registered investment advisers, broker-dealers, or fiduciaries, and no advisory relationship is created by your use of this software.

Backtested results are hypothetical. They do not represent actual trading, are constructed with the benefit of hindsight, and do not reflect the impact your own trading would have had on prices. Dividends are modeled per each experiment's Dividends setting — reinvested (total return) or taken as cash — and dividend income is taxed; an acquisition or merger forces a taxable sale at the deal price. Tax and fee modeling are simplified approximations and not tax advice. Data comes from third-party providers and may contain errors, gaps, or revisions; the trust check discloses known gaps but cannot verify provider correctness.

Past performance does not guarantee future results. Markets change; strategies that performed well historically can fail. You can lose money, including your entire investment. Do your own research and consult a licensed financial adviser, tax professional, or attorney before making investment decisions. By using Midas you accept full responsibility for any decisions you make.

Read the full Disclaimer →

Consider

If an experiment looks promising, here are steps a careful researcher might take next — for education, research and analysis only. None of this is investment advice or a recommendation to buy, sell, or hold anything.

  1. Treat the backtest as a hypothesis, not a verdict. A single historical run is one draw from history, built with hindsight. The question to explore is whether the edge is real and repeatable — not whether the past number is impressive.
  2. Pressure-test it out of the window. Re-run over different start dates, sub-periods, and market regimes (bull, bear, sideways). A result that only holds in one window may be fit to that window rather than to anything durable.
  3. Re-read the assumptions. Check this run's data coverage, fees, taxes, dividends, and rebalancing settings. Small changes to costs or timing can quietly erase an apparent edge — turn friction up and see what survives.
  4. Compare against a plain benchmark. See whether the strategy beats a simple index (e.g. buy-and-hold) after costs — and not only on return, but on the Risk and Consistency measures too.
  5. Look at what you'd actually hold. Use the Portfolio and Scorecard cards to inspect the real positions, concentration, and turnover, and ask honestly whether you could hold them through the worst drawdown shown here.
  6. Paper-trade before any real money. Track the strategy on paper or in a simulated account going forward, so you observe its behaviour out-of-sample, in real time, with live prices — where no backtest can flatter it.
  7. Account for real-world frictions a backtest misses. Bid/ask spreads, slippage, minimum lot sizes, order timing, tax lot treatment, and your own behaviour under stress all affect outcomes and are only approximated here.
  8. Consult licensed professionals. Before committing capital, discuss your own goals, time horizon, and risk tolerance with a licensed financial adviser and a tax professional. Midas cannot know your situation and does not give advice.

Reminder. Midas is research software. Backtested results are hypothetical, constructed with hindsight, and past performance does not guarantee future results — you can lose money, including your entire investment. See the Disclaimer.

Settings

Appearance

Theme

Five themes, darkest to lightest, all on the same design foundation — only the palette and brightness change. Purely cosmetic: results, math and workflow are identical in every theme. Applies instantly and is remembered.

Text size
Brightness

Dims the whole interface, popups included. 100% is the design default; lower it if the screen is bright in a dark room.

Donut TEMP

Strategy donuts only — the portfolio disk is untouched. Not saved; resets on reload.

Thickness
Hole size
shipped: thickness 0.40, hole 0.40

Intro choreography TEMP

Logo flies → sidebar fades in → nav text staggers → right-side content arrives. Not saved; resets on reload. Press Replay to watch it again.

Animation speed
Sidebar fade
Sidebar direction
Nav stagger
Right-side fade
Right-side direction
Rise distance
Rise duration

Chart line TEMP

Only affects 5Y/10Y and MAX, where the chart has more points than pixels. Open a Result and pan the chart to compare.

Accessibility

Backtest end date

Where every backtest stops. Applies to all experiments.

End date

Today (default) — run through the most recent available data. Results can shift slightly on re-runs as fresh market data arrives.

End of timeline — stop at the last date you scheduled (final score date or cash-flow). Fixed window, so re-runs stay reproducible. Clamped to today if the timeline runs into the future.

Chart precision — speed vs. detail

How finely a backtest samples portfolio value through time. Daily is exact; coarser grids run faster by taking far fewer steps. Re-score dates and rebalances still fire on their exact days, but deposits, rebalance fills and the value curve snap to the nearest sampled day — so a coarser grid can shift the headline CAGR by a point or more and will understate drawdowns (it skips the troughs between samples). Daily is the ground truth; coarser grids are for fast iteration, not the numbers you report.

Value grid

Use Weekly/Monthly for fast iteration, then switch to Daily for the numbers you report — CAGR and max drawdown can change between grids. The results page shows which grid a run used. Changing this recomputes on the next run.

Special Conditions — trigger rules step

Adds a Special Conditions step to the experiment editor (both modes, after Cashflows): point-in-time rules that watch each held position daily and act when conditions are met — e.g. “up 50% from my cost basis → sell 10%”, or “3-mo and 12-mo moving averages flip negative → exit, re-buy when the trend turns”. Conditions combine with AND / OR / NAND / NOR; sales run through the normal tax-lot and transaction-cost machinery; reentry can be blocked by a cooldown or a condition.

Benchmarks — measurement basis

By default an index benchmark (S&P 500, NASDAQ-100) is the ETF's own price series — real, but measured differently from your experiments (its Breadth comes from a one-window approximation and its Turnover reads 0). This option instead simulates the index as a portfolio of its point-in-time members — cap-weighted, reconstituted quarterly, taxes and transaction costs applied to its internal rebalancing — so every Balance axis is computed exactly the way your experiments are. "Beating the NASDAQ" then means beating it on identical rules.

Costs & taxes — model real-world friction

By default every backtest charges a realistic transaction cost on each trade and models taxes on realized gains, so the returns you see resemble what you'd actually keep. These apply to all experiments (an experiment can still set its own cost). Re-run experiments after changing them.

Transaction cost basis points per trade — 10 bps = 0.10%, charged on every buy and sell (incl. rebalancing)
Short-term rate % Long-term rate % Lot method
Income tax rate %
Dividend tax applies to every experiment's dividend income

Risk-free rate — for Sharpe & Sortino

The benchmark "safe" return that risk-adjusted ratios measure excess return against. The traditional proxy is the short U.S. Treasury bill. This single rate feeds the Report card and the Return card (Sharpe / Sortino) on the results page — both read the same value, so they never disagree.

Maturity

Fetching the latest rate…

Default: latest 13-week (3-month) T-bill — the standard Sharpe risk-free proxy — fetched from the U.S. Treasury daily series (no key). A single constant rate is applied across the whole period (traditional convention). Changing it updates Sharpe/Sortino on the results page instantly — no re-run needed.

Data providers

Choose which sources Midas may use. Free sources are on by default. The Strategy metrics on offer are limited to what your enabled providers can actually supply, so the trust check never fails on data that never existed.

Recommended setup

SEC EDGAR is free and public-domain, and supplies filing-dated US fundamentals, SIC sectors and corporate-event detection. On its own it cannot make a backtest survivorship-free: it carries no prices, and a delisted company you cannot price is a company you can never hold.

For reference-grade, fully survivorship-free data, add Sharadar — the Core US Equities Bundle (SF1 fundamentals + SEP prices incl. delisted names back to 1998). With a key set it becomes Midas's preferred source across the whole universe. Use “Get a key” in the table below.

Note: “Data coverage” means a provider can supply a metric for representative companies — it does not guarantee 100% availability for every ticker and date. Coverage is probed on a few large, well-reported names; specific companies (especially smaller, younger, non-US, or with limited history) may still be missing a given metric, in which case the name is kept and that one metric is scored at a neutral median rank (the unbiased default; you can switch to dropping such names under the missing-data policy below).

Missing-data policy

Default: keep the name and score a missing metric as (0–100, where 50 = neutral median rank)

Changes here save and re-scan automatically.

Point-in-time data cache — prepare once, run instantly

A point-in-time S&P 500 backtest draws from every company that was ever in the index (1996–present) — about 1,180 names, including ones that have since delisted. The first deep-history run normally downloads all of them, which can take a while. Prepare that data now and it's cached on your computer, so long backtests start immediately. It runs in the background while you keep working (a backtest pauses it and it resumes after), and is safe to re-run — names already cached are reused, not re-downloaded. Midas also starts this automatically the first time you launch it, so it's usually ready without any action.

Uses your enabled providers above. Prices for delisted names are most complete on a paid source (Sharadar); free providers may miss some, which the trust check flags at run time. As broader baked datasets are added (e.g. NASDAQ-100, all-listed), they'll appear here too.

Corporate events — automatic & pre-built

Midas models the two ways a stock leaves the market, from public record — no per-user confirmation, so backtests are consistent and reproducible. A bankruptcy forces a held position to $0 on the filing date. An acquisition / delisting is sold at its last price on the delisting date (the deal payout), and that cash redeploys on the next rebalance — it is never forced to $0. Landmark historical events are curated into the app; everything new is detected automatically from SEC filings.

Bankruptcies → forced to $0

Landmark equity wipeouts are curated in; any company in your universe that later files for Chapter 11 (SEC 8-K item 1.03) is added automatically. This list looks short by design — a current-index universe is itself survivorship-biased (failed names already left the index). Midas counters that with built-in point-in-time S&P 500 membership (1996–present, no data provider required): when an experiment starts in the past, the universe includes the companies that were index members then — Enron, Lehman, WaMu, WorldCom and ~500 others — even though they have since delisted. (Holding a dead name still needs its price history, which is best on a paid provider; the trust check flags any name dropped for missing data.)

Acquisitions & delistings → sold at last price

Automatic detection

On startup Midas scans SEC EDGAR (bankruptcy 8-Ks item 1.03 + Form 25 delistings) and Sharadar's delisting record for every ticker your experiments reference, then applies each finding automatically (bankruptcy → $0, delisting → sold). Each event is self-validated against the ticker's own price history, so a recycled symbol (e.g. a defunct company's ticker later reused by a new one) is never mis-applied.

Account

Working…