Cython
Here you will find guidance and tips for working on NautilusTrader using the Cython language. More information on Cython syntax and conventions can be found by reading the Cython docs.
What is Cython?
Cython is a compiled programming language that aims to be a superset of the Python programming language, designed to give C-like performance with code that is written mostly in Python with optional additional C-inspired syntax.
The project heavily utilizes Cython to provide static type safety and increased performance for Python through C extension modules. The vast majority of the production code is actually written in Cython, however the libraries can be accessed from both Python and Cython.
Function and method signatures
Ensure that all functions and methods returning void
or a primitive C type (such as bint
, int
, double
) include the except *
keyword in the signature.
This will ensure Python exceptions are not ignored, and instead are “bubbled up” to the caller as expected.
Debugging
PyCharm
Improved debugging support for Cython has remained a highly up-voted PyCharm feature for many years. Unfortunately, it's safe to assume that PyCharm will not be receiving first class support for Cython debugging https://youtrack.jetbrains.com/issue/PY-9476.
Cython Docs
The following recommendations are contained in the Cython docs: https://cython.readthedocs.io/en/latest/src/userguide/debugging.html
The summary is it involves manually running a specialized version of gdb
from the command line.
We don't recommend this workflow.
Tips
When debugging and seeking to understand a complex system such as NautilusTrader, it can be quite helpful to step through the code with a debugger. With this not being available for the Cython part of the codebase, there are a few things which can help:
- Ensure
LogLevel.DEBUG
is configured for the backtesting or live system you are debugging. This is available onBacktestEngineConfig(logging=LoggingConfig(log_level="DEBUG"))
orTradingNodeConfig(logging=LoggingConfig=log_level="DEBUG"))
. WithDEBUG
mode active you will see more granular and verbose log traces which could be what you need to understand the flow. - Beyond this, if you still require more granular visibility around a part of the system, we recommend some well-placed calls
to a components logger (normally
self._log.debug(f"HERE {variable}"
is enough).