Ticker Plant
Problem Description
Normalize 2 million trade messages from 4 exchanges (NYSE, NASDAQ, BATS, IEX) into consolidated 1-second OHLCV bars with VWAP and trade count. Each exchange uses a different message format and timestamp resolution.
Parse exchange-specific pipe-delimited formats, normalize timestamps to seconds, aggregate trades into bars per symbol per second, compute VWAP, and output sorted results.
Tier System & Performance Targets
| LANGUAGE | GOLD | SILVER | BRONZE |
|---|---|---|---|
| C++ / Rust | < 10000ms | < 30000ms | < 90000ms |
| Java | < 15000ms | < 45000ms | < 100000ms |
| Python | < 30000ms | < 60000ms | < 120000ms |
Evaluation Criteria
Correctness: Output must be sorted by timestamp then symbol. Float values (prices, VWAP) are compared with tolerance 0.001. Integer values must match exactly.
Performance: Wall-clock time to process all messages determines tier placement.
Input Format
Read from stdin. The first line is the number of messages N. The next N lines are pipe-delimited trade messages from 4 exchanges, each with a different format:
NYSE|nanoseconds|SYMBOL|price|qty|side
NASDAQ|microseconds|SYMBOL|side|qty|price
BATS|milliseconds|SYMBOL|price|qty|side|trade_id
IEX|seconds.microseconds|SYMBOL|price|qty|side
Key differences:
NYSE: Timestamps in nanosecondsNASDAQ: Timestamps in microseconds, side/qty/price order differsBATS: Timestamps in milliseconds, includes trade_id fieldIEX: Timestamps in decimal seconds (e.g., 1704067200.123456)
Output Format
First line: num_symbols num_bars. Then one line per OHLCV bar, sorted by timestamp then symbol:
num_symbols num_bars
timestamp_second symbol open high low close volume vwap trade_count
Where:
timestamp_second: Bar start time (integer seconds)symbol: Trading symbolopen, high, low, close: Bar prices (float, 6 decimal places)volume: Total bar volume (integer)vwap: Volume-weighted average price (float, 6 decimal places)trade_count: Number of trades in the bar (integer)
Example
Input
4
NYSE|1704067200000000000|AAPL|150.25|500|B
NASDAQ|1704067200000100|AAPL|S|300|150.50
BATS|1704067200100|MSFT|300.00|200|B|T001
IEX|1704067200.500000|AAPL|150.75|400|B
Output
2 2
1704067200 AAPL 150.250000 150.750000 150.250000 150.750000 1200 150.475000 3
1704067200 MSFT 300.000000 300.000000 300.000000 300.000000 200 300.000000 1
All 4 messages fall within the same second. AAPL has 3 trades aggregated into one bar. MSFT has 1 trade. Output is sorted by timestamp then symbol.
Submission Rules
- Your program receives input via stdin
- Output header line + sorted OHLCV bars to stdout
- Program must complete within 120 seconds
- Memory usage must not exceed 2GB
- Single-file solutions only
- Java class must be named
Solution
Starter Templates
C++
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
struct Trade {
long long ts_seconds;
std::string symbol;
double price;
long long qty;
};
struct Bar {
double open, high, low, close, vwap_num;
long long volume, count;
};
int main() {
int N;
scanf("%d", &N);
// key = (ts_seconds, symbol)
std::map<std::pair<long long, std::string>, Bar> bars;
char line[512];
for (int i = 0; i < N; i++) {
scanf(" %[^\n]", line);
// Parse exchange-specific format:
// NYSE|ns|SYM|price|qty|side
// NASDAQ|us|SYM|side|qty|price
// BATS|ms|SYM|price|qty|side|trade_id
// IEX|sec.us|SYM|price|qty|side
// Normalize timestamp to seconds
// Aggregate into OHLCV bar with VWAP
}
// Count unique symbols and bars
// Output header: num_symbols num_bars
// Output sorted bars
return 0;
}
Python
import sys
from collections import defaultdict
N = int(input())
# bars[(ts_sec, symbol)] = {open, high, low, close, volume, vwap_num, count}
bars = {}
for _ in range(N):
line = input().strip()
parts = line.split('|')
exchange = parts[0]
# Parse based on exchange format
if exchange == 'NYSE':
ts_ns = int(parts[1])
symbol, price, qty, side = parts[2], float(parts[3]), int(parts[4]), parts[5]
ts_sec = ts_ns // 1_000_000_000
elif exchange == 'NASDAQ':
ts_us = int(parts[1])
symbol, side, qty, price = parts[2], parts[3], int(parts[4]), float(parts[5])
ts_sec = ts_us // 1_000_000
elif exchange == 'BATS':
ts_ms = int(parts[1])
symbol, price, qty, side = parts[2], float(parts[3]), int(parts[4]), parts[5]
ts_sec = ts_ms // 1_000
elif exchange == 'IEX':
ts_dec = float(parts[1])
symbol, price, qty, side = parts[2], float(parts[3]), int(parts[4]), parts[5]
ts_sec = int(ts_dec)
key = (ts_sec, symbol)
if key not in bars:
bars[key] = {'open': price, 'high': price, 'low': price, 'close': price,
'volume': qty, 'vwap_num': price * qty, 'count': 1}
else:
b = bars[key]
b['high'] = max(b['high'], price)
b['low'] = min(b['low'], price)
b['close'] = price
b['volume'] += qty
b['vwap_num'] += price * qty
b['count'] += 1
symbols = set()
for (ts, sym) in bars:
symbols.add(sym)
sorted_keys = sorted(bars.keys())
print(f"{len(symbols)} {len(sorted_keys)}")
for (ts, sym) in sorted_keys:
b = bars[(ts, sym)]
vwap = b['vwap_num'] / b['volume'] if b['volume'] > 0 else 0
print(f"{ts} {sym} {b['open']:.6f} {b['high']:.6f} {b['low']:.6f} {b['close']:.6f} {b['volume']} {vwap:.6f} {b['count']}")
Rust
use std::io::{self, BufRead, Write, BufWriter};
use std::collections::BTreeMap;
fn main() {
let stdin = io::stdin();
let stdout = io::stdout();
let mut out = BufWriter::new(stdout.lock());
let mut lines = stdin.lock().lines();
let n: usize = lines.next().unwrap().unwrap().trim().parse().unwrap();
// BTreeMap for sorted output: (ts_sec, symbol) -> bar data
// Parse each exchange format, normalize timestamps, aggregate OHLCV
// Output: header + sorted bars
for _ in 0..n {
let line = lines.next().unwrap().unwrap();
let parts: Vec<&str> = line.trim().split('|').collect();
let exchange = parts[0];
// Parse based on exchange...
}
}
Java
import java.util.*;
import java.io.*;
public class Solution {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine().trim());
// TreeMap for sorted output: "ts_sec|symbol" -> bar data
TreeMap<String, double[]> bars = new TreeMap<>();
for (int i = 0; i < N; i++) {
String line = br.readLine().trim();
String[] parts = line.split("\\|");
String exchange = parts[0];
// Parse based on exchange format
// NYSE: ns, NASDAQ: us, BATS: ms, IEX: decimal seconds
// Normalize to seconds, aggregate OHLCV + VWAP
}
// Output header: num_symbols num_bars
// Output sorted bars
}
}