RCFA Trading Competition · Rotman Interactive Trader · 2026 · Python
Tender arbitrage and market making
The RCFA competition ran two cases on the Rotman Interactive Trader, a simulated exchange. Speculation and directional bets were fined, so any edge had to come from structure, execution and risk control. Michael Xu and I built a separate algorithm for each case and placed 4th of 26 teams.
- Question
- When is a tender or a quote still worth taking after liquidity, inventory and fees?
- Built
- Tender-arbitrage and market-making algorithms trading against live order books.
- Tenders accepted on VWAP and liquidity rules, quotes skewed to hold inventory near flat, fees priced into every execution, and positions flattened automatically before the close.
- Result
- Fourth of 26 teams.Team entry with Michael Xu.
- Stack
- Python · REST APIs
The rules
Rankings came from aggregate results over several runs of each case. Prices followed a random walk, and the platform fined speculative trading, front-running, market-making behaviour in the tender case, and any position left open at the end of a session ($1 a share).
Avoiding fines was the first filter, so both algorithms were built around it.
Tender arbitrage
In the liability-trading case, clients offer large blocks of stock at a set price. The algorithm walks the live order book level by level and estimates how many shares it could unwind at a profit after fees and a 2.5-cent execution buffer. It accepts a tender only when total profit, profit per share and the share of the block the book can absorb all clear minimum thresholds, which tighten in the last two minutes.
A later version added one more check: if the first unwind slice, a quarter of the block at the top of the book, would lose money, the tender is declined. No new tenders are taken in the last 30 seconds.
Execution runs as a small state machine. With no inventory it places no orders at all. After an accepted tender it trades only in the direction that unwinds that block, and in the final window it cancels everything and flattens with market orders.
Market making
In the market-making case, the algorithm quotes both sides around the mid price and skews its quotes against adding to inventory: when long it bids lower, and when short it asks higher.
Spreads widen when the book is wide or recent volatility rises, and in those conditions it adds two more quote levels further out. That wider mode stays on for a few cycles once triggered, so the quotes don't flicker between modes.
Every order is sized against both gross and net position limits with a safety buffer, so it can't trigger a limit fine, and the book is flattened before the close. One variant also watched for a sustained price drift late in the session and, if inventory was on the wrong side of it, widened quotes, cut size and leaned toward flattening.
What we learned
Polling the API continuously beat fixed sleep intervals on latency. Flattening before the end of each session was critical, since end-of-session fines were large.
Waiting the full 30-second window before declining a tender sometimes paid off, because conditions could turn profitable. Keeping a separate algorithm for each case avoided mixing up the market-maker and liability-trader roles, and with rankings based on several runs, steady results mattered more than one big run.