refactor(backend): extract shared trading persistence types from SupabaseService
Made-with: Cursor
This commit is contained in:
parent
774541289a
commit
b306f3264e
@ -15,6 +15,29 @@ import {
|
||||
type AlpacaSubTagIntent
|
||||
} from '../utils/alpacaSubTag.js';
|
||||
import { SymbolMapper } from '../utils/symbolMapper.js';
|
||||
import type {
|
||||
FilledLifecycleOrderRow,
|
||||
ReconciliationBackfillAuditInsert,
|
||||
ReconciliationBackfillAuditQuery,
|
||||
ReconciliationBackfillAuditRow,
|
||||
ReconciliationBackfillBatchSummary,
|
||||
ReconciliationBackfillOrderInsert,
|
||||
ReconciliationSubTagRepairSummary,
|
||||
StaleOrderScope,
|
||||
VirtualOpenPosition
|
||||
} from './tradingPersistenceTypes.js';
|
||||
|
||||
export type {
|
||||
FilledLifecycleOrderRow,
|
||||
ReconciliationBackfillAuditInsert,
|
||||
ReconciliationBackfillAuditQuery,
|
||||
ReconciliationBackfillAuditRow,
|
||||
ReconciliationBackfillBatchSummary,
|
||||
ReconciliationBackfillOrderInsert,
|
||||
ReconciliationSubTagRepairSummary,
|
||||
StaleOrderScope,
|
||||
VirtualOpenPosition
|
||||
} from './tradingPersistenceTypes.js';
|
||||
|
||||
export interface UserConfig {
|
||||
user_id: string;
|
||||
@ -32,145 +55,6 @@ export interface UserConfig {
|
||||
market_poll_interval_in_seconds: number;
|
||||
}
|
||||
|
||||
export interface VirtualOpenPosition {
|
||||
profileId: string;
|
||||
symbol: string;
|
||||
side: 'BUY' | 'SELL';
|
||||
qty: number;
|
||||
entryPrice: number;
|
||||
stopLoss: number;
|
||||
takeProfit: number;
|
||||
userId?: string;
|
||||
tradeId: string;
|
||||
tradeIds: string[];
|
||||
}
|
||||
|
||||
export interface StaleOrderScope {
|
||||
profileId?: string;
|
||||
userId?: string;
|
||||
includeOrphanUserOrders?: boolean;
|
||||
profileNullOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface FilledLifecycleOrderRow {
|
||||
id?: string;
|
||||
order_id?: string | null;
|
||||
user_id?: string | null;
|
||||
profile_id?: string | null;
|
||||
symbol?: string | null;
|
||||
trade_id?: string | null;
|
||||
action?: string | null;
|
||||
side?: string | null;
|
||||
qty?: number | string | null;
|
||||
quantity?: number | string | null;
|
||||
price?: number | string | null;
|
||||
status?: string | null;
|
||||
source?: string | null;
|
||||
sub_tag?: string | null;
|
||||
stop_loss?: number | string | null;
|
||||
take_profit?: number | string | null;
|
||||
timestamp?: number | string | null;
|
||||
created_at?: string | null;
|
||||
filled_at?: string | null;
|
||||
type?: string | null;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillOrderInsert {
|
||||
user_id: string;
|
||||
profile_id: string;
|
||||
order_id: string;
|
||||
symbol: string;
|
||||
type: string;
|
||||
side: string;
|
||||
qty: number;
|
||||
quantity: number;
|
||||
price: number;
|
||||
status: string;
|
||||
timestamp: number;
|
||||
filled_at?: string;
|
||||
trade_id: string;
|
||||
action: 'EXIT';
|
||||
source: 'BOT';
|
||||
sub_tag?: string;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillAuditInsert {
|
||||
batch_id: string;
|
||||
profile_id: string;
|
||||
symbol: string;
|
||||
trade_id: string;
|
||||
exchange_order_id?: string | null;
|
||||
exchange_client_order_id?: string | null;
|
||||
backfill_order_id?: string | null;
|
||||
filled_qty?: number | null;
|
||||
filled_price?: number | null;
|
||||
filled_at?: string | null;
|
||||
dry_run: boolean;
|
||||
decision: string;
|
||||
reason?: string | null;
|
||||
metadata?: Record<string, any> | null;
|
||||
applied_at?: string | null;
|
||||
reverted_at?: string | null;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillAuditQuery {
|
||||
profileId?: string;
|
||||
symbol?: string;
|
||||
batchId?: string;
|
||||
decisions?: string[];
|
||||
fromIso?: string;
|
||||
toIso?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillAuditRow {
|
||||
id: number;
|
||||
batch_id: string;
|
||||
profile_id: string;
|
||||
symbol: string;
|
||||
trade_id: string;
|
||||
exchange_order_id?: string | null;
|
||||
exchange_client_order_id?: string | null;
|
||||
backfill_order_id?: string | null;
|
||||
filled_qty?: number | null;
|
||||
filled_price?: number | null;
|
||||
filled_at?: string | null;
|
||||
dry_run: boolean;
|
||||
decision: string;
|
||||
reason?: string | null;
|
||||
metadata?: Record<string, any> | null;
|
||||
applied_at?: string | null;
|
||||
reverted_at?: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillBatchSummary {
|
||||
batchId: string;
|
||||
firstSeenAt: string;
|
||||
lastSeenAt: string;
|
||||
profileIds: string[];
|
||||
symbols: string[];
|
||||
totalRows: number;
|
||||
byDecision: Record<string, number>;
|
||||
dryRunRows: number;
|
||||
appliedRows: number;
|
||||
revertedRows: number;
|
||||
}
|
||||
|
||||
export interface ReconciliationSubTagRepairSummary {
|
||||
attempted: boolean;
|
||||
unsupported?: boolean;
|
||||
scannedRows: number;
|
||||
eligibleRows: number;
|
||||
updatedRows: number;
|
||||
skippedNoProfile: number;
|
||||
skippedNoTrade: number;
|
||||
skippedTagDisabled: number;
|
||||
skippedAlreadyTagged: number;
|
||||
dryRun: boolean;
|
||||
}
|
||||
|
||||
class SupabaseService {
|
||||
private client: SupabaseClient | null = null;
|
||||
private tradeHistorySupportsSource: boolean | null = null;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { FilledLifecycleOrderRow } from './SupabaseService.js';
|
||||
import type { FilledLifecycleOrderRow } from './tradingPersistenceTypes.js';
|
||||
|
||||
export type CanonicalLifecycleState = 'OPEN' | 'PARTIAL_EXIT' | 'CLOSED' | 'ORPHAN_EXIT';
|
||||
export type CanonicalSide = 'BUY' | 'SELL';
|
||||
|
||||
@ -4,11 +4,11 @@ import logger from '../utils/logger.js';
|
||||
import { normalizeOrderAction, normalizeOrderStatus, normalizeTradeSide } from '../domain/tradingEnums.js';
|
||||
import { healthTracker } from './healthTracker.js';
|
||||
import { observabilityService } from './observabilityService.js';
|
||||
import {
|
||||
import type {
|
||||
FilledLifecycleOrderRow,
|
||||
ReconciliationBackfillAuditInsert,
|
||||
ReconciliationBackfillOrderInsert
|
||||
} from './SupabaseService.js';
|
||||
} from './tradingPersistenceTypes.js';
|
||||
import * as runtimeOrderRepository from './runtimeOrderRepository.js';
|
||||
import type { TradeExecutor } from './TradeExecutor.js';
|
||||
import {
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { config } from '../config/index.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import { observabilityService } from './observabilityService.js';
|
||||
import {
|
||||
type ReconciliationSubTagRepairSummary
|
||||
} from './SupabaseService.js';
|
||||
import type { ReconciliationSubTagRepairSummary } from './tradingPersistenceTypes.js';
|
||||
import { repairMissingSubTagsForProfile } from './runtimeOrderRepository.js';
|
||||
|
||||
export interface ReconciliationSubTagRepairContext {
|
||||
|
||||
@ -25,7 +25,7 @@ import type {
|
||||
ReconciliationSubTagRepairSummary,
|
||||
StaleOrderScope,
|
||||
VirtualOpenPosition
|
||||
} from './SupabaseService.js';
|
||||
} from './tradingPersistenceTypes.js';
|
||||
import {
|
||||
ORDER_CONTAINER,
|
||||
RECONCILIATION_AUDIT_CONTAINER,
|
||||
|
||||
143
backend/src/services/tradingPersistenceTypes.ts
Normal file
143
backend/src/services/tradingPersistenceTypes.ts
Normal file
@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Shared shapes for orders, reconciliation audit, and virtual positions.
|
||||
* Used by Cosmos-first repositories and legacy SupabaseService persistence.
|
||||
*/
|
||||
|
||||
export interface VirtualOpenPosition {
|
||||
profileId: string;
|
||||
symbol: string;
|
||||
side: 'BUY' | 'SELL';
|
||||
qty: number;
|
||||
entryPrice: number;
|
||||
stopLoss: number;
|
||||
takeProfit: number;
|
||||
userId?: string;
|
||||
tradeId: string;
|
||||
tradeIds: string[];
|
||||
}
|
||||
|
||||
export interface StaleOrderScope {
|
||||
profileId?: string;
|
||||
userId?: string;
|
||||
includeOrphanUserOrders?: boolean;
|
||||
profileNullOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface FilledLifecycleOrderRow {
|
||||
id?: string;
|
||||
order_id?: string | null;
|
||||
user_id?: string | null;
|
||||
profile_id?: string | null;
|
||||
symbol?: string | null;
|
||||
trade_id?: string | null;
|
||||
action?: string | null;
|
||||
side?: string | null;
|
||||
qty?: number | string | null;
|
||||
quantity?: number | string | null;
|
||||
price?: number | string | null;
|
||||
status?: string | null;
|
||||
source?: string | null;
|
||||
sub_tag?: string | null;
|
||||
stop_loss?: number | string | null;
|
||||
take_profit?: number | string | null;
|
||||
timestamp?: number | string | null;
|
||||
created_at?: string | null;
|
||||
filled_at?: string | null;
|
||||
type?: string | null;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillOrderInsert {
|
||||
user_id: string;
|
||||
profile_id: string;
|
||||
order_id: string;
|
||||
symbol: string;
|
||||
type: string;
|
||||
side: string;
|
||||
qty: number;
|
||||
quantity: number;
|
||||
price: number;
|
||||
status: string;
|
||||
timestamp: number;
|
||||
filled_at?: string;
|
||||
trade_id: string;
|
||||
action: 'EXIT';
|
||||
source: 'BOT';
|
||||
sub_tag?: string;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillAuditInsert {
|
||||
batch_id: string;
|
||||
profile_id: string;
|
||||
symbol: string;
|
||||
trade_id: string;
|
||||
exchange_order_id?: string | null;
|
||||
exchange_client_order_id?: string | null;
|
||||
backfill_order_id?: string | null;
|
||||
filled_qty?: number | null;
|
||||
filled_price?: number | null;
|
||||
filled_at?: string | null;
|
||||
dry_run: boolean;
|
||||
decision: string;
|
||||
reason?: string | null;
|
||||
metadata?: Record<string, any> | null;
|
||||
applied_at?: string | null;
|
||||
reverted_at?: string | null;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillAuditQuery {
|
||||
profileId?: string;
|
||||
symbol?: string;
|
||||
batchId?: string;
|
||||
decisions?: string[];
|
||||
fromIso?: string;
|
||||
toIso?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillAuditRow {
|
||||
id: number;
|
||||
batch_id: string;
|
||||
profile_id: string;
|
||||
symbol: string;
|
||||
trade_id: string;
|
||||
exchange_order_id?: string | null;
|
||||
exchange_client_order_id?: string | null;
|
||||
backfill_order_id?: string | null;
|
||||
filled_qty?: number | null;
|
||||
filled_price?: number | null;
|
||||
filled_at?: string | null;
|
||||
dry_run: boolean;
|
||||
decision: string;
|
||||
reason?: string | null;
|
||||
metadata?: Record<string, any> | null;
|
||||
applied_at?: string | null;
|
||||
reverted_at?: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface ReconciliationBackfillBatchSummary {
|
||||
batchId: string;
|
||||
firstSeenAt: string;
|
||||
lastSeenAt: string;
|
||||
profileIds: string[];
|
||||
symbols: string[];
|
||||
totalRows: number;
|
||||
byDecision: Record<string, number>;
|
||||
dryRunRows: number;
|
||||
appliedRows: number;
|
||||
revertedRows: number;
|
||||
}
|
||||
|
||||
export interface ReconciliationSubTagRepairSummary {
|
||||
attempted: boolean;
|
||||
unsupported?: boolean;
|
||||
scannedRows: number;
|
||||
eligibleRows: number;
|
||||
updatedRows: number;
|
||||
skippedNoProfile: number;
|
||||
skippedNoTrade: number;
|
||||
skippedTagDisabled: number;
|
||||
skippedAlreadyTagged: number;
|
||||
dryRun: boolean;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user