Every prediction tracked. Every result reconciled.

AI-Powered Stock Intelligence
That Proves Itself

Not another black-box AI trading tool. FutureMarket writes down every call it makes — with the entry price attached — then goes back days later and marks its own homework against what actually happened. Five model stages argue the case, quant factors score the tape, and nothing touches real money until it has earned it on paper.

Analysis Pipeline
> deep_analysis --stages 5
[1 analyst] synthesises the evidence stored
[2 bull] strongest case to buy stored
[3 bear] strongest case against stored
[4 judge] reads both briefs, rules stored
[5 risk committee] parsed
Prediction Log AWAITING MARKS
30 most recent calls Marked at T+1 / +5 / +20d
Illustrative — direction called, not outcome
5
Pipeline Stages
5
Signal Sources
36
Alpha Factors
8
Dashboard Views

Honest AI, Not Hype

01
🔬
Honest AI
Research shows language models cannot predict prices — their backtest wins are memory, not skill. We use them where they genuinely help: reading filings, calls and news at speed.
02
Adversarial by Design
A bull and a bear build the strongest case each way from identical evidence. A judge reads both and rules. Structured disagreement catches what one confident model misses.
03
📋
Marked Against Reality
Every call is logged with its entry price, then reconciled against the realised return at 1, 5 and 20 days. Elo ranks the strategies. Calibration checks whether the confidence was honest.
04
🛡
Safety First
A five-state circuit breaker, half-Kelly sizing against a 2% risk cap, and a graduation gate that has to pass before anything graduates off paper.

Five Calls, One Verdict

Most LLM analysts hand the model a bag of tools and let it wander. The cost is unpredictable and the trace is impossible to reproduce. We inverted it: gather everything first with free calls, then spend exactly five model invocations. Every analysis costs the same and runs the same way.

Before any model runs, seven fetches go out — a quote, technical indicators, fundamentals, up to eight news articles and three fixed web searches. They are concatenated into a single markdown block. That block is the only thing the pipeline ever sees about the outside world. No retrieval loop, no agent deciding to look something up.

Then five stages run in order, each with its own system prompt and a payload assembled from what came before. An analyst synthesises the evidence. A bull and a bear each build the strongest case their way — from identical inputs, without seeing each other. A judge reads only the two briefs, deliberately starved of the raw evidence so it has to rule on argument quality rather than re-derive a view. Finally a risk committee sees everything and is the only stage bound to an output contract: a recommendation, a confidence percentage and a target price, in labelled form.

The bull and the bear never read each other. It is adversarial construction followed by adjudication — and calling it anything grander would be overselling it.

Only that fifth stage is machine-read. The other four are stored verbatim for a human to read and are never parsed. That is a deliberate split: the parts of the system that make decisions are small and inspectable, and the parts that produce prose stay prose.

Figure 01 What each stage is allowed to see
↔ Scroll to explore
Five-stage language model pipeline with per-stage context composition A top band shows seven free data fetches that build a single research context block. Five rows follow, one per model call: analyst, bull, bear, judge, and risk committee. Each row shows a horizontal bar composed of the context segments that stage receives. The analyst sees only research. Bull and bear see research plus the analyst report. The judge sees only the bull and bear briefs. The risk committee sees everything. A bottom band shows regex extraction of decision, confidence, and target price from the fifth stage only, with the default values used when a pattern fails to match. STAGE 0 — SEVEN FREE FETCHES, NO MODEL INVOLVED quoteprice provider technicalsRSI · MACD · BB fundamentals news ×8company feed web search 1outlook web search 2analyst rating web search 3institutional flow research_context — one markdown block, seven sections, no truncation or token budgeting FIVE MODEL CALLS — sequential, on worker threads research analyst bull bear judge verdict CALL 1 Analyst five named sections; must cite figures, rank top 3 research_context sees the evidence only market_report → stored CALL 2 Bull case strongest case to buy; quantify, pre-rebut research_context analyst does not see the bear bull_case → stored CALL 3 Bear case mirror image of call 2; identical inputs research_context analyst independent of call 2 — identical inputs, no cross-talk bear_case → stored CALL 4 Judge score evidence quality, name fallacies, rule bull bear no raw research deliberately starved — adjudicates on argument, not evidence judge_decision → stored CALL 5 Risk committee the only stage with an output contract research_context analyst bull bear judge must emit three literal labels: recommendation, confidence %, target price risk_assessment → PARSED STRUCTURED EXTRACTION — ONLY STAGE 5 IS MACHINE-READ _extract_decision 4 patterns, then a keyword heuristic falls back to HOLD _extract_confidence 3 patterns; divides by 100 if > 1.0 falls back to 0.65 _extract_price 2 patterns for a dollar target falls back to 0.00
Figure 1. Context composition per stage. The bars are the substance of the design — they grow as the pipeline accumulates context, then deliberately shrink at the judge, who receives the two briefs and nothing else. The risk committee gets everything, because it is the one being held to an answer.

