Refresh dailyPnL on a fixed hourly interval instead of throttling
- Replace the reactive throttle with a proactive setInterval in requestSync that fires fetchDaysTraded exactly once per hour per client - Remove post-fill fetchDaysTraded calls from auto-trade.ts — no longer needed and were causing bursts of report API requests on simultaneous fills - Guard against duplicate intervals if requestSync fires more than once Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
92b929f4ce
commit
d0065ab047
@@ -180,11 +180,6 @@ export async function runTrade(action: 'Buy' | 'Sell' | 'Random', symbol: string
|
|||||||
const exitAction: 'Buy' | 'Sell' = resolvedAction === 'Buy' ? 'Sell' : 'Buy';
|
const exitAction: 'Buy' | 'Sell' = resolvedAction === 'Buy' ? 'Sell' : 'Buy';
|
||||||
const exitFill = await client.sendOrder(acc.id, mnqContract.name, 1, exitAction, 'Market');
|
const exitFill = await client.sendOrder(acc.id, mnqContract.name, 1, exitAction, 'Market');
|
||||||
|
|
||||||
// Refresh daily P&L immediately after the extra-day round-trip completes
|
|
||||||
client.fetchDaysTraded().catch((err) =>
|
|
||||||
console.error('[auto-trade] post-fill fetchDaysTraded error:', err)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`[auto-trade] ${acc.name} (${item.firmName}) extra-day: ${resolvedAction} 1xMNQ @ ${fill.price} | exited @ ${exitFill.price} (market)`);
|
console.log(`[auto-trade] ${acc.name} (${item.firmName}) extra-day: ${resolvedAction} 1xMNQ @ ${fill.price} | exited @ ${exitFill.price} (market)`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -226,15 +221,6 @@ export async function runTrade(action: 'Buy' | 'Sell' | 'Random', symbol: string
|
|||||||
const exitAction: 'Buy' | 'Sell' = resolvedAction === 'Buy' ? 'Sell' : 'Buy';
|
const exitAction: 'Buy' | 'Sell' = resolvedAction === 'Buy' ? 'Sell' : 'Buy';
|
||||||
const exitOrder = await client.placeOrderNoWait(acc.id, contract.name, contracts, exitAction, 'Limit', exitPrice);
|
const exitOrder = await client.placeOrderNoWait(acc.id, contract.name, contracts, exitAction, 'Limit', exitPrice);
|
||||||
|
|
||||||
// Refresh daily P&L as soon as the exit limit order fills
|
|
||||||
if (exitOrder.orderId != null) {
|
|
||||||
client.onFill(exitOrder.orderId, () => {
|
|
||||||
client.fetchDaysTraded().catch((err) =>
|
|
||||||
console.error('[auto-trade] post-fill fetchDaysTraded error:', err)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[auto-trade] ${acc.name} (${item.firmName}) ${resolvedAction} ${contracts}x${resolvedSymbol} @ ${fill.price} | target $${target.amount} [${target.path}] (+$${totalCommission.toFixed(2)} comm) | exit @ ${exitPrice} (orderId=${exitOrder.orderId})`);
|
console.log(`[auto-trade] ${acc.name} (${item.firmName}) ${resolvedAction} ${contracts}x${resolvedSymbol} @ ${fill.price} | target $${target.amount} [${target.path}] (+$${totalCommission.toFixed(2)} comm) | exit @ ${exitPrice} (orderId=${exitOrder.orderId})`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ export class TradovateClient {
|
|||||||
|
|
||||||
/** True once fetchDaysTraded() has finished its last full run */
|
/** True once fetchDaysTraded() has finished its last full run */
|
||||||
public fetchDaysComplete = false;
|
public fetchDaysComplete = false;
|
||||||
/** Timestamp (ms) of the last successful fetchDaysTraded run — throttled to once per hour */
|
/** NodeJS.Timeout handle for the hourly dailyPnL refresh */
|
||||||
private lastDaysFetch = 0;
|
private daysFetchInterval: ReturnType<typeof setInterval> | null = null;
|
||||||
/** Last error per account name from fetchDaysTraded() */
|
/** Last error per account name from fetchDaysTraded() */
|
||||||
public lastFetchErrors: Record<string, string> = {};
|
public lastFetchErrors: Record<string, string> = {};
|
||||||
/** Raw reports API response sample per account (first 100 chars) for debugging */
|
/** Raw reports API response sample per account (first 100 chars) for debugging */
|
||||||
@@ -290,6 +290,13 @@ export class TradovateClient {
|
|||||||
|
|
||||||
this.fetchDaysTraded();
|
this.fetchDaysTraded();
|
||||||
|
|
||||||
|
// Refresh daily P&L once per hour — avoids hammering the reports API
|
||||||
|
if (this.daysFetchInterval) clearInterval(this.daysFetchInterval);
|
||||||
|
this.daysFetchInterval = setInterval(
|
||||||
|
() => this.fetchDaysTraded().catch((err) => console.error('[hourly fetchDaysTraded]', err)),
|
||||||
|
60 * 60 * 1_000
|
||||||
|
);
|
||||||
|
|
||||||
if (this.products.length > 0) {
|
if (this.products.length > 0) {
|
||||||
this.syncComplete = true;
|
this.syncComplete = true;
|
||||||
this.callbackOnSyncRequest();
|
this.callbackOnSyncRequest();
|
||||||
@@ -315,10 +322,6 @@ export class TradovateClient {
|
|||||||
|
|
||||||
public async fetchDaysTraded(): Promise<void> {
|
public async fetchDaysTraded(): Promise<void> {
|
||||||
if (!this.accessInfo?.accessToken) return;
|
if (!this.accessInfo?.accessToken) return;
|
||||||
// Throttle to at most once per hour to avoid rate-limiting the reports API
|
|
||||||
const ONE_HOUR = 60 * 60 * 1_000;
|
|
||||||
if (Date.now() - this.lastDaysFetch < ONE_HOUR) return;
|
|
||||||
this.lastDaysFetch = Date.now();
|
|
||||||
this.fetchDaysComplete = false;
|
this.fetchDaysComplete = false;
|
||||||
|
|
||||||
const authHeaders = { Authorization: `Bearer ${this.accessInfo.accessToken}` };
|
const authHeaders = { Authorization: `Bearer ${this.accessInfo.accessToken}` };
|
||||||
|
|||||||
Reference in New Issue
Block a user