Skip to content

Instantly share code, notes, and snippets.

@oNddleo
Created March 10, 2025 03:44
Show Gist options
  • Save oNddleo/d2852b62a9295b4b6a813ebb9df8ef70 to your computer and use it in GitHub Desktop.
Save oNddleo/d2852b62a9295b4b6a813ebb9df8ef70 to your computer and use it in GitHub Desktop.
Trading system

Detailed Trading System Design

Let's delve deeper into the architecture, data models, and flows for your trading system:

Data Layer: Detailed Design

Database Schema

Market Data (TimescaleDB/InfluxDB)

Table: market_data
- ticker (string, index)
- timestamp (datetime, index)
- open_price (decimal)
- high_price (decimal)
- low_price (decimal)
- close_price (decimal)
- volume (integer)
- vwap (decimal) // Volume Weighted Average Price

User Management (PostgreSQL)

Table: users
- user_id (UUID, primary key)
- username (string, unique)
- email (string, unique)
- password_hash (string)
- created_at (timestamp)
- last_login (timestamp)
- account_status (enum: active, suspended, closed)
- verification_status (enum: verified, pending, rejected)

Table: user_preferences
- preference_id (UUID, primary key)
- user_id (UUID, foreign key)
- theme (string: light, dark)
- notification_settings (jsonb)
- default_order_type (enum)
- risk_tolerance (enum: low, medium, high)

Trading (PostgreSQL)

Table: portfolios
- portfolio_id (UUID, primary key)
- user_id (UUID, foreign key)
- name (string)
- created_at (timestamp)
- base_currency (string)

Table: positions
- position_id (UUID, primary key)
- portfolio_id (UUID, foreign key)
- instrument_id (UUID, foreign key)
- quantity (decimal)
- average_entry_price (decimal)
- current_market_value (decimal)
- unrealized_pnl (decimal)
- realized_pnl (decimal)
- last_updated (timestamp)

Table: orders
- order_id (UUID, primary key)
- user_id (UUID, foreign key)
- portfolio_id (UUID, foreign key)
- instrument_id (UUID, foreign key)
- order_type (enum: market, limit, stop, etc.)
- side (enum: buy, sell)
- quantity (decimal)
- price (decimal, nullable)
- stop_price (decimal, nullable)
- status (enum: pending, filled, partially_filled, canceled, rejected)
- created_at (timestamp)
- executed_at (timestamp, nullable)
- expiration (timestamp, nullable)

Financial Instruments (PostgreSQL)

Table: instruments
- instrument_id (UUID, primary key)
- symbol (string, index)
- name (string)
- type (enum: stock, option, future, crypto, forex, etc.)
- exchange (string)
- currency (string)
- is_tradable (boolean)
- lot_size (integer)
- tick_size (decimal)

Cache Layer (Redis)

  • Real-time prices (key: ticker, value: latest price data)
  • User sessions
  • Order book snapshots
  • Recent trade history

Data Flow Processes

1. Market Data Ingestion Flow

  1. External data provider sends market data through API/WebSocket
  2. Data ingestion service validates and normalizes the data
  3. Real-time data is published to message queue (Kafka/RabbitMQ)
  4. Subscribers process data:
    • Store in time-series DB for historical records
    • Update Redis cache for real-time access
    • Trigger alerts based on price movements
    • Update portfolio valuations

2. Order Processing Flow

  1. User submits order through UI/API
  2. Order validation service checks:
    • Sufficient funds/positions
    • Risk parameters
    • Market conditions
  3. Valid order is sent to order management system
  4. Order is routed to appropriate execution venue
  5. Execution service monitors order status
  6. Upon fill/partial fill:
    • Position database is updated
    • Transaction is recorded
    • User is notified
    • Portfolio is recalculated

3. Portfolio Reconciliation Flow

  1. Scheduled job triggers reconciliation process
  2. System fetches all open positions
  3. Current market prices are obtained
  4. Position values are recalculated
  5. Unrealized P&L is updated
  6. Risk metrics are recalculated
  7. Portfolio summary is updated

4. User Authentication Flow

  1. User submits credentials
  2. Authentication service validates credentials
  3. If valid, JWT token is generated with appropriate claims
  4. Token is returned to client
  5. Subsequent requests include token in Authorization header
  6. Token is validated on each request

