|
| 1 | +# FIX Message Parser & Execution Break Simulator |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +A recruiter-ready trading operations portfolio project that parses simulated FIX execution-report messages, reconciles them against internal order records and broker drop-copy-style records, and generates exception reports for trade support investigation. |
| 6 | + |
| 7 | +> **Important:** All data in this repository is simulated. This project does not use real broker, OMS, EMS, hedge fund, client, exchange, or proprietary trading data. |
| 8 | +
|
| 9 | +## Why This Project Exists |
| 10 | + |
| 11 | +Trading Operations, Trade Support, and Production Support teams often investigate issues such as missing execution reports, stale orders, rejected orders, broker discrepancies, duplicate execution IDs, and order-state breaks. |
| 12 | + |
| 13 | +This project demonstrates those workflows in a student-accessible way using Python, SQL, SQLite, pandas, CSV files, pytest, and GitHub Actions. |
| 14 | + |
| 15 | +## What the Project Demonstrates |
| 16 | + |
| 17 | +- Parse simulated FIX tag-value execution reports. |
| 18 | +- Convert raw FIX messages into structured CSV rows. |
| 19 | +- Understand core order lifecycle states: New, Partially Filled, Filled, Rejected, and stale/open. |
| 20 | +- Reconcile internal orders, FIX reports, broker drop-copy records, and expected order states. |
| 21 | +- Detect common trade support exceptions using SQL. |
| 22 | +- Generate CSV exception reports for investigation. |
| 23 | +- Maintain a simple operational runbook. |
| 24 | +- Validate parser and reconciliation behavior with automated tests and CI. |
| 25 | + |
| 26 | +## Core FIX Concepts Used |
| 27 | + |
| 28 | +FIX messages are commonly represented as tag-value pairs. For readability, this project uses the pipe character `|` as the delimiter in sample files. Real FIX messages typically use the SOH delimiter. |
| 29 | + |
| 30 | +Example simulated execution report: |
| 31 | + |
| 32 | +```text |
| 33 | +8=FIX.4.2|35=8|49=BROKER1|56=CLIENT1|34=2|52=2026-06-14 09:30:07|37=B-1001|11=ORD-1001|17=E-1001-F1|150=1|39=1|55=AAPL|54=1|38=1000|32=400|31=190.2200|151=600|14=400|6=190.2200|10=002| |
| 34 | +``` |
| 35 | + |
| 36 | +| Tag | Field | Meaning in this project | |
| 37 | +|---:|---|---| |
| 38 | +| 35 | MsgType | Message type. `35=8` means Execution Report. | |
| 39 | +| 11 | ClOrdID | Client order ID from the internal system. | |
| 40 | +| 37 | OrderID | Broker-assigned order ID. | |
| 41 | +| 17 | ExecID | Broker execution identifier. Should be unique per execution event. | |
| 42 | +| 150 | ExecType | Event type, such as New, Partial Fill, Fill, or Reject. | |
| 43 | +| 39 | OrdStatus | Current order status after the event. | |
| 44 | +| 55 | Symbol | Instrument ticker in this simulation. | |
| 45 | +| 54 | Side | `1=BUY`, `2=SELL`. | |
| 46 | +| 38 | OrderQty | Original order quantity. | |
| 47 | +| 32 | LastQty | Quantity executed on the current execution report. | |
| 48 | +| 31 | LastPx | Price for the current execution. | |
| 49 | +| 151 | LeavesQty | Remaining open quantity. | |
| 50 | +| 14 | CumQty | Cumulative executed quantity. | |
| 51 | +| 6 | AvgPx | Average execution price so far. | |
| 52 | + |
| 53 | +## Repository Structure |
| 54 | + |
| 55 | +```text |
| 56 | +. |
| 57 | +├── .github/workflows/ci.yml |
| 58 | +├── data/ |
| 59 | +│ ├── raw/fix_messages.txt |
| 60 | +│ ├── input/internal_orders.csv |
| 61 | +│ ├── input/broker_drop_copy.csv |
| 62 | +│ ├── input/expected_order_states.csv |
| 63 | +│ └── generated/fix_execution_reports.csv |
| 64 | +├── db/ |
| 65 | +├── reports/exceptions/ |
| 66 | +├── sql/ |
| 67 | +│ ├── schema.sql |
| 68 | +│ └── reconciliation_queries.sql |
| 69 | +├── src/fixops/ |
| 70 | +│ ├── config.py |
| 71 | +│ ├── fix_parser.py |
| 72 | +│ ├── generate_sample_data.py |
| 73 | +│ ├── load_db.py |
| 74 | +│ └── reconcile.py |
| 75 | +├── tests/ |
| 76 | +│ ├── test_parser.py |
| 77 | +│ └── test_reconciliation.py |
| 78 | +├── PROJECT_SCOPE.md |
| 79 | +├── RUNBOOK.md |
| 80 | +├── Makefile |
| 81 | +├── pyproject.toml |
| 82 | +└── requirements.txt |
| 83 | +``` |
| 84 | + |
| 85 | +## Data Files |
| 86 | + |
| 87 | +| File | Purpose | |
| 88 | +|---|---| |
| 89 | +| `data/raw/fix_messages.txt` | Raw simulated FIX execution-report messages. | |
| 90 | +| `data/input/internal_orders.csv` | Internal order records from a simulated order-management source. | |
| 91 | +| `data/generated/fix_execution_reports.csv` | Parsed structured output from the FIX parser. | |
| 92 | +| `data/input/broker_drop_copy.csv` | Broker/drop-copy-style execution data. | |
| 93 | +| `data/input/expected_order_states.csv` | Expected final order states used for status reconciliation. | |
| 94 | + |
| 95 | +## Reconciliation Controls |
| 96 | + |
| 97 | +The project generates separate CSV reports for: |
| 98 | + |
| 99 | +1. Missing execution report |
| 100 | +2. Missing broker drop copy |
| 101 | +3. Rejected order |
| 102 | +4. Stale open order |
| 103 | +5. Quantity mismatch |
| 104 | +6. Price mismatch |
| 105 | +7. Side mismatch |
| 106 | +8. Symbol mismatch |
| 107 | +9. Order status mismatch |
| 108 | +10. Duplicate ExecID |
| 109 | +11. Unexpected fill |
| 110 | +12. CumQty / LeavesQty inconsistency |
| 111 | + |
| 112 | +Reports are written to: |
| 113 | + |
| 114 | +```text |
| 115 | +reports/exceptions/ |
| 116 | +``` |
| 117 | + |
| 118 | +## Quickstart |
| 119 | + |
| 120 | +```bash |
| 121 | +python -m venv .venv |
| 122 | +source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1 |
| 123 | +python -m pip install -r requirements.txt |
| 124 | +make run |
| 125 | +``` |
| 126 | + |
| 127 | +Or run each step manually: |
| 128 | + |
| 129 | +```bash |
| 130 | +python -m fixops.generate_sample_data |
| 131 | +python -m fixops.fix_parser |
| 132 | +python -m fixops.load_db |
| 133 | +python -m fixops.reconcile |
| 134 | +``` |
| 135 | + |
| 136 | +Expected terminal output from reconciliation: |
| 137 | + |
| 138 | +```text |
| 139 | +Reconciliation complete. Exception report counts: |
| 140 | +- missing_execution_report: 1 |
| 141 | +- missing_broker_drop_copy: 1 |
| 142 | +- rejected_order: 1 |
| 143 | +- stale_open_order: 3 |
| 144 | +- quantity_mismatch: 1 |
| 145 | +- price_mismatch: 1 |
| 146 | +- side_mismatch: 1 |
| 147 | +- symbol_mismatch: 1 |
| 148 | +- order_status_mismatch: 2 |
| 149 | +- duplicate_exec_id: 1 |
| 150 | +- unexpected_fill: 1 |
| 151 | +- cumqty_leavesqty_inconsistency: 1 |
| 152 | +``` |
| 153 | + |
| 154 | +## Run Tests |
| 155 | + |
| 156 | +```bash |
| 157 | +pytest |
| 158 | +``` |
| 159 | + |
| 160 | +GitHub Actions runs tests on Python 3.10, 3.11, and 3.12 and also runs the end-to-end sample pipeline. |
| 161 | + |
| 162 | +## Example Exception Report |
| 163 | + |
| 164 | +`reports/exceptions/duplicate_exec_id.csv` |
| 165 | + |
| 166 | +| exec_id | duplicate_count | cl_ord_ids | exception_reason | |
| 167 | +|---|---:|---|---| |
| 168 | +| E-DUP-900 | 2 | ORD-1009, ORD-1009 | Same ExecID appears multiple times in the FIX execution-report stream | |
| 169 | + |
| 170 | +## How I Would Explain This in an Interview |
| 171 | + |
| 172 | +I built a simulated trade-support workflow that parses FIX-style execution reports, normalizes important tags like `ClOrdID`, `OrderID`, `ExecID`, `ExecType`, `OrdStatus`, `LastQty`, `LeavesQty`, `CumQty`, and `AvgPx`, and reconciles the parsed messages against internal order records, broker drop-copy records, and expected order states. |
| 173 | + |
| 174 | +The goal was to demonstrate how a trading operations or production support analyst investigates execution breaks: missing acknowledgements, rejected orders, stale open orders, broker mismatches, duplicate execution IDs, unexpected fills, and invalid order-state math. I intentionally used simulated data and lightweight tools—Python, pandas, SQLite, SQL, pytest, and GitHub Actions—so the logic is transparent and easy to validate. |
| 175 | + |
| 176 | +## Truthful Resume Bullets |
| 177 | + |
| 178 | +- Built a simulated FIX execution-report parser in Python to normalize tag-value messages into structured CSV records for order lifecycle analysis. |
| 179 | +- Designed SQLite reconciliation controls to compare internal orders, parsed FIX reports, broker drop-copy-style data, and expected order states. |
| 180 | +- Implemented exception detection for missing execution reports, missing broker drop copies, rejects, stale open orders, field mismatches, duplicate ExecIDs, unexpected fills, and invalid `CumQty` / `LeavesQty` states. |
| 181 | +- Created pytest coverage and GitHub Actions CI to validate parser behavior and run an end-to-end reconciliation pipeline. |
| 182 | +- Wrote operational runbook documentation explaining investigation steps, severity classification, and escalation logic for simulated trade-support breaks. |
| 183 | + |
| 184 | +## Suggested Commit Sequence |
| 185 | + |
| 186 | +1. `Initialize project structure and documentation` |
| 187 | +2. `Add simulated order and broker datasets` |
| 188 | +3. `Implement FIX execution report parser` |
| 189 | +4. `Add SQLite schema and database loader` |
| 190 | +5. `Implement reconciliation controls and exception exports` |
| 191 | +6. `Add parser and reconciliation tests` |
| 192 | +7. `Add GitHub Actions CI workflow` |
| 193 | +8. `Expand README with runbook, interview notes, and resume bullets` |
| 194 | + |
| 195 | +## Disclaimer |
| 196 | + |
| 197 | +This repository is a portfolio simulation. It does not connect to a live FIX session, broker, OMS, EMS, execution venue, hedge fund system, or trading database. |
0 commit comments