fix: login mutex, zero-qty realised PnL, market cache-on-error, UI preserve cards
This commit is contained in:
parent
882d55adad
commit
6f06755e11
4 changed files with 18 additions and 10 deletions
|
|
@ -6,6 +6,7 @@ import { AngelAuthResponse } from './types.js';
|
|||
let jwtToken: string | null = null;
|
||||
let refreshToken: string | null = null;
|
||||
let tokenExpiry: Date | null = null;
|
||||
let loginMutex: Promise<void> | null = null; // prevents concurrent logins
|
||||
|
||||
const BASE_URL = 'https://apiconnect.angelbroking.com';
|
||||
|
||||
|
|
@ -87,9 +88,12 @@ export async function login(): Promise<void> {
|
|||
export async function getToken(): Promise<string> {
|
||||
const now = new Date();
|
||||
|
||||
// No token yet, or past expiry
|
||||
if (!jwtToken || !tokenExpiry || now >= tokenExpiry) {
|
||||
await login();
|
||||
// Mutex: wait for in-progress login instead of starting a second one
|
||||
if (!loginMutex) {
|
||||
loginMutex = login().finally(() => { loginMutex = null; });
|
||||
}
|
||||
await loginMutex;
|
||||
}
|
||||
|
||||
return jwtToken!;
|
||||
|
|
|
|||
|
|
@ -54,8 +54,9 @@ export async function fetchHoldings(): Promise<AngelHolding[]> {
|
|||
*/
|
||||
function normalisePosition(p: AngelPosition): Position | null {
|
||||
const netqty = parseFloat(p.netqty);
|
||||
// Skip positions with zero net qty (fully closed intraday)
|
||||
if (netqty === 0) return null;
|
||||
const realisedPnl = parseFloat(p.realised) || 0;
|
||||
// Only skip if qty=0 AND no realised PnL (truly empty row)
|
||||
if (netqty === 0 && realisedPnl === 0) return null;
|
||||
|
||||
const ltp = parseFloat(p.ltp) || 0;
|
||||
const unrealised = parseFloat(p.unrealised) || 0;
|
||||
|
|
|
|||
|
|
@ -93,13 +93,14 @@ export async function fetchMarketData(): Promise<MarketQuote[]> {
|
|||
try {
|
||||
const live = await fetchFromAngel();
|
||||
if (live.length > 0) {
|
||||
saveToCache(live); // update cache whenever we get fresh data
|
||||
saveToCache(live);
|
||||
return live;
|
||||
}
|
||||
// Empty from Angel (market closed) — serve cache
|
||||
return loadFromCache();
|
||||
} catch (err) {
|
||||
console.error('[market] Angel fetch error:', err instanceof Error ? err.message : err);
|
||||
// Auth/network error — always serve last known cache so UI never goes blank
|
||||
console.error('[market] fetch error, serving cache:', err instanceof Error ? err.message : err);
|
||||
return loadFromCache();
|
||||
}
|
||||
// Market closed or error — serve cached data
|
||||
const cached = loadFromCache();
|
||||
return cached; // empty array if never cached (first run before market open)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,9 @@ async function evaluateAlerts(positions: Position[], today: string): Promise<voi
|
|||
@delta_abs, @delta_pct, @direction, @ltp, @netqty, datetime('now'))
|
||||
`);
|
||||
|
||||
for (const pos of positions) {
|
||||
// Only evaluate alerts for positions that are still open (netqty != 0)
|
||||
const openPositions = positions.filter(p => p.netqty !== 0);
|
||||
for (const pos of openPositions) {
|
||||
let state = getBandState.get(pos.key) as BandState | undefined;
|
||||
|
||||
// First time seeing this position, or new trading day → initialise anchor
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue