Skip to content

ThetaPrime v0.35.16

Choose a tag to compare

@dsharma01 dsharma01 released this 27 Aug 02:00
· 8 commits to main since this release

Download ThetaPrime-0.35.16-setup.exe

Fixed

Batches 10-11 of the 2026-08-25 systematic bug hunt (findings #45-57), closing out all 58 findings. Full suite: 1232 passed (up from 1220).

  • _run_short_reentry now reuses the parked long legs' actual units for re-entered short legs instead of recomputing sizing.qty() fresh, which could land a different lot count under capital_pct sizing days after entry — leaving the diagonal naked on mismatched lots.
  • scanner.py OI/price baselines no longer treat a genuine 0 (fresh-listed strike's previous-day OI, or a flat net_change) the same as missing/undefined — both now show their correct "Flat"/0 state instead of falling back to a misleading label.
  • storage.py decrypt/re-encrypt of pending DB files now attempts every file before raising, instead of one bad file blocking every later file in the list from being (de/re)crypted.
  • app.py _leg_token_cache now resets on a date change instead of growing unbounded for the life of the waitress process.
  • Rejected-leg reconciliation now matches the position-count change since a snapshot taken right before order placement, instead of raw broker quantity, so it can no longer mistake a coincidentally-same-sized pre-existing position for a genuine new fill.
  • storage.is_token_fresh() is now memoized per-request instead of doing 2 keyring reads twice per page load.
  • /api/margins now fetches all 3 brokers' margins concurrently instead of a slow broker blocking the others.
  • Strategy list + archived list are now computed from one directory scan instead of two.
  • run_monitor now batches one ltp() call per tick across all held legs instead of a separate round-trip per leg group.
  • Close-and-verify logic shared between _close_legs/_close_for_reentry, and the OTM strike-scan shared across PremiumTarget/GammaTarget/DeltaOtm, are now single implementations (pure refactor, no behavior change).
  • publish-release.ps1 release notes now scope to the current version's changelog section instead of the whole file, avoiding GitHub's 125000-char release-body cap as CHANGELOG.md grows.

[0.35.15] — 2026-08-26

Fixed

Batches 3-9 of the 2026-08-25 systematic bug hunt (findings #6-44), plus the 2026-08-26 orphaned-fill incident. Full suite: 1220 passed.

  • KiteAdapter now tracks dead-session state at the class level (mirrors the fix already shipped for Breeze/Dhan) — a fresh adapter per request previously meant it never armed.
  • Dhan contract validation now clears the class-level dead-token flag between checks, not just the instance flag, avoiding a repeat of the 2026-07-19 incident.
  • convert_to_limit (Kite/Breeze/Dhan) no longer re-places a marketable LIMIT on top of an order whose cancel wasn't confirmed CANCELLED/REJECTED, which could double a leg.
  • Strategy engine now aborts cleanly when a structure builds zero legs, instead of leaving status=ACTIVE with no orders placed.
  • Fixed an unpadded-hour bug ("9:45" vs "09:45") that silently broke entry-time filters, EOD exits, and the fullday-sim/scheduler "latest exit time" calc; spec save-time validation now rejects unpadded hours.
  • Fullday-sim orphaned-thread handling now waits for the orphaned thread to finish before restoring env / releasing its lock, so a second concurrent sim can't corrupt the first's date/hour/minute env vars; the lock is also released on exception instead of deadlocking.
  • One strategy's malformed active-trade state no longer crashes reconciliation for every other strategy.
  • .secrets.json now writes via temp-file + os.replace instead of truncating in place, so a crash mid-write can no longer wipe every stored credential.
  • Fixed a stuck AWAITING_REENTRY status left over from a day run_eod() never ran, which had been silently skipping the next day's entry.
  • Fill verification no longer treats a genuine 0.0 average fill price as "no fill" and skips backfilling it.
  • Orphaned-fill incident (2026-08-26): subprocess timeout raised to 240s (was shorter than Breeze's own worst-case fill-poll budget, guaranteeing a mid-poll kill); a killed run now gets a proper run-history row and crash notification instead of vanishing; entry legs are checkpointed to disk after each successful placement, not only on failure. Reconciliation now reads _partial_entry legs and a diagonal's held long legs on the ACTIVE branch; the periodic reconcile safety net now runs whenever real trading is configured, not only once a leg is already believed open; the UI modal no longer hides held long legs after a successful short re-entry.
  • Close orders get the same mid-poll checkpoint as entries, across all 7 close call sites (close, close-long, close-for-reentry, adjustment rolls, retry-unconfirmed, rollback).
  • lot_size() now raises for a genuinely unrecognized underlying instead of silently defaulting to NIFTY's lot size.
  • Long-leg monitor context (diagonal hedges) now carries entry_vix, sets position_dte (not just long_dte), and fetches a fresh VIX reading when a delta_stop/iv_stop is in scope — these exits previously never fired on long legs.
  • Black-Scholes formulas no longer raise ZeroDivisionError on vix=0; return the correct zero-vol limit instead.
  • Margin estimate no longer treats a genuine 0.0 wing_pts (same-strike wing) as undefined risk.
  • Nine JSON-body routes switched from request.json or {} (raises on missing/non-JSON Content-Type) to request.get_json(silent=True) or {}.
  • Concurrent safety/broker/backup config saves are now lock-guarded against a lost-update race.
  • _settle_close_order now catches broker exceptions instead of letting one dead session abort the whole retry/roll loop for every other unconfirmed leg.
  • AI ask() now raises a clean error on a tool-calls-only reply (content: null) instead of crashing callers with AttributeError.
  • Scheduled backup pruning now rejects keep <= 0 instead of deleting every backup including the one just made.
  • Strategy archiving now derives the state-file path the same way app.py does, fixing a false "no open position" check for legacy .py strategies.
  • GammaTarget/DeltaOtm selectors now raise a clean error when min_otm_pct > max_otm_pct empties the scan range.
  • License revocation check now stamps "checked" even on a failed network call, so a sustained outage doesn't force the blocking 5s check on every page load.
  • Cloning a strategy now also checks for an existing display/param sidecar file, not just the strategy file itself.
  • multi_sim.extend() no longer widens the session's date range before the corresponding batch of days has actually run.
  • Local-credential-store writes (storage.py) are now lock-guarded against concurrent read-modify-write races, including the trial-start write-once guard.
  • Revocation state and pending-request storage now go through the OS keyring first, local file only as fallback.
  • Fixed a SQLite connection leak in the app-events table helpers.
  • The X-MCP-Auth header now shares /login's brute-force lockout, instead of being uncapped.
  • MCP server error responses now surface app.py's actual error message instead of a generic HTTP status line.
  • First-run data-encryption setup no longer raises unguarded on a keyring/disk failure.
  • sync_backup_job() no longer takes down the entire scheduler when a saved backup time is out of range.
  • Run IDs are now unique to sub-second resolution, preventing two same-second runs from overwriting each other's tracking entry.
  • _send_email() now validates user/password up front instead of a bare KeyError on a partial config.
  • Sim logging handler cleanup now only removes handlers the sim itself added, instead of clearing whatever's present.