/**
* Orders table - single source of truth for positions
*
* OPEN orders = active positions (shown in Positions tab)
* CLOSED orders = completed trades (shown in Trades tab)
*
* Unrealized P&L is calculated live from current prices, not stored.
* When an order is closed, exitPrice and realizedPnl are populated.
*/
export const orders = pgTable(
"Orders",
{
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
modelId: text("modelId")
.notNull()
.references(() => models.id, {
onDelete: "restrict",
onUpdate: "cascade",
}),
// Position details
symbol: text("symbol").notNull(),
side: orderSideEnum("side").notNull(),
quantity: numeric("quantity", { precision: 18, scale: 8 }).notNull(),
leverage: numeric("leverage", { precision: 10, scale: 2 }),
// Entry details
entryPrice: numeric("entryPrice", { precision: 18, scale: 8 }).notNull(),
// Exit plan (stop-loss, take-profit, confidence in the plan)
exitPlan: jsonb("exitPlan").$type<{
stop: number | null;
target: number | null;
invalidation: string | null;
invalidationPrice: number | null;
confidence: number | null;
timeExit: string | null;
cooldownUntil: string | null;
}>(),
// Status: OPEN = active position, CLOSED = completed trade
status: orderStatusEnum("status").notNull().default("OPEN"),
// Exit details (populated when closed)
exitPrice: numeric("exitPrice", { precision: 18, scale: 8 }),
realizedPnl: numeric("realizedPnl", { precision: 18, scale: 2 }),
// Auto-close trigger (null = manual close, "STOP" or "TARGET" = auto)
closeTrigger: text("closeTrigger"),
// Lighter exchange order indices for real SL/TP orders
slOrderIndex: text("slOrderIndex"),
tpOrderIndex: text("tpOrderIndex"),
// Trigger prices for SL/TP orders (stored for reference)
slTriggerPrice: numeric("slTriggerPrice", { precision: 18, scale: 8 }),
tpTriggerPrice: numeric("tpTriggerPrice", { precision: 18, scale: 8 }),
// Timestamps
openedAt: timestamp("openedAt").defaultNow().notNull(),
closedAt: timestamp("closedAt"),
updatedAt: timestamp("updatedAt").defaultNow().notNull(),
},
(table) => ({
modelIdx: index("Orders_modelId_idx").on(table.modelId),
statusIdx: index("Orders_status_idx").on(table.status),
modelStatusIdx: index("Orders_modelId_status_idx").on(table.modelId, table.status),
symbolIdx: index("Orders_symbol_idx").on(table.symbol),
}),
);