Interface: Detailed Design

API Endpoints

Authentication

  • POST /api/auth/login - User login
  • POST /api/auth/logout - User logout
  • POST /api/auth/refresh - Refresh token
  • POST /api/auth/password/reset - Password reset

User Management

  • GET /api/users/me - Get current user profile
  • PATCH /api/users/me - Update user profile
  • GET /api/users/preferences - Get user preferences
  • PUT /api/users/preferences - Update preferences

Market Data

  • GET /api/market/quotes/{symbol} - Get latest quote
  • GET /api/market/history/{symbol} - Get historical data
  • GET /api/market/watchlists - Get user watchlists
  • POST /api/market/watchlists - Create watchlist

Trading

  • GET /api/portfolios - List portfolios

  • GET /api/portfolios/{id} - Get portfolio details

  • GET /api/portfolios/{id}/positions - Get portfolio positions

  • GET /api/portfolios/{id}/performance - Get portfolio performance

  • POST /api/orders - Place new order

  • GET /api/orders - List orders

  • GET /api/orders/{id} - Get order details

  • DELETE /api/orders/{id} - Cancel order

WebSocket Channels

  • /ws/market/quotes - Real-time quotes stream
  • /ws/market/trades - Real-time trades stream
  • /ws/user/orders - User's order updates
  • /ws/user/positions - User's position updates

UI Components

Dashboard Layout

  • Header with account info, notifications, settings
  • Main navigation sidebar
  • Market overview panel (indices, trending)
  • Watchlist panel
  • Portfolio summary panel
  • Recent orders panel
  • News feed
  • Footer with system status

Order Entry Form

  • Symbol lookup with autocomplete
  • Order type selection (market, limit, stop, etc.)
  • Quantity input with validation
  • Price input (for limit orders)
  • Time-in-force options
  • Preview button showing estimated costs
  • Submit button

Position Details View

  • Current market price and change
  • Position size and value
  • Entry price and date
  • Unrealized P&L (absolute and percentage)
  • Cost basis
  • Return metrics
  • Trade history for the position
  • Close position button

Analytics Dashboard

  • Asset allocation chart
  • Performance over time chart
  • Risk metrics (Beta, Sharpe ratio, etc.)
  • Sector exposure
  • Geographic exposure
  • Daily P&L chart
  • Comparison against benchmarks

System Architecture Flow

  1. Front-end (React/Angular/Vue) communicates with the backend via RESTful APIs and WebSockets
  2. API Gateway handles routing, rate limiting, and authentication
  3. Microservices:
    • User Service (authentication, profiles)
    • Market Data Service (quotes, charts)
    • Order Service (entry, execution)
    • Portfolio Service (positions, performance)
    • Analytics Service (risk, performance metrics)
  4. Message Queue (Kafka/RabbitMQ) handles event-driven communication between services
  5. Databases:
    • Time-series DB for market data
    • PostgreSQL for user and trading data
    • Redis for caching and real-time data
  6. Background Jobs:
    • Portfolio reconciliation
    • End-of-day processing
    • Report generation
    • Alert monitoring

Would you like me to expand on any particular component or provide a visual representation of any part of this design?​​​​​​​​​​​​​​​​

Trading System Architecture with Java

Let's refine the architecture to specifically leverage Java technologies across the system layers:

Java Technology Stack

Core Technologies

  • Java 17+ (LTS version)
  • Spring Boot (Application framework)
  • Spring Cloud (Microservices implementation)
  • Hibernate/JPA (Object-relational mapping)
  • Project Reactor (Reactive programming)
  • Resilience4j (Circuit breaking and fault tolerance)

Data Layer Implementation with Java

Database Access

  • Spring Data JPA for relational database access
  • Spring Data R2DBC for reactive database access
  • Spring Data Redis for cache management
  • Spring Data Elasticsearch for search functionality
  • JOOQ for type-safe SQL queries (as an alternative to JPA where performance is critical)

Example Repository Implementation:

@Repository
public interface OrderRepository extends JpaRepository<Order, UUID> {
    List<Order> findByUserIdAndStatus(UUID userId, OrderStatus status);
    
