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 jwtToken: string | null = null;
|
||||||
let refreshToken: string | null = null;
|
let refreshToken: string | null = null;
|
||||||
let tokenExpiry: Date | null = null;
|
let tokenExpiry: Date | null = null;
|
||||||
|
let loginMutex: Promise<void> | null = null; // prevents concurrent logins
|
||||||
|
|
||||||
const BASE_URL = 'https://apiconnect.angelbroking.com';
|
const BASE_URL = 'https://apiconnect.angelbroking.com';
|
||||||
|
|
||||||
|
|
@ -87,9 +88,12 @@ export async function login(): Promise<void> {
|
||||||
export async function getToken(): Promise<string> {
|
export async function getToken(): Promise<string> {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
// No token yet, or past expiry
|
|
||||||
if (!jwtToken || !tokenExpiry || now >= tokenExpiry) {
|
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!;
|
return jwtToken!;
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,9 @@ export async function fetchHoldings(): Promise<AngelHolding[]> {
|
||||||
*/
|
*/
|
||||||
function normalisePosition(p: AngelPosition): Position | null {
|
function normalisePosition(p: AngelPosition): Position | null {
|
||||||
const netqty = parseFloat(p.netqty);
|
const netqty = parseFloat(p.netqty);
|
||||||
// Skip positions with zero net qty (fully closed intraday)
|
const realisedPnl = parseFloat(p.realised) || 0;
|
||||||
if (netqty === 0) return null;
|
// 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 ltp = parseFloat(p.ltp) || 0;
|
||||||
const unrealised = parseFloat(p.unrealised) || 0;
|
const unrealised = parseFloat(p.unrealised) || 0;
|
||||||
|
|
|
||||||
|
|
@ -93,13 +93,14 @@ export async function fetchMarketData(): Promise<MarketQuote[]> {
|
||||||
try {
|
try {
|
||||||
const live = await fetchFromAngel();
|
const live = await fetchFromAngel();
|
||||||
if (live.length > 0) {
|
if (live.length > 0) {
|
||||||
saveToCache(live); // update cache whenever we get fresh data
|
saveToCache(live);
|
||||||
return live;
|
return live;
|
||||||
}
|
}
|
||||||
|
// Empty from Angel (market closed) — serve cache
|
||||||
|
return loadFromCache();
|
||||||
} catch (err) {
|
} 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'))
|
@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;
|
let state = getBandState.get(pos.key) as BandState | undefined;
|
||||||
|
|
||||||
// First time seeing this position, or new trading day → initialise anchor
|
// First time seeing this position, or new trading day → initialise anchor
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue