Background Info
Why develop a new platform
Before we started to develop roboquant, we looked at existing frameworks and platforms to see if these could fit the bill. However, for our use-cases none of them checked all the boxes that we required:
-
Deal with large volumes of data and run extensive back-tests
-
Trade assets in multiple currencies at the same time
-
Support many asset classes including cryptocurrencies
-
Solid live trading, including support for advanced order types to further reduce risk
-
Support for trading in multiple markets in different regions at the same time
Some of these might be unique to our situation, but since we believe that others might also benefit from the platform we decided to open source it and make it available for free to everyone.
Why use Kotlin
There are many computer languages available to choose from. After having developed several prototypes in different languages, we decided to go with Kotlin. Some main benefits being:
-
Easy to learn and use with excellent tooling support
-
It is very concise with almost no boilerplate code required
-
You can use it both within Jupyter Notebooks and traditional IDEs
-
Fast enough to even handle the largest data sets during back testing
-
Access to the huge Java ecosystem with libraries available for almost any task at hand
-
Excellent for building robust software, a necessity in our opinion when developing complex trading strategies and your own money at risk
One often heard question is Why didn’t you choose Python instead? Truth be told, we would have loved to be able to use Python. However, during the prototype phase of roboquant we discovered that the performance was lacking too much for our use-cases. In some scenarios the performance was over 100x slower. This was including using libraries like Numpy and Pandas and even some Cython to speedup processing. One problem is that in back testing many things cannot be vectorized and these fast libraries like Numpy are no longer a good match.
The main reason for this lackluster performance is not only that Python is an interpreted language, but also the fact that it is has a single threaded runtime that makes it difficult and inefficient to use all the cores found on modern CPU’s.
The good news is that if you really want to stick with Python, there are plenty of alternatives available. For example, you could have a look at Backtrader, pyalgotrade or zipline. But we recommend to give roboquant and Kotlin a try, and we are confident you will not regret that decision.
Interactive and traditional development
From the start we developed roboquant to be used either as a library included in your standalone application or interactively from a Jupyter Notebook. The various APIs have been designed so that they support both use-cases equally well.
Where some Kotlin/Java based applications require a lot of ceremony to implement even the simplest piece of functionality, roboquant it designed to remove most of that. Especially in a Jupyter notebook environment, it is very easy to get started. Because of this the API exposed by roboquant follows certain rules:
-
Minimize need for imports, for example don’t expose third party types if it can be avoided
-
Use sensible defaults for method parameters where possible
-
Use informative toString() implementations and explanatory exception messages
-
Provide overloaded convenience methods if it makes life easier for the user of the API
-
Use a flat package structure, so import statements are simple to remember
-
Leverage type inference where possible so no additional type info needs to be provided
Time handling
When testing strategies that trade simultaneously in multiple time-zones, like stocks in New York and London, it is key to have proper time management. Otherwise, you run the risk that your strategy performs very well but only because it can peep into the future due to faulty handling of time-zones.
Because of that, roboquant internally only uses the Java Instant type to represent a moment in time. So all time events can be easily compared without having to consider time zones.
When importing data, there is functionality to convert the data from timezone specific value towards the Instant type. When displaying time related information, it can be converted back the other way around if desired.
But the fact remains that all internal logic relies only on the Instant type in order to prevent timezone mistakes from happening.
Performance
With historic data sets growing, it is important that a strategy can still be quickly evaluated and tuned. If this develop-test cycle becomes too slow, it is nearly impossible to create high performing strategies.
Some of the measures that have been taken to ensure the highest performance possible:
-
Roboquant isn’t setup to be a financial ledger and in general trading applications don’t require this accuracy. The native Java Double type provides enough precision for most algo-trading purposes and there is no need to use (the much slower and more memory hungry) BigDecimal type. The area where roboquant uses more precise calculation is when dealing with order and position sizes.
-
The data Feed API supports data that is kept in-memory as well data that is stored on disk and only accessed when required. This allows for running back test where the test data doesn’t fit in memory or running back-tests on machines with limited memory. In fact roboquant can be used on a JVM with only 200 MB of heap allocated.
-
Much of the builtin functionality uses multithreading to speedup processing. For example the CSVFeed parses CSV files in parallel so directories with thousands of CSV files can be parsed in seconds.
-
Avoid (auto)boxing, so the JVM can access these variables directly. This means where possible use native types and not the wrapped ones. See background
-
Overall the latency is kept very low when processing a new event and generating orders. So it is feasible to create fast, low latency (milliseconds) trading strategies.
Reliability
Even more important than performance, is reliability when it comes to trading software. So roboquant takes several quality assurance measures in order to catch as many bugs as possible before the software is released:
-
Type and null checks where possible to leverage the compiler to identify possible mistakes
-
Good unit test suite with more than 300 unit tests that covers most of the code base (> 90%)
-
Using several code analysis tools: Detekt, Sonarcloud.io and CheckMarx (IntelliJ IDEA builtin).
-
Extensive error logging to alert possible issues, including data quality
-
Immutable data classes (when appropriate)
-
Assert/requires to validate input parameters
-
Proven third party libraries
Why an event-driven approach?
Event-driven software is a paradigm in which the flow of the application is determined by events such as user actions, sensor outputs, or message passing from other programs. In the case of algo-trading, these actions are often price actions that happen in the financial markets.
Event-driven algo-trading platforms provide several advantages over a vectorised approach:
-
Reuse - roboquant uses the same event-driven approach for all 4 stages of developing trading strategies, ensuring minimal friction when moving from one stage to the next.
-
Avoid Lookahead bias - With event-driven back-tests, it is unlikely that the strategy will actually peep into the future since at the time of making any decision in the code, the future data is not yet available. In fact, within roboquant the simulated broker is guaranteed to see pricing information before your strategy does.
-
Robustness - Live trading is by definition event-driven. So by using the same approach during back testing, it ensures you got have to address use-cases that otherwise wouldn’t show up until it is too late.
Although event-driven systems come with the above benefits, they traditionally suffer from two disadvantages over simpler vectorised systems:
-
They are more complex to implement and test. That is why using platform like roboquant makes a lot of sense, since much of the heavy lifting is done by the platform.
-
They can be slower to execute compared to a vectorised system. But by using Kotlin and a highly optimized execution engine, roboquant is actually faster than other algo-trading platforms.
To find out more about how Events and Actions are implemented in roboquant, check out the documentation on feeds.