Stopping the Profit Mirage

Ask a language model to analyse a named company on a named historical date and it may not be analysing at all. It may simply be remembering what the stock did. The published framing of this failure is the “profit mirage” problem (arXiv:2510.07920), and it quietly invalidates a great many impressive-looking LLM backtests.

A backtest that lets a model recognise the company and the date is not measuring predictive skill — it is measuring recall. Any strategy validated that way looks excellent in sample and fails live, and the failure is inexplicable because the harness reported success.

So FutureMarket takes the direct countermeasure: strip the identifying information before the model sees it, and put it back afterwards. Six ordered passes rewrite the research context. Company names become Company A, Company B. Tickers map to the same labels, anchored on word boundaries and skipping anything under two characters so stray single letters do not match everywhere. Dates in three formats become Period 1, Period 2. Sector names become Sector 1. Company names are replaced longest-first, so “Apple Inc.” wins over “Apple”.

When the five stages finish, the same map runs in reverse across all five outputs, so the reports a human reads still name the real company. The guard engages when the pipeline is invoked in backtest mode; live analysis runs un-neutered, correctly, because there is nothing to protect against when the future genuinely has not happened yet.

Building the countermeasure before building the strategy is the right order of operations. It is also, in this field, rare.
Figure 02 Six-pass transform and inverse restore
↔ Scroll to explore
Entity neutering transform and restoration Raw research text on the left passes through six ordered replacement passes — register primary symbol, register additional symbols and aliases, replace company names longest first, replace tickers with word boundaries, replace three date formats, and replace sector names — producing neutered text where companies become Company A, dates become Period 1, and sectors become Sector 1. The neutered text goes to the model. Model output passes back through an inverse restore step using the same entity map. RAW RESEARCH CONTEXT Apple Inc. (AAPL) shares rose on 2024-03-14 as the Technology sector rallied. Alphabet and Microsoft also gained. Analysts at ... cite AAPL's margin expansion since March 2023. SIX ORDERED PASSES 1 register primary symbol → Company A 2 register additional symbols + aliases 25-company alias table: Alphabet, J&J, … 3 company names, longest first so "Apple Inc." wins over "Apple" 4 tickers, word-boundary anchored skips 1-character tickers to avoid noise 5 dates — ISO, US slash, written month 6 sector names → Sector N NEUTERED — WHAT THE MODEL SEES Company A shares rose on Period 1 as the Sector 1 sector rallied. Company B and Company C also gained. Analysts at ... cite Company A's margin expansion since Period 2. five-stage pipeline runs display symbol is "Company A" throughout restore_entities on all five outputs inverse map, applied before return reports naming the real company returned to the caller ACTIVE ONLY WHEN backtest_mode=True live analysis runs un-neutered THE GUARD IS THE POINT — 26 TEST FUNCTIONS COVER IT Longest-first matching, word-boundary anchoring and a two-character minimum ticker length keep the substitution from over-matching. The same map runs in reverse on all five stage outputs, so the reports a human reads still name the real company.
Figure 2. The neutering transform. Alias tables, longest-first matching and word-boundary anchoring do the hard part; an inverse map restores real names on the way out so the audit trail stays readable.

