فهرست منبع

updated database and routes

updated database and routes
uzairrizwan1 9 ماه پیش
والد
کامیت
9ba08e0c28
7فایلهای تغییر یافته به همراه387 افزوده شده و 1249 حذف شده
  1. 225 0
      config/database.js
  2. 0 129
      middleware/errorHandler.js
  3. 0 367
      services/priceUpdateService.js
  4. 27 81
      src/server.js
  5. 0 203
      tests/candleValidation.test.js
  6. 0 166
      tests/server.test.js
  7. 135 303
      utils/databaseInit.js

+ 225 - 0
config/database.js

@@ -1 +1,226 @@
 
+const mysql = require('mysql2/promise');
+const sqlite3 = require('sqlite3').verbose();
+const { Sequelize } = require('sequelize');
+const { logger } = require('../utils/logger');
+
+let sequelize = null;
+let mysqlConnection = null;
+let sqliteDb = null;
+
+const connectDatabase = async () => {
+  try {
+    const dbType = process.env.DB_TYPE || 'postgres';
+
+    switch (dbType) {
+      case 'mysql':
+        await connectMySQL();
+        break;
+      case 'postgres':
+        await connectPostgreSQL();
+        break;
+      case 'sqlite':
+      default:
+        await connectSQLite();
+        break;
+    }
+
+    logger.info(`Database connected successfully: ${dbType}`);
+    return true;
+  } catch (error) {
+    logger.error('Database connection failed:', error);
+    throw error;
+  }
+};
+
+const connectMySQL = async () => {
+  try {
+    // Create connection pool
+    mysqlConnection = mysql.createPool({
+      host: process.env.DB_HOST || 'localhost',
+      port: process.env.DB_PORT || 3306,
+      user: process.env.DB_USER || 'root',
+      password: process.env.DB_PASSWORD || '',
+      database: process.env.DB_NAME || 'financial_data',
+      waitForConnections: true,
+      connectionLimit: 10,
+      queueLimit: 0,
+      acquireTimeout: 60000,
+      timeout: 60000
+    });
+
+    // Test the connection
+    const connection = await mysqlConnection.getConnection();
+    await connection.ping();
+    connection.release();
+
+    logger.info('MySQL database connected successfully');
+  } catch (error) {
+    logger.error('MySQL connection failed:', error);
+    throw error;
+  }
+};
+
+// PostgreSQL connection function
+const connectPostgreSQL = async () => {
+  try {
+    sequelize = new Sequelize(
+      process.env.DB_NAME || 'financial_data',
+      process.env.DB_USER || 'postgres',
+      process.env.DB_PASSWORD || 'mqldev@123',
+      {
+        host: process.env.DB_HOST || 'localhost',
+        port: process.env.DB_PORT || 5432,
+        dialect: 'postgres',
+        pool: {
+          max: 10,
+          min: 0,
+          acquire: 60000,
+          idle: 10000
+        },
+        logging: process.env.NODE_ENV === 'development' ? logger.info.bind(logger) : false
+      }
+    );
+
+    await sequelize.authenticate();
+    logger.info('PostgreSQL database connected successfully');
+  } catch (error) {
+    logger.error('PostgreSQL connection failed:', error);
+    throw error;
+  }
+};
+
+const connectSQLite = async () => {
+  return new Promise((resolve, reject) => {
+    const dbFile = process.env.DB_FILE || './data/financial_data.db';
+
+    sqliteDb = new sqlite3.Database(dbFile, (err) => {
+      if (err) {
+        logger.error('SQLite connection failed:', err);
+        reject(err);
+      } else {
+        logger.info('SQLite database connected successfully');
+        resolve();
+      }
+    });
+  });
+};
+
+const getMySQLConnection = () => {
+  if (!mysqlConnection) {
+    throw new Error('MySQL connection not established');
+  }
+  return mysqlConnection;
+};
+
+const getSequelizeInstance = () => {
+  if (!sequelize) {
+    throw new Error('Sequelize instance not established');
+  }
+  return sequelize;
+};
+
+const getSQLiteInstance = () => {
+  if (!sqliteDb) {
+    throw new Error('SQLite database not established');
+  }
+  return sqliteDb;
+};
+
+const closeDatabase = async () => {
+  try {
+    if (mysqlConnection) {
+      await mysqlConnection.end();
+      logger.info('MySQL connection closed');
+    }
+
+    if (sequelize) {
+      await sequelize.close();
+      logger.info('PostgreSQL connection closed');
+    }
+
+    if (sqliteDb) {
+      await new Promise((resolve) => {
+        sqliteDb.close((err) => {
+          if (err) {
+            logger.error('Error closing SQLite database:', err);
+          } else {
+            logger.info('SQLite connection closed');
+          }
+          resolve();
+        });
+      });
+    }
+  } catch (error) {
+    logger.error('Error closing database connections:', error);
+  }
+};
+
+// Database query helpers
+const executeQuery = async (query, params = []) => {
+  const dbType = process.env.DB_TYPE || 'postgres';
+
+  switch (dbType) {
+    case 'mysql':
+      const [rows] = await mysqlConnection.execute(query, params);
+      return rows;
+
+    case 'postgres':
+      const [results] = await sequelize.query(query, {
+        replacements: params,
+        type: Sequelize.QueryTypes.SELECT
+      });
+      return results;
+
+    case 'sqlite':
+    default:
+      return new Promise((resolve, reject) => {
+        sqliteDb.all(query, params, (err, rows) => {
+          if (err) {
+            reject(err);
+          } else {
+            resolve(rows);
+          }
+        });
+      });
+  }
+};
+
+const executeNonQuery = async (query, params = []) => {
+  const dbType = process.env.DB_TYPE || 'postgres';
+
+  switch (dbType) {
+    case 'mysql':
+      const [result] = await mysqlConnection.execute(query, params);
+      return result;
+
+    case 'postgres':
+      const [updateResults] = await sequelize.query(query, {
+        replacements: params,
+        type: Sequelize.QueryTypes.UPDATE
+      });
+      return updateResults;
+
+    case 'sqlite':
+    default:
+      return new Promise((resolve, reject) => {
+        sqliteDb.run(query, params, function(err) {
+          if (err) {
+            reject(err);
+          } else {
+            resolve({ changes: this.changes, lastID: this.lastID });
+          }
+        });
+      });
+  }
+};
+
+module.exports = {
+  connectDatabase,
+  closeDatabase,
+  executeQuery,
+  executeNonQuery,
+  getMySQLConnection,
+  getSequelizeInstance,
+  getSQLiteInstance
+};

+ 0 - 129
middleware/errorHandler.js

@@ -1,129 +0,0 @@
-const { logger } = require('../utils/logger');
-
-// Custom Error class
-class AppError extends Error {
-  constructor(message, statusCode, isOperational = true) {
-    super(message);
-    this.statusCode = statusCode;
-    this.isOperational = isOperational;
-    this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
-
-    Error.captureStackTrace(this, this.constructor);
-  }
-}
-
-// Global error handler middleware
-const errorHandler = (err, req, res, next) => {
-  let error = { ...err };
-  error.message = err.message;
-
-  // Log error
-  logger.error('Error occurred:', {
-    message: err.message,
-    stack: err.stack,
-    url: req.originalUrl,
-    method: req.method,
-    ip: req.ip,
-    userAgent: req.get('User-Agent')
-  });
-
-  // Mongoose bad ObjectId
-  if (err.name === 'CastError') {
-    const message = 'Resource not found';
-    error = new AppError(message, 404);
-  }
-
-  // Mongoose duplicate key
-  if (err.code === 11000) {
-    const message = 'Duplicate field value entered';
-    error = new AppError(message, 400);
-  }
-
-  // Mongoose validation error
-  if (err.name === 'ValidationError') {
-    const message = Object.values(err.errors).map(val => val.message).join(', ');
-    error = new AppError(message, 400);
-  }
-
-  // JWT errors
-  if (err.name === 'JsonWebTokenError') {
-    const message = 'Invalid token';
-    error = new AppError(message, 401);
-  }
-
-  if (err.name === 'TokenExpiredError') {
-    const message = 'Token expired';
-    error = new AppError(message, 401);
-  }
-
-  // Database connection errors
-  if (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND') {
-    const message = 'Database connection failed';
-    error = new AppError(message, 503);
-  }
-
-  // Send error response
-  const statusCode = error.statusCode || 500;
-  const status = error.status || 'error';
-  const message = error.message || 'Something went wrong';
-
-  res.status(statusCode).json({
-    status,
-    message,
-    ...(process.env.NODE_ENV === 'development' && {
-      stack: err.stack,
-      error: err
-    })
-  });
-};
-
-// 404 handler
-const notFound = (req, res, next) => {
-  const error = new AppError(`Not found - ${req.originalUrl}`, 404);
-  next(error);
-};
-
-// Async error wrapper
-const catchAsync = (fn) => {
-  return (req, res, next) => {
-    fn(req, res, next).catch(next);
-  };
-};
-
-// Development error sender (for debugging)
-const sendErrorDev = (err, res) => {
-  res.status(err.statusCode || 500).json({
-    status: err.status,
-    error: err,
-    message: err.message,
-    stack: err.stack
-  });
-};
-
-// Production error sender (security-conscious)
-const sendErrorProd = (err, res) => {
-  // Operational, trusted error: send message to client
-  if (err.isOperational) {
-    res.status(err.statusCode).json({
-      status: err.status,
-      message: err.message
-    });
-  } else {
-    // Programming or other unknown error: don't leak error details
-    logger.error('ERROR 💥', err);
-
-    res.status(500).json({
-      status: 'error',
-      message: 'Something went wrong!'
-    });
-  }
-};
-
-module.exports = {
-  AppError,
-  errorHandler,
-  notFound,
-  catchAsync,
-  sendErrorDev,
-  sendErrorProd
-};

+ 0 - 367
services/priceUpdateService.js

