Download ThetaPrime-0.35.24-setup.exe
Fixed
Bug hunt area 8 — frontend (templates/static), 14 findings.
index.html: dashboard card no longer drops_long_activeP&L; two leg-symbol XSS gaps (state card, Mark Exited form) escaped; January weekly-expiry date-parsing collision in_symbolExpiry()fixed.composer.js:chipLabel()XSS on an untrusted spec.json block type escaped; draft-restore no longer loses its dirty/cleansavedSnapshotbaseline.multi_sim_results.html:renderRow()/renderSessionMeta()unescaped fields fixed;stopSim()now surfaces failure feedback instead of failing silently.performance.html:JSON.stringify-in-onclickapostrophe breakout fixed across 8 sites;eventBadge()event type escaped.option_scanner.html: underlyings/expiries escaped into<option>values.docs.html: DOMPurify added aroundmarked.parse()output (defense-in-depth — the/docs/<path>route is already locked todocs/*.mdvia regex).reports.html: falsy-zero strikes check fixed; dead row-highlight code fixed (wrong operator precedence + missingclassList.add).
Validated archive/CODE_REVIEW_TEMPLATES_STATIC_2026-08-28.md — 6/8 confirmed and folded into the above, 2 stale-loading-UI findings deferred as refactor-scoped.
Bug hunt area 9 — performance.py, 2 findings.
add_event()/today_pnl(): trade dates were derived from the machine's local clock instead of IST, so a host not set to IST could attribute an exit to the wrong trading day. Now uses a fixed IST offset, matchingholidays.py's_ISTpattern.get_summary(): a strategy/mode bucket was created for any matching row before checkingREALIZED_EVENT_TYPES, so a strategy with only entry/monitor/skip events rendered as a phantom "0 trades" summary card. Bucket creation is now gated on a realized exit event.- Also hardened
today_pnl()/get_summary()against malformed JSON rows so a damaged row is skipped instead of 500ing the dashboard.
Validated archive/CODE_REVIEW_PERFORMANCE_2026-08-28.md, 2/2 confirmed and fixed.
Bug hunt area 10 — runner.py/engine.py/reconciliation.py, 3 findings.
engine.py_close_and_record(): a partial/unconfirmed close was booked as a finalized full-quantity exit with no way to later correct the historical_closedrecord. Now taggedunconfirmed_legs, and a new_correct_closed_record()helper lets_retry_unconfirmed_close()'s per-leg true-up patch that record directly._execute_long_roll()(and sibling_execute_roll(), found in passing): a roll's replacement leg was dropped entirely when its fill never confirmed, leaving it untracked by reconciliation. Now kept taggedunconfirmed/order_idsoreconciliation.py's existing fold-in picks it up automatically.runner.py: the TRADE_EVENT parsing loop aborted on the first malformed line, silently dropping every later valid event. Moved to per-line try/except, log-and-continue.
Validated archive/CODE_REVIEW_RUNNER_ENGINE_RECONCILIATION_2026-08-28.md, 3/3 confirmed and fixed. reconciliation.py itself had no additional defect.
[0.35.23] — 2026-08-28
Fixed
Bug hunt area 4 — notifications/AI/MCP, 5 findings.
notifier.pysend_notification(): the dedup cache no longer suppresses a retry after an all-channels-failed outage — the placeholder is popped if nothing actually sent, instead of blocking the same alert for the rest of the 10-minute dedup window.notifier.pyformat_trade_event(): malformed/legacy numeric fields (rs,total_rs, per-leg entry/exit) no longer raiseValueErrorand drop the whole notification — added_safe_float()alongside the existing_sign/_is_negativefallback.notifier.pydesktop channel:get_desktop_alerts()and_send_desktop()now share one lock, fixing aRuntimeError: deque mutated during iterationunder concurrent traffic.mcp_server.py:THETAPRIME_MCP_PASSWORDis no longer sent over plaintexthttp://to a non-loopback host — a non-loopbackTHETAPRIME_URLnow requireshttps://or the server refuses to start.ai.pyask(): the bring-your-ownbase_url(custom OpenAI-compatible endpoint) now rejects non-http(s) schemes and the cloud metadata IP, closing an SSRF path that could forward the stored AI key.
Bug hunt area 5 — strategy components & composer, 2 findings.
strategies/components/exits.py:PremiumPctTargetandStopLossPctPremium's duplicated net-premium calculation deduplicated into a shared_net_premium(ctx)helper.strategies/spec.pyestimate_min_capital(): a covered-call holdings-lookup failure (broker offline, rate limit) now logs a warning instead of silently falling back tocovered_qty=0, which looked identical to "no shares actually held" and quietly inflated the margin estimate.
Bug hunt area 6 — simulation & backtesting, 6 findings.
sim_engine.py/strategies/nifty_strangle_live.py: a user-requested sim stop no longer still runsrun_eod()and books P&L for the aborted day; custom.pystrategies (nifty_strangle_live.py,lib_v1_trade.py,Lib_v1_1_lot.py) can now actually be interrupted via a newsim_engine.should_stop().multi_sim.py: the declared-but-unused_multi_sim_lockis now acquired instart()/extend(), closing a race where two concurrent requests could launch overlapping sessions against the same strategy's carry-forward state file.multi_sim._run_extend(): a stop landing right as the prepend batch finishes no longer skipsrecompute_cumulative(), which left every pre-existing day'scumulative_ptsstale.sim_sessions.compute_summary(): a same-day-opened, still-open position at EOD no longer vanishes from every summary bucket (was excluded from trades, no_trades, and errors alike).sim_engine.py: a non-positiveSTRATEGY_MONITOR_INTERVALnow raisesValueErrorup front instead of spinning the tick loop forever.broker/__init__.pyget_broker(): singleton check/rebuild/assign is now guarded by a lock (found while fixing the sim-engine reset call), via a newbroker.reset_singleton().
Bug hunt area 7 — app.py routes, 11 findings.
square_off(): a close order that failed to place or didn't confirm no longer marks the positionCLOSED— unconfirmed legs stay tracked as open undermanual_controlinstead of silently dropping real exposure from monitoring/reconciliation.square_off():SHORT_CLOSEDfull-open-leg derivation now reads_long_active['legs']instead of the never-pruned top-levellegsdict, matchingmanual_exit's existing fix for the same bug class.square_off()/edit_trade_state(): three falsy-zero bugs fixed (ltp_map.get(...) or entry_price,ref_price or None,average_price or entry_price) — a genuine0.0LTP/reference/average-price is no longer treated as missing.- Daily loss limit can no longer be silently disabled by a
NaN/inf/-infvalue —_parse_optional_float()now rejects non-finite input. - Auth/OAuth callback errors (Kite, Breeze, Dhan — 8 call sites) now route through
_safe_error_message()instead of leaking raw exception text into flash/redirect messages. - Scheduled-backup time validation now range-checks hour/minute instead of accepting shape-only garbage like
99:99. /api/desktop_alerts's loopback auth bypass now checks proxy headers like its sibling dev-only bypass, closing a same-host-proxy P&L/alert content leak.trade_reset()now takes the same.closelockevery other live-state route holds, preventing an interleaved read-then-delete from dropping a just-written position.multi_sim.start()/extend()now return-1(not0) when blocked by an already-active session, so the UI reports "already running" instead of a misleading "no trading days found"./ai/prompt/reportsno longer 500s on an unhandledAttributeErrorwhenreports_data()hits its own exception branch.