Five Opinions, One Number

No single model decides. Five independent sources each return a score normalised to −1…+1, so the fusion step is unit-free. Each carries a base weight — and then that base weight is adjusted by how well the source has actually been performing.

Model Debate
Technical
Sentiment
Alpha Factors
Quant Score
▼  effective = base × elo_factor × calibration_factor  ▼
Composite
−1.00 … +1.00
Deadband ±0.05
BUY / HOLD / SELL
Position Size
Half-Kelly

The weighting is the part worth dwelling on. Each source's base weight is multiplied by two performance terms. The Elo factor is that source's rating divided by the mean rating across all rated strategies — beat your peers head-to-head and you scale above 1.0. The calibration factor asks a different question: if this source says 70% and is right 80% of the time, scale it up; if it is right 60%, scale it down. Both terms are computed from reconciled outcomes, never from assumption.

Weights are then floored at 0.05 so no source is ever zeroed out entirely, and renormalised to sum to one. And then the compositor spends most of its remaining code looking for reasons not to act: a composite inside the deadband is a hold; confidence under 0.55 is skipped; a daily trade cap is skipped; a missing entry price is skipped; and a position check that fails is skipped rather than waved through — the exception path returns a refusal, which is the correct direction for a system that can spend money.

The compositor's opinion of its own inputs is derived from evidence rather than assumption. That is the best idea in the system.
Figure 03 From five scores to one decision — and five ways to refuse
↔ Scroll to explore
Signal compositor: five sources, performance weighting, and rejection gates Five source lanes each produce a normalised score between minus one and plus one, with a base weight. A weighting stage multiplies each base weight by an Elo factor and a calibration factor, applies a floor, and renormalises. A weighted sum produces a composite score, which passes a deadband to become a direction, with confidence set to the absolute value of the composite. Five sequential gates then reject or admit the signal before it reaches the executor. FIVE SOURCES — awaited sequentially, each individually fault-tolerant technical from prediction_log freshness window 8 h sign × confidence w 0.25 sentiment live aggregator call 30-min internal cache (score − 50) / 50 w 0.15 nim_debate from prediction_log freshness window 7 days sign × confidence w 0.30 alpha_factor ICIR-weighted composite neutral 50 if no active factors (score − 50) / 50 w 0.15 qlib optional ML package neutral 50 if unavailable (score − 50) / 50 w 0.15 PERFORMANCE WEIGHTING — the design's central mechanism effective[s] = base[s] × elo_factor[s] × calibration_factor[s] elo_factor = elo_rating(strategy) ÷ mean(all elo_ratings) — centred on 1.0; defaults to 1500 both sides when the table is empty calibration_factor = count-weighted mean of (bayesian_accuracy ÷ stated_confidence) per bin, hard-clamped to [0.5, 1.5] then floor each at 0.05 and renormalise to sum 1.0 composite = Σ(scoreᵢ × wᵢ) ÷ Σ(wᵢ), clamped ±1.0 weights already sum to 1 over available sources, so absent sources do not dilute — one source alone becomes the whole composite DEADBAND HOLD SELL ← −1.0 +1.0 → BUY −0.05 +0.05 confidence := |composite| FIVE SKIP GATES — evaluated in this order, first match wins 1 · direction HOLD → skip logged, not discarded 2 · confidence < 0.55 → skip a genuinely high bar 3 · daily cap ≥ 10 trades → skip counter rolls at UTC midnight 4 · entry price ≤ 0 → skip quote, then DB fallback 5 · duplicate same-side position → skip fails closed on error AND BEFORE ANY OF IT — three cycle-level preconditions autonomous cycle enabled operator-controlled, off by default inside market hours 09:30–16:00 ET, weekdays circuit breaker permits trading see Figure 10 ADMITTED → trade_executor direction mapped BUY→UP, everything else→DOWN shrunk, half-Kelly sized, bracketed, and written to prediction_log SKIPPED → still written to prediction_log every decision is recorded, including HOLD, with a suffixed model_version the refusals are part of the record, not swept out of it
Figure 3. Composition and refusal. Confidence is defined as the magnitude of the composite, so the 0.55 gate demands a weighted average of normalised source scores above 0.55 — a genuinely high bar. Skipped decisions are written to the log too, so the refusals are part of the record.