    @Query("SELECT o FROM Order o WHERE o.userId = :userId AND o.createdAt >= :startDate")
    List<Order> findRecentOrders(@Param("userId") UUID userId, @Param("startDate") LocalDateTime startDate);
    
    @Modifying
    @Query("UPDATE Order o SET o.status = :newStatus WHERE o.id = :orderId")
    void updateOrderStatus(@Param("orderId") UUID orderId, @Param("newStatus") OrderStatus newStatus);
}

Domain Model (JPA Entities)

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;
    
    @Column(name = "user_id", nullable = false)
    private UUID userId;
    
    @Column(name = "portfolio_id", nullable = false)
    private UUID portfolioId;
    
    @Column(name = "instrument_id", nullable = false)
    private UUID instrumentId;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "order_type", nullable = false)
    private OrderType orderType;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "side", nullable = false)
    private OrderSide side;
    
    @Column(name = "quantity", nullable = false)
    private BigDecimal quantity;
    
    @Column(name = "price")
    private BigDecimal price;
    
    @Column(name = "stop_price")
    private BigDecimal stopPrice;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private OrderStatus status;
    
    @Column(name = "created_at", nullable = false)
    private LocalDateTime createdAt;
    
    @Column(name = "executed_at")
    private LocalDateTime executedAt;
    
    @Column(name = "expiration")
    private LocalDateTime expiration;
    
    // Getters, setters, constructors, etc.
}

Service Layer Implementation

Market Data Service

@Service
@Slf4j
public class MarketDataServiceImpl implements MarketDataService {
    private final MarketDataRepository marketDataRepository;
    private final RedisTemplate<String, MarketQuote> redisTemplate;
    private final KafkaTemplate<String, MarketEvent> kafkaTemplate;
    
    @Autowired
    public MarketDataServiceImpl(
            MarketDataRepository marketDataRepository,
            RedisTemplate<String, MarketQuote> redisTemplate,
            KafkaTemplate<String, MarketEvent> kafkaTemplate) {
        this.marketDataRepository = marketDataRepository;
        this.redisTemplate = redisTemplate;
        this.kafkaTemplate = kafkaTemplate;
    }
    
    @Override
    public MarketQuote getLatestQuote(String symbol) {
        // Try to get from cache first
        String cacheKey = "quote:" + symbol;
        MarketQuote quote = redisTemplate.opsForValue().get(cacheKey);
        
        if (quote != null) {
            return quote;
        }
        
        // If not in cache, get from database
        quote = marketDataRepository.findLatestBySymbol(symbol)
            .orElseThrow(() -> new ResourceNotFoundException("Quote not found for: " + symbol));
            
        // Update cache
        redisTemplate.opsForValue().set(cacheKey, quote, 30, TimeUnit.SECONDS);
        
        return quote;
    }
    
    @Override
    @Scheduled(fixedRate = 60000) // Run every minute
    public void refreshMarketData() {
        log.info("Starting scheduled market data refresh");
        // Implementation to refresh market data
    }
    
    @Override
    public void processMarketUpdate(MarketUpdate update) {
        // Validate update
        // Store in time-series database
        MarketData data = convertToMarketData(update);
        marketDataRepository.save(data);
        
        // Update cache
        MarketQuote quote = convertToQuote(update);
        redisTemplate.opsForValue().set("quote:" + update.getSymbol(), quote, 30, TimeUnit.SECONDS);
        
        // Publish event for other services
        MarketEvent event = new MarketEvent(update.getSymbol(), update.getPrice(), update.getTimestamp());
        kafkaTemplate.send("market-updates", update.getSymbol(), event);
    }
    
    // Helper methods
    private MarketData convertToMarketData(MarketUpdate update) {
        // Conversion logic
        return new MarketData(/* ... */);
    }
    
    private MarketQuote convertToQuote(MarketUpdate update) {
        // Conversion logic
        return new MarketQuote(/* ... */);
    }
}

Order Processing Service

@Service
@Transactional
public class OrderServiceImpl implements OrderService {
    private final OrderRepository orderRepository;
    private final PositionRepository positionRepository;
    private final MarketDataService marketDataService;
    private final ApplicationEventPublisher eventPublisher;
    
