Vest: record every trade, the bot's and outside ones, and list them
Vest's position history (GET /v3/positions) gives each position's size, open and close price, P&L, fees, funding and why it closed. The client reads it hourly and a minute after a position closes (or a flat balance moves) into a new trades table, and stores open positions as they appear. Vest can't tell an API order from a click, so the bot marks its own opens and closes as it sends them; an unmarked trade since marking began was someone else's. The dashboard's Vest firm row gets a Trades button listing every trade on its accounts with who opened it and how it closed; the account page shows its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
29eaf64a6b
commit
95cc3bd23f
@@ -283,6 +283,57 @@ export function parsePosition(raw: unknown): VestPosition | null {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* One position from GET /v3/positions — Vest's position history, the app's
|
||||
* History tab: closed positions with how they ended (an open one has no
|
||||
* close yet). pnl is Vest's realized P&L before fees and funding.
|
||||
*/
|
||||
export interface VestTrade {
|
||||
positionId: string;
|
||||
symbol: string;
|
||||
side: 'long' | 'short';
|
||||
/** 0 when Vest doesn't say (a store keeps the size it already knows). */
|
||||
quantity: number;
|
||||
leverage: number | null;
|
||||
openPrice: number | null;
|
||||
closePrice: number | null;
|
||||
pnl: number | null;
|
||||
fee: number | null;
|
||||
funding: number | null;
|
||||
openedAt: number;
|
||||
closedAt: number | null;
|
||||
/** user_requested, stop_loss, take_profit, liquidation, auto_deleverage,
|
||||
* temporary_leverage_limit, corporate_action. */
|
||||
closeReason: string | null;
|
||||
}
|
||||
|
||||
export function parseHistoryPosition(raw: unknown): VestTrade | null {
|
||||
const p = raw as Record<string, unknown>;
|
||||
const id = p?.positionId ?? p?.position_id;
|
||||
if (!p || typeof id !== 'string' || typeof p.symbol !== 'string') return null;
|
||||
const openedAt = toMs(p.openDate ?? p.open_date ?? p.createdAt ?? p.created_at);
|
||||
if (!Number.isFinite(openedAt)) return null;
|
||||
const closedAt = toMs(p.closeDate ?? p.close_date);
|
||||
const openPrice = num(p.openPrice ?? p.open_price);
|
||||
const closePrice = num(p.closePrice ?? p.close_price);
|
||||
const reason = p.closeReason ?? p.close_reason;
|
||||
return {
|
||||
positionId: id,
|
||||
symbol: p.symbol,
|
||||
side: String(p.side).toLowerCase() === 'short' ? 'short' : 'long',
|
||||
quantity: Math.abs(num(p.quantity) ?? 0),
|
||||
leverage: num(p.leverage) ?? null,
|
||||
openPrice: openPrice !== undefined && openPrice > 0 ? openPrice : null,
|
||||
closePrice: closePrice !== undefined && closePrice > 0 ? closePrice : null,
|
||||
pnl: num(p.pnl) ?? null,
|
||||
fee: num(p.fee) ?? null,
|
||||
funding: num(p.funding) ?? null,
|
||||
openedAt,
|
||||
closedAt: Number.isFinite(closedAt) && closedAt > 0 ? closedAt : null,
|
||||
closeReason: typeof reason === 'string' && reason !== '' ? reason : null,
|
||||
};
|
||||
}
|
||||
|
||||
/** Exit legs still waiting to trigger. */
|
||||
export function awaitingLegs(p: VestPosition): VestLeg[] {
|
||||
return [...p.stopLosses, ...p.takeProfits].filter((l) => l.status === 'awaiting');
|
||||
|
||||
Reference in New Issue
Block a user