Spaces:
Running
Running
File size: 3,736 Bytes
f568a4f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import { DataIngestionSnapshot } from './dataIngestion';
import { RiskAdjustedOrder } from './riskManagement';
export interface ExecutionFill {
exchange: string;
price: number;
size: number;
latencyMs: number | null;
providerFillId: string;
}
export interface ExecutionReport {
success: boolean;
fills: ExecutionFill[];
averagePrice: number;
slippage: number;
providerOrderId: string;
sourceId: string;
sourceEventId: string;
providerTimestamp: number;
truthStatus: 'live';
generated: false;
}
export interface ProviderExecutionReceipt {
success: boolean;
fills: ExecutionFill[];
providerOrderId: string;
sourceId: string;
sourceEventId: string;
providerTimestamp: number;
generated: false;
}
export interface ExecutionConfig {
maxSlippageBps: number;
latencyRange: { min: number; max: number };
partialFillProbability: number;
}
const DEFAULT_CONFIG: ExecutionConfig = {
maxSlippageBps: 18,
latencyRange: { min: 0, max: 0 },
partialFillProbability: 0,
};
const timestampMs = (value: number): number => value < 10_000_000_000 ? value * 1000 : value;
/**
* Validates provider receipts. Order placement belongs to the authenticated
* exchange connector; this class never invents latency, slippage, partial
* fills, or a successful execution.
*/
export class ExecutionEngine {
private readonly config: ExecutionConfig;
constructor(config: Partial<ExecutionConfig> = {}) {
this.config = { ...DEFAULT_CONFIG, ...config };
}
execute(_order: RiskAdjustedOrder, _snapshot: DataIngestionSnapshot): never {
throw new Error('DIRECT_EXECUTION_RETIRED: invoke the authenticated exchange connector and record its receipt');
}
recordProviderExecution(
order: RiskAdjustedOrder,
snapshot: DataIngestionSnapshot,
receipt: ProviderExecutionReceipt
): ExecutionReport {
if (!receipt || receipt.generated !== false || !receipt.sourceId || !receipt.sourceEventId) {
throw new Error('EXECUTION_RECEIPT_PROVENANCE_REQUIRED');
}
const providerTimestamp = timestampMs(receipt.providerTimestamp);
const ageMs = Date.now() - providerTimestamp;
if (ageMs < -30_000 || ageMs > 300_000) {
throw new Error(`EXECUTION_RECEIPT_STALE:${ageMs}`);
}
if (!receipt.success || !receipt.providerOrderId || !receipt.fills.length) {
throw new Error('EXECUTION_NOT_CONFIRMED_BY_PROVIDER');
}
for (const fill of receipt.fills) {
if (!fill.exchange || !fill.providerFillId || !Number.isFinite(fill.price) || fill.price <= 0) {
throw new Error('EXECUTION_FILL_INVALID');
}
if (!Number.isFinite(fill.size) || fill.size <= 0) {
throw new Error('EXECUTION_FILL_SIZE_INVALID');
}
}
const totalNotional = receipt.fills.reduce((sum, fill) => sum + fill.price * fill.size, 0);
const totalSize = receipt.fills.reduce((sum, fill) => sum + fill.size, 0);
const averagePrice = totalNotional / totalSize;
const referencePrice = snapshot.consolidatedOHLCV.close;
const direction = order.direction === 'long' ? 1 : -1;
const slippage = ((averagePrice - referencePrice) / referencePrice) * direction;
if (Math.abs(slippage) * 10_000 > this.config.maxSlippageBps) {
throw new Error(`EXECUTION_SLIPPAGE_LIMIT_EXCEEDED:${slippage}`);
}
return {
success: true,
fills: receipt.fills,
averagePrice,
slippage,
providerOrderId: receipt.providerOrderId,
sourceId: receipt.sourceId,
sourceEventId: receipt.sourceEventId,
providerTimestamp,
truthStatus: 'live',
generated: false,
};
}
}
|