initial setup

This commit is contained in:
Bojan Kucera 2025-06-02 08:15:20 -04:00
commit 232a63dfe8
61 changed files with 4985 additions and 0 deletions

View file

@ -0,0 +1,21 @@
{
"name": "@stock-bot/config",
"version": "1.0.0",
"description": "Shared configuration for the trading bot",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"test": "echo \"No tests yet\""
},
"dependencies": {
"@stock-bot/shared-types": "workspace:*",
"dotenv": "^16.4.5"
},
"devDependencies": {
"typescript": "^5.4.5",
"@types/node": "^20.12.12"
}
}

View file

@ -0,0 +1,156 @@
import { config } from 'dotenv';
import type { DatabaseConfig, BrokerConfig, DataProviderConfig } from '@stock-bot/shared-types';
// Load environment variables
config();
export const env = {
NODE_ENV: process.env.NODE_ENV || 'development',
PORT: parseInt(process.env.PORT || '3000'),
// Database URLs
QUESTDB_URL: process.env.QUESTDB_URL || 'postgresql://admin:quest@localhost:8812/qdb',
POSTGRES_URL: process.env.POSTGRES_URL || 'postgresql://postgres:password@localhost:5432/stockbot',
DRAGONFLY_URL: process.env.DRAGONFLY_URL || 'redis://localhost:6379',
// API Keys
ALPHA_VANTAGE_API_KEY: process.env.ALPHA_VANTAGE_API_KEY || '',
ALPACA_API_KEY: process.env.ALPACA_API_KEY || '',
ALPACA_SECRET_KEY: process.env.ALPACA_SECRET_KEY || '',
// Trading Configuration
PAPER_TRADING: process.env.PAPER_TRADING === 'true',
MAX_POSITION_SIZE: parseFloat(process.env.MAX_POSITION_SIZE || '0.1'),
MAX_DAILY_LOSS: parseFloat(process.env.MAX_DAILY_LOSS || '1000'),
// Logging
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
// Feature Flags
ENABLE_ML_SIGNALS: process.env.ENABLE_ML_SIGNALS === 'true',
ENABLE_SENTIMENT_ANALYSIS: process.env.ENABLE_SENTIMENT_ANALYSIS === 'true',
} as const;
export const databaseConfig: DatabaseConfig = {
questdb: {
host: process.env.QUESTDB_HOST || 'localhost',
port: parseInt(process.env.QUESTDB_PORT || '9000'),
database: process.env.QUESTDB_DATABASE || 'qdb',
},
postgres: {
host: process.env.POSTGRES_HOST || 'localhost',
port: parseInt(process.env.POSTGRES_PORT || '5432'),
database: process.env.POSTGRES_DATABASE || 'stockbot',
username: process.env.POSTGRES_USERNAME || 'postgres',
password: process.env.POSTGRES_PASSWORD || 'password',
}, dragonfly: {
host: process.env.DRAGONFLY_HOST || 'localhost',
port: parseInt(process.env.DRAGONFLY_PORT || '6379'),
password: process.env.DRAGONFLY_PASSWORD,
},
};
export const brokerConfigs: Record<string, BrokerConfig> = {
alpaca: {
name: 'Alpaca',
apiKey: env.ALPACA_API_KEY,
secretKey: env.ALPACA_SECRET_KEY,
baseUrl: env.PAPER_TRADING
? 'https://paper-api.alpaca.markets'
: 'https://api.alpaca.markets',
sandbox: env.PAPER_TRADING,
},
};
export const dataProviderConfigs: Record<string, DataProviderConfig> = {
alphaVantage: {
name: 'Alpha Vantage',
apiKey: env.ALPHA_VANTAGE_API_KEY,
baseUrl: 'https://www.alphavantage.co',
rateLimits: {
requestsPerSecond: 5,
requestsPerDay: 500,
},
},
};
export const serviceDefaults = {
healthCheckInterval: 30000, // 30 seconds
retryAttempts: 3,
requestTimeout: 10000, // 10 seconds
circuitBreakerThreshold: 5,
circuitBreakerTimeout: 60000, // 1 minute
};
export const tradingHours = {
market: {
open: '09:30',
close: '16:00',
timezone: 'America/New_York',
},
premarket: {
open: '04:00',
close: '09:30',
timezone: 'America/New_York',
},
afterHours: {
open: '16:00',
close: '20:00',
timezone: 'America/New_York',
},
};
export const riskDefaults = {
maxPositionSize: 0.1, // 10% of portfolio
maxDailyLoss: 0.02, // 2% of portfolio
maxDrawdown: 0.1, // 10% of portfolio
stopLossPercent: 0.05, // 5%
takeProfitPercent: 0.15, // 15%
};
// Environment-specific configurations
export const getConfig = () => {
const base = {
env: env.NODE_ENV,
port: env.PORT,
database: databaseConfig,
brokers: brokerConfigs,
dataProviders: dataProviderConfigs,
services: serviceDefaults,
trading: {
hours: tradingHours,
risk: riskDefaults,
paperTrading: env.PAPER_TRADING,
},
};
switch (env.NODE_ENV) {
case 'development':
return {
...base,
logging: {
level: 'debug',
console: true,
file: false,
},
cache: {
ttl: 300, // 5 minutes
},
};
case 'production':
return {
...base,
logging: {
level: 'info',
console: false,
file: true,
},
cache: {
ttl: 60, // 1 minute
},
};
default:
return base;
}
};

