- execution.py: dual-write SIP_NO_FILL and SIP_PARTIAL to engine_event
so the strategy summary can surface them to users
- execution.py: emit SIP_NO_FILL event (with cash/required amounts) on
the paper path instead of silently returning when funds are insufficient
- strategy_service.py: improve insufficient_funds message to show exact
shortfall and reassure user that next SIP will auto-execute when funded
- strategy_service.py: clear SIP_NO_FILL warning after a successful
SIP_TRIGGERED so it does not persist after funds are added
- runner.py: always write PRICE_FETCH_ERROR and HISTORY_LOAD_ERROR to
engine_event regardless of ENGINE_DEBUG flag
- db.py (backend + engine): raise default pool sizes to 20/50 max
connections to handle 100 concurrent users without pool exhaustion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Every time pm2 restarts, the Zerodha token may be in EXPIRED state
(knocked out by the engine between midnight and 6:05 AM auto-login).
Now on startup we check each auto-login user's broker auth_state and
immediately re-login anyone who is expired/disconnected, so the broker
shows as connected the moment the user opens the website.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- start_strategy filters running check by mode so starting LIVE
won't clash with an active PAPER run and vice versa
- stop_strategy and resume_strategy accept optional mode param
so each tab stops/resumes only its own run
- paper_broker_service scopes all run lookups to mode=PAPER
- paper_mtm scopes run lookup to mode=PAPER
- routers/strategy exposes ?mode= query param on /stop and /resume
- run_service get_active_run_id and get_running_run_id already
support mode filtering (added in previous session)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Frontend checks authState === 'VALID' to clear the session-expired
banner. Using 'CONNECTED' left the banner stuck even after a successful
token refresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When start_strategy is called with a new strategy on an active run,
update strategy_config in DB before building engine config so the
new strategy is used both now and on future resumes/restarts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When restarting an existing run with a different strategy, the saved
DB config was winning over the user's selection. req.strategy_name
now takes priority so switching strategies works correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After twofa verifies identity, re-visit connect/login as authenticated user.
Zerodha then redirects to the registered callback URL with request_token.
This mirrors what the browser JS does to complete the OAuth flow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The sess_id from the connect/login redirect is Zerodha's OAuth session
identifier. Without it in the twofa POST, Zerodha returns profile:{}
(regular web login) instead of redirect_url with request_token.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Following the connect/login redirect chain overwrites kf_session with a
plain web session, stripping the OAuth context. Stop at the first 302
so kf_session retains the api_key OAuth context through the twofa step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Referer on POST was causing Zerodha to reject login with Invalid username.
Add Accept, Accept-Language, Origin headers for proper browser-like requests.
Keep redirect_url body check for twofa. Add login step debug logging.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: X-Kite-Version header on web login endpoints caused Zerodha
to return plain profile response instead of OAuth redirect_url.
Changes:
- Remove X-Kite-Version from session headers (only valid for Kite Connect API)
- Use allow_redirects=False on connect/login GET to preserve OAuth cookie
- Add Referer header to login/twofa POSTs
- Check data.redirect_url in twofa JSON body (modern Zerodha SPA behavior)
- Keep Location header fallback for legacy behavior
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints twofa response status, Location header, and body so we can see
exactly what Zerodha returns after TOTP submission.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without first GETting the connect/login URL with the api_key,
Zerodha doesn't know which app is logging in and never returns
a request_token after TOTP — causing the redirect loop to fail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- auth_service.py: RESET_OTP_SECRET no longer crashes at import; read lazily
inside _hash_otp() so the module always loads cleanly
- main.py: _validate_runtime_secrets() now checks both BROKER_TOKEN_KEY and
RESET_OTP_SECRET together, reporting all missing vars in one clear message
- .env.example: documents every required/optional env var with generation commands
With load_dotenv() + .env file, all secrets survive pm2 restarts automatically.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New auto_login_service.py: stores encrypted credentials (login ID,
password, TOTP secret), performs headless Zerodha login via pyotp,
and refreshes the session daily at 6:05 AM IST via background thread
- New auto_login router: setup, status, remove, and manual trigger endpoints
- Scheduler started at app boot alongside existing daemons
- Added pyotp==2.9.0 dependency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>