Marking Its Own Homework

A prediction is only a claim until something checks it. One nightly job does the converting, and every other accountability mechanism in the system is downstream of that conversion.

When a call is made, a row goes into the prediction log carrying the direction, the predicted magnitude, the confidence, the strategy that produced it and — critically — the entry price at the moment of the call. Without that column, no return can ever be computed, and the whole apparatus is decorative.

Days later, reconciliation comes back for it. The job selects rows roughly 1, 5 or 20 days old, with a twelve-hour tolerance either side, that carry an entry price and do not yet have a return recorded for that horizon. The return is the simplest possible expression — current price minus entry price, over entry price — and the null check on the return column is what makes the job idempotent: a row already filled is never selected twice.

Then the chain runs, and the order it runs in is the architecture. Reconciliation must precede the tournament; the tournament must precede calibration; calibration must precede the weight update. Each depends on what the one before it wrote.

Figure 04 The life of one prediction, and the nightly chain that grades it
↔ Scroll to explore
Prediction lifecycle and nightly reconciliation chain An upper timeline follows a single prediction from the moment it is written, through reconciliation at one, five and twenty days, showing which columns are filled at each point and which twelve-hour tolerance window admits it. A lower panel shows the four nightly jobs in dependency order with their first-run offsets, what each reads and writes, and which of their outputs survive a process restart. PART A — ONE ROW IN prediction_log, OVER TWENTY DAYS T + 0 T + 1 day T + 5 days T + 20 days ±12 h window ±12 h window ±12 h window ROW WRITTEN direction · magnitude confidence · strategy_id entry_price captured here FILL 1-DAY actual_return_1d correct_direction the only horizon scored FILL 5-DAY actual_return_5d return measured from entry FILL 20-DAY actual_return_20d the longest horizon held before the row is closed actual_return = (current_price − entry_price) ÷ entry_price — then correct_direction = (predicted_direction == sign of that return), for the 1-day horizon only PART B — THE NIGHTLY CHAIN, IN DEPENDENCY ORDER 1 · RECONCILIATION T+2 min reads prediction_log + quotes writes actual_return_1d/5d/20d correct_direction CLAIM BECOMES EVIDENCE idempotent via the null-column guard 2 · ELO TOURNAMENT T+17 min reads all reconciled rows writes strategy_ratings pairs same symbol, same day K = 32 NEW / 16 ESTABLISHED start 1500, divisor 400 3 · CALIBRATION T+22 min reads prediction_log computes the reliability curve Brier score, Beta posterior 5 BINS, PRIOR STRENGTH 10 rebuilt from the record each run 4 · WEIGHT UPDATE T+27 min reads 30-day accuracy per source writes signal_weight_log needs ≥5 samples per source RATIO CLAMPED TO [0.5, 1.5] a snapshot per run WEEKLY, MUCH LATER Alpha factor lifecycle — T+155 min evaluate candidates → retire decayed → generate exactly as many as were retired Walk-forward backtests — T+185 min four strategies, 90/30-day windows writes backtest_runs · see Figure 12 Deep analysis — T+125 min the five-stage pipeline, all tracked names batches of five, five-second spacing Offsets are deliberate — the source comments explain the stagger as avoiding a thundering herd of upstream data requests, and the ordering as a dependency chain.
Figure 4. Lifecycle and feedback chain. The staggered offsets are deliberate — they avoid a thundering herd of upstream data requests, and the ordering encodes the dependency between the four jobs.

