Trading Game

March 2025

Card-based trading simulator with real-time order matching and Monte Carlo AI strategies

Overview

Built for quantitative finance internship preparation, this card-based trading simulator implements real-time order matching, custom contract creation, and Monte Carlo AI strategies. Players trade futures contracts on card properties, with information revealing progressively through the game—combining expected value calculations with market microstructure analysis.

Trading Terminal live trading interface showing order book, cards, and trading controls
Live trading interface featuring real-time order book, market data, and trading controls

System Architecture

Electron Multi-Process Design

The application leverages Electron's architecture to separate concerns. The main process handles game state, AI execution, and order matching, while the renderer process manages UI and visualization. Secure IPC channels enable real-time market updates without blocking either process.

Game Phases

Preparation phase showing player cards and community cards
Preparation: Analyze initial card information before trading

The game progresses through four phases:

  1. Configuration: Select active contracts and AI opponent strategies
  2. Preparation: Analyze initial card information and contract values
  3. Live Trading: Real-time order placement with continuous price discovery as cards reveal
  4. Settlement: Calculate final contract values and P&L across all positions

Core Implementation Systems

Real-Time Order Matching Engine

The matching engine implements price-time priority: best prices execute first, then by arrival time at each level. The order book maintains separate buy/sell queues sorted by price and timestamp.

Order Matching Process
function matchOrder(newOrder):
  opposingOrders = getOpposingOrders(newOrder)
  sortedOrders = sortByPriceTimePriority(opposingOrders)
  
  for each existingOrder in sortedOrders:
      if newOrder.volume <= 0: break
      
      tradeVolume = min(newOrder.volume, existingOrder.volume)
      executeTrade(newOrder, existingOrder, tradeVolume)
      
      updateOrderStatus(existingOrder, tradeVolume)
      newOrder.volume -= tradeVolume
  
  broadcastMarketUpdate()

Large orders execute via partial fills across multiple counterparties at different price levels. The system supports market orders (immediate execution) and limit orders (rest in book until matched). IPC broadcasts market updates to all clients immediately, creating realistic bid-ask spreads through natural price-time priority dynamics.

Visual Contract Definition System

A node-based editor enables custom financial instruments via directed acyclic graphs. Players chain operations (data sources → filters → arithmetic → aggregations) to define contract payoffs without hard-coding.

Visual contract builder interface showing drag-and-drop node editor
Visual contract builder with drag-and-drop interface

Example Pipeline: "Sum of black community number cards"

  1. Source: Community cards
  2. Filter: Black cards
  3. Filter: Number cards (exclude face)
  4. Aggregate: Sum values

The evaluation engine performs topological sorting to determine execution order and validates dependencies before contract creation. Sequential evaluation maintains intermediate results, supporting branching logic for complex multi-operation contracts.

Monte Carlo AI Strategy

The AI uses pluggable strategies for market analysis. The Monte Carlo implementation estimates fair value through simulation, operating as an "anytime" algorithm where confidence improves with successive batches across trading turns.

The simulation identifies unknown cards not yet revealed, then generates thousands of scenarios by randomly distributing these unknowns. For each scenario, it calculates contract values and maintains a running average (fair value estimate) and variance (confidence measure). Higher confidence drives more aggressive trading behavior.

Monte Carlo Fair Value Estimation
function estimateFairValue(gameState, contractId):
  knownCards = getVisibleCards(gameState)
  unknownCards = createDeck() - knownCards
  
  totalValue = 0
  simulationCount = 0
  
  for i = 1 to SIMULATIONS_PER_BATCH:
      shuffledUnknown = shuffle(unknownCards)
      simulatedState = distributeCards(gameState, shuffledUnknown)
      
      contractValue = evaluateContract(contractId, simulatedState)
      totalValue += contractValue
      simulationCount++
  
  fairValueEstimate = totalValue / simulationCount
  confidence = calculateConfidence(simulationResults)
  
  return {fairValueEstimate, confidence}

Challenges

Opponent Modeling

Monte Carlo simulation estimates contract values but misses a critical element: modeling adaptive opponents. The difficultly with creating a opponent model is that it is quite subjective and intuitive. It's a mix of logic and heuristics. Even with good microstructure, there is little to be gained playing against a opponent that cannot model your actions.

My proposed approach was quite Bayesian. For each agent, the goal is to build a probability distribution over the other agent's possible cards. Using this, when running a MC simulation, instead of using a uniform distribtion, we sample using the predicted probabilities, known as importance sampling. I think a Bayes net would be a solid architecture, with trades/initations as the observed variables. Even with this, there are a lot of varaibles to represent and the parameters might be hard to estimate.

However, this approach is quite computationally expensive and I did not have time to implement it. In the future, I would like to test this and see if it is sensible. Even still, I don't believe it will able to compete even close to a human trader, making it not very useful for practice.

Execution

The other issue was how to execute the orders. The Monte Carlo simulation provides a strong estimate of the fair value, but then the bot needs to execute the order. I implemented a few strategies for this, but this is bot dependent and does not have a single answer. On the bright side, this allows for diversity in the bots' behavior, and certainly has a lot of room for future improvement with interesting approaches.


Conclusion

Ultimately, while I don't believe this project helped improve my trading abilities, mainly due to the inability to model adaptive opponents, it was a valuable learning experience. I gained a good understanding of how markets function and how to build a trading system.

© 2026 Taj Gillin. All rights reserved.