https://screener.openalgo.theworkpc.com/ can you tell me what recent changes have happened in this site at the backend and frintend
2026-08-22 16:45
ASSISTANT (hermes, deepseek-v4-flash:0731)
I'll investigate the screener site's recent changes. Let me load the relevant skill and find the project.
2026-08-22 16:46
TOOL (hermes, deepseek-v4-flash:0731)
[Tool: skill_view]
{"success": true, "name": "screener-tool", "description": "Use for the screener rule-builder tool.", "tags": [], "related_skills": [], "content": "---\nname: screener-tool\ndescription: Use for the screener rule-builder tool.\n---\n\n# Screener — fully-flexible tabbed rule builder over the 13-stock universe\n\nURL: https://screener.openalgo.theworkpc.com\nStack: **RUST (axum :5304, systemd `rust-screener.service`)** — replaced the\nFlask version (:5303, `screener.service`) on Aug 12, 2026 (user: \"nuke it build\nit again on rust\"). Flask service stopped but NOT deleted (rollback:\n`sudo systemctl start screener` + point nginx back to 5303).\nFiles: /home/ubuntu/rust-screener/src/main.rs (single binary, ~1600 lines),\nstate/<sid>.json, nginx/rust-screener.service. Frontend = server-rendered\nHTML strings in main.rs (zero JS, same act= contract as Flask).\nThe Flask version lives at /home/ubuntu/bots/screener/ (historical reference —\nthe Rust port's logic mirrors it 1:1).\n\n## Non-negotiable design rules\n\n1. **100% server-side rendering.** The user explicitly rejected browser-side\n computation. EVERYTHING happens in Python: rule evaluation, tab\n add/remove/move (server round-trips via `act=`), per-tab font (`act=font&id=<tab>`),\n auto-refresh. NO JavaScript logic — even \"+ Add condition\" is a form submit\n with `name=\"act\" value=\"add_cond\"`.\n\n2. **Session state** = per-session JSON in state/<sid>.json, keyed by opaque\n cookie `screener_sid` (set via Set-Cookie, httponly). Tabs: `rules`,\n `scope`, plus one `scan_<n>` results tab per scan run. `order` list = tab\n bar order; results tabs insert right after scope. State is saved on every\n action; only last 15 scans kept.\n\n3. **Single source of truth = values DB** for indicators/daily/xover +\n **chart API (127.0.0.1:5050) for OHLC candles** (open/high/low/close/volume,\n intervals 5m/15m/30m/1h/2h/D). Never recompute indicators.\n\n4. **Universe = equity only** (exchange in NSE/NSE_INDEX) — CRUDEOILM (MCX)\n excluded. 13 symbols: SBIN, INDIGO, HAL, TCS, ULTRACEMCO, LT, DLF, INFY,\n INDUSINDBK, ASHOKLEY, BIOCON, BANKNIFTY, CUPID.\n\n5. **Flat table columns only** in results; passes sorted first (server-side\n sort in decorate_units? No — results render in symbol order; pass/fail\n shown as green/red badges + row tint).\n\n## Rule builder (v3 — variable + connector model)\n\nRules are built as **[Var1] [Connector] [Var2/Value]** — three linked\ndropdowns, NOT a fixed condition list:\n\n- VARS (dropdown 1 & 3): price, open, high, low, prev_close, vidya, sma20,\n sma50, rsi, atr, atr_pct, macd, macd_signal, macd_hist, stoch_k, stoch_d,\n volume, avg_volume, change_pct, range_pct, n_high, n_low, high_dist_pct,\n low_dist_pct, lipi, lipi_settled, three_candle, bias (text), x3 (text),\n xa (text). Plus `__custom__` → free-form expression (safe_eval_expr).\n- **LIPI is daily BUT developing — TWO vars since Aug 17, 2026**: `lipi`\n (\"LIP
... [18026 chars total, truncated]
The service was restarted today (Aug 22 13:06) and main.rs was modified today at 13:05 — so there's a change deployed today. Let me dig into what changed.
Let me confirm the tcharts frontend deep-link support (the other half of the frontend change).
2026-08-22 16:46
TOOL (hermes, deepseek-v4-flash:0731)
[Tool: terminal]
{"output": "81: <button class=\"toggle-btn\" id=\"mode-candles\" onclick=\"setMode('candles')\">Candles</button>\n91: <option value=\"Daily\">Daily</option>\n160:let snap15m = null; // 15m interval snapshots (vidya + rsi series) for overlay on daily chart\n161:async function loadDevelopingDaily(symbol, dateOverride) {\n168: ? `${API}/developing-daily/${symbol}?date=${dateOverride}`\n169: : `${API}/developing-daily/${symbol}`;\n196:let chartMode = 'renko'; // 'renko' | 'candles'\n198:let barData = null; // bricks or candles\n201:let lastCandleData = null; // raw 5m candles (days=1) — tail = true last price/time even when renko prints no brick\n286:async function loadSymbols() {\n312: document.getElementById('mode-candles').classList.toggle('active', mode === 'candles');\n315: document.getElementById('days-group').classList.toggle('hidden', mode !== 'candles');\n326:// ─── Fill Data button — calls Flask 5min-fill endpoint to fetch latest candles from broker ───\n378: // Reset developing-daily cache when symbol changes — fire-and-forget fetch\n380: loadDevelopingDaily(currentSymbol).then(d => { if (d) renderAll(); });\n401: promises.push(fetch(`${API}/candles/${currentSymbol}?interval=5m&days=1`).then(r => { if(!r.ok) throw new Error(`candles ${r.status}`); return r.json(); }));\n405: // Candle mode: fetch candles + pre-computed indicators for this interval (two calls)\n406: promises.unshift(fetch(`${API}/candles/${currentSymbol}?interval=${interval}&days=${days}`).then(r => { if(!r.ok) throw new Error(`candles ${r.status}`); return r.json(); }));\n407: // Pre-computed indicators from snapshots table filtered by interval — capture index (candle array is 4 long; length-2 would hit daily-values!)\n415: // renko: [bricks(0), snap_default(1), daily-values(2), snap_interval(3), candles_5m(4)]", "exit_code": 0, "error": null, "cwd": "/home/ubuntu/charting-project/static"}
2026-08-22 16:46
ASSISTANT (hermes, deepseek-v4-flash:0731)
2026-08-22 16:46
TOOL (hermes, deepseek-v4-flash:0731)
[Tool: terminal]
{"output": "5:<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n505: let minP = Infinity, maxP = -Infinity;\n1119: let minV = Infinity, maxV = -Infinity;\n1468:loadSymbols().then(() => {\n1471: const up = new URLSearchParams(window.location.search);", "exit_code": 0, "error": null}
2026-08-22 16:46
ASSISTANT (hermes, deepseek-v4-flash:0731)
2026-08-22 16:46
TOOL (hermes, deepseek-v4-flash:0731)
[Tool: read_file]
{"content": "1465|\n1466|// ─── Init ───\n1467|applyFontScale();\n1468|loadSymbols().then(() => {\n1469| // Deep-link support: ?symbol=SBIN&interval=Daily&chartType=renko (used by the\n1470| // screener's chart links). Absent params = current default behaviour.\n1471| const up = new URLSearchParams(window.location.search);\n1472| const psym = up.get('symbol');\n1473| if (psym) {\n1474| const sel = document.getElementById('symbol-select');\n1475| const found = Array.from(sel.options).some(o => o.value === psym);\n1476| if (found) { currentSymbol = psym; sel.value = psym; }\n1477| }\n1478| const pivl = up.get('interval');\n1479| if (pivl) {\n1480| const mapped = (pivl === 'D' || pivl === 'Daily') ? 'Daily' : pivl;\n1481| const isel = document.getElementById('interval-select');\n1482| if (Array.from(isel.options).some(o => o.value === mapped)) isel.value = mapped;\n1483| }\n1484| const pct = up.get('chartType');\n1485| if (pct && (pct === 'renko' || pct === 'candles' || pct === 'candle')) {\n1486| const mode = pct === 'candle' ? 'candles' : pct;\n1487| chartMode = mode;\n1488| document.getElementById('mode-renko').classList.toggle('active', mode === 'renko');\n1489| document.getElementById('mode-candles').classList.toggle('active', mode === 'candles');\n1490| document.getElementById('days-group').classList.toggle('hidden', mode !== 'candles');\n1491| document.getElementById('brick-group').classList.toggle('hidden', mode !== 'renko');\n1492| }\n1493| if (psym) updateBrickDefault();\n1494| sendWatch();\n1495| loadAll();\n1496|});\n1497|// 60s incremental refresh: fetch only NEW bricks since the last one we hold\n1498|async function refreshIncremental() {\n1499| if (isLoading) return;\n1500| if (chartMode !== 'renko' || !barData || !barData.bricks || !barData.bricks.length) {\n1501| loadAll(); return;\n1502| }\n1503| const interval = document.getElementById('interval-select').value;\n1504| const bs = document.getElementById('brick-input').value;\n1505|", "total_lines": 1535, "file_size": 68617, "truncated": true, "hint": "Use offset=1505 to continue reading (showing 1465-1504 of 1535 lines)", "is_binary": false, "is_image": false}
2026-08-22 16:46
ASSISTANT (hermes, deepseek-v4-flash:0731)
I've traced the full change history. Here's what's changed recently on the screener site.
## What changed and when
The backend (`/home/ubuntu/rust-screener/src/main.rs`) was last edited and rebuilt today, **Aug 22 13:05 IST**, and the service restarted at 13:06. I diffed it against the Aug 18 backup (`main.rs.bak.20260818_pre_ladder`) to isolate exactly what's new since then.
## Backend (Rust, :5304)
1. **What-if ladder (the big one)** — a new "⏱ Track" button on each saved bot. Clicking it starts a background task that re-evaluates that preset's rules every 5 minutes during market hours (09:15–15:35 IST, weekdays) and builds a time-ladder table: Time | PASS-count | per-symbol ✓/✗. Green/red ring highlights ENTER (was FAIL, now PASS) and DROP (was PASS, now FAIL) cells. Keeps 60 snaps. Controls: Track / Stop / Snap now (manual, works while paused) / Clear. The background task is a `tokio::spawn` loop that scans every state file every 30s and only fires on 5-min marks.
2. **Chart Viewer tab** — a new "chart" tab was added to the tab bar, but it's currently a placeholder ("Chart viewer coming soon"). The `set_chart_sym` / `set_chart_tf` / `set_chart_type` act handlers were added to back it.
3. **Chart links retargeted to TCHARTS** — both the action strip and result-row 📊 links now point to `//tcharts.openalgo.theworkpc.com/?symbol=X&interval=Y&chartType=Z` instead of the old `chart.openalgo...` py page. Also maps `D` → `Daily` for the tcharts interval param.
4. **Scope symbol persistence fix** — when a scan submits the full universe, it now stores `symbols: []` (all) instead of a redundant full list; only a genuinely narrowed selection is persisted.
5. **Favicon** — added an inline SVG favicon (`/favicon.svg` route + `<link rel="icon">`), a green "VG" mark.
## Frontend
The frontend is server-rendered HTML from main.rs (no JS logic), so the visible UI changes are the ladder card, the Chart tab, and the new favicon. The one real client-side change is on the **tcharts page** (`/home/ubuntu/charting-project/static/index.html`, edited Aug 18 22:44): its init hook now reads `?symbol=&interval=&chartType=` from the URL and pre-selects the symbol, interval (mapping `D`→`Daily`, `candle`→`candles`), and renko/candles mode before loading — that's what makes the screener's new chart links land on the right chart.
## Live state right now
The anonymous session currently has tracking **ON** for the preset **"within 1% of LIPI"** — the ladder has 20 snaps from 14:00 to 15:35 today (PASS count ranged 5–9, ending at 9). Presets present: "LIPI Long", "safe to swing", "within 1% of LIPI". Scope is D / lookback 20 / renko / all symbols.
One thing worth flagging: the ladder is still tracking "within 1% of LIPI" with `on: true`. That's intentional per the design (it idles overnight and resumes at 09:15), but if you don't want it snapping tomorrow, hit Stop on that ladder.