    @Autowired
    public OrderServiceImpl(
            OrderRepository orderRepository,
            PositionRepository positionRepository,
            MarketDataService marketDataService,
            ApplicationEventPublisher eventPublisher) {
        this.orderRepository = orderRepository;
        this.positionRepository = positionRepository;
        this.marketDataService = marketDataService;
        this.eventPublisher = eventPublisher;
    }
    
    @Override
    public OrderResponse submitOrder(OrderRequest request) {
        // Validate order
        validateOrder(request);
        
        // Create order entity
        Order order = createOrderFromRequest(request);
        
        // Save to database
        order = orderRepository.save(order);
        
        // Publish event for execution service
        OrderCreatedEvent event = new OrderCreatedEvent(order);
        eventPublisher.publishEvent(event);
        
        return new OrderResponse(order.getId(), order.getStatus());
    }
    
    @Override
    public void processOrderExecution(OrderExecutionEvent execution) {
        Order order = orderRepository.findById(execution.getOrderId())
            .orElseThrow(() -> new ResourceNotFoundException("Order not found"));
            
        // Update order status
        order.setStatus(execution.getStatus());
        order.setExecutedAt(LocalDateTime.now());
        
        // If filled or partially filled, update position
        if (execution.getStatus() == OrderStatus.FILLED || 
            execution.getStatus() == OrderStatus.PARTIALLY_FILLED) {
            updatePosition(order, execution.getFilledQuantity(), execution.getExecutionPrice());
        }
        
        // Save updated order
        orderRepository.save(order);
        
        // Notify user
        OrderExecutedEvent event = new OrderExecutedEvent(order);
        eventPublisher.publishEvent(event);
    }
    
    // Helper methods
    private void validateOrder(OrderRequest request) {
        // Validation logic
    }
    
    private Order createOrderFromRequest(OrderRequest request) {
        // Creation logic
        return new Order(/* ... */);
    }
    
    private void updatePosition(Order order, BigDecimal filledQuantity, BigDecimal executionPrice) {
        // Position update logic
    }
}

API Layer Implementation

Controller Implementation with Spring MVC

@RestController
@RequestMapping("/api/orders")
@Validated
public class OrderController {
    private final OrderService orderService;
    
    @Autowired
    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }
    
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public OrderResponse createOrder(@Valid @RequestBody OrderRequest orderRequest) {
        return orderService.submitOrder(orderRequest);
    }
    
    @GetMapping
    public Page<OrderDto> getOrders(
            @RequestParam(required = false) OrderStatus status,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        return orderService.getOrders(status, PageRequest.of(page, size));
    }
    
    @GetMapping("/{orderId}")
    public OrderDto getOrder(@PathVariable UUID orderId) {
        return orderService.getOrderById(orderId);
    }
    
    @DeleteMapping("/{orderId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void cancelOrder(@PathVariable UUID orderId) {
        orderService.cancelOrder(orderId);
    }
    
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleResourceNotFound(ResourceNotFoundException ex) {
        return new ErrorResponse(ex.getMessage());
    }
    
    @ExceptionHandler(ValidationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidation(ValidationException ex) {
        return new ErrorResponse(ex.getMessage());
    }
}

Event-Driven Architecture with Spring Cloud Stream

@Configuration
public class StreamConfig {
    @Bean
    public Function<KStream<String, MarketEvent>, KStream<String, PortfolioUpdateEvent>> processMarketEvents() {
        return input -> input
            .filter((key, value) -> value != null)
            .mapValues((key, value) -> {
                // Process market event and calculate portfolio updates
                return new PortfolioUpdateEvent(/* ... */);
            });
    }
    
    @Bean
    public Consumer<OrderExecutionEvent> processOrderExecutions() {
        return event -> {
            // Process order execution
            // Update positions, etc.
        };
    }
}

WebSocket Implementation for Real-Time Updates

@Controller
public class MarketDataWebSocketController {
    private final SimpMessagingTemplate messagingTemplate;
    
    @Autowired
    public MarketDataWebSocketController(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }
    
    @EventListener
    public void handleMarketDataUpdate(MarketUpdateEvent event) {
        // Convert event to DTO
        MarketUpdateDto dto = convertToDto(event);
        
        // Send to all subscribers for this symbol
        messagingTemplate.convertAndSend("/topic/market/" + event.getSymbol(), dto);
    }
    
    private MarketUpdateDto convertToDto(MarketUpdateEvent event) {
        // Conversion logic
        return new MarketUpdateDto(/* ... */);
    }
}