Elo asks which strategy was better. The tournament groups reconciled predictions by day and symbol, then plays every unique cross-strategy pair inside each group. The update is textbook: expected score from the rating difference over 400, then the rating moves by K times the gap between actual and expected. K is 32 for strategies with fewer than thirty comparisons and 16 after that, so new entrants move fast and established ones settle. Ratings start at 1500. Winner rules run in order — correct direction beats incorrect; if both were right or both wrong, the smaller magnitude error wins; and errors within a tenth of a percent are a draw.

Calibration asks a harder question: was the stated confidence honest? Five bins span 50 to 100 percent stated confidence. Within each bin the tracker forms a Beta posterior over the realised hit rate using a prior worth ten virtual observations, centred on the bin's own stated confidence — so the tracker starts by assuming the strategy is perfectly calibrated and demands real evidence to move it. Two numbers come out: a Brier score, rescaled so a coin flip maps to zero and perfection to a hundred, and an adjustment factor — the count-weighted ratio of realised accuracy to stated confidence, hard-clamped to between 0.5 and 1.5.

That adjustment factor is not a dashboard ornament. It is multiplied into the compositor's source weights, and it is applied to confidence before position sizing — and for any strategy with fewer than ten reconciled predictions, confidence is simply halved toward 0.5 regardless of history. Being overconfident costs you weight and it costs you size.

Reconciliation horizons
1 / 5 / 20 d
±12 hour matching tolerance; entry price required
Elo K-factor
32 → 16
Switches at 30 comparisons. Ratings start at 1500
Calibration prior
Beta, n=10
Five bins from 50% to 100% stated confidence
Adjustment clamp
[0.5, 1.5]
Feeds both signal weighting and position sizing

Built to Not Fool You

Most AI trading tools show you a backtest that looks amazing. The interesting engineering is in the machinery that stops a backtest from lying to you in the first place.

Start with the subtlest way to cheat. A daily bar for a Tuesday describes Tuesday — but you could not have acted on it during Tuesday's session, because it did not exist until the close. Any backtest that treats a bar's own date as the moment it became usable will systematically buy at prices nobody could have seen, and will report returns nobody could have earned.

The countermeasure is two timestamps per row instead of one. One records what period the row describes; available_at records when the row became knowable. A point-in-time query filters on the second, never the first. FutureMarket carries both on three tables and routes reads through three query helpers that apply the filter.

Figure 05 When it happened, and when you could have known
↔ Scroll to explore
Bitemporal filtering of price bars against a decision time Two parallel timelines. The upper as-of axis shows five daily bars at their nominal dates. The lower available-at axis shows the same bars shifted right by the delay before they became knowable. A vertical decision-time line cuts both axes. Under a naive filter on the as-of date, four bars are admitted, one of which was not yet knowable. Under the bitemporal filter on available-at, only three bars are admitted. The difference is labelled as look-ahead leakage. decision_time AXIS 1 — timestamp « as_of » what period the row describes Mon Tue Wed Thu Fri Naive filter timestamp < decision_time admits four bars — Mon, Tue, Wed and Thu. shift right by publication delay AXIS 2 — available_at when the row became knowable Mon Tue Wed Thu Fri Bitemporal filter available_at ≤ decision_time admits three — Thursday's bar was not yet published. THE DIFFERENCE one bar of look-ahead leakage THE IMPLEMENTED PREDICATE — a disjunction, to tolerate legacy rows available_at <= decision_time OR ( available_at IS NULL AND timestamp < decision_time − 4 hours ) The second branch is a compatibility path for rows written before the column existed: it treats such a row as knowable four hours after the period it describes.
Figure 5. The two axes. The dashed Thursday box on the lower axis is the bar a naive filter would admit and the bitemporal filter correctly rejects. In one query it looks like a rounding error; compounded across a backtest it is the difference between a strategy that works on paper and one that works.

Then the backtester itself. It slices the reconciled prediction history into overlapping windows — 90 days of train, 30 days of test, stepping forward 30 days at a time — and computes metrics on each test window only. With the default step equal to the test length, test windows tile without overlapping, so no realised return is ever counted twice. Nothing is fitted to the training slice; it is measured for its row count and otherwise left alone. That makes this honest out-of-sample scoring of already-logged predictions rather than a parameter search dressed up as validation, which is exactly the distinction that flatters most published backtests.