@@ -1,367 +0,0 @@
-const { logger } = require('../utils/logger');
-const { executeQuery } = require('../config/database');
-const { broadcastPriceUpdate, broadcastMultiplePriceUpdates } = require('./websocketService');
-const { addTick } = require('./candlestickService');
-
-// In-memory cache for current prices
-const priceCache = new Map();
-const symbolSubscriptions = new Map();
-
-// Simulated price data for development
-const generateMockPriceData = (symbol) => {
-  const basePrice = priceCache.get(symbol)?.close || 1.0;
-  const change = (Math.random() - 0.5) * 0.02; // ±1% change
-  const newPrice = basePrice * (1 + change);
-
-  return {
-    symbol,
-    open: basePrice,
-    high: Math.max(basePrice, newPrice) * (1 + Math.random() * 0.001),
-    low: Math.min(basePrice, newPrice) * (1 - Math.random() * 0.001),
-    close: newPrice,
-    volume: Math.floor(Math.random() * 1000000) + 100000,
-    timestamp: new Date(),
-    timeframe: 'H1'
-  };
-};
-
-class PriceUpdateService {
-  constructor() {
-    this.isRunning = false;
-    this.updateInterval = null;
-    this.supportedSymbols = [];
-    this.updateCallbacks = [];
-
-    this.initialize();
-  }
-
-  initialize() {
-    // Load supported symbols from environment
-    this.supportedSymbols = (process.env.SUPPORTED_SYMBOLS || 'EURUSD,GBPUSD,USDJPY')
-      .split(',')
-      .map(symbol => symbol.trim());
-
-    logger.info(`Price update service initialized with symbols: ${this.supportedSymbols.join(', ')}`);
-
-    // Initialize price cache with mock data
-    this.initializePriceCache();
-  }
-
-  initializePriceCache() {
-    this.supportedSymbols.forEach(symbol => {
-      priceCache.set(symbol, generateMockPriceData(symbol));
-    });
-    logger.info('Price cache initialized');
-  }
-
-  start() {
-    if (this.isRunning) {
-      logger.warn('Price update service is already running');
-      return;
-    }
-
-    const interval = parseInt(process.env.PRICE_UPDATE_INTERVAL) || 1000;
-
-    this.updateInterval = setInterval(() => {
-      this.updatePrices();
-    }, interval);
-
-    this.isRunning = true;
-    logger.info(`Price update service started with ${interval}ms interval`);
-
-    // Start cleanup interval
-    setInterval(() => {
-      this.cleanup();
-    }, 60000); // Cleanup every minute
-  }
-
-  stop() {
-    if (!this.isRunning) {
-      return;
-    }
-
-    if (this.updateInterval) {
-      clearInterval(this.updateInterval);
-      this.updateInterval = null;
-    }
-
-    this.isRunning = false;
-    logger.info('Price update service stopped');
-  }
-
-  async updatePrices() {
-    try {
-      const updates = [];
-
-      for (const symbol of this.supportedSymbols) {
-        const priceData = await this.generatePriceUpdate(symbol);
-        updates.push(priceData);
-
-        // Update cache
-        priceCache.set(symbol, priceData);
-
-        // Store in database (if needed)
-        await this.storePriceData(priceData);
-      }
-
-      // Broadcast updates to WebSocket clients
-      if (updates.length > 0) {
-        broadcastMultiplePriceUpdates(updates);
-      }
-
-      // Call registered update callbacks
-      this.updateCallbacks.forEach(callback => {
-        try {
-          callback(updates);
-        } catch (error) {
-          logger.error('Error in price update callback:', error);
-        }
-      });
-
-    } catch (error) {
-      logger.error('Error updating prices:', error);
-    }
-  }
-
-  async generatePriceUpdate(symbol) {
-    // In a real implementation, this would fetch from external APIs
-    // For now, we'll generate mock data
-    const currentPrice = priceCache.get(symbol);
-    const change = (Math.random() - 0.5) * 0.02; // ±1% change
-    const newPrice = currentPrice ? currentPrice.close * (1 + change) : 1.0;
-
-    const priceData = {
-      symbol,
-      open: currentPrice ? currentPrice.close : newPrice,
-      high: Math.max(currentPrice ? currentPrice.close : newPrice, newPrice) * (1 + Math.random() * 0.001),
-      low: Math.min(currentPrice ? currentPrice.close : newPrice, newPrice) * (1 - Math.random() * 0.001),
-      close: newPrice,
-      volume: Math.floor(Math.random() * 1000000) + 100000,
-      timestamp: new Date(),
-      timeframe: 'H1'
-    };
-
-    // Add tick data for candlestick aggregation
-    // Generate multiple ticks within this price update period
-    const tickCount = Math.floor(Math.random() * 5) + 3; // 3-7 ticks per update
-    for (let i = 0; i < tickCount; i++) {
-      const tickPrice = newPrice + (Math.random() - 0.5) * 0.001; // Small variations
-      const tickTimestamp = new Date(priceData.timestamp.getTime() - (tickCount - i) * 100); // Spread over the interval
-      addTick(symbol, tickPrice, tickTimestamp);
-    }
-
-    return priceData;
-  }
-
-  async storePriceData(priceData) {
-    try {
-      const dbType = process.env.DB_TYPE || 'sqlite';
-
-      if (dbType === 'sqlite') {
-        await this.storePriceDataSQLite(priceData);
-      } else if (dbType === 'mysql') {
-        await this.storePriceDataMySQL(priceData);
-      } else if (dbType === 'postgres') {
-        await this.storePriceDataPostgreSQL(priceData);
-      }
-    } catch (error) {
-      logger.error('Error storing price data:', error);
-    }
-  }
-
-  async storePriceDataSQLite(priceData) {
-    const query = `
-      INSERT OR IGNORE INTO price_data (symbol, timeframe, timestamp, open, high, low, close, volume)
-      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
-    `;
-
-    await executeQuery(query, [
-      priceData.symbol,
-      priceData.timeframe,
-      priceData.timestamp,
-      priceData.open,
-      priceData.high,
-      priceData.low,
-      priceData.close,
-      priceData.volume
-    ]);
-  }
-
-  async storePriceDataMySQL(priceData) {
-    const query = `
-      INSERT IGNORE INTO price_data (symbol, timeframe, timestamp, open, high, low, close, volume)
-      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
-    `;
-
-    await executeQuery(query, [
-      priceData.symbol,
-      priceData.timeframe,
-      priceData.timestamp,
-      priceData.open,
-      priceData.high,
-      priceData.low,
-      priceData.close,
-      priceData.volume
-    ]);
-  }
-
-  async storePriceDataPostgreSQL(priceData) {
-    const query = `
-      INSERT INTO price_data (symbol, timeframe, timestamp, open, high, low, close, volume)
-      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
-      ON CONFLICT DO NOTHING
-    `;
-
-    await executeQuery(query, [
-      priceData.symbol,
-      priceData.timeframe,
-      priceData.timestamp,
-      priceData.open,
-      priceData.high,
-      priceData.low,
-      priceData.close,
-      priceData.volume
-    ]);
-  }
-
-  // Get current price for a symbol
-  getCurrentPrice(symbol) {
-    return priceCache.get(symbol);
-  }
-
-  // Get current prices for multiple symbols
-  getCurrentPrices(symbols = null) {
-    const targetSymbols = symbols || this.supportedSymbols;
-    const prices = {};
-
-    targetSymbols.forEach(symbol => {
-      prices[symbol] = priceCache.get(symbol);
-    });
-
-    return prices;
-  }
-
-  // Get historical data for a symbol
-  async getHistoricalData(symbol, timeframe = 'H1', limit = 1000) {
-    try {
-      const dbType = process.env.DB_TYPE || 'sqlite';
-      let query;
-
-      if (dbType === 'sqlite') {
-        query = `
-          SELECT * FROM price_data
-          WHERE symbol = ? AND timeframe = ?
-          ORDER BY timestamp DESC
-          LIMIT ?
-        `;
-      } else {
-        query = `
-          SELECT * FROM price_data
-          WHERE symbol = ? AND timeframe = ?
-          ORDER BY timestamp DESC
-          LIMIT ?
-        `;
-      }
-
-      const params = [symbol, timeframe, limit];
-      const data = await executeQuery(query, params);
-
-      return data.reverse(); // Return in chronological order
-    } catch (error) {
-      logger.error(`Error fetching historical data for ${symbol}:`, error);
-      return [];
-    }
-  }
-
-  // Register callback for price updates
-  onPriceUpdate(callback) {
-    this.updateCallbacks.push(callback);
-  }
-
-  // Remove price update callback
-  removePriceUpdateCallback(callback) {
-    const index = this.updateCallbacks.indexOf(callback);
-    if (index > -1) {
-      this.updateCallbacks.splice(index, 1);
-    }
-  }
-
-  // Cleanup old data
-  async cleanup() {
-    try {
-      const cutoffDate = new Date();
-      cutoffDate.setDate(cutoffDate.getDate() - 30); // Keep 30 days of data
-
-      const dbType = process.env.DB_TYPE || 'sqlite';
-      let query;
-
-      if (dbType === 'sqlite') {
-        query = 'DELETE FROM price_data WHERE timestamp < ?';
-      } else {
-        query = 'DELETE FROM price_data WHERE timestamp < ?';
-      }
-
-      const params = [cutoffDate];
-      await executeQuery(query, params);
-
-      logger.info('Price data cleanup completed');
-    } catch (error) {
-      logger.error('Error during price data cleanup:', error);
-    }
-  }
-
-  // Get service statistics
-  getStats() {
-    return {
-      isRunning: this.isRunning,
-      supportedSymbols: this.supportedSymbols,
-      cachedSymbols: Array.from(priceCache.keys()),
-      updateCallbacks: this.updateCallbacks.length,
-      cacheSize: priceCache.size,
-      uptime: process.uptime()
-    };
-  }
-}
-
-// Create singleton instance
-const priceUpdateService = new PriceUpdateService();
-
-// Export functions for external use
-const startPriceUpdates = (io) => {
-  priceUpdateService.start();
-};
-
-const stopPriceUpdates = () => {
-  priceUpdateService.stop();
-};
-
-const getCurrentPrice = (symbol) => {
-  return priceUpdateService.getCurrentPrice(symbol);
-};
-
-const getCurrentPrices = (symbols) => {
-  return priceUpdateService.getCurrentPrices(symbols);
-};
-
-const getHistoricalData = (symbol, timeframe, limit) => {
-  return priceUpdateService.getHistoricalData(symbol, timeframe, limit);
-};
-
-const onPriceUpdate = (callback) => {
-  priceUpdateService.onPriceUpdate(callback);
-};
-
-const getPriceUpdateStats = () => {
-  return priceUpdateService.getStats();
-};
-
-module.exports = {
-  startPriceUpdates,
-  stopPriceUpdates,
-  getCurrentPrice,
-  getCurrentPrices,
-  getHistoricalData,
-  onPriceUpdate,
-  getPriceUpdateStats,
-  priceUpdateService
-};

+ 27 - 81
src/server.js

@@ -1,74 +1,49 @@
 const express = require('express');
-const http = require('http');
-const socketIo = require('socket.io');
 const cors = require('cors');
-const helmet = require('helmet');
-const morgan = require('morgan');
-const compression = require('compression');
-const rateLimit = require('express-rate-limit');
-
+const path = require('path');
 require('dotenv').config();
 
-// Import custom modules
-const { errorHandler } = require('../middleware/errorHandler');
 const { logger } = require('../utils/logger');
 const { connectDatabase } = require('../config/database');
 const { initializeDatabase } = require('../utils/databaseInit');
 const priceRoutes = require('../routes/priceRoutes');
-const symbolRoutes = require('../routes/symbolRoutes');
-const { initializeWebSocket } = require('../services/websocketService');
-const { startPriceUpdates } = require('../services/priceUpdateService');
 