Task Scheduling for Background Processes

@Configuration
@EnableScheduling
public class SchedulingConfig {
    private final PortfolioService portfolioService;
    
    @Autowired
    public SchedulingConfig(PortfolioService portfolioService) {
        this.portfolioService = portfolioService;
    }
    
    @Scheduled(cron = "0 0 18 * * MON-FRI") // 6:00 PM weekdays
    public void performEndOfDayReconciliation() {
        portfolioService.performEndOfDayReconciliation();
    }
    
    @Scheduled(fixedRate = 300000) // Every 5 minutes
    public void refreshPositionValues() {
        portfolioService.refreshAllPositionValues();
    }
}

System Architecture Flow (Java-specific)

  1. Data Ingestion

    • External data provider sends market data via HTTP/WebSocket
    • Spring WebClient/WebSocket client receives data
    • Data is validated and normalized using Java Bean Validation
    • Updates are published to Kafka topic using Spring Cloud Stream
  2. Market Data Processing

    • Kafka consumer (Spring Cloud Stream) consumes market updates
    • Data is stored in time-series DB using Spring Data
    • Redis cache is updated using Spring Data Redis
    • WebSocket messages are sent to subscribed clients using STOMP/SockJS
  3. Order Processing

    • REST controller receives order request
    • Request is validated using Bean Validation
    • Transaction is managed with Spring's @Transactional
    • Order is saved to PostgreSQL using Spring Data JPA
    • Order execution message is published to Kafka
    • Position is updated after execution is confirmed
  4. Portfolio Management

    • Scheduled tasks run using Spring's @Scheduled
    • Portfolio values are recalculated
    • Risk metrics are computed
    • Historical performance data is updated
  5. User Authentication

    • Spring Security handles authentication
    • JWT tokens are validated by filter
    • Method-level security with @PreAuthorize annotations
    • Role-based access control

Java Performance Considerations

  1. Database Optimization

    • Use query caching with Hibernate second-level cache
    • Implement batch processing for bulk operations
    • Use projections for partial entity loading
  2. Reactive Programming

    • Use Project Reactor for non-blocking I/O
    • Implement reactive repositories with R2DBC for high-throughput scenarios
    • Use WebFlux for high-concurrency API endpoints
  3. Caching Strategy

    • Multi-level caching with local cache and Redis
    • Cache warming for frequently accessed data
    • Cache invalidation strategy based on events
  4. Deployment and Scaling

    • Spring Boot applications packaged as Docker containers
    • Kubernetes for orchestration
    • Horizontal scaling of stateless services
    • Vertical scaling for database instances

Would you like me to elaborate on any specific aspect of this Java-based architecture? I can provide more details on Spring configurations, performance tuning, or any other area that's most important for your implementation.​​​​​​​​​​​​​​​​

I'd be happy to help design a system architecture for your trading platform. Let's create a robust design for both the data layer and interface.

Data Layer Design

Let's design a data layer that can handle trading data efficiently:

Key Components

  1. Database Structure

    • Time-series database for market data (like InfluxDB or TimescaleDB)
    • Relational database for user accounts, portfolios, and orders (PostgreSQL)
    • In-memory cache for real-time pricing and frequently accessed data (Redis)
  2. Data Flow

    • Market data ingestion pipeline
    • Order processing system
    • Portfolio reconciliation system
    • Historical data storage and retrieval
  3. Data Models

    • Market data (ticker, timestamp, price, volume)
    • Orders (order ID, user ID, ticker, quantity, price, status)
    • Positions (user ID, ticker, quantity, average price)
    • User profiles (authentication, preferences, risk parameters)

Interface Design

For the user interface, I recommend a modular approach:

Web/Desktop Interface

  • Dashboard with market overview
  • Portfolio view with detailed positions
  • Order entry interface with validation
  • Historical performance charts
  • Risk analytics dashboard

API Layer

  • RESTful API for account management
  • WebSocket for real-time data streaming
  • Authentication and authorization middleware
  • Rate limiting and throttling

Would you like me to expand on any specific aspect of this design? For example, I could provide more details on the database schema, API endpoints, or create a visual representation of the architecture.​​​​​​​​​​​​​​​​

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment