Alpha layout¶
The web app's layout for the fantasy alpha (owner, 2026-10-12): four tabs and nothing else. It is a switch, not a
rewrite. The pages it hides are archived, so their routes, templates and tests stay in the code and come back with
one environment variable. The code is in racinglines/web/layout.py.
The last staging commit before the layout is 8c3c05d ("[app] Fantasy first cut: My F$ balance page, manual IOC trading on recorded books, leaderboard (staging only)", #151). Check it out to see the app as it was.
What it shows¶
| Tab | Address | What is on it | Code |
|---|---|---|---|
| Markets | /markets |
Unchanged: the prediction markets now, and what the model says about the busiest prices | web/views.py, templates/board.html |
| Trade | /trade |
Fantasy trading on the recorded order books: pick a market, see its book, place an IOC order in F$. An order never goes past the recorded book (depth 10) | web/fantasy_routes.py, templates/fantasy_trade.html, fantasy/exchange.py |
| History | /history |
Your F$ (total, cash, by hand, strategy), F$ by hand through the run, open trades with Sell links, every order by hand (refused ones with the reason), your strategy's trades, and the leaderboard (/history#leaderboard) |
web/fantasy_routes.py history_page, templates/history.html, fantasy/ledger.py |
| Lab | /strategy/pick |
Opens on Follow a strategy (owner, 2026-10-13). The advanced tools: follow a strategy (/strategy/pick), its performance (/strategy), its positions (/positions), and for Pro accounts backtests and research (/lab). An account without Pro that opens /lab goes to /strategy. The unread-signals badge sits on the tab |
templates/_lab_nav.html |
Admins also get Admin. The right side of the top bar keeps only the GitHub badge and the account links (name, Settings or Sign up, Log out).
The leaderboard's score¶
Score = ROI × (trades ÷ 10)^0.3 (owner, 2026-10-25 21:03Z-21:04Z: "ROI is primary figure of merit, trade volume
adds a gradual boost. 1000 trades significantly better (2x?) than 100 trades and same ROI"). The boost is ×1 at 10
trades, ×1.4 at 30, ×2 at 100 and ×4 at 1,000: ten times the trades doubles it, so a player must trade ten times as
much to make up for half the ROI. It replaces 2026-10-12's ROI × √trades, which let volume outweigh ROI (100 trades
at +5% beat 9 at +15%). This is the fantasy alpha's scoring rule and is likely to stay for the alpha unless major
issues turn up (owner, 21:04Z). ROI is the P&L (by hand plus strategy) over the F$ staked: what an
account's buys paid, fees included, plus what its strategy paid in, net of what it sold back. Trades counts the
filled orders by hand plus the markets the strategy traded. An account needs MIN_TRADES (5) trades to be
ranked, so one lucky trade can't top the board. Accounts with fewer are listed after the ranked ones, by total
F$, with "–" for rank. The demo accounts aren't listed. Open trades count at what they would sell for now (the best
recorded bid). The code is fantasy/ledger.py (MIN_TRADES, VOLUME_BASE, VOLUME_POWER, TRADE_STATS, score(), ranked()).
Old addresses¶
| Old | Now |
|---|---|
/fantasy (My F$) |
303 to /history |
/fantasy/trade?... |
303 to /trade?... (the query string is kept) |
/leaderboard |
303 to /history#leaderboard |
POST /fantasy/orders keeps its address and sends you back to /trade?link=....
Picking a style (/strategy/pick)¶
Under the alpha layout the picker is five style cards instead of the full list (owner, 2026-10-12 19:23-19:55Z,
asking for variety over best performance). Each card has a name, one sentence for a first-timer, its 2026 and 2025
backtests as a season return on F$1,000 ("backtest, season return on F$1,000 at our standard sizing": the profile's why P&L over the grant; no dollars, owner 2026-10-13) and a Follow button.
| Style | Profile | Note |
|---|---|---|
| Steady | T1 | |
| Head start | T2 | |
| Early bird | T8 | labelled in-sample: tuned on the same seasons it is scored on |
| Big markets only | T6 | |
| Hair trigger | T5 |
- The names, sentences, numbers and order are one data structure:
ALPHA_STYLESandALPHA_ORDERinpipelines/profiles.py. Users never see the codes or thewhytext. - Sizing: Standard (the backtests' fixed stakes) or Kelly, with a fraction slider from 10% to 100% (default 25%),
quick picks for Quarter, Half and Full, and a tier label (Nitty, Shark, Spicy, Degen). Kelly is labelled untested.
The choice is saved on the profile as
sizingandkelly, and the live signal pass sizes to it (fantasy/sizing.py). Hand trades and the followed strategy share one F$1,000: each can use only what the other hasn't tied up. - Tweak drawer (closed by default, everyone): two sliders (edge needed, market volume) and the dice. A moved slider is labelled "untested: scored live from the next race weekend".
- One user level (owner, 21:04Z): under the alpha layout a basic account runs as pro (
layout.role), so everyone gets the Lab, the full picker and the tweaks.users.roleis not rewritten; the classic layout brings the basic tier back. An account already running a "Your picks" draw keeps it until it picks a style. - Makers, the TB blend and the other codes aren't offered.
POST /strategy/pickrefuses them for everyone but admins (the Edge Finder still shows makers). - Saves still pause during a race weekend's signal window.
- Fixed 2026-10-14: Head start (T2) and Hair trigger (T5), whose stages include pre-weekend, saved as "· adjusted" with the pre-weekend stage off when followed with no tweak (the drawer sends no pre-weekend field and it read as off). They now save as tuned. A player who saved one before keeps the "· adjusted" profile until saving again.
- From MCP and the CLI (2026-10-14):
fantasy_strategyreads the same cards, the profile followed and the lock;fantasy_followsaves through the same function as the page (fantasy/follow.follow), so a pick from either writes the same profile row, with the same lock, refusals and words. It offers the five styles (admins also the other codes) and the drawer's two tweaks, on the caller's own account only.racinglines remote call fantasy_followreaches it from a terminal (MCP, CLI: racinglines remote). /strategydrops the venue tabs, the sport select and the "How it chooses" tab. Admins keep the user select.- The switch is
strategy_pick.alpha_picker(). With the classic layout the page is unchanged.
What it hides¶
- Live events:
/liveand everything under it. The bar's Live link goes too. - Private books:
/bookand everything under it (Books / My book). On Markets the "My open markets" KPI goes; on Positions the private book's venue option, its P&L plot button, its mention in "About these positions", its rows and the in-app bets go, and the "In-app markets you quote are on My book" line goes.?venue=privateshows all venues instead. History's strategy trades leave the private book out. - Pitch and Docs links in the top bar's right side. The pages themselves still answer.
- The old bar's Strategy, Positions, My F$ and Leaderboard links. Their pages live under Lab and History.
Hidden routes answer 404 to everyone but admins: layout.guard() runs inside authenticate in
web/app.py, for every signed-in page, and checks HIDDEN_PREFIXES (/live, /book). Admins can still open
them to check on them.
The switch¶
RACINGLINES_LAYOUT |
Layout |
|---|---|
alpha |
The alpha layout |
classic |
The old bar and every page, as before (the fantasy pages, if on, are linked as Trade and My F$) |
| unset | Follows the fantasy switch, fantasy/ledger.on(): alpha where RACINGLINES_FANTASY=1, or on staging (RACINGLINES_ENV=staging) with that switch unset; classic otherwise, as on production today |
Templates read it through the alpha_layout() global (web/app.py). positions_page in web/views.py passes
hide_private to its template.
Bringing the archived pages back¶
- For one deploy: set
RACINGLINES_LAYOUT=classicin the app's environment (staging: its env file on the VM) and restart the web service. Everything comes back as it was, and nothing in the database changes. - For good, page by page: remove a prefix from
HIDDEN_PREFIXESinweb/layout.pyto stop the 404, then add its link to the alpha branch of the bar intemplates/base.html(the{% if user and alpha_layout() %}block) and drop thealpha_layout()/hide_privateconditions inboard.htmlandpositions.htmlthat hide it. That is a code change, so it is a deploy. - The whole alpha: delete the alpha branch of the bar in
base.htmland makealpha()return False. The old bar is still there below it, unchanged.
Tests: tests/test_fantasy_trading.py (the pages, the redirects, the nav under both layouts, the 404s, the
Positions page) and tests/test_fantasy_exchange.py (the score and the switch, without a database).