-class FinancialDataServer {
+class MarketDataServer {
   constructor() {
     this.app = express();
-    this.server = http.createServer(this.app);
-    this.io = socketIo(this.server, {
-      cors: {
-        origin: process.env.CLIENT_URL || "http://localhost:3000",
-        methods: ["GET", "POST"]
-      }
-    });
     this.port = process.env.PORT || 3001;
 
     this.initializeMiddleware();
     this.initializeRoutes();
-    this.initializeWebSocket();
-    this.initializeErrorHandling();
     this.initializeDatabase();
   }
 
   initializeMiddleware() {
-    // Security middleware
-    this.app.use(helmet());
-
-    // CORS configuration
+    // ✅ Enable CORS
     this.app.use(cors({
       origin: process.env.CLIENT_URL || "http://localhost:3000",
       credentials: true
     }));
 
-    // Rate limiting
-    const limiter = rateLimit({
-      windowMs: 15 * 60 * 1000, // 15 minutes
-      max: 1000, // limit each IP to 1000 requests per windowMs
-      message: 'Too many requests from this IP, please try again later.'
-    });
-    this.app.use('/api/', limiter);
-
-    // Body parsing middleware
-    this.app.use(express.json({ limit: '10mb' }));
-    this.app.use(express.urlencoded({ extended: true, limit: '10mb' }));
-
-    // Compression middleware
-    this.app.use(compression());
+    // ✅ Enable JSON and URL Encoded body parsing
+    this.app.use(express.json({
+      strict: true, // reject invalid JSON
+      limit: '1mb'  // prevent large payload attacks
+    }));
+    this.app.use(express.urlencoded({ extended: true }));
 
-    // Logging middleware
-    this.app.use(morgan('combined', { stream: { write: msg => logger.info(msg.trim()) } }));
+    // ✅ Handle invalid JSON gracefully
+    this.app.use((err, req, res, next) => {
+      if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
+        logger.error('Invalid JSON received:', err.message);
+        return res.status(400).json({ success: false, message: 'Invalid JSON format' });
+      }
+      next();
+    });
   }
 
   initializeRoutes() {
-    // Health check endpoint
+    // Health check
     this.app.get('/health', (req, res) => {
       res.status(200).json({
         status: 'OK',
@@ -77,27 +52,11 @@ class FinancialDataServer {
       });
     });
 
-    // API routes
-    this.app.use('/api/prices', priceRoutes);
-    this.app.use('/api/symbols', symbolRoutes);
-
-    // Serve static files from public directory
-    this.app.use(express.static('public'));
+    // ✅ API Routes
+    this.app.use('/api', priceRoutes);
 
-    // Catch all handler: send back React's index.html file for client-side routing
-    if (process.env.NODE_ENV === 'production') {
-      this.app.get('*', (req, res) => {
-        res.sendFile(path.join(__dirname, '../public/index.html'));
-      });
-    }
-  }
-
-  initializeWebSocket() {
-    initializeWebSocket(this.io);
-  }
-
-  initializeErrorHandling() {
-    this.app.use(errorHandler);
+    // ✅ Serve static files
+    this.app.use(express.static(path.join(__dirname, '../public')));
   }
 
   async initializeDatabase() {
@@ -105,7 +64,6 @@ class FinancialDataServer {
       await connectDatabase();
       logger.info('Database connected successfully');
 
-      // Initialize database tables and sample data
       await initializeDatabase();
       logger.info('Database initialized successfully');
     } catch (error) {
@@ -114,20 +72,12 @@ class FinancialDataServer {
     }
   }
 
-  startPriceUpdates() {
-    startPriceUpdates(this.io);
-  }
-
   async start() {
     try {
-      this.server.listen(this.port, () => {
-        logger.info(`Financial Data Server running on port ${this.port}`);
+      this.app.listen(this.port, () => {
+        logger.info(`✅ Market Data Server running on port ${this.port}`);
         logger.info(`Environment: ${process.env.NODE_ENV || 'development'}`);
       });
-
-      // Start real-time price updates
-      this.startPriceUpdates();
-
     } catch (error) {
       logger.error('Failed to start server:', error);
       process.exit(1);
@@ -136,21 +86,17 @@ class FinancialDataServer {
 
   async stop() {
     logger.info('Shutting down server...');
-    this.server.close(() => {
-      logger.info('Server closed');
-      process.exit(0);
-    });
+    process.exit(0);
   }
 }
 
-// Create and start server
-const server = new FinancialDataServer();
+// Create and start server
+const server = new MarketDataServer();
 
 // Graceful shutdown
 process.on('SIGTERM', () => server.stop());
 process.on('SIGINT', () => server.stop());
 
-// Start the server
 server.start().catch(error => {
   logger.error('Failed to start server:', error);
   process.exit(1);

+ 0 - 203
tests/candleValidation.test.js

@@ -1,203 +0,0 @@
-const request = require('supertest');
-const { expect } = require('chai');
-const app = require('../src/server');
-const { getHistoricalCandles, validateCandles, generateTestCandles } = require('../services/candlestickService');
-
-describe('Candlestick API Tests', () => {
-  const testSymbol = 'EURUSD';
-  const testTimeframe = 'H1';
-
-  describe('GET /api/prices/validate-candles/:symbol', () => {
-    it('should validate candles for a valid symbol', async () => {
-      const response = await request(app)
-        .get(`/api/prices/validate-candles/${testSymbol}`)
-        .query({ timeframe: testTimeframe, limit: 50 })
-        .expect(200);
-
-      expect(response.body.status).to.equal('success');
-      expect(response.body.data).to.have.property('total');
-      expect(response.body.data).to.have.property('valid');
-      expect(response.body.data).to.have.property('invalid');
-      expect(response.body.data.total).to.be.greaterThan(0);
-    });
-
-    it('should return 400 for missing symbol', async () => {
-      const response = await request(app)
-        .get('/api/prices/validate-candles/')
-        .expect(404); // Express will return 404 for missing route param
-    });
-
-    it('should handle different timeframes', async () => {
-      const timeframes = ['M1', 'M5', 'M15', 'H1', 'H4', 'D1'];
-
-      for (const timeframe of timeframes) {
-        const response = await request(app)
-          .get(`/api/prices/validate-candles/${testSymbol}`)
-          .query({ timeframe, limit: 10 })
-          .expect(200);
-
-        expect(response.body.status).to.equal('success');
-        expect(response.body.timeframe).to.equal(timeframe);
-      }
-    });
-  });
-
-  describe('GET /api/prices/generate-test-candles/:symbol', () => {
-    it('should generate test candles for a valid symbol', async () => {
-      const response = await request(app)
-        .get(`/api/prices/generate-test-candles/${testSymbol}`)
-        .query({ timeframe: testTimeframe, count: 20 })
-        .expect(200);
-
-      expect(response.body.status).to.equal('success');
-      expect(response.body.data).to.be.an('array');
-      expect(response.body.data.length).to.equal(20);
-      expect(response.body.validation).to.have.property('total', 20);
-    });
-
-    it('should validate generated test candles', async () => {
-      const response = await request(app)
-        .get(`/api/prices/generate-test-candles/${testSymbol}`)
-        .query({ timeframe: testTimeframe, count: 10 })
-        .expect(200);
-
-      expect(response.body.meta.validationPassed).to.equal(true);
-      expect(response.body.meta.successRate).to.equal('100.00%');
-    });
-  });
-
-  describe('GET /api/prices/candle-info/:symbol', () => {
-    it('should return candle statistics for a valid symbol', async () => {
-      const response = await request(app)
-        .get(`/api/prices/candle-info/${testSymbol}`)
-        .query({ timeframe: testTimeframe })
-        .expect(200);
-
-      expect(response.body.status).to.equal('success');
-      expect(response.body.data).to.have.property('count');
-      expect(response.body.data).to.have.property('priceRange');
-      expect(response.body.data).to.have.property('volume');
-      expect(response.body.data.symbol).to.equal(testSymbol.toUpperCase());
-    });
-  });
-
-  describe('Candlestick Service Unit Tests', () => {
-    it('should generate valid test candles', () => {
-      const candles = generateTestCandles(testSymbol, testTimeframe, 10);
-      expect(candles).to.have.length(10);
-
-      candles.forEach(candle => {
-        expect(candle.symbol).to.equal(testSymbol);
-        expect(candle.timeframe).to.equal(testTimeframe);
-        expect(candle).to.have.property('open');
-        expect(candle).to.have.property('high');
-        expect(candle).to.have.property('low');
-        expect(candle).to.have.property('close');
-        expect(candle).to.have.property('volume');
-        expect(candle).to.have.property('timestamp');
-      });
-    });
-
-    it('should validate correct candles', () => {
-      const validCandles = generateTestCandles(testSymbol, testTimeframe, 5);
-      const results = validateCandles(validCandles);
-
-      expect(results.total).to.equal(5);
-      expect(results.valid).to.equal(5);
-      expect(results.invalid).to.equal(0);
-      expect(results.issues).to.have.length(0);
-    });
-
-    it('should detect invalid candles', () => {
-      const invalidCandles = [
-        {
-          symbol: testSymbol,
-          timeframe: testTimeframe,
-          timestamp: new Date(),
-          open: 'invalid',
-          high: 1.1,
-          low: 1.0,
-          close: 1.05,
-          volume: 1000
-        },
-        {
-          symbol: testSymbol,
-          timeframe: testTimeframe,
-          timestamp: new Date(),
-          open: 1.0,
-          high: 0.9, // Invalid: high < open
-          low: 1.0,
-          close: 1.05,
-          volume: 1000
-        }
-      ];
-
-      const results = validateCandles(invalidCandles);
-      expect(results.invalid).to.be.greaterThan(0);
-      expect(results.issues.length).to.be.greaterThan(0);
-    });
-  });
-
-  describe('GET /api/prices/historical/:symbol (Integration)', () => {
-    it('should return historical data that can be validated', async () => {
-      const response = await request(app)
-        .get(`/api/prices/historical/${testSymbol}`)
-        .query({ timeframe: testTimeframe, limit: 20 })
-        .expect(200);
-
-      expect(response.body.status).to.equal('success');
-      expect(response.body.data).to.be.an('array');
-
-      if (response.body.data.length > 0) {
-        // Validate the returned candles
-        const validationResults = validateCandles(response.body.data);
-        expect(validationResults.total).to.equal(response.body.data.length);
-
-        // Log validation results for debugging
-        console.log(`Historical data validation: ${validationResults.valid}/${validationResults.total} valid candles`);
-      }
-    });
-  });
-
-  describe('Chart Data Format Tests', () => {
-    it('should return data in correct format for charting', async () => {
-      const response = await request(app)
-        .get(`/api/prices/historical/${testSymbol}`)
-        .query({ timeframe: testTimeframe, limit: 10 })
-        .expect(200);
-
-      expect(response.body.status).to.equal('success');
-      expect(response.body.data).to.be.an('array');
-
-      if (response.body.data.length > 0) {
-        const candle = response.body.data[0];
-
-        // Check required fields for charting
-        expect(candle).to.have.property('timestamp');
-        expect(candle).to.have.property('open');
-        expect(candle).to.have.property('high');
-        expect(candle).to.have.property('low');
-        expect(candle).to.have.property('close');
-
-        // Validate data types
-        expect(typeof candle.open).to.equal('number');
-        expect(typeof candle.high).to.equal('number');
-        expect(typeof candle.low).to.equal('number');
-        expect(typeof candle.close).to.equal('number');
-
-        // Validate price logic
-        expect(candle.high).to.be.at.least(Math.max(candle.open, candle.close));
-        expect(candle.low).to.be.at.most(Math.min(candle.open, candle.close));
-      }
-    });
-  });
-});
-
-// Helper function to wait for price updates
-const waitForPriceUpdate = (ms = 2000) => {
-  return new Promise(resolve => setTimeout(resolve, ms));
-};
-
-module.exports = {
-  waitForPriceUpdate
-};

+ 0 - 166
tests/server.test.js

@@ -1,166 +0,0 @@
-const request = require('supertest');
-const { expect } = require('chai');
-const server = require('../src/server');
-
-describe('Financial Data Server', () => {
-  let app;
-
-  before(async () => {
-    // Get the Express app instance from the server
-    app = server.app;
-  });
-
-  describe('Health Check', () => {
-    it('should return server health status', (done) => {
-      request(app)
-        .get('/health')
-        .expect(200)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'OK');
-          expect(res.body).to.have.property('timestamp');
-          expect(res.body).to.have.property('uptime');
-          done();
-        });
-    });
-  });
-
-  describe('Price API', () => {
-    it('should return current price for valid symbol', (done) => {
-      request(app)
-        .get('/api/prices/current/EURUSD')
-        .expect(200)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'success');
-          expect(res.body).to.have.property('data');
-          expect(res.body.data).to.have.property('symbol', 'EURUSD');
-          expect(res.body.data).to.have.property('price');
-          expect(res.body.data).to.have.property('change');
-          expect(res.body.data).to.have.property('changePercent');
-          done();
-        });
-    });
-
-    it('should return 404 for invalid symbol', (done) => {
-      request(app)
-        .get('/api/prices/current/INVALID')
-        .expect(404)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'error');
-          expect(res.body).to.have.property('message');
-          done();
-        });
-    });
-
-    it('should return historical data for valid symbol', (done) => {
-      request(app)
-        .get('/api/prices/historical/EURUSD?timeframe=H1&limit=10')
-        .expect(200)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'success');
-          expect(res.body).to.have.property('data');
-          expect(res.body.data).to.be.an('array');
-          expect(res.body).to.have.property('symbol', 'EURUSD');
-          expect(res.body).to.have.property('timeframe', 'H1');
-          done();
-        });
-    });
-  });
-
-  describe('Symbol API', () => {
-    it('should return list of symbols', (done) => {
-      request(app)
-        .get('/api/symbols')
-        .expect(200)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'success');
-          expect(res.body).to.have.property('data');
-          expect(res.body.data).to.be.an('array');
-          expect(res.body).to.have.property('pagination');
-          done();
-        });
-    });
-
-    it('should return specific symbol details', (done) => {
-      request(app)
-        .get('/api/symbols/EURUSD')
-        .expect(200)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'success');
-          expect(res.body).to.have.property('data');
-          expect(res.body.data).to.have.property('symbol', 'EURUSD');
-          expect(res.body.data).to.have.property('name');
-          expect(res.body.data).to.have.property('category');
-          expect(res.body.data).to.have.property('exchange');
-          done();
-        });
-    });
-
-    it('should return 404 for non-existent symbol', (done) => {
-      request(app)
-        .get('/api/symbols/NONEXISTENT')
-        .expect(404)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'error');
-          expect(res.body).to.have.property('message');
-          done();
-        });
-    });
-
-    it('should return symbol categories', (done) => {
-      request(app)
-        .get('/api/symbols/categories/list')
-        .expect(200)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'success');
-          expect(res.body).to.have.property('data');
-          expect(res.body.data).to.be.an('array');
-          done();
-        });
-    });
-  });
-
-  describe('Error Handling', () => {
-    it('should handle 404 for unknown routes', (done) => {
-      request(app)
-        .get('/api/unknown-route')
-        .expect(404)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'error');
-          expect(res.body).to.have.property('message');
-          done();
-        });
-    });
-
-    it('should handle malformed JSON', (done) => {
-      request(app)
-        .post('/api/prices/subscribe')
-        .set('Content-Type', 'application/json')
-        .send('{ malformed json }')
-        .expect(400)
-        .end((err, res) => {
-          if (err) return done(err);
-
-          expect(res.body).to.have.property('status', 'error');
-          done();
-        });
-    });
-  });
-});

+ 135 - 303
utils/databaseInit.js

@@ -1,7 +1,5 @@
 const { executeQuery, executeNonQuery } = require('../config/database');
 const { logger } = require('./logger');
-const fs = require('fs');
-const path = require('path');
 
 class DatabaseInitializer {
   constructor() {
@@ -18,7 +16,7 @@ class DatabaseInitializer {
       logger.info('Starting database initialization...');
 
       // Create tables based on database type
-      const dbType = process.env.DB_TYPE || 'sqlite';
+      const dbType = process.env.DB_TYPE || 'postgres';
 
       switch (dbType) {
         case 'mysql':
@@ -31,9 +29,6 @@ class DatabaseInitializer {
           break;
       }
 
-      // Insert sample data
-      await this.insertSampleData();
-
       this.initialized = true;
       logger.info('Database initialization completed successfully');
 
@@ -45,7 +40,7 @@ class DatabaseInitializer {
 
   async initializeRelationalDatabase() {
     try {
-      const dbType = process.env.DB_TYPE || 'mysql';
+      const dbType = process.env.DB_TYPE || 'postgres';
 
       if (dbType === 'mysql') {
         await this.initializeMySQL();
@@ -61,47 +56,45 @@ class DatabaseInitializer {
 
   async initializeMySQL() {
     try {
-      // Create price_data table for MySQL
-      const createPriceTableQuery = `
-        CREATE TABLE IF NOT EXISTS price_data (
-          id INT PRIMARY KEY AUTO_INCREMENT,
-          symbol VARCHAR(10) NOT NULL,
-          timeframe VARCHAR(5) NOT NULL,
-          timestamp DATETIME NOT NULL,
-          open DECIMAL(15,8) NOT NULL,
-          high DECIMAL(15,8) NOT NULL,
-          low DECIMAL(15,8) NOT NULL,
-          close DECIMAL(15,8) NOT NULL,
-          volume BIGINT NOT NULL,
-          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-          INDEX idx_symbol_timeframe (symbol, timeframe),
-          INDEX idx_timestamp (timestamp),
-          INDEX idx_symbol_timestamp (symbol, timestamp)
+      // Create candles_h1 table for storing H1 candlestick data
+      const createCandlesH1TableQuery = `
+        CREATE TABLE IF NOT EXISTS candles_h1 (
+          id INT AUTO_INCREMENT PRIMARY KEY,
+          symbol TEXT NOT NULL,
+          market TEXT NOT NULL,
+          open FLOAT NOT NULL,
+          high FLOAT NOT NULL,
+          low FLOAT NOT NULL,
+          close FLOAT NOT NULL,
+          volume FLOAT NOT NULL,
+          timestamp TIMESTAMP NOT NULL,
+          UNIQUE KEY unique_symbol_timestamp (symbol, timestamp),
+          INDEX idx_symbol (symbol),
+          INDEX idx_market (market),
+          INDEX idx_timestamp (timestamp)
         ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
       `;
 
-      await executeNonQuery(createPriceTableQuery);
-      logger.info('MySQL price data table created successfully');
-
-      // Create symbols table for MySQL
-      const createSymbolsTableQuery = `
-        CREATE TABLE IF NOT EXISTS symbols (
-          id INT PRIMARY KEY AUTO_INCREMENT,
-          symbol VARCHAR(10) UNIQUE NOT NULL,
-          name VARCHAR(100) NOT NULL,
-          category VARCHAR(20) NOT NULL,
-          exchange VARCHAR(20) NOT NULL,
-          is_active BOOLEAN DEFAULT TRUE,
-          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-          updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+      await executeNonQuery(createCandlesH1TableQuery);
+      logger.info('MySQL candles_h1 table created successfully');
+
+      // Create live_prices table for real-time price updates
+      const createLivePricesTableQuery = `
+        CREATE TABLE IF NOT EXISTS live_prices (
+          id INT AUTO_INCREMENT PRIMARY KEY,
+          symbol TEXT NOT NULL,
+          market TEXT NOT NULL,
+          price FLOAT NOT NULL,
+          updated_at TIMESTAMP NOT NULL,
+          UNIQUE KEY unique_symbol_market (symbol, market),
           INDEX idx_symbol (symbol),
-          INDEX idx_category (category),
-          INDEX idx_exchange (exchange)
+          INDEX idx_market (market),
+          INDEX idx_updated_at (updated_at)
         ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
       `;
 
-      await executeNonQuery(createSymbolsTableQuery);
-      logger.info('MySQL symbols table created successfully');
+      await executeNonQuery(createLivePricesTableQuery);
+      logger.info('MySQL live_prices table created successfully');
 
     } catch (error) {
       logger.error('Error creating MySQL tables:', error);
@@ -111,54 +104,65 @@ class DatabaseInitializer {
 
   async initializePostgreSQL() {
     try {
-      // Create price_data table for PostgreSQL
-      const createPriceTableQuery = `
-        CREATE TABLE IF NOT EXISTS price_data (
+      // Create candles_h1 table for PostgreSQL
+      const createCandlesH1TableQuery = `
+        CREATE TABLE IF NOT EXISTS candles_h1 (
           id SERIAL PRIMARY KEY,
-          symbol VARCHAR(10) NOT NULL,
-          timeframe VARCHAR(5) NOT NULL,
+          symbol TEXT NOT NULL,
+          market TEXT NOT NULL,
+          open FLOAT NOT NULL,
+          high FLOAT NOT NULL,
+          low FLOAT NOT NULL,
+          close FLOAT NOT NULL,
+          volume FLOAT NOT NULL,
           timestamp TIMESTAMP NOT NULL,
-          open DECIMAL(15,8) NOT NULL,
-          high DECIMAL(15,8) NOT NULL,
-          low DECIMAL(15,8) NOT NULL,
-          close DECIMAL(15,8) NOT NULL,
-          volume BIGINT NOT NULL,
-          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+          UNIQUE(symbol, timestamp)
         );
       `;
 
-      await executeNonQuery(createPriceTableQuery);
-      logger.info('PostgreSQL price data table created successfully');
+      await executeNonQuery(createCandlesH1TableQuery);
+      logger.info('PostgreSQL candles_h1 table created successfully');
 
-      // Create indexes for PostgreSQL
-      const createIndexes = [
-        'CREATE INDEX IF NOT EXISTS idx_symbol_timeframe ON price_data(symbol, timeframe);',
-        'CREATE INDEX IF NOT EXISTS idx_timestamp ON price_data(timestamp);',
-        'CREATE INDEX IF NOT EXISTS idx_symbol_timestamp ON price_data(symbol, timestamp);'
+      // Create indexes for candles_h1
+      const createCandlesH1Indexes = [
+        'CREATE INDEX IF NOT EXISTS idx_candles_symbol ON candles_h1(symbol);',
+        'CREATE INDEX IF NOT EXISTS idx_candles_market ON candles_h1(market);',
+        'CREATE INDEX IF NOT EXISTS idx_candles_timestamp ON candles_h1(timestamp);'
       ];
 
-      for (const indexQuery of createIndexes) {
+      for (const indexQuery of createCandlesH1Indexes) {
         await executeNonQuery(indexQuery);
       }
 
-      logger.info('PostgreSQL indexes created successfully');
+      logger.info('PostgreSQL candles_h1 indexes created successfully');
 
-      // Create symbols table for PostgreSQL
-      const createSymbolsTableQuery = `
-        CREATE TABLE IF NOT EXISTS symbols (
+      // Create live_prices table for PostgreSQL
+      const createLivePricesTableQuery = `
+        CREATE TABLE IF NOT EXISTS live_prices (
           id SERIAL PRIMARY KEY,
-          symbol VARCHAR(10) UNIQUE NOT NULL,
-          name VARCHAR(100) NOT NULL,
-          category VARCHAR(20) NOT NULL,
-          exchange VARCHAR(20) NOT NULL,
-          is_active BOOLEAN DEFAULT TRUE,
-          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-          updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+          symbol TEXT NOT NULL,
+          market TEXT NOT NULL,
+          price FLOAT NOT NULL,
+          updated_at TIMESTAMP NOT NULL,
+          UNIQUE(symbol, market)
         );
       `;
 
-      await executeNonQuery(createSymbolsTableQuery);
-      logger.info('PostgreSQL symbols table created successfully');
+      await executeNonQuery(createLivePricesTableQuery);
+      logger.info('PostgreSQL live_prices table created successfully');
+
+      // Create indexes for live_prices
+      const createLivePricesIndexes = [
+        'CREATE INDEX IF NOT EXISTS idx_live_symbol ON live_prices(symbol);',
+        'CREATE INDEX IF NOT EXISTS idx_live_market ON live_prices(market);',
+        'CREATE INDEX IF NOT EXISTS idx_live_updated_at ON live_prices(updated_at);'
+      ];
+
+      for (const indexQuery of createLivePricesIndexes) {
+        await executeNonQuery(indexQuery);
+      }
+
+      logger.info('PostgreSQL live_prices indexes created successfully');
 
     } catch (error) {
       logger.error('Error creating PostgreSQL tables:', error);
@@ -168,259 +172,87 @@ class DatabaseInitializer {
 
   async initializeSQLite() {
     try {
-      // Create price_data table
-      const createPriceTableQuery = `
-        CREATE TABLE IF NOT EXISTS price_data (
+      // Create candles_h1 table for SQLite
+      const createCandlesH1TableQuery = `
+        CREATE TABLE IF NOT EXISTS candles_h1 (
           id INTEGER PRIMARY KEY AUTOINCREMENT,
           symbol TEXT NOT NULL,
-          timeframe TEXT NOT NULL,
-          timestamp DATETIME NOT NULL,
+          market TEXT NOT NULL,
           open REAL NOT NULL,
           high REAL NOT NULL,
           low REAL NOT NULL,
           close REAL NOT NULL,
-          volume INTEGER NOT NULL,
-          created_at DATETIME DEFAULT CURRENT_TIMESTAMP
+          volume REAL NOT NULL,
+          timestamp DATETIME NOT NULL,
+          UNIQUE(symbol, timestamp)
         );
       `;
 
-      await executeNonQuery(createPriceTableQuery);
-      logger.info('SQLite price data table created successfully');
+      await executeNonQuery(createCandlesH1TableQuery);
+      logger.info('SQLite candles_h1 table created successfully');
 
-      // Create indexes for better performance
-      const createIndexes = [
-        'CREATE INDEX IF NOT EXISTS idx_symbol_timeframe ON price_data(symbol, timeframe);',
-        'CREATE INDEX IF NOT EXISTS idx_timestamp ON price_data(timestamp);',
-        'CREATE INDEX IF NOT EXISTS idx_symbol_timestamp ON price_data(symbol, timestamp);'
+      // Create indexes for candles_h1
+      const createCandlesH1Indexes = [
+        'CREATE INDEX IF NOT EXISTS idx_candles_symbol ON candles_h1(symbol);',
+        'CREATE INDEX IF NOT EXISTS idx_candles_market ON candles_h1(market);',
+        'CREATE INDEX IF NOT EXISTS idx_candles_timestamp ON candles_h1(timestamp);'
       ];
 
-      for (const indexQuery of createIndexes) {
+      for (const indexQuery of createCandlesH1Indexes) {
         await executeNonQuery(indexQuery);
       }
 
-      logger.info('SQLite indexes created successfully');
+      logger.info('SQLite candles_h1 indexes created successfully');
 
-      // Create symbols table
-      const createSymbolsTableQuery = `
-        CREATE TABLE IF NOT EXISTS symbols (
+      // Create live_prices table for SQLite
+      const createLivePricesTableQuery = `
+        CREATE TABLE IF NOT EXISTS live_prices (
           id INTEGER PRIMARY KEY AUTOINCREMENT,
-          symbol TEXT UNIQUE NOT NULL,
-          name TEXT NOT NULL,
-          category TEXT NOT NULL,
-          exchange TEXT NOT NULL,
-          is_active INTEGER DEFAULT 1,
-          created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-          updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
+          symbol TEXT NOT NULL,
+          market TEXT NOT NULL,
+          price REAL NOT NULL,
+          updated_at DATETIME NOT NULL,
+          UNIQUE(symbol, market)
         );
       `;
 
-      await executeNonQuery(createSymbolsTableQuery);
-      logger.info('SQLite symbols table created successfully');
-
-    } catch (error) {
-      logger.error('Error creating SQLite tables:', error);
-      throw error;
-    }
-  }
-
-  async insertSampleData() {
-    try {
-      const dbType = process.env.DB_TYPE || 'sqlite';
-
-      // Check if symbols already exist
-      let existingSymbols;
-      if (dbType === 'sqlite') {
-        existingSymbols = await executeQuery('SELECT COUNT(*) as count FROM symbols');
-      } else {
-        existingSymbols = await executeQuery('SELECT COUNT(*) as count FROM symbols');
-      }
-
-      // Handle different database result formats
-      let symbolCount = 0;
-      if (existingSymbols && existingSymbols.length > 0) {
-        symbolCount = existingSymbols[0].count || 0;
-      }
-
-      if (symbolCount > 0) {
-        logger.info('Sample symbols already exist, skipping insertion');
-        return;
-      }
+      await executeNonQuery(createLivePricesTableQuery);
+      logger.info('SQLite live_prices table created successfully');
 
-      // Insert sample symbols
-      const sampleSymbols = [
-        { symbol: 'EURUSD', name: 'Euro vs US Dollar', category: 'forex', exchange: 'FX' },
-        { symbol: 'GBPUSD', name: 'British Pound vs US Dollar', category: 'forex', exchange: 'FX' },
-        { symbol: 'USDJPY', name: 'US Dollar vs Japanese Yen', category: 'forex', exchange: 'FX' },
-        { symbol: 'USDCHF', name: 'US Dollar vs Swiss Franc', category: 'forex', exchange: 'FX' },
-        { symbol: 'USDCAD', name: 'US Dollar vs Canadian Dollar', category: 'forex', exchange: 'FX' },
-        { symbol: 'AUDUSD', name: 'Australian Dollar vs US Dollar', category: 'forex', exchange: 'FX' },
-        { symbol: 'NZDUSD', name: 'New Zealand Dollar vs US Dollar', category: 'forex', exchange: 'FX' },
-        { symbol: 'BTCUSD', name: 'Bitcoin vs US Dollar', category: 'crypto', exchange: 'Crypto' },
-        { symbol: 'ETHUSD', name: 'Ethereum vs US Dollar', category: 'crypto', exchange: 'Crypto' },
-        { symbol: 'AAPL', name: 'Apple Inc.', category: 'stocks', exchange: 'NASDAQ' },
-        { symbol: 'GOOGL', name: 'Alphabet Inc.', category: 'stocks', exchange: 'NASDAQ' },
-        { symbol: 'MSFT', name: 'Microsoft Corporation', category: 'stocks', exchange: 'NASDAQ' },
-        { symbol: 'TSLA', name: 'Tesla Inc.', category: 'stocks', exchange: 'NASDAQ' },
-        { symbol: 'AMZN', name: 'Amazon.com Inc.', category: 'stocks', exchange: 'NASDAQ' },
-        { symbol: 'META', name: 'Meta Platforms Inc.', category: 'stocks', exchange: 'NASDAQ' }
+      // Create indexes for live_prices
+      const createLivePricesIndexes = [
+        'CREATE INDEX IF NOT EXISTS idx_live_symbol ON live_prices(symbol);',
+        'CREATE INDEX IF NOT EXISTS idx_live_market ON live_prices(market);',
+        'CREATE INDEX IF NOT EXISTS idx_live_updated_at ON live_prices(updated_at);'
       ];
 
-      for (const symbolData of sampleSymbols) {
-        let insertQuery;
-        if (dbType === 'sqlite') {
-          insertQuery = `
-            INSERT OR IGNORE INTO symbols (symbol, name, category, exchange, is_active)
-            VALUES (?, ?, ?, ?, 1)
-          `;
-        } else if (dbType === 'postgres') {
-          insertQuery = `
-            INSERT INTO symbols (symbol, name, category, exchange, is_active)
-            VALUES (?, ?, ?, ?, ?)
-            ON CONFLICT (symbol) DO NOTHING
-          `;
-        } else {
-          insertQuery = `
-            INSERT IGNORE INTO symbols (symbol, name, category, exchange, is_active)
-            VALUES (?, ?, ?, ?, 1)
-          `;
-        }
-
-        await executeNonQuery(insertQuery, [
-          symbolData.symbol,
-          symbolData.name,
-          symbolData.category,
-          symbolData.exchange,
-          true
-        ]);
-      }
-
-      logger.info(`Inserted ${sampleSymbols.length} sample symbols`);
-
-      // Generate sample price data for the last 1000 H1 candles
-      await this.generateSamplePriceData(sampleSymbols.slice(0, 7)); // Generate for first 7 symbols
-
-    } catch (error) {
-      logger.error('Error inserting sample data:', error);
-      throw error;
-    }
-  }
-
-  async generateSamplePriceData(symbols) {
-    try {
-      logger.info('Generating sample price data...');
-
-      const now = new Date();
-      const dbType = process.env.DB_TYPE || 'sqlite';
-
-      for (const symbolData of symbols) {
-        logger.info(`Generating price data for ${symbolData.symbol}...`);
-
-        // Generate 1000 H1 candles (about 41 days of data)
-        const priceData = [];
-        let currentPrice = this.getInitialPrice(symbolData.symbol);
-
-        for (let i = 999; i >= 0; i--) {
-          const timestamp = new Date(now.getTime() - (i * 60 * 60 * 1000)); // H1 intervals
-          const open = currentPrice;
-
-          // Generate realistic price movement (±1%)
-          const change = (Math.random() - 0.5) * 0.02;
-          const close = open * (1 + change);
-
-          const high = Math.max(open, close) * (1 + Math.random() * 0.001);
-          const low = Math.min(open, close) * (1 - Math.random() * 0.001);
-          const volume = Math.floor(Math.random() * 1000000) + 100000;
-
-          priceData.push({
-            symbol: symbolData.symbol,
-            timeframe: 'H1',
-            timestamp,
-            open: open.toFixed(8),
-            high: high.toFixed(8),
-            low: low.toFixed(8),
-            close: close.toFixed(8),
-            volume
-          });
-
-          currentPrice = close;
-        }
-
-        // Insert price data in batches
-        const batchSize = 100;
-        for (let i = 0; i < priceData.length; i += batchSize) {
-          const batch = priceData.slice(i, i + batchSize);
-
-          for (const price of batch) {
-            let insertQuery;
-            if (dbType === 'sqlite') {
-              insertQuery = `
-                INSERT OR IGNORE INTO price_data (symbol, timeframe, timestamp, open, high, low, close, volume)
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?)
-              `;
-            } else if (dbType === 'postgres') {
-              insertQuery = `
-                INSERT INTO price_data (symbol, timeframe, timestamp, open, high, low, close, volume)
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?)
-                ON CONFLICT DO NOTHING
-              `;
-            } else {
-              insertQuery = `
-                INSERT IGNORE INTO price_data (symbol, timeframe, timestamp, open, high, low, close, volume)
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?)
-              `;
-            }
-
-            await executeNonQuery(insertQuery, [
-              price.symbol,
-              price.timeframe,
-              price.timestamp,
-              price.open,
-              price.high,
-              price.low,
-              price.close,
-              price.volume
-            ]);
-          }
-        }
-
-        logger.info(`Generated ${priceData.length} price records for ${symbolData.symbol}`);
+      for (const indexQuery of createLivePricesIndexes) {
+        await executeNonQuery(indexQuery);
       }
 
-      logger.info('Sample price data generation completed');
+      logger.info('SQLite live_prices indexes created successfully');
 
     } catch (error) {
-      logger.error('Error generating sample price data:', error);
+      logger.error('Error creating SQLite tables:', error);
       throw error;
     }
   }
 
-  getInitialPrice(symbol) {
-    const initialPrices = {
-      'EURUSD': 1.0850,
-      'GBPUSD': 1.2650,
-      'USDJPY': 150.50,
-      'USDCHF': 0.9150,
-      'USDCAD': 1.3450,
-      'AUDUSD': 0.6550,
-      'NZDUSD': 0.6050
-    };
-
-    return initialPrices[symbol] || 1.0000;
-  }
+  // Removed all sample data generation methods as per user requirements
 
   async reset() {
     try {
       logger.info('Resetting database...');
 
-      const dbType = process.env.DB_TYPE || 'sqlite';
+      const dbType = process.env.DB_TYPE || 'postgres';
 
-      // Drop tables
+      // Drop tables in correct order (considering foreign key constraints)
       if (dbType === 'sqlite') {
-        await executeNonQuery('DROP TABLE IF EXISTS price_data');
-        await executeNonQuery('DROP TABLE IF EXISTS symbols');
+        await executeNonQuery('DROP TABLE IF EXISTS candles_h1');
+        await executeNonQuery('DROP TABLE IF EXISTS live_prices');
       } else {
-        await executeNonQuery('DROP TABLE IF EXISTS price_data');
-        await executeNonQuery('DROP TABLE IF EXISTS symbols');
+        await executeNonQuery('DROP TABLE IF EXISTS candles_h1');
+        await executeNonQuery('DROP TABLE IF EXISTS live_prices');
       }
 
       this.initialized = false;
@@ -437,41 +269,41 @@ class DatabaseInitializer {
 
   async getStats() {
     try {
-      const dbType = process.env.DB_TYPE || 'sqlite';
+      const dbType = process.env.DB_TYPE || 'postgres';
 
-      let symbolCount, priceCount;
+      let candlesH1Count, livePricesCount;
 
       if (dbType === 'sqlite') {
-        symbolCount = await executeQuery('SELECT COUNT(*) as count FROM symbols');
-        priceCount = await executeQuery('SELECT COUNT(*) as count FROM price_data');
+        candlesH1Count = await executeQuery('SELECT COUNT(*) as count FROM candles_h1');
+        livePricesCount = await executeQuery('SELECT COUNT(*) as count FROM live_prices');
       } else {
-        symbolCount = await executeQuery('SELECT COUNT(*) as count FROM symbols');
-        priceCount = await executeQuery('SELECT COUNT(*) as count FROM price_data');
+        candlesH1Count = await executeQuery('SELECT COUNT(*) as count FROM candles_h1');
+        livePricesCount = await executeQuery('SELECT COUNT(*) as count FROM live_prices');
       }
 
       // Handle different database result formats
-      let symbols = 0;
-      let priceRecords = 0;
+      let candlesH1 = 0;
+      let livePrices = 0;
 
-      if (symbolCount && symbolCount.length > 0) {
-        symbols = symbolCount[0].count || 0;
+      if (candlesH1Count && candlesH1Count.length > 0) {
+        candlesH1 = candlesH1Count[0].count || 0;
       }
 
-      if (priceCount && priceCount.length > 0) {
-        priceRecords = priceCount[0].count || 0;
+      if (livePricesCount && livePricesCount.length > 0) {
+        livePrices = livePricesCount[0].count || 0;
       }
 
       return {
-        symbols,
-        price_records: priceRecords,
+        candles_h1: candlesH1,
+        live_prices: livePrices,
         initialized: this.initialized
       };
 
     } catch (error) {
       logger.error('Error getting database stats:', error);
       return {
-        symbols: 0,
-        price_records: 0,
+        candles_h1: 0,
+        live_prices: 0,
         initialized: false
       };
     }