Four strategy identifiers are eligible. The model-debate and sentiment sources are deliberately excluded, because their calls cannot be replayed faithfully — and replaying them badly would be worse than not replaying them at all. A run needs at least ten reconciled predictions and a date range longer than one full window, or it returns an error rather than a flattering result.

Figure 06 Window geometry, aggregate metrics, and the graduation gate
↔ Scroll to explore
Walk-forward backtest window geometry and graduation criteria A date axis with four successive windows, each composed of a ninety-day training segment and a thirty-day test segment, stepping forward thirty days at a time so that training segments overlap. An annotation marks that the training segment is counted but never trained on. Below, the aggregate metric formulas are listed, followed by the four graduation conditions that must all hold for a strategy to be marked as graduated. WINDOW GEOMETRY — train 90 d, test 30 d, step 30 d first prediction most recent win 1 train 90 d — counted, never fitted test 30 d win 2 train 90 d test 30 d win 3 train 90 d test 30 d win 4 train 90 d test 30 d step 30 d — test windows tile without overlap at the default step WHAT THE WINDOWS MEASURE Each test window is scored strictly out of sample, on predictions that were already logged and reconciled before the window opened. Nothing is fitted to the train slice — it is counted, not tuned. AGGREGATE METRICS OVER ALL TEST RETURNS strategy_return = sign(direction) × actual_return_1d sharpe = mean ÷ std × √252 no risk-free rate max_drawdown = max(running_max − cumsum) additive, not compounded; return-fraction units profit_factor = Σ gains ÷ |Σ losses| capped at 999 annualised = total_return × (252 ÷ n) consistency = 1 − std(per-window win rates) GRADUATION GATE — all four must hold ≥ 20 predictions minimum sample Sharpe > 0 risk-adjusted, not raw win rate ≥ 0.55 directional accuracy max drawdown ≤ 0.20 in return-fraction units
Figure 6. The backtest geometry. Train windows overlap by sixty days while test windows tile cleanly, so every window is scored on returns the strategy had not yet seen when the window opened.

Paper First, and It Has to Earn It

FutureMarket starts on paper trading. It is designed to catch its own mistakes — and to prevent the tricks that make bad systems look good.

🚫
Entity-Neutered Backtesting
Names, tickers, dates and sectors are stripped before the model sees historical data, so it has to reason rather than remember. Restored on the way out so the audit trail stays readable.
🕑
Point-in-Time Queries
A second timestamp records when each row became knowable, and reads filter on that — not on the date the row describes. Look-ahead leakage is closed at the query layer.
🎯
Calibration Tracking
When it says 80% confident, is it right 80% of the time? A Beta posterior per confidence bin and a Brier score answer that, and overconfidence is penalised in both weight and position size.
🟥
Five-State Circuit Breaker
Checked hourly against a running equity peak. A bad day tightens, a bad week halves position size, a deep drawdown halts new entries outright, and a cooldown timer governs the way back.
Figure 07 Circuit breaker states, thresholds and effects
↔ Scroll to explore
Portfolio circuit breaker state machine and per-state effects Five states run left to right: normal, caution, reduced, halted and cooldown. A two per cent daily loss moves normal to caution. A five per cent weekly loss moves normal or caution to reduced, which halves position size. A fifteen per cent drawdown from the running equity peak moves any state to halted. Halted leads to a twenty-four hour cooldown and then back to normal. A table below lists, for each state, whether new entries are permitted and the position size multiplier that applies. SEVERITY LADDER — EVALUATED WORST-FIRST, EVERY HOUR, AGAINST A RUNNING EQUITY PEAK NORMAL full size, trading on multiplier 1.0 CAUTION new entries held stops tightened REDUCED trading on, half size multiplier 0.5 HALTED no new entries multiplier 0.0 COOLDOWN waiting out the clock 24 hours −2% day −5% week −15% drawdown 24 h timer a 15% drawdown jumps straight to HALTED from any state — the ladder is checked worst-first cooldown expires → NORMAL, and the equity peak carries forward PER-STATE EFFECT ON THE EXECUTION PATH STATE NEW ENTRIES SIZE MULTIPLIER TRIGGER normal permitted 1.0 caution blocked 0.0 daily loss reaches 2% reduced permitted 0.5 weekly loss reaches 5% halted blocked 0.0 drawdown from peak reaches 15% cooldown blocked 0.0 24-hour timer after a halt All four thresholds are constructor arguments with the defaults shown; the compositor asks the breaker for permission before any signal is admitted.
Figure 7. The breaker as coded. The ladder is checked worst-first, so a deep drawdown goes straight to a halt from whatever state it was in. Trading is permitted only in normal and reduced, and the compositor asks the breaker for permission before any signal is admitted.

