no idea- added loki and other stuff to market-data-gateway, also added config lib
This commit is contained in:
parent
b957fb99aa
commit
1b71fc87ab
72 changed files with 6178 additions and 153 deletions
53
libs/config/.env.example
Normal file
53
libs/config/.env.example
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Base environment variables for Stock Bot
|
||||
|
||||
# Environment
|
||||
NODE_ENV=development
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=debug
|
||||
|
||||
# Database configuration
|
||||
DRAGONFLY_HOST=localhost
|
||||
DRAGONFLY_PORT=6379
|
||||
DRAGONFLY_PASSWORD=
|
||||
DRAGONFLY_MAX_RETRIES_PER_REQUEST=3
|
||||
|
||||
TIMESCALE_HOST=localhost
|
||||
TIMESCALE_PORT=5432
|
||||
TIMESCALE_DB=stockbot
|
||||
TIMESCALE_USER=postgres
|
||||
TIMESCALE_PASSWORD=postgres
|
||||
|
||||
# Data providers
|
||||
DEFAULT_DATA_PROVIDER=alpaca
|
||||
ALPACA_API_KEY=your_alpaca_key_here
|
||||
ALPACA_API_SECRET=your_alpaca_secret_here
|
||||
POLYGON_API_KEY=your_polygon_key_here
|
||||
|
||||
# Risk parameters
|
||||
RISK_MAX_DRAWDOWN=0.05
|
||||
RISK_MAX_POSITION_SIZE=0.1
|
||||
RISK_MAX_LEVERAGE=1.5
|
||||
RISK_STOP_LOSS_DEFAULT=0.02
|
||||
RISK_TAKE_PROFIT_DEFAULT=0.05
|
||||
|
||||
# Market Data Gateway
|
||||
SERVICE_PORT=4000
|
||||
WEBSOCKET_ENABLED=true
|
||||
WEBSOCKET_PATH=/ws/market-data
|
||||
WEBSOCKET_HEARTBEAT_INTERVAL=30000
|
||||
THROTTLING_MAX_REQUESTS=300
|
||||
THROTTLING_MAX_CONNECTIONS=5
|
||||
CACHING_ENABLED=true
|
||||
CACHING_TTL_SECONDS=60
|
||||
|
||||
# Risk Guardian
|
||||
RISK_CHECKS_PRE_TRADE=true
|
||||
RISK_CHECKS_PORTFOLIO=true
|
||||
RISK_CHECKS_LEVERAGE=true
|
||||
RISK_CHECKS_CONCENTRATION=true
|
||||
ALERTING_ENABLED=true
|
||||
ALERTING_CRITICAL_THRESHOLD=0.8
|
||||
ALERTING_WARNING_THRESHOLD=0.6
|
||||
WATCHDOG_ENABLED=true
|
||||
WATCHDOG_CHECK_INTERVAL=60
|
||||
28
libs/config/.env.production.example
Normal file
28
libs/config/.env.production.example
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Production environment variables for Stock Bot
|
||||
|
||||
# Environment
|
||||
NODE_ENV=production
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Database configuration (use environment-specific values)
|
||||
DRAGONFLY_HOST=dragonfly.production
|
||||
DRAGONFLY_PORT=6379
|
||||
DRAGONFLY_MAX_RETRIES_PER_REQUEST=5
|
||||
|
||||
TIMESCALE_HOST=timescale.production
|
||||
TIMESCALE_PORT=5432
|
||||
TIMESCALE_DB=stockbot_prod
|
||||
|
||||
# Risk parameters (more conservative for production)
|
||||
RISK_MAX_DRAWDOWN=0.03
|
||||
RISK_MAX_POSITION_SIZE=0.05
|
||||
RISK_MAX_LEVERAGE=1.0
|
||||
|
||||
# Service settings
|
||||
WEBSOCKET_HEARTBEAT_INTERVAL=15000
|
||||
THROTTLING_MAX_REQUESTS=500
|
||||
THROTTLING_MAX_CONNECTIONS=20
|
||||
CACHING_ENABLED=true
|
||||
CACHING_TTL_SECONDS=30
|
||||
103
libs/config/README.md
Normal file
103
libs/config/README.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# @stock-bot/config
|
||||
|
||||
A configuration management library for the Stock Bot trading platform.
|
||||
|
||||
## Overview
|
||||
|
||||
This library provides a centralized way to manage configurations across all Stock Bot microservices and components. It includes:
|
||||
|
||||
- Environment-based configuration loading
|
||||
- Strong TypeScript typing and validation using Zod
|
||||
- Default configurations for services
|
||||
- Environment variable parsing helpers
|
||||
- Service-specific configuration modules
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```typescript
|
||||
import { databaseConfig, dataProviderConfigs, riskConfig } from '@stock-bot/config';
|
||||
|
||||
// Access database configuration
|
||||
const dragonflyHost = databaseConfig.dragonfly.host;
|
||||
|
||||
// Access data provider configuration
|
||||
const alpacaApiKey = dataProviderConfigs.providers.find(p => p.name === 'alpaca')?.apiKey;
|
||||
|
||||
// Access risk configuration
|
||||
const maxPositionSize = riskConfig.maxPositionSize;
|
||||
```
|
||||
|
||||
### Service-Specific Configuration
|
||||
|
||||
```typescript
|
||||
import { marketDataGatewayConfig, riskGuardianConfig } from '@stock-bot/config';
|
||||
|
||||
// Access Market Data Gateway configuration
|
||||
const websocketPath = marketDataGatewayConfig.websocket.path;
|
||||
|
||||
// Access Risk Guardian configuration
|
||||
const preTradeValidation = riskGuardianConfig.riskChecks.preTradeValidation;
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The library automatically loads environment variables from `.env` files. You can create environment-specific files:
|
||||
|
||||
- `.env` - Base environment variables
|
||||
- `.env.development` - Development-specific variables
|
||||
- `.env.production` - Production-specific variables
|
||||
- `.env.local` - Local overrides (not to be committed to git)
|
||||
|
||||
## Configuration Modules
|
||||
|
||||
### Core Configuration
|
||||
|
||||
- `Environment` - Enum for different environments
|
||||
- `loadEnvVariables()` - Load environment variables from .env files
|
||||
- `getEnvironment()` - Get the current environment
|
||||
- `validateConfig()` - Validate configuration with Zod schema
|
||||
|
||||
### Database Configuration
|
||||
|
||||
- `databaseConfig` - Database connection settings (Dragonfly, TimescaleDB)
|
||||
|
||||
### Data Provider Configuration
|
||||
|
||||
- `dataProviderConfigs` - Settings for market data providers
|
||||
|
||||
### Risk Configuration
|
||||
|
||||
- `riskConfig` - Risk management parameters (max drawdown, position size, etc.)
|
||||
|
||||
### Service-Specific Configuration
|
||||
|
||||
- `marketDataGatewayConfig` - Configs for the Market Data Gateway service
|
||||
- `riskGuardianConfig` - Configs for the Risk Guardian service
|
||||
|
||||
## Extending
|
||||
|
||||
To add a new service configuration:
|
||||
|
||||
1. Create a new file in `src/services/`
|
||||
2. Define a Zod schema for validation
|
||||
3. Create loading and default configuration functions
|
||||
4. Export from `src/services/index.ts`
|
||||
5. The new configuration will be automatically available from the main package
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
bun install
|
||||
|
||||
# Run tests
|
||||
bun test
|
||||
|
||||
# Type check
|
||||
bun run type-check
|
||||
|
||||
# Lint
|
||||
bun run lint
|
||||
```
|
||||
37
libs/config/package.json
Normal file
37
libs/config/package.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "@stock-bot/config",
|
||||
"version": "1.0.0",
|
||||
"description": "Configuration management library for Stock Bot platform",
|
||||
"main": "src/index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "bun test",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.3.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.0",
|
||||
"typescript": "^5.3.0",
|
||||
"eslint": "^8.56.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"bun-types": "^1.2.15"
|
||||
},
|
||||
"keywords": [
|
||||
"configuration",
|
||||
"settings",
|
||||
"env",
|
||||
"stock-bot"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./src/index.ts",
|
||||
"require": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
24
libs/config/setup.bat
Normal file
24
libs/config/setup.bat
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
@echo off
|
||||
echo Building @stock-bot/config library...
|
||||
|
||||
cd /d g:\repos\stock-bot
|
||||
echo Installing dependencies...
|
||||
bun install
|
||||
|
||||
echo Running type check...
|
||||
cd /d g:\repos\stock-bot\libs\config
|
||||
bun run type-check
|
||||
|
||||
echo Running tests...
|
||||
bun test
|
||||
|
||||
echo Setting up example configuration...
|
||||
copy .env.example .env
|
||||
|
||||
echo Running example to display configuration...
|
||||
bun run src/example.ts
|
||||
|
||||
echo.
|
||||
echo Configuration library setup complete!
|
||||
echo.
|
||||
echo You can now import @stock-bot/config in your services.
|
||||
113
libs/config/src/core.test.ts
Normal file
113
libs/config/src/core.test.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* Tests for the configuration library
|
||||
*/
|
||||
import { describe, expect, test, beforeAll, afterAll } from 'bun:test';
|
||||
import {
|
||||
getEnvironment,
|
||||
Environment,
|
||||
validateConfig,
|
||||
ConfigurationError,
|
||||
loadEnvVariables,
|
||||
getEnvVar,
|
||||
getNumericEnvVar,
|
||||
getBooleanEnvVar
|
||||
} from './core';
|
||||
|
||||
import { databaseConfigSchema } from './types';
|
||||
|
||||
describe('Core configuration', () => {
|
||||
// Save original environment variables
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
// Setup test environment variables
|
||||
beforeAll(() => {
|
||||
process.env.NODE_ENV = 'testing';
|
||||
process.env.TEST_STRING = 'test-value';
|
||||
process.env.TEST_NUMBER = '42';
|
||||
process.env.TEST_BOOL_TRUE = 'true';
|
||||
process.env.TEST_BOOL_FALSE = 'false';
|
||||
});
|
||||
|
||||
// Restore original environment variables
|
||||
afterAll(() => {
|
||||
process.env = { ...originalEnv };
|
||||
});
|
||||
|
||||
test('getEnvironment returns correct environment', () => {
|
||||
expect(getEnvironment()).toBe(Environment.Testing);
|
||||
|
||||
// Test different environments
|
||||
process.env.NODE_ENV = 'development';
|
||||
expect(getEnvironment()).toBe(Environment.Development);
|
||||
|
||||
process.env.NODE_ENV = 'production';
|
||||
expect(getEnvironment()).toBe(Environment.Production);
|
||||
|
||||
process.env.NODE_ENV = 'staging';
|
||||
expect(getEnvironment()).toBe(Environment.Staging);
|
||||
|
||||
// Test default environment
|
||||
process.env.NODE_ENV = 'unknown';
|
||||
expect(getEnvironment()).toBe(Environment.Development);
|
||||
});
|
||||
|
||||
test('getEnvVar retrieves environment variables', () => {
|
||||
expect(getEnvVar('TEST_STRING')).toBe('test-value');
|
||||
expect(getEnvVar('NON_EXISTENT')).toBeUndefined();
|
||||
expect(getEnvVar('NON_EXISTENT', false)).toBeUndefined();
|
||||
|
||||
// Test required variables
|
||||
expect(() => getEnvVar('NON_EXISTENT', true)).toThrow(ConfigurationError);
|
||||
});
|
||||
|
||||
test('getNumericEnvVar converts to number', () => {
|
||||
expect(getNumericEnvVar('TEST_NUMBER')).toBe(42);
|
||||
expect(getNumericEnvVar('NON_EXISTENT', 100)).toBe(100);
|
||||
|
||||
// Test invalid number
|
||||
process.env.INVALID_NUMBER = 'not-a-number';
|
||||
expect(() => getNumericEnvVar('INVALID_NUMBER')).toThrow(ConfigurationError);
|
||||
});
|
||||
|
||||
test('getBooleanEnvVar converts to boolean', () => {
|
||||
expect(getBooleanEnvVar('TEST_BOOL_TRUE')).toBe(true);
|
||||
expect(getBooleanEnvVar('TEST_BOOL_FALSE')).toBe(false);
|
||||
expect(getBooleanEnvVar('NON_EXISTENT', true)).toBe(true);
|
||||
});
|
||||
|
||||
test('validateConfig validates against schema', () => {
|
||||
// Valid config
|
||||
const validConfig = {
|
||||
dragonfly: {
|
||||
host: 'localhost',
|
||||
port: 6379,
|
||||
maxRetriesPerRequest: 3
|
||||
},
|
||||
timescaleDB: {
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'stockbot',
|
||||
user: 'postgres'
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(validConfig, databaseConfigSchema)).not.toThrow();
|
||||
|
||||
// Invalid config (missing required field)
|
||||
const invalidConfig = {
|
||||
dragonfly: {
|
||||
host: 'localhost',
|
||||
// missing port
|
||||
maxRetriesPerRequest: 3
|
||||
},
|
||||
timescaleDB: {
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'stockbot',
|
||||
user: 'postgres'
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(invalidConfig, databaseConfigSchema)).toThrow(ConfigurationError);
|
||||
});
|
||||
});
|
||||
162
libs/config/src/core.ts
Normal file
162
libs/config/src/core.ts
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/**
|
||||
* Core configuration module for the Stock Bot platform
|
||||
*/
|
||||
import { config as dotenvConfig } from 'dotenv';
|
||||
import path from 'path';
|
||||
import { z } from 'zod';
|
||||
import { Environment } from './types';
|
||||
|
||||
/**
|
||||
* Represents an error related to configuration validation
|
||||
*/
|
||||
export class ConfigurationError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'ConfigurationError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads environment variables from .env files based on the current environment
|
||||
*/
|
||||
export function loadEnvVariables(envOverride?: string): void {
|
||||
const env = envOverride || process.env.NODE_ENV || 'development';
|
||||
|
||||
// Order of loading:
|
||||
// 1. .env (base environment variables)
|
||||
// 2. .env.{environment} (environment-specific variables)
|
||||
// 3. .env.local (local overrides, not to be committed)
|
||||
|
||||
const envFiles = [
|
||||
'.env',
|
||||
`.env.${env}`,
|
||||
'.env.local'
|
||||
];
|
||||
|
||||
for (const file of envFiles) {
|
||||
dotenvConfig({ path: path.resolve(process.cwd(), file) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current environment from process.env.NODE_ENV
|
||||
*/
|
||||
export function getEnvironment(): Environment {
|
||||
const env = process.env.NODE_ENV?.toLowerCase() || 'development';
|
||||
|
||||
switch (env) {
|
||||
case 'development':
|
||||
return Environment.Development;
|
||||
case 'testing':
|
||||
return Environment.Testing;
|
||||
case 'staging':
|
||||
return Environment.Staging;
|
||||
case 'production':
|
||||
return Environment.Production;
|
||||
default:
|
||||
return Environment.Development;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates configuration using Zod schema
|
||||
*/
|
||||
export function validateConfig<T>(config: unknown, schema: z.ZodSchema<T>): T {
|
||||
try {
|
||||
return schema.parse(config);
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
const issues = error.issues.map(issue =>
|
||||
`${issue.path.join('.')}: ${issue.message}`
|
||||
).join('\n');
|
||||
|
||||
throw new ConfigurationError(`Configuration validation failed:\n${issues}`);
|
||||
}
|
||||
throw new ConfigurationError('Invalid configuration');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an environment variable with validation
|
||||
*/
|
||||
export function getEnvVar(key: string, required: boolean = false): string | undefined {
|
||||
const value = process.env[key];
|
||||
|
||||
if (required && (value === undefined || value === '')) {
|
||||
throw new ConfigurationError(`Required environment variable ${key} is missing`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a numeric environment variable with validation
|
||||
*/
|
||||
export function getNumericEnvVar(key: string, defaultValue?: number): number {
|
||||
const value = process.env[key];
|
||||
if (value === undefined || value === '') {
|
||||
if (defaultValue !== undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
throw new ConfigurationError(`Required numeric environment variable ${key} is missing`);
|
||||
}
|
||||
|
||||
const numValue = Number(value);
|
||||
|
||||
if (isNaN(numValue)) {
|
||||
throw new ConfigurationError(`Environment variable ${key} is not a valid number`);
|
||||
}
|
||||
|
||||
return numValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a boolean environment variable with validation
|
||||
*/
|
||||
export function getBooleanEnvVar(key: string, defaultValue?: boolean): boolean {
|
||||
const value = process.env[key];
|
||||
if (value === undefined || value === '') {
|
||||
if (defaultValue !== undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
throw new ConfigurationError(`Required boolean environment variable ${key} is missing`);
|
||||
}
|
||||
|
||||
return value.toLowerCase() === 'true' || value === '1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a typed dynamic configuration loader for a specific service
|
||||
*/
|
||||
export function createConfigLoader<T>(
|
||||
serviceName: string,
|
||||
schema: z.ZodSchema<T>,
|
||||
defaultConfig: Partial<T> = {}
|
||||
): () => T {
|
||||
return (): T => {
|
||||
try {
|
||||
loadEnvVariables();
|
||||
const configEnvVar = `${serviceName.toUpperCase()}_CONFIG`;
|
||||
let config = { ...defaultConfig } as unknown as T;
|
||||
|
||||
// Try to load JSON from environment variable if available
|
||||
const configJson = process.env[configEnvVar];
|
||||
if (configJson) {
|
||||
try {
|
||||
const parsedConfig = JSON.parse(configJson);
|
||||
config = { ...config, ...parsedConfig };
|
||||
} catch (error) {
|
||||
throw new ConfigurationError(`Invalid JSON in ${configEnvVar} environment variable`);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate and return the config
|
||||
return validateConfig(config, schema);
|
||||
} catch (error) {
|
||||
if (error instanceof ConfigurationError) {
|
||||
throw error;
|
||||
}
|
||||
throw new ConfigurationError(`Failed to load configuration for service ${serviceName}: ${error}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
73
libs/config/src/data-providers.ts
Normal file
73
libs/config/src/data-providers.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Data provider configurations for market data
|
||||
*/
|
||||
import { getEnvVar, validateConfig } from './core';
|
||||
import { dataProvidersConfigSchema, DataProvidersConfig, DataProviderConfig } from './types';
|
||||
|
||||
/**
|
||||
* Default data provider configurations
|
||||
*/
|
||||
const defaultDataProviders: DataProviderConfig[] = [
|
||||
{
|
||||
name: 'alpaca',
|
||||
type: 'rest',
|
||||
baseUrl: 'https://data.alpaca.markets/v1beta1',
|
||||
apiKey: '',
|
||||
apiSecret: '',
|
||||
rateLimits: {
|
||||
maxRequestsPerMinute: 200
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'polygon',
|
||||
type: 'rest',
|
||||
baseUrl: 'https://api.polygon.io/v2',
|
||||
apiKey: '',
|
||||
rateLimits: {
|
||||
maxRequestsPerMinute: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'alpaca-websocket',
|
||||
type: 'websocket',
|
||||
wsUrl: 'wss://stream.data.alpaca.markets/v2/iex',
|
||||
apiKey: '',
|
||||
apiSecret: ''
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Load data provider configurations from environment variables
|
||||
*/
|
||||
export function loadDataProviderConfigs(): DataProvidersConfig {
|
||||
// Get provider specific environment variables
|
||||
const providers = defaultDataProviders.map(provider => {
|
||||
const nameUpper = provider.name.toUpperCase().replace('-', '_');
|
||||
|
||||
const updatedProvider: DataProviderConfig = {
|
||||
...provider,
|
||||
apiKey: getEnvVar(`${nameUpper}_API_KEY`) || provider.apiKey || '',
|
||||
};
|
||||
|
||||
if (provider.apiSecret !== undefined) {
|
||||
updatedProvider.apiSecret = getEnvVar(`${nameUpper}_API_SECRET`) || provider.apiSecret || '';
|
||||
}
|
||||
|
||||
return updatedProvider;
|
||||
});
|
||||
|
||||
// Load default provider from environment
|
||||
const defaultProvider = getEnvVar('DEFAULT_DATA_PROVIDER') || 'alpaca';
|
||||
|
||||
const config: DataProvidersConfig = {
|
||||
providers,
|
||||
defaultProvider
|
||||
};
|
||||
|
||||
return validateConfig(config, dataProvidersConfigSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton data provider configurations
|
||||
*/
|
||||
export const dataProviderConfigs = loadDataProviderConfigs();
|
||||
52
libs/config/src/database.ts
Normal file
52
libs/config/src/database.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Database configuration for Stock Bot services
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
import { getEnvVar, getNumericEnvVar, validateConfig } from './core';
|
||||
import { databaseConfigSchema, DatabaseConfig } from './types';
|
||||
|
||||
/**
|
||||
* Default database configuration
|
||||
*/
|
||||
const defaultDatabaseConfig: DatabaseConfig = {
|
||||
dragonfly: {
|
||||
host: 'localhost',
|
||||
port: 6379,
|
||||
maxRetriesPerRequest: 3
|
||||
},
|
||||
timescaleDB: {
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'stockbot',
|
||||
user: 'postgres'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load database configuration from environment variables
|
||||
*/
|
||||
export function loadDatabaseConfig(): DatabaseConfig {
|
||||
const config: DatabaseConfig = {
|
||||
dragonfly: {
|
||||
host: getEnvVar('DRAGONFLY_HOST') || defaultDatabaseConfig.dragonfly.host,
|
||||
port: getNumericEnvVar('DRAGONFLY_PORT', defaultDatabaseConfig.dragonfly.port),
|
||||
password: getEnvVar('DRAGONFLY_PASSWORD'),
|
||||
maxRetriesPerRequest: getNumericEnvVar('DRAGONFLY_MAX_RETRIES_PER_REQUEST',
|
||||
defaultDatabaseConfig.dragonfly.maxRetriesPerRequest)
|
||||
},
|
||||
timescaleDB: {
|
||||
host: getEnvVar('TIMESCALE_HOST') || defaultDatabaseConfig.timescaleDB.host,
|
||||
port: getNumericEnvVar('TIMESCALE_PORT', defaultDatabaseConfig.timescaleDB.port),
|
||||
database: getEnvVar('TIMESCALE_DB') || defaultDatabaseConfig.timescaleDB.database,
|
||||
user: getEnvVar('TIMESCALE_USER') || defaultDatabaseConfig.timescaleDB.user,
|
||||
password: getEnvVar('TIMESCALE_PASSWORD')
|
||||
}
|
||||
};
|
||||
|
||||
return validateConfig(config, databaseConfigSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton database configuration
|
||||
*/
|
||||
export const databaseConfig = loadDatabaseConfig();
|
||||
73
libs/config/src/example.ts
Normal file
73
libs/config/src/example.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Example usage of the @stock-bot/config library
|
||||
*/
|
||||
import {
|
||||
databaseConfig,
|
||||
dataProviderConfigs,
|
||||
riskConfig,
|
||||
Environment,
|
||||
getEnvironment,
|
||||
marketDataGatewayConfig,
|
||||
riskGuardianConfig,
|
||||
ConfigurationError,
|
||||
validateConfig
|
||||
} from './index';
|
||||
|
||||
/**
|
||||
* Display current configuration values
|
||||
*/
|
||||
export function printCurrentConfig(): void {
|
||||
console.log('\n=== Stock Bot Configuration ===');
|
||||
|
||||
console.log('\nEnvironment:', getEnvironment());
|
||||
|
||||
console.log('\n--- Database Config ---');
|
||||
console.log('Dragonfly Host:', databaseConfig.dragonfly.host);
|
||||
console.log('Dragonfly Port:', databaseConfig.dragonfly.port);
|
||||
console.log('TimescaleDB Host:', databaseConfig.timescaleDB.host);
|
||||
console.log('TimescaleDB Database:', databaseConfig.timescaleDB.database);
|
||||
|
||||
console.log('\n--- Data Provider Config ---');
|
||||
console.log('Default Provider:', dataProviderConfigs.defaultProvider);
|
||||
console.log('Providers:');
|
||||
dataProviderConfigs.providers.forEach(provider => {
|
||||
console.log(` - ${provider.name} (${provider.type})`);
|
||||
if (provider.baseUrl) console.log(` URL: ${provider.baseUrl}`);
|
||||
if (provider.wsUrl) console.log(` WebSocket: ${provider.wsUrl}`);
|
||||
});
|
||||
|
||||
console.log('\n--- Risk Config ---');
|
||||
console.log('Max Drawdown:', riskConfig.maxDrawdown * 100, '%');
|
||||
console.log('Max Position Size:', riskConfig.maxPositionSize * 100, '%');
|
||||
console.log('Max Leverage:', riskConfig.maxLeverage, 'x');
|
||||
console.log('Default Stop Loss:', riskConfig.stopLossDefault * 100, '%');
|
||||
console.log('Default Take Profit:', riskConfig.takeProfitDefault * 100, '%');
|
||||
|
||||
console.log('\n--- Market Data Gateway Config ---');
|
||||
console.log('Service Port:', marketDataGatewayConfig.service.port);
|
||||
console.log('WebSocket Enabled:', marketDataGatewayConfig.websocket.enabled);
|
||||
console.log('WebSocket Path:', marketDataGatewayConfig.websocket.path);
|
||||
console.log('Caching Enabled:', marketDataGatewayConfig.caching.enabled);
|
||||
console.log('Caching TTL:', marketDataGatewayConfig.caching.ttlSeconds, 'seconds');
|
||||
|
||||
console.log('\n--- Risk Guardian Config ---');
|
||||
console.log('Service Port:', riskGuardianConfig.service.port);
|
||||
console.log('Pre-Trade Validation:', riskGuardianConfig.riskChecks.preTradeValidation);
|
||||
console.log('Portfolio Validation:', riskGuardianConfig.riskChecks.portfolioValidation);
|
||||
console.log('Alerting Enabled:', riskGuardianConfig.alerting.enabled);
|
||||
console.log('Critical Threshold:', riskGuardianConfig.alerting.criticalThreshold * 100, '%');
|
||||
}
|
||||
|
||||
// Execute example if this file is run directly
|
||||
if (require.main === module) {
|
||||
try {
|
||||
printCurrentConfig();
|
||||
} catch (error) {
|
||||
if (error instanceof ConfigurationError) {
|
||||
console.error('Configuration Error:', error.message);
|
||||
} else {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
24
libs/config/src/index.ts
Normal file
24
libs/config/src/index.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* @stock-bot/config
|
||||
*
|
||||
* Configuration management library for Stock Bot platform
|
||||
*/
|
||||
|
||||
// Core configuration functionality
|
||||
export * from './core';
|
||||
export * from './types';
|
||||
|
||||
// Database configurations
|
||||
export * from './database';
|
||||
|
||||
// Data provider configurations
|
||||
export * from './data-providers';
|
||||
|
||||
// Risk management configurations
|
||||
export * from './risk';
|
||||
|
||||
// Logging configurations
|
||||
export * from './logging';
|
||||
|
||||
// Service-specific configurations
|
||||
export * from './services';
|
||||
75
libs/config/src/logging.ts
Normal file
75
libs/config/src/logging.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* Loki logging configuration for Stock Bot platform
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
import { getEnvVar, getNumericEnvVar, getBooleanEnvVar } from './core';
|
||||
|
||||
/**
|
||||
* Loki configuration schema
|
||||
*/
|
||||
export const lokiConfigSchema = z.object({
|
||||
host: z.string().default('localhost'),
|
||||
port: z.number().default(3100),
|
||||
username: z.string().optional(),
|
||||
password: z.string().optional(),
|
||||
retentionDays: z.number().default(30),
|
||||
labels: z.record(z.string()).default({}),
|
||||
batchSize: z.number().default(100),
|
||||
flushIntervalMs: z.number().default(5000)
|
||||
});
|
||||
|
||||
export type LokiConfig = z.infer<typeof lokiConfigSchema>;
|
||||
|
||||
/**
|
||||
* Logging configuration schema
|
||||
*/
|
||||
export const loggingConfigSchema = z.object({
|
||||
level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
||||
console: z.boolean().default(true),
|
||||
loki: lokiConfigSchema
|
||||
});
|
||||
|
||||
export type LoggingConfig = z.infer<typeof loggingConfigSchema>;
|
||||
|
||||
/**
|
||||
* Parse labels from environment variable string
|
||||
* Format: key1=value1,key2=value2
|
||||
*/
|
||||
function parseLabels(labelsStr?: string): Record<string, string> {
|
||||
if (!labelsStr) return {};
|
||||
|
||||
const labels: Record<string, string> = {};
|
||||
labelsStr.split(',').forEach(labelPair => {
|
||||
const [key, value] = labelPair.trim().split('=');
|
||||
if (key && value) {
|
||||
labels[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load logging configuration from environment variables
|
||||
*/
|
||||
export function loadLoggingConfig(): LoggingConfig {
|
||||
return {
|
||||
level: (getEnvVar('LOG_LEVEL') || 'info') as 'debug' | 'info' | 'warn' | 'error',
|
||||
console: getBooleanEnvVar('LOG_CONSOLE', true),
|
||||
loki: {
|
||||
host: getEnvVar('LOKI_HOST') || 'localhost',
|
||||
port: getNumericEnvVar('LOKI_PORT', 3100),
|
||||
username: getEnvVar('LOKI_USERNAME'),
|
||||
password: getEnvVar('LOKI_PASSWORD'),
|
||||
retentionDays: getNumericEnvVar('LOKI_RETENTION_DAYS', 30),
|
||||
labels: parseLabels(getEnvVar('LOKI_LABELS')),
|
||||
batchSize: getNumericEnvVar('LOKI_BATCH_SIZE', 100),
|
||||
flushIntervalMs: getNumericEnvVar('LOKI_FLUSH_INTERVAL_MS', 5000)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton logging configuration
|
||||
*/
|
||||
export const loggingConfig = loadLoggingConfig();
|
||||
36
libs/config/src/risk.ts
Normal file
36
libs/config/src/risk.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* Risk management configuration for trading operations
|
||||
*/
|
||||
import { getNumericEnvVar, validateConfig } from './core';
|
||||
import { riskConfigSchema, RiskConfig } from './types';
|
||||
|
||||
/**
|
||||
* Default risk configuration
|
||||
*/
|
||||
const defaultRiskConfig: RiskConfig = {
|
||||
maxDrawdown: 0.05,
|
||||
maxPositionSize: 0.1,
|
||||
maxLeverage: 1,
|
||||
stopLossDefault: 0.02,
|
||||
takeProfitDefault: 0.05
|
||||
};
|
||||
|
||||
/**
|
||||
* Load risk configuration from environment variables
|
||||
*/
|
||||
export function loadRiskConfig(): RiskConfig {
|
||||
const config: RiskConfig = {
|
||||
maxDrawdown: getNumericEnvVar('RISK_MAX_DRAWDOWN', defaultRiskConfig.maxDrawdown),
|
||||
maxPositionSize: getNumericEnvVar('RISK_MAX_POSITION_SIZE', defaultRiskConfig.maxPositionSize),
|
||||
maxLeverage: getNumericEnvVar('RISK_MAX_LEVERAGE', defaultRiskConfig.maxLeverage),
|
||||
stopLossDefault: getNumericEnvVar('RISK_STOP_LOSS_DEFAULT', defaultRiskConfig.stopLossDefault),
|
||||
takeProfitDefault: getNumericEnvVar('RISK_TAKE_PROFIT_DEFAULT', defaultRiskConfig.takeProfitDefault)
|
||||
};
|
||||
|
||||
return validateConfig(config, riskConfigSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton risk configuration
|
||||
*/
|
||||
export const riskConfig = loadRiskConfig();
|
||||
5
libs/config/src/services/index.ts
Normal file
5
libs/config/src/services/index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/**
|
||||
* Export all service-specific configurations
|
||||
*/
|
||||
export * from './market-data-gateway';
|
||||
export * from './risk-guardian';
|
||||
106
libs/config/src/services/market-data-gateway.ts
Normal file
106
libs/config/src/services/market-data-gateway.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* Market Data Gateway service configuration
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
import { getEnvVar, getNumericEnvVar, getBooleanEnvVar, createConfigLoader } from './core';
|
||||
import { Environment, BaseConfig } from './types';
|
||||
import { getEnvironment } from './core';
|
||||
|
||||
/**
|
||||
* Market Data Gateway specific configuration schema
|
||||
*/
|
||||
export const marketDataGatewayConfigSchema = z.object({
|
||||
environment: z.nativeEnum(Environment),
|
||||
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
||||
service: z.object({
|
||||
name: z.string().default('market-data-gateway'),
|
||||
version: z.string().default('1.0.0'),
|
||||
port: z.number().default(4000)
|
||||
}),
|
||||
websocket: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
path: z.string().default('/ws/market-data'),
|
||||
heartbeatInterval: z.number().default(30000)
|
||||
}),
|
||||
throttling: z.object({
|
||||
maxRequestsPerMinute: z.number().default(300),
|
||||
maxConnectionsPerIP: z.number().default(5)
|
||||
}),
|
||||
caching: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
ttlSeconds: z.number().default(60)
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Market Data Gateway configuration type
|
||||
*/
|
||||
export type MarketDataGatewayConfig = z.infer<typeof marketDataGatewayConfigSchema>;
|
||||
|
||||
/**
|
||||
* Default Market Data Gateway configuration
|
||||
*/
|
||||
const defaultConfig: Partial<MarketDataGatewayConfig> = {
|
||||
environment: getEnvironment(),
|
||||
logLevel: 'info',
|
||||
service: {
|
||||
name: 'market-data-gateway',
|
||||
version: '1.0.0',
|
||||
port: 4000
|
||||
},
|
||||
websocket: {
|
||||
enabled: true,
|
||||
path: '/ws/market-data',
|
||||
heartbeatInterval: 30000 // 30 seconds
|
||||
},
|
||||
throttling: {
|
||||
maxRequestsPerMinute: 300,
|
||||
maxConnectionsPerIP: 5
|
||||
},
|
||||
caching: {
|
||||
enabled: true,
|
||||
ttlSeconds: 60
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load Market Data Gateway configuration
|
||||
*/
|
||||
export function loadMarketDataGatewayConfig(): MarketDataGatewayConfig {
|
||||
return {
|
||||
environment: getEnvironment(),
|
||||
logLevel: (getEnvVar('LOG_LEVEL') || defaultConfig.logLevel) as 'debug' | 'info' | 'warn' | 'error',
|
||||
service: {
|
||||
name: getEnvVar('SERVICE_NAME') || defaultConfig.service!.name,
|
||||
version: getEnvVar('SERVICE_VERSION') || defaultConfig.service!.version,
|
||||
port: getNumericEnvVar('SERVICE_PORT', defaultConfig.service!.port)
|
||||
},
|
||||
websocket: {
|
||||
enabled: getBooleanEnvVar('WEBSOCKET_ENABLED', defaultConfig.websocket!.enabled),
|
||||
path: getEnvVar('WEBSOCKET_PATH') || defaultConfig.websocket!.path,
|
||||
heartbeatInterval: getNumericEnvVar('WEBSOCKET_HEARTBEAT_INTERVAL', defaultConfig.websocket!.heartbeatInterval)
|
||||
},
|
||||
throttling: {
|
||||
maxRequestsPerMinute: getNumericEnvVar('THROTTLING_MAX_REQUESTS', defaultConfig.throttling!.maxRequestsPerMinute),
|
||||
maxConnectionsPerIP: getNumericEnvVar('THROTTLING_MAX_CONNECTIONS', defaultConfig.throttling!.maxConnectionsPerIP)
|
||||
},
|
||||
caching: {
|
||||
enabled: getBooleanEnvVar('CACHING_ENABLED', defaultConfig.caching!.enabled),
|
||||
ttlSeconds: getNumericEnvVar('CACHING_TTL_SECONDS', defaultConfig.caching!.ttlSeconds)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dynamic configuration loader for the Market Data Gateway
|
||||
*/
|
||||
export const createMarketDataGatewayConfig = createConfigLoader<MarketDataGatewayConfig>(
|
||||
'market-data-gateway',
|
||||
marketDataGatewayConfigSchema,
|
||||
defaultConfig
|
||||
);
|
||||
|
||||
/**
|
||||
* Singleton Market Data Gateway configuration
|
||||
*/
|
||||
export const marketDataGatewayConfig = loadMarketDataGatewayConfig();
|
||||
112
libs/config/src/services/risk-guardian.ts
Normal file
112
libs/config/src/services/risk-guardian.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* Risk Guardian service configuration
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
import { getEnvVar, getNumericEnvVar, getBooleanEnvVar, createConfigLoader } from '../core';
|
||||
import { Environment, BaseConfig } from '../types';
|
||||
import { getEnvironment } from '../core';
|
||||
|
||||
/**
|
||||
* Risk Guardian specific configuration schema
|
||||
*/
|
||||
export const riskGuardianConfigSchema = z.object({
|
||||
environment: z.nativeEnum(Environment),
|
||||
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
||||
service: z.object({
|
||||
name: z.string().default('risk-guardian'),
|
||||
version: z.string().default('1.0.0'),
|
||||
port: z.number().default(4001)
|
||||
}),
|
||||
riskChecks: z.object({
|
||||
preTradeValidation: z.boolean().default(true),
|
||||
portfolioValidation: z.boolean().default(true),
|
||||
leverageValidation: z.boolean().default(true),
|
||||
concentrationValidation: z.boolean().default(true)
|
||||
}),
|
||||
alerting: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
criticalThreshold: z.number().default(0.8),
|
||||
warningThreshold: z.number().default(0.6)
|
||||
}),
|
||||
watchdog: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
checkIntervalSeconds: z.number().default(60)
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Risk Guardian configuration type
|
||||
*/
|
||||
export type RiskGuardianConfig = z.infer<typeof riskGuardianConfigSchema>;
|
||||
|
||||
/**
|
||||
* Default Risk Guardian configuration
|
||||
*/
|
||||
const defaultConfig: Partial<RiskGuardianConfig> = {
|
||||
environment: getEnvironment(),
|
||||
logLevel: 'info',
|
||||
service: {
|
||||
name: 'risk-guardian',
|
||||
version: '1.0.0',
|
||||
port: 4001
|
||||
},
|
||||
riskChecks: {
|
||||
preTradeValidation: true,
|
||||
portfolioValidation: true,
|
||||
leverageValidation: true,
|
||||
concentrationValidation: true
|
||||
},
|
||||
alerting: {
|
||||
enabled: true,
|
||||
criticalThreshold: 0.8,
|
||||
warningThreshold: 0.6
|
||||
},
|
||||
watchdog: {
|
||||
enabled: true,
|
||||
checkIntervalSeconds: 60
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load Risk Guardian configuration
|
||||
*/
|
||||
export function loadRiskGuardianConfig(): RiskGuardianConfig {
|
||||
return {
|
||||
environment: getEnvironment(),
|
||||
logLevel: (getEnvVar('LOG_LEVEL') || defaultConfig.logLevel) as 'debug' | 'info' | 'warn' | 'error',
|
||||
service: {
|
||||
name: getEnvVar('SERVICE_NAME') || defaultConfig.service!.name,
|
||||
version: getEnvVar('SERVICE_VERSION') || defaultConfig.service!.version,
|
||||
port: getNumericEnvVar('SERVICE_PORT', defaultConfig.service!.port)
|
||||
},
|
||||
riskChecks: {
|
||||
preTradeValidation: getBooleanEnvVar('RISK_CHECKS_PRE_TRADE', defaultConfig.riskChecks!.preTradeValidation),
|
||||
portfolioValidation: getBooleanEnvVar('RISK_CHECKS_PORTFOLIO', defaultConfig.riskChecks!.portfolioValidation),
|
||||
leverageValidation: getBooleanEnvVar('RISK_CHECKS_LEVERAGE', defaultConfig.riskChecks!.leverageValidation),
|
||||
concentrationValidation: getBooleanEnvVar('RISK_CHECKS_CONCENTRATION', defaultConfig.riskChecks!.concentrationValidation)
|
||||
},
|
||||
alerting: {
|
||||
enabled: getBooleanEnvVar('ALERTING_ENABLED', defaultConfig.alerting!.enabled),
|
||||
criticalThreshold: getNumericEnvVar('ALERTING_CRITICAL_THRESHOLD', defaultConfig.alerting!.criticalThreshold),
|
||||
warningThreshold: getNumericEnvVar('ALERTING_WARNING_THRESHOLD', defaultConfig.alerting!.warningThreshold)
|
||||
},
|
||||
watchdog: {
|
||||
enabled: getBooleanEnvVar('WATCHDOG_ENABLED', defaultConfig.watchdog!.enabled),
|
||||
checkIntervalSeconds: getNumericEnvVar('WATCHDOG_CHECK_INTERVAL', defaultConfig.watchdog!.checkIntervalSeconds)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dynamic configuration loader for the Risk Guardian
|
||||
*/
|
||||
export const createRiskGuardianConfig = createConfigLoader<RiskGuardianConfig>(
|
||||
'risk-guardian',
|
||||
riskGuardianConfigSchema,
|
||||
defaultConfig
|
||||
);
|
||||
|
||||
/**
|
||||
* Singleton Risk Guardian configuration
|
||||
*/
|
||||
export const riskGuardianConfig = loadRiskGuardianConfig();
|
||||
87
libs/config/src/types.ts
Normal file
87
libs/config/src/types.ts
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Configuration type definitions for the Stock Bot platform
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Environment enum for different deployment environments
|
||||
*/
|
||||
export enum Environment {
|
||||
Development = 'development',
|
||||
Testing = 'testing',
|
||||
Staging = 'staging',
|
||||
Production = 'production'
|
||||
}
|
||||
|
||||
/**
|
||||
* Common configuration interface for all service configs
|
||||
*/
|
||||
export interface BaseConfig {
|
||||
environment: Environment;
|
||||
logLevel: 'debug' | 'info' | 'warn' | 'error';
|
||||
service: {
|
||||
name: string;
|
||||
version: string;
|
||||
port: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Database configuration schema
|
||||
*/
|
||||
export const databaseConfigSchema = z.object({
|
||||
dragonfly: z.object({
|
||||
host: z.string().default('localhost'),
|
||||
port: z.number().default(6379),
|
||||
password: z.string().optional(),
|
||||
maxRetriesPerRequest: z.number().default(3)
|
||||
}),
|
||||
timescaleDB: z.object({
|
||||
host: z.string().default('localhost'),
|
||||
port: z.number().default(5432),
|
||||
database: z.string().default('stockbot'),
|
||||
user: z.string().default('postgres'),
|
||||
password: z.string().optional()
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Data provider configuration schema
|
||||
*/
|
||||
export const dataProviderSchema = z.object({
|
||||
name: z.string(),
|
||||
type: z.enum(['rest', 'websocket', 'file']),
|
||||
baseUrl: z.string().url().optional(),
|
||||
wsUrl: z.string().url().optional(),
|
||||
apiKey: z.string().optional(),
|
||||
apiSecret: z.string().optional(),
|
||||
refreshInterval: z.number().optional(),
|
||||
rateLimits: z.object({
|
||||
maxRequestsPerMinute: z.number().optional(),
|
||||
maxRequestsPerSecond: z.number().optional()
|
||||
}).optional()
|
||||
});
|
||||
|
||||
export const dataProvidersConfigSchema = z.object({
|
||||
providers: z.array(dataProviderSchema),
|
||||
defaultProvider: z.string()
|
||||
});
|
||||
|
||||
/**
|
||||
* Risk management configuration schema
|
||||
*/
|
||||
export const riskConfigSchema = z.object({
|
||||
maxDrawdown: z.number().default(0.05),
|
||||
maxPositionSize: z.number().default(0.1),
|
||||
maxLeverage: z.number().default(1),
|
||||
stopLossDefault: z.number().default(0.02),
|
||||
takeProfitDefault: z.number().default(0.05)
|
||||
});
|
||||
|
||||
/**
|
||||
* Type definitions based on schemas
|
||||
*/
|
||||
export type DatabaseConfig = z.infer<typeof databaseConfigSchema>;
|
||||
export type DataProviderConfig = z.infer<typeof dataProviderSchema>;
|
||||
export type DataProvidersConfig = z.infer<typeof dataProvidersConfigSchema>;
|
||||
export type RiskConfig = z.infer<typeof riskConfigSchema>;
|
||||
10
libs/config/tsconfig.json
Normal file
10
libs/config/tsconfig.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue