Polybot is the most complex technical undertaking to date.

This blog post will dive into the specifics behind the latency, systems and data engineering approach as a whole - discussing the engineering rather than the monetary status. The strategy/approach to these markets is proprietary, and therefore will not be covered here.

A big battle throughout development was latency engineering and optimisation. It was naive to think at the start of this system that building in Rust would be enough to combat a lot of the latency issues other bots on the network deal with. Progress was made on this front through kernel scheduling, keeping a warm connection and logging every single element of the order path to isolate any bottlenecks, including a slight amendment to the SDK code the system uses to track latency for the full round-trip order path where possible. During earlier runs, Dublin -> London ping was roughly 10ms, and maker post bids sat around the 20-30ms mark round trip on the low end, with occasional tail spikes. Geolocation closer to Polymarket infrastructure through KYC application was considered; however, Dublin to London had not been a bottleneck for the system and, with ambiguity around price and geographic restrictions on prediction markets, it was not pursued.

The part that stands out most is the systems engineering of the bot. All key components are separated, with a coherent architectural design that has allowed expansion when it has been called upon, including daemons in the form of signal-instructed watchers, self-optimising scoring algorithms based on real-time market data and a full data ingestion pipeline including a simulator for testing different strategies against real market conditions. Strict Rust protocol rules were set out from the start and followed throughout, as stated explicitly below:

Non-Negotiable: After every module and before every phase transition:

  • cargo fmt --check passes
  • cargo clippy -- -D warnings passes with zero warnings
  • cargo test passes with zero failures
  • Zero .unwrap() in production code; .expect() with message permitted in init-only paths
  • Zero panic! in production paths
  • Zero String errors - all errors are BotError variants
  • Every public function has at least one test
  • No TODO, FIXME, or HACK left in code
  • No #[allow(unused)] or #[allow(dead_code)]
  • Ask yourself: would a staff engineer approve this in review? If the answer is anything other than yes, fix it now.

Rust Rules

  • All errors use the BotError enum. Add variants as needed, never stringify.
  • No floating-point == comparisons. Use >, < with epsilon, or MicroPrice integer representation.
  • All matches on enums are exhaustive. No wildcard _ on state machine or gate results.
  • No unsafe unless required for FFI (unlikely). Each block gets a // SAFETY: proof.
  • No pub on items that don't need it. Minimise API surface.
  • Functions over 40 lines get broken up. Each function does one thing.
  • Comments explain why, not what.
  • Pin exact dependency versions in Cargo.toml.

A system that touches real capital must be strict in regard to what is acceptable, and in a system that is pushing 100k lines (including data analysis scripts etc.), lack of diligence compounds in a way that makes life harder in the long run.

Finally, the data engineering that has driven this system from start to finish has been instrumental in deriving ideas and stress-testing strategies. A walk-forward approach has been taken when it comes to backtesting, with a focus on granularity of data. Early on, taking alpha from a data set that didn't have the correct granularity to warrant decision-making proved costly, and real capital was lost because of this; however, learning valuable lessons is worth the cost. Since then it has been paramount to treat a data set only as authoritative if it matches real market conditions AND if the thesis is derived based on walking through the data from the start to the finish. Results must be validated under strict and stringent conditions.

Alongside the philosophy that drove the data analysis came a greater understanding of Python as a tool. Python is viewed here as more of a tool for research and analysis due to its rich libraries, but in this system that's where its utility ends. Rust was chosen for the system because Python's built-in garbage collection and automatic memory allocation make it unsuitable as the primary driver for complex multi-threaded systems like this one. Python still has its place, and for data engineering and analysis it is probably the best language out there.

Polybot was another system where the majority of the syntax was implemented via AI tools such as Claude Code, including the Cortex system, further proving that AI is more than capable of being steered in the right direction under strict direction and guardrails to produce highly complex systems.

Polybot provides a foundation that could be expanded in future as more markets become available.

Development and operation are currently paused.