added initial integration tests with bun

This commit is contained in:
Bojan Kucera 2025-06-04 12:26:55 -04:00
parent 3e451558ac
commit fb22815450
52 changed files with 7588 additions and 364 deletions

View file

@ -0,0 +1,32 @@
{
"name": "@stock-bot/ib-websocket-gateway",
"version": "1.0.0",
"description": "Interactive Brokers WebSocket Gateway Service",
"main": "dist/index.js",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"test": "jest",
"lint": "eslint src/**/*.ts",
"clean": "rm -rf dist"
},
"dependencies": {
"@hono/node-server": "^1.12.2",
"hono": "^4.6.8",
"ws": "^8.18.0",
"eventemitter3": "^5.0.1",
"uuid": "^10.0.0",
"@stock-bot/logger": "workspace:*"
},
"devDependencies": {
"@types/node": "^20.12.12",
"@types/ws": "^8.5.12",
"@types/uuid": "^10.0.0",
"tsx": "^4.19.1",
"typescript": "^5.4.5"
},
"engines": {
"node": ">=18.0.0"
}
}

View file

@ -0,0 +1,283 @@
// Interactive Brokers WebSocket message types and interfaces
export interface IBWebSocketConfig {
server: {
port: number;
host: string;
maxConnections: number;
cors: {
origins: string[];
methods: string[];
headers: string[];
};
};
tws: {
host: string;
port: number;
clientId: number;
reconnectInterval: number;
heartbeatInterval: number;
connectionTimeout: number;
};
gateway: {
host: string;
port: number;
username?: string;
password?: string;
};
subscriptions: {
marketData: boolean;
accountUpdates: boolean;
orderUpdates: boolean;
positions: boolean;
executions: boolean;
};
monitoring: {
enabled: boolean;
port: number;
healthCheckInterval: number;
};
}
// IB API Connection Status
export interface IBConnectionStatus {
tws: 'connected' | 'disconnected' | 'connecting' | 'error';
gateway: 'connected' | 'disconnected' | 'connecting' | 'error';
lastConnected?: Date;
lastError?: string;
clientId: number;
}
// Market Data Types
export interface IBMarketDataTick {
tickerId: number;
tickType: string;
price: number;
size?: number;
timestamp: Date;
symbol?: string;
exchange?: string;
}
export interface IBMarketDataSnapshot {
symbol: string;
conId: number;
exchange: string;
currency: string;
bid: number;
ask: number;
last: number;
volume: number;
high: number;
low: number;
close: number;
timestamp: Date;
}
// Account & Portfolio Types
export interface IBAccountUpdate {
accountId: string;
key: string;
value: string;
currency: string;
timestamp: Date;
}
export interface IBPosition {
accountId: string;
contract: {
conId: number;
symbol: string;
secType: string;
exchange: string;
currency: string;
};
position: number;
marketPrice: number;
marketValue: number;
averageCost: number;
unrealizedPnL: number;
realizedPnL: number;
timestamp: Date;
}
// Order Types
export interface IBOrder {
orderId: number;
clientId: number;
permId: number;
action: 'BUY' | 'SELL';
totalQuantity: number;
orderType: string;
lmtPrice?: number;
auxPrice?: number;
tif: string;
orderRef?: string;
transmit: boolean;
parentId?: number;
blockOrder?: boolean;
sweepToFill?: boolean;
displaySize?: number;
triggerMethod?: number;
outsideRth?: boolean;
hidden?: boolean;
}
export interface IBOrderStatus {
orderId: number;
status: string;
filled: number;
remaining: number;
avgFillPrice: number;
permId: number;
parentId: number;
lastFillPrice: number;
clientId: number;
whyHeld: string;
mktCapPrice: number;
timestamp: Date;
}
export interface IBExecution {
execId: string;
time: string;
acctNumber: string;
exchange: string;
side: string;
shares: number;
price: number;
permId: number;
clientId: number;
orderId: number;
liquidation: number;
cumQty: number;
avgPrice: number;
orderRef: string;
evRule: string;
evMultiplier: number;
modelCode: string;
lastLiquidity: number;
timestamp: Date;
}
// WebSocket Message Types
export interface IBWebSocketMessage {
type: string;
id: string;
timestamp: number;
payload: any;
}
export interface IBSubscriptionRequest {
type: 'subscribe' | 'unsubscribe';
channel: 'marketData' | 'account' | 'orders' | 'positions' | 'executions';
symbols?: string[];
accountId?: string;
tickerId?: number;
}
export interface IBWebSocketClient {
id: string;
ws: any; // WebSocket instance
subscriptions: Set<string>;
connectedAt: Date;
lastPing: Date;
metadata: {
userAgent?: string;
ip?: string;
userId?: string;
};
}
// Error Types
export interface IBError {
id: number;
errorCode: number;
errorString: string;
timestamp: Date;
}
// Normalized Message Types for Platform Integration
export interface PlatformMarketDataUpdate {
type: 'market_data_update';
timestamp: string;
data: {
symbol: string;
price: number;
volume: number;
bid: number;
ask: number;
change: number;
changePercent: number;
timestamp: string;
source: 'interactive_brokers';
};
}
export interface PlatformOrderUpdate {
type: 'order_update';
timestamp: string;
data: {
orderId: string;
status: string;
symbol: string;
side: string;
quantity: number;
filled: number;
remaining: number;
avgPrice: number;
timestamp: string;
source: 'interactive_brokers';
};
}
export interface PlatformPositionUpdate {
type: 'position_update';
timestamp: string;
data: {
accountId: string;
symbol: string;
position: number;
marketValue: number;
unrealizedPnL: number;
avgCost: number;
timestamp: string;
source: 'interactive_brokers';
};
}
export interface PlatformAccountUpdate {
type: 'account_update';
timestamp: string;
data: {
accountId: string;
key: string;
value: string;
currency: string;
timestamp: string;
source: 'interactive_brokers';
};
}
export interface PlatformExecutionReport {
type: 'execution_report';
timestamp: string;
data: {
execId: string;
orderId: string;
symbol: string;
side: string;
shares: number;
price: number;
timestamp: string;
source: 'interactive_brokers';
};
}
// Unified Platform Message Type
export type PlatformMessage =
| PlatformMarketDataUpdate
| PlatformOrderUpdate
| PlatformPositionUpdate
| PlatformAccountUpdate
| PlatformExecutionReport;

View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}