Four Conditions, All of Them

A strategy is only marked as graduated when every one of these holds across the walk-forward test windows. Any single failure and the answer is no.

Alongside this sits a broader readiness report covering paper-trading duration, realised Sharpe, how many strategies have shown an edge, and whether the breaker has been exercised. It is published as a report you can read — not a badge the system awards itself.

8 Dashboard Views

📈
Markets
Watchlist with live prices, sparklines and quick signals
🤖
Analysis + AI Chat
The full five-stage output, plus interactive follow-up
🎯
Predict
Directional calls with confidence and signal breakdowns
Strategies
The Elo tournament table, with wins, losses and comparisons
Trade
Paper trading via Alpaca, with positions and order history
📋
Accuracy
Reconciled scorecards and the calibration reliability curve
📉
Alpha Factors
36 quant features ranked by information coefficient
📄
Tear Sheet
Portfolio analytics, drawdowns and risk metrics

Platform Features

📡
Free-Tier Data Pipeline
Market data through OpenBB, global news from GDELT, SEC EDGAR filings and Alpaca for execution. Everything the system knows, it knows without a data subscription.
Free Data
🧠
Local FinBERT Sentiment
Financial sentiment runs on your own machine. No per-call cost, no rate limits. News, earnings tone and filing risk are blended and renormalised over whichever sources returned.
On-Device
📊
36 Alpha Factors
Factors are scored by information coefficient — the rank correlation with forward returns — and by the ratio of that coefficient's mean to its standard deviation. Weak factors decay out.
IC-Ranked
Scheduled, Staggered, Logged
Composition runs every four hours in market hours. Reconciliation, the tournament, calibration and the weight update run nightly in dependency order. Every decision is written down.
Automated
💰
Paper Trading via Alpaca
Free paper trading, no funding required. Bracket orders with take-profit and stop-loss legs, sized by half-Kelly against a 2% maximum risk per trade.
Free
Hierarchical Risk Parity
Portfolio allocation via PyPortfolioOpt, diversifying across correlated assets by hierarchical clustering rather than by a single covariance inversion.
Risk-Managed

Technology Stack

NVIDIA NIM
LLM Inference
GPU-accelerated inference driving the five-stage analysis pipeline.
FinBERT
Sentiment
Financial sentiment, running locally over news, calls and filings.
Qlib
Quant ML
Microsoft's quantitative platform, backing the alpha factor and quant legs.
Alpaca
Trading
Free paper trading with full order and position management.
FastAPI
Backend
Async Python handling ingestion, scoring, scheduling and execution.
React 19 + TypeScript
Frontend
Eight dashboard views built for professional analysis workflows.
SQLite + Alembic
Persistence
A single file, thirteen tables, and versioned migrations. Portable by design.
OpenBB + GDELT
Data
Market data and a global open news archive, plus SEC EDGAR filings.
13
Tables
5
Signal Sources
36
Alpha Factors
3
Return Horizons

Start With Paper Trading

Free to try. No credit card. No funding required. Run it locally, connect Alpaca's free paper trading API, and let the system build its own record before you trust it with anything real.

Self-hosted. Your data stays on your machine. Requires Python 3.11+, Node 18+, a free Alpaca account for paper trading, and an inference key for the analysis pipeline.