feat: Schema für Live-Engine (positions, paper_trades, decision_logs, bot_state, equity_snapshots)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { doublePrecision, jsonb, pgTable, primaryKey, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core';
|
||||
import { doublePrecision, integer, jsonb, pgTable, primaryKey, serial, text, timestamp, uniqueIndex, varchar } from 'drizzle-orm/pg-core';
|
||||
|
||||
export const candles = pgTable(
|
||||
'candles',
|
||||
@@ -14,6 +14,67 @@ export const candles = pgTable(
|
||||
(t) => [primaryKey({ columns: [t.pair, t.ts] })],
|
||||
);
|
||||
|
||||
export const positions = pgTable('positions', {
|
||||
pair: varchar('pair', { length: 16 }).primaryKey(),
|
||||
side: text('side').notNull(), // 'long' | 'short'
|
||||
qty: doublePrecision('qty').notNull(),
|
||||
entryTs: timestamp('entry_ts', { withTimezone: true }).notNull(),
|
||||
entryPrice: doublePrecision('entry_price').notNull(),
|
||||
entryCost: doublePrecision('entry_cost').notNull(),
|
||||
initialStop: doublePrecision('initial_stop').notNull(),
|
||||
stop: doublePrecision('stop').notNull(),
|
||||
trailExtreme: doublePrecision('trail_extreme').notNull(),
|
||||
riskAmount: doublePrecision('risk_amount').notNull(),
|
||||
});
|
||||
|
||||
export const paperTrades = pgTable('paper_trades', {
|
||||
id: serial('id').primaryKey(),
|
||||
pair: varchar('pair', { length: 16 }).notNull(),
|
||||
side: text('side').notNull(),
|
||||
entryTs: timestamp('entry_ts', { withTimezone: true }).notNull(),
|
||||
entryPrice: doublePrecision('entry_price').notNull(),
|
||||
exitTs: timestamp('exit_ts', { withTimezone: true }).notNull(),
|
||||
exitPrice: doublePrecision('exit_price').notNull(),
|
||||
qty: doublePrecision('qty').notNull(),
|
||||
pnl: doublePrecision('pnl').notNull(),
|
||||
r: doublePrecision('r').notNull(),
|
||||
exitReason: text('exit_reason').notNull(),
|
||||
});
|
||||
|
||||
export const decisionLogs = pgTable(
|
||||
'decision_logs',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
pair: varchar('pair', { length: 16 }).notNull(),
|
||||
barTs: timestamp('bar_ts', { withTimezone: true }).notNull(), // Start der 4h-Bar
|
||||
signal: text('signal'), // 'long' | null
|
||||
blockedBy: text('blocked_by'), // Evaluation.blockedBy | 'position_open' | 'max_positions' | Sizing-Block
|
||||
close: doublePrecision('close').notNull(),
|
||||
atr: doublePrecision('atr'),
|
||||
adx: doublePrecision('adx'),
|
||||
donchianHigh: doublePrecision('donchian_high'),
|
||||
trendEma: doublePrecision('trend_ema'),
|
||||
priceAfter4h: doublePrecision('price_after_4h'),
|
||||
priceAfter24h: doublePrecision('price_after_24h'),
|
||||
priceAfter72h: doublePrecision('price_after_72h'),
|
||||
},
|
||||
(t) => [uniqueIndex('decision_logs_pair_bar_ts').on(t.pair, t.barTs)],
|
||||
);
|
||||
|
||||
export const botState = pgTable('bot_state', {
|
||||
id: integer('id').primaryKey(), // immer 1
|
||||
cash: doublePrecision('cash').notNull(),
|
||||
startCapital: doublePrecision('start_capital').notNull(),
|
||||
cursorTs: timestamp('cursor_ts', { withTimezone: true }).notNull(), // letzte verarbeitete 15m-Candle
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const equitySnapshots = pgTable('equity_snapshots', {
|
||||
ts: timestamp('ts', { withTimezone: true }).primaryKey(), // 4h-Bucket
|
||||
equity: doublePrecision('equity').notNull(),
|
||||
cash: doublePrecision('cash').notNull(),
|
||||
});
|
||||
|
||||
export const backtestRuns = pgTable('backtest_runs', {
|
||||
id: serial('id').primaryKey(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
|
||||
Reference in New Issue
Block a user