View file

@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,23 @@
{
"name": "@stock-bot/shared-types",
"version": "1.0.0",
"description": "Shared TypeScript definitions for the trading bot",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"test": "echo \"No tests yet\""
},
"devDependencies": {
"typescript": "^5.4.5"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.js"
}
}
}

View file

@ -0,0 +1,204 @@
// Market Data Types
export interface OHLCV {
symbol: string;
timestamp: Date;
open: number;
high: number;
low: number;
close: number;
volume: number;
}
export interface MarketData {
symbol: string;
price: number;
bid: number;
ask: number;
volume: number;
timestamp: Date;
}
export interface OrderBook {
symbol: string;
bids: [number, number][]; // [price, size]
asks: [number, number][]; // [price, size]
timestamp: Date;
}
// Trading Types
export type OrderSide = 'BUY' | 'SELL';
export type OrderType = 'MARKET' | 'LIMIT' | 'STOP' | 'STOP_LIMIT';
export type OrderStatus = 'PENDING' | 'FILLED' | 'PARTIALLY_FILLED' | 'CANCELLED' | 'REJECTED';
export interface Order {
id: string;
symbol: string;
side: OrderSide;
type: OrderType;
quantity: number;
price?: number;
stopPrice?: number;
status: OrderStatus;
timestamp: Date;
strategyId: string;
}
export interface Position {
symbol: string;
quantity: number;
averagePrice: number;
marketValue: number;
unrealizedPnL: number;
timestamp: Date;
}
export interface Portfolio {
cash: number;
totalValue: number;
positions: Position[];
dayPnL: number;
totalPnL: number;
timestamp: Date;
}
// Strategy Types
export type SignalType = 'BUY' | 'SELL' | 'HOLD';
export interface TradingSignal {
symbol: string;
type: SignalType;
strength: number; // 0-1
price: number;
timestamp: Date;
strategyId: string;
metadata?: Record<string, any>;
}
export interface Strategy {
id: string;
name: string;
description: string;
isActive: boolean;
riskLimits: RiskLimits;
parameters: Record<string, any>;
}
export interface RiskLimits {
maxPositionSize: number;
maxDailyLoss: number;
maxDrawdown: number;
allowedSymbols?: string[];
}
// Event Types
export interface MarketDataEvent {
type: 'MARKET_DATA';
data: MarketData;
timestamp: Date;
}
export interface OrderEvent {
type: 'ORDER_CREATED' | 'ORDER_FILLED' | 'ORDER_CANCELLED';
order: Order;
timestamp: Date;
}
export interface SignalEvent {
type: 'SIGNAL_GENERATED';
signal: TradingSignal;
timestamp: Date;
}
export type TradingEvent = MarketDataEvent | OrderEvent | SignalEvent;
// Service Types
export interface ServiceConfig {
name: string;
version: string;
environment: 'development' | 'staging' | 'production';
port?: number;
dependencies?: string[];
}
export interface HealthStatus {
service: string;
status: 'healthy' | 'unhealthy' | 'degraded';
timestamp: Date;
details?: Record<string, any>;
}
// API Response Types
export interface ApiResponse<T> {
success: boolean;
data?: T;
error?: string;
timestamp: Date;
}
export interface PaginatedResponse<T> {
data: T[];
total: number;
page: number;
limit: number;
hasNext: boolean;
}
// Fundamental Data Types
export interface CompanyFundamentals {
symbol: string;
marketCap: number;
peRatio?: number;
pbRatio?: number;
roe?: number;
revenue: number;
netIncome: number;
lastUpdated: Date;
}
export interface NewsItem {
id: string;
headline: string;
summary: string;
sentiment: number; // -1 to 1
symbols: string[];
source: string;
publishedAt: Date;
}
// Configuration Types
export interface DatabaseConfig {
questdb: {
host: string;
port: number;
database: string;
};
postgres: {
host: string;
port: number;
database: string;
username: string;
password: string;
}; dragonfly: {
host: string;
port: number;
password?: string;
};
}
export interface BrokerConfig {
name: string;
apiKey: string;
secretKey: string;
baseUrl: string;
sandbox: boolean;
}
export interface DataProviderConfig {
name: string;
apiKey: string;
baseUrl: string;
rateLimits: {
requestsPerSecond: number;
requestsPerDay: number;
};
}

View file

@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}