Selling Playing Cards
This week, I participated in a market-making competition with IMC. There were around fifty participants, yet I somehow managed to sneak into first place. I had a tremendous amount of fun playing this game, so I wanted to reflect on how those few hours went for me.
First market
The first round of trading went okay, placing reasonably well. The game was simple: six playing cards would be sampled randomly and sequentially, with replacement. The market to be made was on the sum of the ranks of those playing cards (Ace is 1, King is 13). The order book reached equilibrium very quickly, with lots of quotes offering 41 @ 43. (super tight!)
Close to the entirety of the money I made there was during information releases – when one of the hosts would reveal one more of the six cards.
Although the computations in play are pretty simple, I knew that in a room of 50 people interested in trading, there were probably a good number who were better than me at mental math. So instead of recomputing the EV properly, I would simply take the difference of the rank with 7 and incrementally move my quotes in the right direction, counting from that difference to zero. That allowed me to hit or lift the stale quotes faster than people could withdraw them.
In between information releases, I would read the SDK docs they published. I put Claude on it, and within a few minutes, I had a Python script that could connect to the exchange. I didn't have anything working in the first round, but that was alright, because everyone else was trading manually too.
Automating
The second round was a lot more fun, in my mind. The product was now something much less stable, whose theo was much harder to compute:
The script was now running, with the updated logic. I abstracted all of the math and theo computation to it. It used a simple watcher to parse what card was just revealed (there were a lot of typos or inconsistencies in the way cards were announced, probably intentionally). A mistake on my part originally caused it to have a ~2s latency due to fetching information that could be pre-fetched, but I quickly brought it down to ~0.1s. The script allowed me to manually type the new card if the watcher missed it, as a fallback.
At the same time, I was crafting a dashboard whose goal was to monitor my positions and let me manage the spread, which was a lot more vibes-based than the theo. The script would give me suggestions, but a lot of those decisions were in reaction to how other people were trading.

The following round had nothing special, besides more complicated rules on what the market would resolve to. It followed a similar format, with cards being drawn sequentially over several minutes.
All at once
For round 4, both markets we'd traded previously were tradable at once. That was very fun too – but after I'd told everyone I was using an algorithm (at the end of each round, the hosts would ask the podium how they did it, and I'd placed first in the prior rounds), you could tell the vibe in the room had shifted, with people trying to automate their trading the same way I did.
It was a very weird experience, because many of the 'retail' traders would often push the price in the wrong direction upon information releases, making my P&L dip and then soar again. There was a lot of herding behavior going on. It could probably have been monetized in some way. By that point, I was happy with my system. I spent a lot of my time having fun fine-tuning my interface, and monitoring my trades with little intervention needed. Much of my energy went into making sure there were no edge cases that would cause my system to go offline.
Martial arts
This one was very different. The hosts played a video of an Indian martial arts match, and opened three markets: points for TEAM_1, TEAM_2, and ABS(TEAM_1 - TEAM_2). The quotes across those markets were extremely inconsistent, and often very wrong. I suppose part of it was due to insiders who looked up the result of the game (which I thought of doing, but our regulators said it was illegal).
I noticed on the manual interface that someone's bot probably had a sign error, and I could get it to sell things very low and buy them very high. So, I did that for a while. I did not bother automating it, because I assumed it would go offline (or run out of money) fairly quickly, and couldn't risk others finding out about it, so I spent a few minutes slamming my trackpad to make the number go up. It felt like being part of some kind of experiment on gambling.
The main source of profit in this market, of course, was arbitrage, which is this very cool concept that can emerge when assets on different markets depend on the same thing. For instance, the ABS market should never have traded below , where and are the two teams' prices: whenever it did, there was an arbitrage. Unfortunately, the exposure of a given trader was limited, like in previous rounds, so I suspected my profits with this strategy would be capped, and decided against pursuing it. The exchange didn't understand that positions in different markets can cancel each other out.
As a fun fact: in French, the word for referee (including in martial arts) is arbitre! It's no coincidence: English borrowed arbitrage from French, where arbitrage is also what an arbitre does.
Conclusion
I really loved this game. I believe the main reason I placed so well was that I automated early, while making sure I understood my script and that my trades always matched what I would have done manually.
Some assets were harder to reason about, especially the product-of-sums one, but I trusted that the logic I'd built transferred. In hindsight, I spent a very large amount of time trying to build a neat and clean system that I could iterate on without taking it offline, that was nice to look at, and that made important actions and takeovers quick, especially from the keyboard.
If my utility had only been a function of the number on the screen, I probably would have spent less time on that, but it turned out to be very useful, and made the whole process much more enjoyable!