|
@@ -46,8 +46,8 @@ export async function getDashboardSummary(): Promise<DashboardSummary> {
|
|
|
}),
|
|
}),
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
- const todayPnl = todayTrades.reduce((sum, t) => sum + (t.pnl ?? 0), 0);
|
|
|
|
|
- const wins = last30Trades.filter((t) => (t.pnl ?? 0) > 0).length;
|
|
|
|
|
|
|
+ const todayPnl = todayTrades.reduce((sum: number, t: { pnl: number | null }) => sum + (t.pnl ?? 0), 0);
|
|
|
|
|
+ const wins = last30Trades.filter((t: { pnl: number | null }) => (t.pnl ?? 0) > 0).length;
|
|
|
const winRate = last30Trades.length > 0 ? wins / last30Trades.length : 0;
|
|
const winRate = last30Trades.length > 0 ? wins / last30Trades.length : 0;
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
@@ -220,7 +220,7 @@ export async function getRecentTrades(limit = 50): Promise<TradeRecord[]> {
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- return rows.map((t) => {
|
|
|
|
|
|
|
+ return rows.map((t: typeof rows[number]) => {
|
|
|
const sig = t.signals[0];
|
|
const sig = t.signals[0];
|
|
|
return {
|
|
return {
|
|
|
id: t.id,
|
|
id: t.id,
|
|
@@ -261,7 +261,7 @@ export async function getMarkets(): Promise<WeatherMarket[]> {
|
|
|
}
|
|
}
|
|
|
// Only keep latest per bucket
|
|
// Only keep latest per bucket
|
|
|
const existing = grouped.get(key)!;
|
|
const existing = grouped.get(key)!;
|
|
|
- const existingBucket = existing.find((s) => s.bucketLabel === snap.bucketLabel);
|
|
|
|
|
|
|
+ const existingBucket = existing.find((s: typeof snap) => s.bucketLabel === snap.bucketLabel);
|
|
|
if (!existingBucket) {
|
|
if (!existingBucket) {
|
|
|
existing.push(snap);
|
|
existing.push(snap);
|
|
|
}
|
|
}
|
|
@@ -274,9 +274,9 @@ export async function getMarkets(): Promise<WeatherMarket[]> {
|
|
|
for (const [key, snaps] of grouped) {
|
|
for (const [key, snaps] of grouped) {
|
|
|
const [city, date] = key.split('|');
|
|
const [city, date] = key.split('|');
|
|
|
const tempUnit = ['New York', 'Chicago', 'Miami', 'Houston', 'Denver', 'Los Angeles', 'Phoenix', 'Seattle'].includes(city) ? 'F' : 'C';
|
|
const tempUnit = ['New York', 'Chicago', 'Miami', 'Houston', 'Denver', 'Los Angeles', 'Phoenix', 'Seattle'].includes(city) ? 'F' : 'C';
|
|
|
- const totalVolume = snaps.reduce((s, b) => s + b.volume24h, 0);
|
|
|
|
|
|
|
+ const totalVolume = snaps.reduce((s: number, b: typeof snapshots[number]) => s + b.volume24h, 0);
|
|
|
|
|
|
|
|
- const buckets: MarketBucket[] = snaps.map((s) => ({
|
|
|
|
|
|
|
+ const buckets: MarketBucket[] = snaps.map((s: typeof snapshots[number]) => ({
|
|
|
label: s.bucketLabel,
|
|
label: s.bucketLabel,
|
|
|
modelProb: 0, // Will be filled when forecasts are available
|
|
modelProb: 0, // Will be filled when forecasts are available
|
|
|
marketPrice: s.yesPrice,
|
|
marketPrice: s.yesPrice,
|
|
@@ -306,7 +306,8 @@ export async function getPnLData(): Promise<{ data: PnLDataPoint[]; metrics: PnL
|
|
|
|
|
|
|
|
// Build cumulative PnL series
|
|
// Build cumulative PnL series
|
|
|
let cumulative = 0;
|
|
let cumulative = 0;
|
|
|
- const data: PnLDataPoint[] = dailyMetrics.map((dm) => {
|
|
|
|
|
|
|
+ type DM = typeof dailyMetrics[number];
|
|
|
|
|
+ const data: PnLDataPoint[] = dailyMetrics.map((dm: DM) => {
|
|
|
cumulative += dm.netPnl;
|
|
cumulative += dm.netPnl;
|
|
|
return {
|
|
return {
|
|
|
date: dm.date.toISOString().slice(0, 10),
|
|
date: dm.date.toISOString().slice(0, 10),
|
|
@@ -316,16 +317,16 @@ export async function getPnLData(): Promise<{ data: PnLDataPoint[]; metrics: PnL
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// Aggregate metrics
|
|
// Aggregate metrics
|
|
|
- const totalTrades = dailyMetrics.reduce((s, d) => s + d.totalTrades, 0);
|
|
|
|
|
- const winningTrades = dailyMetrics.reduce((s, d) => s + d.winningTrades, 0);
|
|
|
|
|
|
|
+ const totalTrades = dailyMetrics.reduce((s: number, d: DM) => s + d.totalTrades, 0);
|
|
|
|
|
+ const winningTrades = dailyMetrics.reduce((s: number, d: DM) => s + d.winningTrades, 0);
|
|
|
const totalPnl = cumulative;
|
|
const totalPnl = cumulative;
|
|
|
const winRate = totalTrades > 0 ? winningTrades / totalTrades : 0;
|
|
const winRate = totalTrades > 0 ? winningTrades / totalTrades : 0;
|
|
|
|
|
|
|
|
// Sharpe ratio (annualized from daily)
|
|
// Sharpe ratio (annualized from daily)
|
|
|
- const dailyReturns = dailyMetrics.map((d) => d.netPnl);
|
|
|
|
|
- const avgReturn = dailyReturns.length > 0 ? dailyReturns.reduce((s, r) => s + r, 0) / dailyReturns.length : 0;
|
|
|
|
|
|
|
+ const dailyReturns = dailyMetrics.map((d: DM) => d.netPnl);
|
|
|
|
|
+ const avgReturn = dailyReturns.length > 0 ? dailyReturns.reduce((s: number, r: number) => s + r, 0) / dailyReturns.length : 0;
|
|
|
const variance = dailyReturns.length > 1
|
|
const variance = dailyReturns.length > 1
|
|
|
- ? dailyReturns.reduce((s, r) => s + (r - avgReturn) ** 2, 0) / (dailyReturns.length - 1)
|
|
|
|
|
|
|
+ ? dailyReturns.reduce((s: number, r: number) => s + (r - avgReturn) ** 2, 0) / (dailyReturns.length - 1)
|
|
|
: 0;
|
|
: 0;
|
|
|
const stdDev = Math.sqrt(variance);
|
|
const stdDev = Math.sqrt(variance);
|
|
|
const sharpe = stdDev > 0 ? (avgReturn / stdDev) * Math.sqrt(252) : 0;
|
|
const sharpe = stdDev > 0 ? (avgReturn / stdDev) * Math.sqrt(252) : 0;
|