-
\ No newline at end of file
diff --git a/docs/api_reference/conf.py b/docs/api_reference/conf.py
new file mode 100644
index 000000000000..e4a53e6a10cc
--- /dev/null
+++ b/docs/api_reference/conf.py
@@ -0,0 +1,51 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+
+import nautilus_trader
+
+
+# -- Project information -----------------------------------------------------
+project = "NautilusTrader"
+author = "Nautech Systems Pty Ltd."
+copyright = "2015-2024 Nautech Systems Pty Ltd"
+version = nautilus_trader.__version__
+
+# -- General configuration ---------------------------------------------------
+extensions = [
+ "myst_parser",
+ "sphinx.ext.autodoc",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.napoleon",
+ "sphinx_markdown_builder",
+ "sphinx_comments",
+]
+
+comments_config = {"hypothesis": False, "utterances": False}
+exclude_patterns = ["**.ipynb_checkpoints", ".DS_Store", "Thumbs.db", "_build"]
+source_suffix = [".rst", ".md"]
+
+myst_enable_extensions = [
+ "colon_fence",
+ "dollarmath",
+ "linkify",
+ "substitution",
+ "tasklist",
+]
+myst_url_schemes = ("mailto", "http", "https")
+suppress_warnings = ["myst.domains"]
+
+add_module_names = False
+todo_include_todos = False
+
+autosummary_generate = True
+autodoc_member_order = "bysource"
diff --git a/docs/api_reference/index.md b/docs/api_reference/index.md
index 4aafd5a097bd..3673b97a00f7 100644
--- a/docs/api_reference/index.md
+++ b/docs/api_reference/index.md
@@ -1,31 +1,5 @@
# Python API
-```{eval-rst}
-.. toctree::
- :maxdepth: 1
- :glob:
-
- accounting.md
- adapters/index.md
- analysis.md
- backtest.md
- cache.md
- common.md
- config.md
- core.md
- data.md
- execution.md
- indicators.md
- live.md
- model/index.md
- persistence.md
- portfolio.md
- risk.md
- serialization.md
- system.md
- trading.md
-```
-
Welcome to the Python API reference for NautilusTrader!
The API reference provides detailed technical documentation for the NautilusTrader framework,
@@ -37,11 +11,7 @@ Please note that there are separate references for different versions of Nautilu
- **Latest:** This API reference is built from the head of the `master` branch and represents the latest stable release.
- **Nightly:** This API reference is built from the head of the `nightly` branch and represents bleeding edge and experimental changes/features currently in development.
-You can select the desired API reference from the **Versions** top right drop down menu.
-
-```{note}
-If you select an item from the top level navigation, this will take you to the **Latest** API reference.
-```
+You can select the desired API reference from the **Versions** top left drop down menu.
Use the right navigation sidebar to explore the available modules and their contents.
You can click on any item to view its detailed documentation, including parameter descriptions, and return value explanations.
diff --git a/docs/concepts/adapters.md b/docs/concepts/adapters.md
index b9fa99276735..6bd8ac4ec11b 100644
--- a/docs/concepts/adapters.md
+++ b/docs/concepts/adapters.md
@@ -87,7 +87,7 @@ In this particular case, the `Actor` implements a separate method `request_instr
On the actor/strategy:
-```cython
+```python
# nautilus_trader/common/actor.pyx
cpdef void request_instrument(self, InstrumentId instrument_id, ClientId client_id=None):
diff --git a/docs/concepts/advanced/actors.md b/docs/concepts/advanced/actors.md
index 069fd3934c21..c5c84b5faf35 100644
--- a/docs/concepts/advanced/actors.md
+++ b/docs/concepts/advanced/actors.md
@@ -1,7 +1,7 @@
# Actors
The `Strategy` class actually inherits from `Actor`, and additionally provides order management
-methods on top. This means everything discussed in the [Strategies](../../concepts/strategies.md) guide
+methods on top. This means everything discussed in the [Strategies](../strategies.md) guide
also applies to actors.
This doc is an evolving work in progress and will continue to describe actors more fully…
diff --git a/docs/concepts/advanced/advanced_orders.md b/docs/concepts/advanced/advanced_orders.md
index ba4238497d45..b7c815d4bc9f 100644
--- a/docs/concepts/advanced/advanced_orders.md
+++ b/docs/concepts/advanced/advanced_orders.md
@@ -15,9 +15,9 @@ specific exchange they are being routed to.
- `OCO` are linked orders with `linked_order_ids` which are contingent on the other(s) (one-cancels-other when triggered).
- `OUO` are linked orders with `linked_order_ids` which are contingent on the other(s) (one-updates-other when triggered or modified).
-```{note}
+:::info
These contingency types relate to ContingencyType FIX tag <1385> https://www.onixs.biz/fix-dictionary/5.0.sp2/tagnum_1385.html.
-```
+:::
### *'One Triggers the Other'* (OTO)
An OTO orders involves two orders—a parent order and a child order. The parent order is a live
@@ -46,10 +46,10 @@ When the parent order is executed, the two child orders are also placed in the m
If the market moves in favor of the trade, the take-profit order will be filled, closing the position and locking in profits.
If the market moves against the trade, the stop-loss order will be filled, closing the position and limiting losses.
-Bracket orders can be created using the [OrderFactory](https://docs.nautilustrader.io/api_reference/common.html#module-nautilus_trader.common.factories) class in the Nautilus Trader API.
+Bracket orders can be created using the [OrderFactory](https://nautilustrader.io/docs/api_reference/common.html#module-nautilus_trader.common.factories) class in the Nautilus Trader API.
This allows for easy and efficient creation of bracket orders, with different order types, parameters and instructions.
-```{warning}
-You should be aware of the margin requirements of positions, as bracketing a position will consume
+:::warning
+You should be aware of the margin requirements of positions, as bracketing a position will consume
more order margin.
-```
+:::
diff --git a/docs/concepts/advanced/custom_data.md b/docs/concepts/advanced/custom_data.md
index 361d9456e8c8..a40c9ea3c49f 100644
--- a/docs/concepts/advanced/custom_data.md
+++ b/docs/concepts/advanced/custom_data.md
@@ -6,9 +6,9 @@ guide covers some possible use cases for this functionality.
It's possible to create custom data types within the Nautilus system. First you
will need to define your data by subclassing from `Data`.
-```{note}
+:::info
As `Data` holds no state, it is not strictly necessary to call `super().__init__()`.
-```
+:::
```python
from nautilus_trader.core.data import Data
@@ -71,10 +71,10 @@ The recommended approach to satisfy the contract is to assign `ts_event` and `ts
to backing fields, and then implement the `@property` for each as shown above
(for completeness, the docstrings are copied from the `Data` base class).
-```{note}
-These timestamps are what allow Nautilus to correctly order data streams for backtests
+:::info
+These timestamps are what allow Nautilus to correctly order data streams for backtests
by monotonically increasing `ts_init` UNIX nanoseconds.
-```
+:::
We can now work with this data type for backtesting and live trading. For instance,
we could now create an adapter which is able to parse and create objects of this
diff --git a/docs/concepts/advanced/emulated_orders.md b/docs/concepts/advanced/emulated_orders.md
index 29af99176163..4132b411cb33 100644
--- a/docs/concepts/advanced/emulated_orders.md
+++ b/docs/concepts/advanced/emulated_orders.md
@@ -5,9 +5,9 @@ of whether the type is supported on a trading venue. The logic and code paths fo
order emulation are exactly the same for all environment contexts (`backtest`, `sandbox`, `live`)
and utilize a common `OrderEmulator` component.
-```{note}
+:::info
There is no limitation on the number of emulated orders you can have per running instance.
-```
+:::
## Submitting for emulation
The only requirement to emulate an order is to pass a `TriggerType` to the `emulation_trigger`
@@ -21,9 +21,9 @@ Emulated orders are subject to the same risk controls as 'regular' orders, and c
modified and canceled by a trading strategy in the normal way. They will also be included
when canceling all orders.
-```{note}
+:::info
An emulated order will retain its original client order ID throughout its entire life cycle, making it easy to query through the cache.
-```
+:::
## Life cycle
An emulated order will progress through the following stages:
@@ -78,11 +78,11 @@ You can also query order objects directly:
If either of these return `False`, then the order has been _released_ from the
`OrderEmulator`, and so is no longer considered an emulated order.
-```{warning}
+:::warning
It's not advised to hold a local reference to an emulated order, as the order
object will be transformed when/if the emulated order is _released_. You should rely
on the `Cache` which is made for the job.
-```
+:::
## Persisted emulated orders
If a running system either crashes or shuts down with active emulated orders, then
diff --git a/docs/concepts/advanced/index.md b/docs/concepts/advanced/index.md
index fd2bdd4e71bb..2350515e0ecd 100644
--- a/docs/concepts/advanced/index.md
+++ b/docs/concepts/advanced/index.md
@@ -8,21 +8,6 @@ features and functionality of the platform.
You can choose different subjects on the left, which are generally ordered from
highest to lowest level (although they are self-contained and can be read in any order).
-```{eval-rst}
-.. toctree::
- :maxdepth: 2
- :glob:
- :titlesonly:
- :hidden:
-
- actors.md
- custom_data.md
- advanced_orders.md
- emulated_orders.md
- synthetic_instruments.md
- portfolio_statistics.md
-```
-
## Guides
Explore more advanced concepts of NautilusTrader through these guides:
diff --git a/docs/concepts/advanced/portfolio_statistics.md b/docs/concepts/advanced/portfolio_statistics.md
index 7a88e032ba4b..cfced0ea3a33 100644
--- a/docs/concepts/advanced/portfolio_statistics.md
+++ b/docs/concepts/advanced/portfolio_statistics.md
@@ -47,11 +47,11 @@ stat = WinRate()
engine.portfolio.analyzer.register_statistic(stat)
```
-```{tip}
+:::tip
Ensure your statistic is robust to degenerate inputs such as ``None``, empty series, or insufficient data.
The expectation is that you would then return ``None``, NaN or a reasonable default.
-```
+:::
## Backtest Analysis
Following a backtest run a performance analysis will be carried out by passing realized PnLs, returns, positions and orders data to each registered
diff --git a/docs/concepts/advanced/synthetic_instruments.md b/docs/concepts/advanced/synthetic_instruments.md
index 496bbf9313b4..abdbb69bf098 100644
--- a/docs/concepts/advanced/synthetic_instruments.md
+++ b/docs/concepts/advanced/synthetic_instruments.md
@@ -14,9 +14,9 @@ useful metrics based on its component instruments.
In the future, we plan to support order management for synthetic instruments, which would involve
trading their component instruments based on the behavior of the synthetic instrument.
-```{note}
-Note that the venue for a synthetic instrument is always designated as `'SYNTH'`.
-```
+:::info
+The venue for a synthetic instrument is always designated as `'SYNTH'`.
+:::
## Formula
A synthetic instrument is composed of a combination of two or more component instruments (which
@@ -27,9 +27,9 @@ from the incoming component instrument prices.
See the `evalexpr` documentation for a full description of available features, operators and precedence.
-```{tip}
+:::tip
Before defining a new synthetic instrument, ensure that all component instruments are already defined and exist in the cache.
-```
+:::
## Subscribing
The following example demonstrates the creation of a new synthetic instrument with an actor/strategy.
@@ -66,9 +66,9 @@ self.add_synthetic(synthetic)
self.subscribe_quote_ticks(self._synthetic_id)
```
-```{note}
+:::note
The `instrument_id` for the synthetic instrument in the above example will be structured as `{symbol}.{SYNTH}`, resulting in `'BTC-ETH:BINANCE.SYNTH'`.
-```
+:::
## Updating formulas
It's also possible to update a synthetic instrument formulas at any time. The following example
@@ -110,5 +110,5 @@ Considerable effort has been made to validate inputs, including the derivation f
synthetic instruments. Despite this, caution is advised as invalid or erroneous inputs may lead to
undefined behavior.
-Refer to the `SyntheticInstrument` [API reference](https://docs.nautilustrader.io/api_reference/model/instruments.html#nautilus_trader.model.instruments.synthetic.SyntheticInstrument)
+Refer to the `SyntheticInstrument` [API reference](https://nautilustrader.io/docs/api_reference/model/instruments.html#nautilus_trader.model.instruments.synthetic.SyntheticInstrument)
for a detailed understanding of input requirements and potential exceptions.
diff --git a/docs/concepts/architecture.md b/docs/concepts/architecture.md
index fb163f547d2e..2998a153d4cb 100644
--- a/docs/concepts/architecture.md
+++ b/docs/concepts/architecture.md
@@ -14,6 +14,7 @@ of NautilusTrader, this exposition covers:
- And finally, the **Implementation Techniques** that are crucial for performance, reliability, and robustness
## Design philosophy
+
The major architectural techniques and design patterns employed by NautilusTrader are:
- [Domain driven design (DDD)](https://en.wikipedia.org/wiki/Domain-driven_design)
- [Event-driven architecture](https://en.wikipedia.org/wiki/Event-driven_programming)
@@ -24,6 +25,7 @@ The major architectural techniques and design patterns employed by NautilusTrade
These techniques have been utilized to assist in achieving certain architectural quality attributes.
### Quality attributes
+
Architectural decisions are often a trade-off between competing priorities. The
below is a list of some of the most important quality attributes which are considered
when making design and architectural decisions, roughly in order of 'weighting'.
@@ -41,19 +43,21 @@ The NautilusTrader codebase is actually both a framework for composing trading
systems, and a set of default system implementations which can operate in various
environment contexts.
-```{note}
+:::note
Throughout the documentation, the term _"Nautilus system boundary"_ refers to operations within
the runtime of a single Nautilus node (also known as a "trader instance").
-```
+:::
![Architecture](https://github.com/nautechsystems/nautilus_trader/blob/develop/docs/_images/architecture-overview.png?raw=true "architecture")
### Environment contexts
+
- `Backtest` - Historical data with simulated venues
- `Sandbox` - Real-time data with simulated venues
- `Live` - Real-time data with live venues (paper trading or real accounts)
### Common core
+
The platform has been designed to share as much common code between backtest, sandbox and live trading systems as possible.
This is formalized in the `system` subpackage, where you will find the `NautilusKernel` class,
providing a common core system 'kernel'.
@@ -62,6 +66,7 @@ A _ports and adapters_ architectural style allows modular components to be 'plug
core system, providing many hooks for user defined / custom component implementations.
### Messaging
+
To facilitate modularity and loose coupling, an extremely efficient `MessageBus` passes messages (data, commands and events) between components.
From a high level architectural view, it's important to understand that the platform has been designed to run efficiently
@@ -72,17 +77,19 @@ didn't actually result in improved performance.
When considering the logic of how your algo trading will work within the system boundary, you can expect each component to consume messages
in a deterministic synchronous way (_similar_ to the [actor model](https://en.wikipedia.org/wiki/Actor_model)).
-```{note}
+:::note
Of interest is the LMAX exchange architecture, which achieves award winning performance running on
a single thread. You can read about their _disruptor_ pattern based architecture in [this interesting article](https://martinfowler.com/articles/lmax.html) by Martin Fowler.
-```
+:::
## Framework organization
+
The codebase is organized with a layering of abstraction levels, and generally
grouped into logical subpackages of cohesive concepts. You can navigate to the documentation
for each of these subpackages from the left nav menu.
### Core / low-Level
+
- `core` - constants, functions and low-level components used throughout the framework
- `common` - common parts for assembling the frameworks various components
- `network` - low-level base components for networking clients
@@ -90,6 +97,7 @@ for each of these subpackages from the left nav menu.
- `model` - defines a rich trading domain model
### Components
+
- `accounting` - different account types and account management machinery
- `adapters` - integration adapters for the platform including brokers and exchanges
- `analysis` - components relating to trading performance statistics and analysis
@@ -105,22 +113,26 @@ for each of these subpackages from the left nav menu.
- `trading` - trading domain specific components and tooling
### System implementations
+
- `backtest` - backtesting componentry as well as a backtest engine and node implementations
- `live` - live engine and client implementations as well as a node for live trading
- `system` - the core system kernel common between `backtest`, `sandbox`, `live` environment contexts
## Code structure
+
The foundation of the codebase is the `nautilus_core` directory, containing a collection of core Rust crates including a C foreign function interface (FFI) generated by `cbindgen`.
The bulk of the production code resides in the `nautilus_trader` directory, which contains a collection of Python/Cython subpackages and modules.
Python bindings for the Rust core are provided by statically linking the Rust libraries to the C extension modules generated by Cython at compile time (effectively extending the CPython API).
-```{note}
+:::note
Both Rust and Cython are build dependencies. The binary wheels produced from a build do not themselves require
Rust or Cython to be installed at runtime.
-```
+:::
+
### Dependency flow
+
```
┌─────────────────────────┐
│ │
@@ -148,6 +160,7 @@ Rust or Cython to be installed at runtime.
```
### Type safety
+
The design of the platform holds software correctness and safety at the highest level.
The Rust codebase in `nautilus_core` is always type safe and memory safe as guaranteed by the `rustc` compiler,
@@ -155,24 +168,26 @@ and so is _correct by construction_ (unless explicitly marked `unsafe`, see the
Cython provides type safety at the C level at both compile time, and runtime:
-```{note}
-If you pass an argument with an invalid type to a Cython implemented module with typed parameters,
-then you will receive a ``TypeError`` at runtime.
+:::info
+If you pass an argument with an invalid type to a Cython implemented module with typed parameters,
+then you will receive a `TypeError` at runtime.
+:::
If a function or methods parameter is not explicitly typed as allowing
``None``, then you can assume you will receive a `ValueError` when passing ``None``
as an argument at runtime.
```
-```{warning}
+:::warning
The above exceptions are not explicitly documented, as this would bloat the docstrings significantly.
-```
+:::
### Errors and exceptions
+
Every attempt has been made to accurately document the possible exceptions which
can be raised from NautilusTrader code, and the conditions which will trigger them.
-```{warning}
+:::warning
There may be other undocumented exceptions which can be raised by Pythons standard
library, or from third party library dependencies.
-```
+:::
diff --git a/docs/concepts/backtesting.md b/docs/concepts/backtesting.md
index edbc28fdb046..cdddffa611ca 100644
--- a/docs/concepts/backtesting.md
+++ b/docs/concepts/backtesting.md
@@ -10,7 +10,7 @@ detailed results and performance metrics for in-depth analysis.
It's paramount to recognize that NautilusTrader offers two distinct API levels for setting up and
conducting backtests: **high-level** and **low-level**.
-## Choosing an API level:
+## Choosing an API level
Consider the **low-level** API when:
@@ -25,7 +25,7 @@ Consider the **high-level** API when:
- You want to harness the performance capabilities and convenience of the `ParquetDataCatalog` and persist your data in the Nautilus-specific Parquet format
- You value the flexibility and advanced functionalities offered by passing configuration objects, which can define diverse backtest runs across many engines at once
-## Low-level API:
+## Low-level API
The low-level API revolves around a single `BacktestEngine`, with inputs initialized and added 'manually' via a Python script.
An instantiated `BacktestEngine` can accept:
@@ -34,7 +34,7 @@ An instantiated `BacktestEngine` can accept:
- Multiple actors (manually initialized and added)
- Multiple execution algorithms (manually initialized and added)
-## High-level API:
+## High-level API
The high-level API revolves around a single `BacktestNode`, which will orchestrate the management
of individual `BacktestEngine`s, each defined by a `BacktestRunConfig`.
diff --git a/docs/concepts/data.md b/docs/concepts/data.md
index c53d751cde3c..cddd69ef1331 100644
--- a/docs/concepts/data.md
+++ b/docs/concepts/data.md
@@ -52,13 +52,13 @@ Currently there exists:
- `TradeTickDataWrangler`
- `BarDataWrangler`
-```{warning}
+:::warning
At the risk of causing confusion, there are also a growing number of DataWrangler v2 components, which will take a `pd.DataFrame` typically
with a different fixed width Nautilus arrow v2 schema, and output pyo3 Nautilus objects which are only compatible with the new version
of the Nautilus core, currently in development.
**These pyo3 provided data objects are not compatible where the legacy Cython objects are currently used (adding directly to a `BacktestEngine` etc).**
-```
+:::
### Transformation pipeline
@@ -118,11 +118,12 @@ We have chosen Parquet as the storage format for the following reasons:
The Arrow schemas used for the Parquet format are either single sourced in the core `persistence` Rust crate, or available
from the `/serialization/arrow/schema.py` module.
-```{note}
+:::note
2023-10-14: The current plan is to eventually phase out the Python schemas module, so that all schemas are single sourced in the Rust core.
-```
+:::
### Initializing
+
The data catalog can be initialized from a `NAUTILUS_PATH` environment variable, or by explicitly passing in a path like object.
The following example shows how to initialize a data catalog where there is pre-existing data already written to disk at the given path.
@@ -139,6 +140,7 @@ catalog = ParquetDataCatalog(CATALOG_PATH)
```
### Writing data
+
New data can be stored in the catalog, which is effectively writing the given data to disk in the Nautilus-specific Parquet format.
All Nautilus built-in `Data` objects are supported, and any data which inherits from `Data` can be written.
@@ -148,6 +150,7 @@ catalog.write_data(deltas)
```
### Basename template
+
Nautilus makes no assumptions about how data may be partitioned between files for a particular
data type and instrument ID.
@@ -161,12 +164,12 @@ and assuming `"date"` is a provided or derivable field, could result in a filena
If not provided, a default naming scheme will be applied. This parameter should be specified as a
keyword argument, like `write_data(data, basename_template="{date}")`.
-```{warning}
+:::warning
Any existing data which already exists under a filename will be overwritten.
If a `basename_template` is not provided, then its very likely existing data for the data type and instrument ID will
be overwritten. To prevent data loss, ensure that the `basename_template` (or the default naming scheme)
generates unique filenames for different data sets.
-```
+:::
Rust Arrow schema implementations are available for the follow data types (enhanced performance):
- `OrderBookDelta`
@@ -188,6 +191,7 @@ deltas = catalog.order_book_deltas(instrument_ids=[instrument.id.value], start=s
```
### Streaming data
+
When running backtests in streaming mode with a `BacktestNode`, the data catalog can be used to stream the data in batches.
The following example shows how to achieve this by initializing a `BacktestDataConfig` configuration object:
@@ -206,4 +210,4 @@ data_config = BacktestDataConfig(
```
This configuration object can then be passed into a `BacktestRunConfig` and then in turn passed into a `BacktestNode` as part of a run.
-See the [Backtest (high-level API)](../tutorials/backtest_high_level.md) tutorial for more details.
+See the [Backtest (high-level API)](../getting_started/backtest_high_level.md) tutorial for more details.
diff --git a/docs/concepts/execution.md b/docs/concepts/execution.md
index 2dcf43c6e44d..fff62ba5f1c6 100644
--- a/docs/concepts/execution.md
+++ b/docs/concepts/execution.md
@@ -37,6 +37,7 @@ The general execution flow looks like the following (each arrow indicates moveme
The `OrderEmulator` and `ExecAlgorithm`(s) components are optional in the flow, depending on
individual order parameters (as explained below).
+This diagram illustrates message flow (commands and events) across the Nautilus execution components.
```
┌───────────────────┐
│ │
@@ -65,7 +66,6 @@ individual order parameters (as explained below).
│ │
└───────────────────┘
-- This diagram illustrates message flow (commands and events) across the Nautilus execution components.
```
## Execution algorithms
@@ -74,6 +74,7 @@ The platform supports customized execution algorithm components and provides som
algorithms, such as the Time-Weighted Average Price (TWAP) algorithm.
### TWAP (Time-Weighted Average Price)
+
The TWAP execution algorithm aims to execute orders by evenly spreading them over a specified
time horizon. The algorithm receives a primary order representing the total size and direction
then splits this by spawning smaller child orders, which are then executed at regular intervals
@@ -126,11 +127,11 @@ Alternatively, you can specify these parameters dynamically per order, determini
actual market conditions. In this case, the strategy configuration parameters could be provided to
an execution model which determines the horizon and interval.
-```{note}
-There is no limit to the number of execution algorithm parameters you can create. The parameters
-just need to be a dictionary with string keys and primitive values (values that can be serialized
+:::info
+There is no limit to the number of execution algorithm parameters you can create. The parameters
+just need to be a dictionary with string keys and primitive values (values that can be serialized
over the wire, such as ints, floats, and strings).
-```
+:::
### Writing execution algorithms
@@ -149,11 +150,11 @@ Once an execution algorithm is registered, and the system is running, it will re
messages bus which are addressed to its `ExecAlgorithmId` via the `exec_algorithm_id` order parameter.
The order may also carry the `exec_algorithm_params` being a `dict[str, Any]`.
-```{warning}
+:::warning
Because of the flexibility of the `exec_algorithm_params` dictionary. It's important to thoroughly
validate all of the key value pairs for correct operation of the algorithm (for starters that the
dictionary is not ``None`` and all necessary parameters actually exist).
-```
+:::
Received orders will arrive via the following `on_order(...)` method. These received orders are
know as "primary" (original) orders when being handled by an execution algorithm.
@@ -184,16 +185,16 @@ When the algorithm is ready to spawn a secondary order, it can use one of the fo
- `spawn_market_to_limit(...)` (spawns a `MARKET_TO_LIMIT` order)
- `spawn_limit(...)` (spawns a `LIMIT` order)
-```{note}
+:::note
Additional order types will be implemented in future versions, as the need arises.
-```
+:::
Each of these methods takes the primary (original) `Order` as the first argument. The primary order
quantity will be reduced by the `quantity` passed in (becoming the spawned orders quantity).
-```{warning}
+:::warning
There must be enough primary order quantity remaining (this is validated).
-```
+:::
Once the desired number of secondary orders have been spawned, and the execution routine is over,
the intention is that the algorithm will then finally send the primary (original) order.
@@ -213,26 +214,25 @@ derives from this original identifier with the following convention:
e.g. `O-20230404-001-000-E1` (for the first spawned order)
-```{note}
+:::note
The "primary" and "secondary" / "spawn" terminology was specifically chosen to avoid conflict
or confusion with the "parent" and "child" contingent orders terminology (an execution algorithm may also deal with contingent orders).
-```
+:::
### Managing execution algorithm orders
The `Cache` provides several methods to aid in managing (keeping track of) the activity of
an execution algorithm:
-```cython
-
-cpdef list orders_for_exec_algorithm(
+```python
+def orders_for_exec_algorithm(
self,
- ExecAlgorithmId exec_algorithm_id,
- Venue venue = None,
- InstrumentId instrument_id = None,
- StrategyId strategy_id = None,
- OrderSide side = OrderSide.NO_ORDER_SIDE,
-):
+ exec_algorithm_id: ExecAlgorithmId,
+ venue: Venue | None = None,
+ instrument_id: InstrumentId | None = None,
+ strategy_id: StrategyId | None = None,
+ side: OrderSide = OrderSide.NO_ORDER_SIDE,
+) -> list[Order]:
"""
Return all execution algorithm orders for the given query filters.
@@ -259,7 +259,7 @@ cpdef list orders_for_exec_algorithm(
As well as more specifically querying the orders for a certain execution series/spawn:
```python
-cpdef list orders_for_exec_spawn(self, ClientOrderId exec_spawn_id):
+def orders_for_exec_spawn(self, exec_spawn_id: ClientOrderId) -> list[Order]:
"""
Return all orders for the given execution spawn ID (if found).
diff --git a/docs/concepts/index.md b/docs/concepts/index.md
index 4ed16103fe45..653680596d6f 100644
--- a/docs/concepts/index.md
+++ b/docs/concepts/index.md
@@ -1,81 +1,72 @@
# Concepts
-```{eval-rst}
-.. toctree::
- :maxdepth: 1
- :glob:
- :titlesonly:
- :hidden:
-
- overview.md
- architecture.md
- strategies.md
- instruments.md
- orders.md
- execution.md
- backtesting.md
- data.md
- adapters.md
- logging.md
- message_bus.md
- advanced/index.md
-```
-
Welcome to NautilusTrader!
Explore the foundational concepts of NautilusTrader through the following guides.
## [Overview](overview.md)
+
The **Overview** guide covers the main use cases for the platform.
## [Architecture](architecture.md)
+
The **Architecture** guide dives deep into the foundational principles, structures, and designs that underpin
the platform. Whether you're a developer, system architect, or just curious about the inner workings
of NautilusTrader.
## [Strategies](strategies.md)
+
The heart of the NautilusTrader user experience is in writing and working with
trading strategies. The **Strategies** guide covers how to implement trading strategies for the platform.
## [Instruments](instruments.md)
+
The `Instrument` base class represents the core specification for any tradable asset/contract.
## [Orders](orders.md)
+
The **Orders** guide provides more details about the available order types for the platform, along with
the execution instructions supported for each.
## [Execution](execution.md)
+
NautilusTrader can handle trade execution and order management for multiple strategies and venues
simultaneously (per instance). Several interacting components are involved in execution, making it
crucial to understand the possible flows of execution messages (commands and events).
## [Backtesting](backtesting.md)
+
Backtesting with NautilusTrader is a methodical simulation process that replicates trading
activities using a specific system implementation.
## [Data](data.md)
+
The NautilusTrader platform defines a range of built-in data types crafted specifically to represent
a trading domain
## [Adapters](adapters.md)
+
The NautilusTrader design allows for integrating data providers and/or trading venues
through adapter implementations, these can be found in the top level `adapters` subpackage.
## [Logging](logging.md)
+
The platform provides logging for both backtesting and live trading using a high-performance logger implemented in Rust.
## [Message Bus](message_bus.md)
+
The heart of the communication channels between components, providing decoupled messaging patterns such as
point-to-point, publish/subscribe and request/response.
## [Advanced](advanced/index.md)
+
Here you will find more detailed documentation and examples covering the more advanced
features and functionality of the platform.
-```{note}
+:::note
The [API Reference](../api_reference/index.md) documentation should be considered the source of truth
for the platform. If there are any discrepancies between concepts described here and the API Reference,
then the API Reference should be considered the correct information. We are working to ensure that
concepts stay up-to-date with the API Reference and will be introducing doc tests in the near future
to help with this.
-```
+:::
diff --git a/docs/concepts/instruments.md b/docs/concepts/instruments.md
index c514fa851546..c7eb86bcb32c 100644
--- a/docs/concepts/instruments.md
+++ b/docs/concepts/instruments.md
@@ -11,18 +11,20 @@ currently a number of subclasses representing a range of _asset classes_ and _in
- `BettingInstrument` (Sports, gaming, or other betting)
## Symbology
+
All instruments should have a unique `InstrumentId`, which is made up of both the native symbol, and venue ID, separated by a period.
For example, on the Binance Futures crypto exchange, the Ethereum Perpetual Futures Contract has the instrument ID `ETHUSDT-PERP.BINANCE`.
All native symbols _should_ be unique for a venue (this is not always the case e.g. Binance share native symbols between spot and futures markets),
and the `{symbol.venue}` combination _must_ be unique for a Nautilus system.
-```{warning}
+:::warning
The correct instrument must be matched to a market dataset such as ticks or order book data for logically sound operation.
An incorrectly specified instrument may truncate data or otherwise produce surprising results.
-```
+:::
## Backtesting
+
Generic test instruments can be instantiated through the `TestInstrumentProvider`:
```python
@@ -54,11 +56,13 @@ instrument = Instrument(...) # <-- provide all necessary parameters
See the full instrument [API Reference](../api_reference/model/instruments.md).
## Live trading
+
Live integration adapters have defined `InstrumentProvider` classes which work in an automated way to cache the
latest instrument definitions for the exchange. Refer to a particular `Instrument`
object by pass the matching `InstrumentId` to data and execution related methods, and classes which require one.
## Finding instruments
+
Since the same actor/strategy classes can be used for both backtest and live trading, you can
get instruments in exactly the same way through the central cache:
@@ -92,17 +96,19 @@ def on_instrument(instrument: Instrument) -> None:
pass
```
-## Precisions and Increments
+## Precisions and increments
+
The instrument objects are a convenient way to organize the specification of an
instrument through _read-only_ properties. Correct price and quantity precisions, as well as
minimum price and size increments, multipliers and standard lot sizes, are available.
-```{note}
+:::note
Most of these limits are checked by the Nautilus `RiskEngine`, otherwise invalid
values for prices and quantities _can_ result in the exchange rejecting orders.
-```
+:::
## Limits
+
Certain value limits are optional for instruments and can be `None`, these are exchange
dependent and can include:
- `max_quantity` (maximum quantity for a single order)
@@ -112,12 +118,13 @@ dependent and can include:
- `max_price` (maximum valid quote or order price)
- `min_price` (minimum valid quote or order price)
-```{note}
+:::note
Most of these limits are checked by the Nautilus `RiskEngine`, otherwise exceeding
published limits _can_ result in the exchange rejecting orders.
-```
+:::
+
+## Prices and quantities
-## Prices and Quantities
Instrument objects also offer a convenient way to create correct prices
and quantities based on given values.
@@ -128,12 +135,12 @@ price = instrument.make_price(0.90500)
quantity = instrument.make_qty(150)
```
-```{tip}
+:::tip
The above is the recommended method for creating valid prices and quantities,
such as when passing them to the order factory to create an order.
-```
+:::
-## Margins and Fees
+## Margins and fees
The current initial and maintenance margin requirements, as well as any trading
fees are also available from an instrument:
- `margin_init` (initial/order margin rate)
@@ -141,7 +148,7 @@ fees are also available from an instrument:
- `maker_fee` (the fee percentage applied to notional order values when providing liquidity)
- `taker_fee` (the fee percentage applied to notional order values when demanding liquidity)
-## Additional Info
+## Additional info
The raw instrument definition as provided by the exchange (typically from JSON serialized data) is also
included as a generic Python dictionary. This is to retain all information
which is not necessarily part of the unified Nautilus API, and is available to the user
diff --git a/docs/concepts/logging.md b/docs/concepts/logging.md
index 5f1ad5ad8f48..a97e4da1e3d7 100644
--- a/docs/concepts/logging.md
+++ b/docs/concepts/logging.md
@@ -24,9 +24,9 @@ Log level (`LogLevel`) values include (and generally match Rusts `tracing` level
- `WARNING` or `WARN`
- `ERROR`
-```{note}
+:::info
See the `LoggingConfig` [API Reference](../api_reference/config.md) for further details.
-```
+:::
Logging can be configured in the following ways:
- Minimum `LogLevel` for stdout/stderr
@@ -113,10 +113,10 @@ log_guard = init_logging()
logger = Logger("MyLogger")
```
-```{note}
+:::info
See the `init_logging` [API Reference](../api_reference/common) for further details.
-```
+:::
-```{warning}
+:::warning
Only one logging system can be initialized per process with an `init_logging` call, and the `LogGuard` which is returned must be kept alive for the lifetime of the program.
-```
+:::
diff --git a/docs/concepts/message_bus.md b/docs/concepts/message_bus.md
index 60dc5cd9e205..216d9186335d 100644
--- a/docs/concepts/message_bus.md
+++ b/docs/concepts/message_bus.md
@@ -1,6 +1,6 @@
# Message Bus
-The `MessageBus` is a fundamental component of the platform, facilitating communicate between
+The `MessageBus` is a fundamental part of the platform, facilitating communicate between
various system components through message passing. This approach enables a loosely coupled architecture,
where components can interact without strong dependencies. Messages exchanged via the message bus
can be categorized into three distinct types:
@@ -33,13 +33,13 @@ self.msgbus.publish("MyTopic", "MyMessage")
## External publishing
-The `MessageBus` can be 'backed' with any database or message broker technology which has an
+The `MessageBus` can be *backed* with any database or message broker technology which has an
integration written for it, this then allows external publishing of messages.
-```{note}
-Currently Redis is supported for all serializable messages which are published.
+:::info
+Redis is currently supported for all serializable messages which are published externally.
The minimum supported Redis version is 6.2.0.
-```
+:::
Under the hood, when a backing database (or any other compatible technology) is configured,
all outgoing messages are first serialized. These serialized messages are then transmitted via a
@@ -102,10 +102,10 @@ Two encodings are currently supported by the built-in `Serializer` used by the `
Use the `encoding` config option to control the message writing encoding.
-```{tip}
+:::tip
The `msgpack` encoding is used by default as it offers the most optimal serialization and memory performance.
It's recommended to use `json` encoding for human readability when performance is not a primary concern.
-```
+:::
### Timestamp formatting
@@ -167,9 +167,9 @@ message_bus = MessageBusConfig(
The `autotrim_mins` configuration parameter allows you to specify the lookback window in minutes for automatic stream trimming in your message streams.
Automatic stream trimming helps manage the size of your message streams by removing older messages, ensuring that the streams remain manageable in terms of storage and performance.
-```{note}
+:::info
The current Redis implementation will maintain the `autotrim_mins` as a maximum width (plus roughly a minute, as streams are trimmed no more than once per minute).
-Rather than for instance a maximum lookback window based on the current wall clock time.
+Rather than a maximum lookback window based on the current wall clock time.
+:::
The minimum supported Redis version is 6.2.0.
-```
diff --git a/docs/concepts/orders.md b/docs/concepts/orders.md
index 1df183199189..ef211eb9f86b 100644
--- a/docs/concepts/orders.md
+++ b/docs/concepts/orders.md
@@ -10,6 +10,7 @@ as possible. This allows traders to define certain conditions and instructions f
order execution and management, which allows essentially any type of trading strategy to be created.
## Overview
+
The two main types of orders are _Market_ orders and _Limit_ orders. All the other order
types are built from these two fundamental types, in terms of liquidity provision they
are exact opposites. _Market_ orders demand liquidity and require immediate trading at the best
@@ -27,12 +28,12 @@ The core order types available for the platform are (using the enum values):
- `TRAILING_STOP_MARKET`
- `TRAILING_STOP_LIMIT`
-```{note}
+:::info
NautilusTrader has unified the API for a large set of order types and execution instructions, however
not all of these are available for every exchange. If an order is submitted where an instruction or option
-is not available, then the system will not submit the order and an error will be logged with
+is not available, then the system will **NOT** submit the order and an error will be logged with
a clear explanatory message.
-```
+:::
### Terminology
@@ -59,13 +60,14 @@ a clear explanatory message.
- `EXPIRED`
- `FILLED`
-## Execution Instructions
+## Execution instructions
Certain exchanges allow a trader to specify conditions and restrictions on
how an order will be processed and executed. The following is a brief
summary of the different execution instructions available.
-### Time In Force
+### Time in force
+
The orders time in force is an instruction to specify how long the order will remain open
or active, before any remaining quantity is canceled.
@@ -77,16 +79,19 @@ or active, before any remaining quantity is canceled.
- `AT_THE_OPEN` (OPG) - The order is only in force at the trading session open
- `AT_THE_CLOSE` - The order is only in force at the trading session close
-### Expire Time
+### Expire time
+
This instruction is to be used in conjunction with the `GTD` time in force to specify the time
at which the order will expire and be removed from the exchanges order book (or order management system).
-### Post Only
+### Post-only
+
An order which is marked as `post_only` will only ever participate in providing liquidity to the
limit order book, and never initiating a trade which takes liquidity as an aggressor. This option is
important for market makers, or traders seeking to restrict the order to a liquidity _maker_ fee tier.
-### Reduce Only
+### Reduce-only
+
An order which is set as `reduce_only` will only ever reduce an existing position on an instrument, and
never open a new position (if already flat). The exact behavior of this instruction can vary between
exchanges, however the behavior as per the Nautilus `SimulatedExchange` is typical of a live exchange.
@@ -94,12 +99,14 @@ exchanges, however the behavior as per the Nautilus `SimulatedExchange` is typic
- Order will be canceled if the associated position is closed (becomes flat)
- Order quantity will be reduced as the associated positions size reduces
-### Display Quantity
+### Display quantity
+
The `display_qty` specifies the portion of a _Limit_ order which is displayed on the limit order book.
These are also known as iceberg orders as there is a visible portion to be displayed, with more quantity which is hidden.
Specifying a display quantity of zero is also equivalent to setting an order as `hidden`.
-### Trigger Type
+### Trigger type
+
Also known as [trigger method](https://guides.interactivebrokers.com/tws/usersguidebook/configuretws/modify_the_stop_trigger_method.htm)
which is applicable to conditional trigger orders, specifying the method of triggering the stop price.
@@ -113,7 +120,8 @@ which is applicable to conditional trigger orders, specifying the method of trig
- `MARK` - The trigger price will be based on the exchanges mark price for the instrument
- `INDEX` - The trigger price will be based on the exchanges index price for the instrument
-### Trigger Offset Type
+### Trigger offset type
+
Applicable to conditional trailing-stop trigger orders, specifies the method of triggering modification
of the stop price based on the offset from the 'market' (bid, ask or last price as applicable).
@@ -123,12 +131,14 @@ of the stop price based on the offset from the 'market' (bid, ask or last price
- `TICKS` - The offset is based on a number of ticks
- `PRICE_TIER` - The offset is based on an exchange specific price tier
-### Contingent Orders
+### Contingent orders
+
More advanced relationships can be specified between orders such as assigning child order(s) which will only
trigger when the parent order is activated or filled, or linking orders together which will cancel or reduce in quantity
contingent on each other. More documentation for these options can be found in the [advanced order guide](advanced/advanced_orders.md).
-## Order Factory
+## Order factory
+
The easiest way to create new orders is by using the built-in `OrderFactory`, which is
automatically attached to every `Strategy` class. This factory will take care
of lower level details - such as ensuring the correct trader ID and strategy ID are assigned, generation
@@ -138,17 +148,18 @@ apply to the order type being created, or are only needed to specify more advanc
This leaves the factory with simpler order creation methods to work with, all the
examples will leverage an `OrderFactory` from within a `Strategy` context.
-[API Reference](https://docs.nautilustrader.io/api_reference/common.html#module-nautilus_trader.common.factories)
+[API Reference](https://nautilustrader.io/docs/api_reference/common.html#module-nautilus_trader.common.factories)
-```{note}
-For clarity, any optional parameters will be clearly marked with a comment which includes the default value.
-```
+:::info
+Any optional parameters will be clearly marked with a comment which includes the default value.
+:::
## Order Types
-The following order types are available for the platform.
+The following describes the order types which are available for the platform with a code example.
### Market
+
A _Market_ order is an instruction by the trader to immediately trade
the given quantity at the best price available. You can also specify several
time in force options, and indicate whether this order is only intended to reduce
@@ -173,9 +184,10 @@ order: MarketOrder = self.order_factory.market(
tags=["ENTRY"], # <-- optional (default None)
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.market)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.market)
### Limit
+
A _Limit_ order is placed on the limit order book at a specific price, and will only
execute at that price (or better).
@@ -203,9 +215,10 @@ order: LimitOrder = self.order_factory.limit(
tags=None, # <-- optional (default None)
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.limit)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.limit)
### Stop-Market
+
A _Stop-Market_ order is a conditional order which once triggered, will immediately
place a _Market_ order. This order type is often used as a stop-loss to limit losses, either
as a SELL order against LONG positions, or as a BUY order against SHORT positions.
@@ -234,9 +247,10 @@ order: StopMarketOrder = self.order_factory.stop_market(
tags=None, # <-- optional (default None)
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.stop_market)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.stop_market)
### Stop-Limit
+
A _Stop-Limit_ order is a conditional order which once triggered will immediately place
a _Limit_ order at the specified price.
@@ -267,9 +281,10 @@ order: StopLimitOrder = self.order_factory.stop_limit(
tags=None, # <-- optional (default None)
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.stop_limit)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.stop_limit)
### Market-To-Limit
+
A _Market-To-Limit_ order is submitted as a market order to execute at the current best market price.
If the order is only partially filled, the remainder of the order is canceled and re-submitted as a _Limit_ order with
the limit price equal to the price at which the filled portion of the order executed.
@@ -295,9 +310,10 @@ order: MarketToLimitOrder = self.order_factory.market_to_limit(
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.market_to_limit)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.market_to_limit)
### Market-If-Touched
+
A _Market-If-Touched_ order is a conditional order which once triggered will immediately
place a _Market_ order. This order type is often used to enter a new position on a stop price in the market orders direction,
or to take profits for an existing position, either as a SELL order against LONG positions,
@@ -328,9 +344,10 @@ order: MarketIfTouchedOrder = self.order_factory.market_if_touched(
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.market_if_touched)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.market_if_touched)
### Limit-If-Touched
+
A _Limit-If-Touched_ order is a conditional order which once triggered will immediately place
a _Limit_ order at the specified price.
@@ -363,9 +380,10 @@ order: StopLimitOrder = self.order_factory.limit_if_touched(
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.limit_if_touched)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.limit_if_touched)
### Trailing-Stop-Market
+
A _Trailing-Stop-Market_ order is a conditional order which trails a stop trigger price
a fixed offset away from the defined market price. Once triggered a _Market_ order will
immediately be placed.
@@ -400,9 +418,10 @@ order: TrailingStopMarketOrder = self.order_factory.trailing_stop_market(
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.trailing_stop_market)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.trailing_stop_market)
### Trailing-Stop-Limit
+
A _Trailing-Stop-Limit_ order is a conditional order which trails a stop trigger price
a fixed offset away from the defined market price. Once triggered a _Limit_ order will
immediately be placed at the defined price (which is also updated as the market moves until triggered).
@@ -440,4 +459,4 @@ order: TrailingStopLimitOrder = self.order_factory.trailing_stop_limit(
)
```
-[API Reference](https://docs.nautilustrader.io/api_reference/model/orders.html#module-nautilus_trader.model.orders.trailing_stop_limit)
+[API Reference](https://nautilustrader.io/docs/api_reference/model/orders.html#module-nautilus_trader.model.orders.trailing_stop_limit)
diff --git a/docs/concepts/overview.md b/docs/concepts/overview.md
index 5d163d66397b..e6fc36578373 100644
--- a/docs/concepts/overview.md
+++ b/docs/concepts/overview.md
@@ -63,25 +63,29 @@ The projects codebase provides a framework for implementing the software layer o
the default `backtest` and `live` system implementations in their respectively named subpackages. A `sandbox` environment can
be built using the sandbox adapter.
-```{note}
+:::note
- All examples will utilize these default system implementations.
- We consider trading strategies to be subcomponents of end-to-end trading systems, these systems
include the application and infrastructure layers.
-```
+:::
## Distributed
+
The platform is designed to be easily integrated into a larger distributed system.
To facilitate this, nearly all configuration and domain objects can be serialized using JSON, MessagePack or Apache Arrow (Feather) for communication over the network.
## Common core
+
The common system core is utilized by all node environment contexts (`backtest`, `sandbox`, and `live`).
User-defined Actor, Strategy and ExecAlgorithm components are managed consistently across these environment contexts.
## Backtesting
+
Backtesting can be achieved by first making data available to a `BacktestEngine` either directly or via
a higher level `BacktestNode` and `ParquetDataCatalog`, and then running the data through the system with nanosecond resolution.
## Live trading
+
A `TradingNode` can ingest data and events from multiple data and execution clients.
Live deployments can use both demo/paper trading accounts, or real accounts.
@@ -90,9 +94,9 @@ The platform supports both demo/paper trading accounts and real accounts. High p
asynchronously on a single [event loop](https://docs.python.org/3/library/asyncio-eventloop.html),
with the potential to further boost performance by leveraging the [uvloop](https://github.com/MagicStack/uvloop) implementation (available for Linux and macOS).
-```{tip}
+:::tip
Python 3.11 offers improved run-time performance, while Python 3.12 additionally offers improved asyncio performance.
-```
+:::
## Domain model
diff --git a/docs/concepts/strategies.md b/docs/concepts/strategies.md
index 096ad1337d28..efbd32c8a080 100644
--- a/docs/concepts/strategies.md
+++ b/docs/concepts/strategies.md
@@ -15,9 +15,9 @@ There are two main parts of a Nautilus trading strategy:
- The strategy implementation itself, defined by inheriting the `Strategy` class
- The _optional_ strategy configuration, defined by inheriting the `StrategyConfig` class
-```{note}
+:::note
Once a strategy is defined, the same source can be used for backtesting and live trading.
-```
+:::
The main capabilities of a strategy include:
- Historical data requests
@@ -28,6 +28,7 @@ The main capabilities of a strategy include:
- Creating and managing orders and positions
## Implementation
+
Since a trading strategy is a class which inherits from `Strategy`, you must define
a constructor where you can handle initialization. Minimally the base/super class needs to be initialized:
@@ -39,10 +40,10 @@ class MyStrategy(Strategy):
super().__init__() # <-- the super class must be called to initialize the strategy
```
-```{warning}
+:::warning
Do not call components such as `clock` and `logger` in the `__init__` constructor (which is prior to registration).
This is because the systems clock and MPSC channel thread for logging have not yet been setup on initialization.
-```
+:::
From here, you can implement handlers as necessary to perform actions based on state transitions
and events.
@@ -221,9 +222,9 @@ def on_start(self) -> None:
Strategies have access to a comprehensive `Clock` which provides a number of methods for creating
different timestamps, as well as setting time alerts or timers.
-```{note}
+:::info
See the `Clock` [API reference](../api_reference/common.md) for a complete list of available methods.
-```
+:::
#### Current timestamps
@@ -249,7 +250,7 @@ specified alert time. In a live context, this might be slightly delayed by a few
This example sets a time alert to trigger one minute from the current time:
```python
-self.clock.set_alert_time(
+self.clock.set_time_alert(
name="MyTimeAlert1",
alert_time=self.clock.utc_now() + pd.Timedelta(minutes=1),
)
@@ -342,9 +343,9 @@ metrics and statistics.
Refer to the `PortfolioAnalyzer` in the [API Reference](../api_reference/analysis.md) for a complete description
of all available methods.
-```{note}
-Also see the [Porfolio statistics](../concepts/advanced/portfolio_statistics.md) guide.
-```
+:::info
+See the [Porfolio statistics](../concepts/advanced/portfolio_statistics.md) guide.
+:::
### Trading commands
@@ -353,9 +354,9 @@ tailored for algorithmic trading. These commands are essential for executing str
and ensuring seamless interaction with various trading venues. In the following sections, we will
delve into the specifics of each command and its use cases.
-```{tip}
+:::info
The [Execution](../concepts/execution.md) guide explains the flow through the system, and can be helpful to read in conjunction with the below.
-```
+:::
#### Submitting orders
@@ -391,9 +392,9 @@ def buy(self) -> None:
self.submit_order(order)
```
-```{note}
+:::info
It's possible to specify both order emulation, and an execution algorithm.
-```
+:::
This example submits a `MARKET` BUY order to a TWAP execution algorithm:
```python
@@ -432,9 +433,9 @@ The component a `CancelOrder`, `CancelAllOrders` or `BatchCancelOrders` command
- If an `exec_algorithm_id` is specified (with no `emulation_trigger`), and the order is still active within the local system, the command will _firstly_ be sent to the relevant `ExecAlgorithm`
- Otherwise, the order will _firstly_ be sent to the `ExecutionEngine`
-```{note}
+:::info
Any managed GTD timer will also be canceled after the command has left the strategy.
-```
+:::
The following shows how to cancel an individual order:
```python
@@ -468,18 +469,18 @@ Orders can be modified individually when emulated, or *open* on a venue (if supp
If the order is already *closed* or already pending cancel, then a warning will be logged.
If the order is currently *open* then the status will become `PENDING_UPDATE`.
-```{warning}
+:::warning
At least one value must differ from the original order for the command to be valid.
-```
+:::
The component a `ModifyOrder` command will flow to for execution depends on the following:
- If the order is currently emulated, the command will _firstly_ be sent to the `OrderEmulator`
- Otherwise, the order will _firstly_ be sent to the `RiskEngine`
-```{note}
+:::info
Once an order is under the control of an execution algorithm, it cannot be directly modified by a strategy (only canceled).
-```
+:::
The following shows how to modify the size of `LIMIT` BUY order currently *open* on a venue:
```python
@@ -491,10 +492,9 @@ self.modify_order(order, new_quantity)
```
-```{note}
+:::info
The price and trigger price can also be modified (when emulated or supported by a venue).
-
-```
+:::
## Configuration
@@ -551,10 +551,10 @@ strategy = MyStrategy(config=config)
```
-```{note}
+:::note
Even though it often makes sense to define a strategy which will trade a single
instrument. The number of instruments a single strategy can work with is only limited by machine resources.
-```
+:::
### Managed GTD expiry
@@ -575,16 +575,16 @@ If you intend running multiple instances of the same strategy, with different
configurations (such as trading different instruments), then you will need to define
a unique `order_id_tag` for each of these strategies (as shown above).
-```{note}
+:::note
The platform has built-in safety measures in the event that two strategies share a
duplicated strategy ID, then an exception will be raised that the strategy ID has already been registered.
-```
+:::
The reason for this is that the system must be able to identify which strategy
various commands and events belong to. A strategy ID is made up of the
strategy class name, and the strategies `order_id_tag` separated by a hyphen. For
example the above config would result in a strategy ID of `MyStrategy-001`.
-```{tip}
+:::tip
See the `StrategyId` [documentation](../api_reference/model/identifiers.md) for further details.
-```
+:::
diff --git a/docs/conf.py b/docs/conf.py
deleted file mode 100644
index 3488bb493de5..000000000000
--- a/docs/conf.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# Configuration file for the Sphinx documentation builder.
-#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
-# https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
-
-import os
-import sys
-
-import nautilus_trader
-
-
-sys.path.insert(0, os.path.abspath(".."))
-sys.path.append(os.path.abspath("./_pygments"))
-
-# -- Project information -----------------------------------------------------
-project = "NautilusTrader"
-author = "Nautech Systems Pty Ltd."
-copyright = "2015-2024 Nautech Systems Pty Ltd"
-version = nautilus_trader.__version__
-
-# -- General configuration ---------------------------------------------------
-extensions = [
- "myst_parser",
- "sphinx.ext.autodoc",
- "sphinx.ext.intersphinx",
- "sphinx.ext.napoleon",
- "sphinx_togglebutton",
- "sphinx_copybutton",
- "sphinx_comments",
-]
-
-# Add any paths that contain templates here, relative to this directory.
-html_static_path = ["_static"]
-html_css_files = ["custom.css"]
-templates_path = ["_templates"]
-html_js_files = ["script.js"]
-
-comments_config = {"hypothesis": False, "utterances": False}
-exclude_patterns = ["**.ipynb_checkpoints", ".DS_Store", "Thumbs.db", "_build"]
-source_suffix = [".rst", ".md"]
-
-# -- Options for HTML output -------------------------------------------------
-html_theme = "sphinx_material"
-html_logo = "_images/nt-white.png"
-html_favicon = "_images/favicon-32x32.png"
-html_title = ""
-html_sidebars = {"**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"]}
-html_show_sphinx = False
-html_show_sourcelink = False
-
-# sphinx-material theme options (see theme.conf for more information)
-html_theme_options = {
- "nav_title": "",
- "base_url": "",
- "repo_type": "github",
- "repo_url": "https://github.com/nautechsystems/nautilus_trader",
- "repo_name": "nautilus_trader",
- "google_analytics_account": "UA-XXXXX",
- "html_minify": False,
- "html_prettify": True,
- "color_primary": "#282f38",
- "color_accent": "#282f38",
- "theme_color": "#282f38",
- "touch_icon": "images/apple-icon-152x152.png",
- "master_doc": False,
- "globaltoc_collapse": False,
- "globaltoc_depth": 3,
- "nav_links": [
- {
- "href": "/getting_started/index",
- "internal": True,
- "title": "Getting Started",
- },
- {
- "href": "/concepts/index",
- "internal": True,
- "title": "Concepts",
- },
- {
- "href": "/api_reference/index",
- "internal": True,
- "title": "Python API",
- },
- {
- "href": "rust",
- "internal": True,
- "title": "Rust API",
- },
- {
- "href": "/integrations/index",
- "internal": True,
- "title": "Integrations",
- },
- {
- "href": "/developer_guide/index",
- "internal": True,
- "title": "Developer Guide",
- },
- {
- "href": "https://github.com/nautechsystems/nautilus_trader/releases",
- "internal": False,
- "title": "Releases ⬀",
- },
- {
- "href": "https://nautilustrader.io/",
- "internal": False,
- "title": "nautilustrader.io ⬀",
- },
- ],
- "version_dropdown": True,
- "version_json": "_static/version.json",
- "table_classes": ["plain"],
-}
-
-myst_enable_extensions = [
- "colon_fence",
- "dollarmath",
- "linkify",
- "substitution",
- "tasklist",
-]
-myst_url_schemes = ("mailto", "http", "https")
-suppress_warnings = ["myst.domains"]
-
-# Do not auto-generate summary for class members
-numpydoc_show_class_members = False
-
-# Do not prepend module name to functions
-add_module_names = False
-todo_include_todos = False
-
-autosummary_generate = True
-autodoc_member_order = "bysource"
-
-napoleon_google_docstring = False
-
-# Do not show the return type as separate section
-napoleon_use_rtype = False
-
-pygments_style = "monokai.MonokaiStyle"
diff --git a/docs/developer_guide/coding_standards.md b/docs/developer_guide/coding_standards.md
index 186dd0838be8..39c2204e960d 100644
--- a/docs/developer_guide/coding_standards.md
+++ b/docs/developer_guide/coding_standards.md
@@ -28,6 +28,7 @@ long_method_with_many_params(
```
### PEP-8
+
The codebase generally follows the PEP-8 style guide. Even though C typing is taken advantage of in the Cython parts of the codebase, we still aim to be idiomatic of Python where possible.
One notable departure is that Python truthiness is not always taken advantage of to check if an argument is `None` for everything other than collections.
@@ -41,22 +42,25 @@ There are two reasons for this;
Having said all of this there are still areas of the codebase which aren’t as performance-critical where it is safe to use Python truthiness to check for `None`.
-```{note}
+:::note
To be clear, it's still encouraged to use Python truthiness `is` and `not` to check if collections are `None` or empty.
-```
+:::
We welcome all feedback on where the codebase departs from PEP-8 for no apparent reason.
### Docstrings
+
The [NumPy docstring spec](https://numpydoc.readthedocs.io/en/latest/format.html) is used throughout the codebase. This needs to be adhered to consistently to ensure the docs build correctly.
### Flake8
+
[Flake8](https://github.com/pycqa/flake8) is utilized to lint the codebase. Current ignores can be found in the top-level `pre-commit-config.yaml`, with the justifications also commented.
### Commit messages
+
Here are some guidelines for the style of your commit messages:
-1. Limit subject titles to 50 characters or fewer. Capitalize subject line; use imperative voice; and do not end with period.
+1. Limit subject titles to 50 characters or fewer. Capitalize subject line and do not end with period.
2. Use 'imperative voice', i.e. the message should describe what the commit will do if applied.
diff --git a/docs/developer_guide/cython.md b/docs/developer_guide/cython.md
index 0ba9587d76d8..8e8ad6c358a8 100644
--- a/docs/developer_guide/cython.md
+++ b/docs/developer_guide/cython.md
@@ -14,6 +14,7 @@ for Python through [C extension modules](https://docs.python.org/3/extending/ext
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.
@@ -21,12 +22,14 @@ This will ensure Python exceptions are not ignored, and instead are “bubbled u
## 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
@@ -34,6 +37,7 @@ The summary is it involves manually running a specialized version of `gdb` from
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. However, with this not being available
for the Cython part of the codebase, there are a few things which can help:
diff --git a/docs/developer_guide/environment_setup.md b/docs/developer_guide/environment_setup.md
index 7a97b7a22b2a..6086f1b3fcfb 100644
--- a/docs/developer_guide/environment_setup.md
+++ b/docs/developer_guide/environment_setup.md
@@ -23,6 +23,18 @@ The following steps are for UNIX-like systems, and only need to be completed onc
pre-commit install
+3. In case of large recompiles for small changes, configure the `PYO3_PYTHON` variable in `nautilus_core/.cargo/config.toml` with the path to the Python interpreter in the poetry managed environment. This is primarily useful for Rust developers working on core and experience frequent recompiles from IDE/rust analyzer based `cargo check`.
+
+ ```
+ poetry shell
+ PYTHON_PATH=$(which python)
+ echo -e "\n[env]\nPYO3_PYTHON = \"$PYTHON_PATH\"" >> nautilus_core/.cargo/config.toml
+ ```
+
+ Since `.cargo/config.toml` is a tracked file, configure git to skip local modifications to it with `git update-index --skip-worktree nautilus_core/.cargo/config.toml`. Git will still pull remote modifications. To push modifications track local modifications using `git update-index --no-skip-worktree nautilus_core/.cargo/config.toml`.
+
+ The git hack is needed till [local cargo config](https://github.com/rust-lang/cargo/issues/7723) feature is merged.
+
## Builds
Following any changes to `.pyx` or `.pxd` files, you can re-compile by running:
@@ -34,6 +46,7 @@ or
make build
## Services
+
You can use `docker-compose.yml` file located in `.docker` directory
to bootstrap the Nautilus working environment. This will start the following services:
@@ -93,9 +106,11 @@ make install-cli
```
## Commands
+
You can run `nautilus --help` to inspect structure of CLI and groups of commands:
### Database
+
These are commands related to the bootstrapping the Postgres database.
For that you work, you need to supply right connection configuration. You can do that through
command line arguments or `.env` file in the root directory or where the commands is being run.
diff --git a/docs/developer_guide/index.md b/docs/developer_guide/index.md
index d43c0e162f81..5f76bd377aac 100644
--- a/docs/developer_guide/index.md
+++ b/docs/developer_guide/index.md
@@ -1,19 +1,5 @@
# Developer Guide
-```{eval-rst}
-.. toctree::
- :maxdepth: 2
- :hidden:
-
- environment_setup.md
- coding_standards.md
- cython.md
- rust.md
- testing.md
- adapters.md
- packaged_data.md
-```
-
Welcome to the developer guide for NautilusTrader!
Here you will find information related to developing and extending the NautilusTrader codebase.
diff --git a/docs/developer_guide/packaged_data.md b/docs/developer_guide/packaged_data.md
index 13f641d10c0d..7e21a2285fb7 100644
--- a/docs/developer_guide/packaged_data.md
+++ b/docs/developer_guide/packaged_data.md
@@ -3,14 +3,17 @@
Various data is contained internally in the `tests/test_kit/data` folder.
## Libor Rates
+
The libor rates for 1 month USD can be updated by downloading the CSV data from https://fred.stlouisfed.org/series/USD1MTD156N.
Ensure you select `Max` for the time window.
## Short Term Interest Rates
+
The interbank short term interest rates can be updated by downloading the CSV data at https://data.oecd.org/interest/short-term-interest-rates.htm.
## Economic Events
+
The economic events can be updated from downloading the CSV data from fxstreet https://www.fxstreet.com/economic-calendar.
Ensure timezone is set to GMT.
diff --git a/docs/developer_guide/rust.md b/docs/developer_guide/rust.md
index d44a162f0f93..23fd94a4c720 100644
--- a/docs/developer_guide/rust.md
+++ b/docs/developer_guide/rust.md
@@ -10,12 +10,14 @@ the language itself can access the lowest level primitives, we can expect the ev
to be highly performant. This combination of correctness and performance is highly valued for a HFT platform.
## Python Binding
+
Interoperating from Python calling Rust can be achieved by binding a Rust C-ABI compatible interface generated using `cbindgen` with
Cython. This approach is to aid a smooth transition to greater amounts
of Rust in the codebase, and reducing amounts of Cython (which will eventually be eliminated).
We want to avoid a need for Rust to call Python using the FFI. In the future [PyO3](https://github.com/PyO3/PyO3) will be used.
## Unsafe Rust
+
It will be necessary to write `unsafe` Rust code to be able to achieve the value
of interoperating between Python and Rust. The ability to step outside the boundaries of safe Rust is what makes it possible to
implement many of the most fundamental features of the Rust language itself, just as C and C++ are used to implement
@@ -27,6 +29,7 @@ from the Rust compiler, and onto us. The goal is to realize the advantages of th
The definition for what the Rust language designers consider undefined behavior can be found in the [language reference](https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html).
## Safety Policy
+
To maintain the high standards of correctness the project strives for, it's necessary to specify a reasonable policy
to adhere to when implementing `unsafe` Rust.
- If a function is `unsafe` to call, there _must_ be a `Safety` section in the documentation explaining why the function is `unsafe`
@@ -34,6 +37,7 @@ and covering the invariants which the function expects the callers to uphold, an
- All `unsafe` code blocks must be completely covered by unit tests within the same source file.
## Resources
+
- [The Rustonomicon](https://doc.rust-lang.org/nomicon/) - The Dark Arts of Unsafe Rust
- [The Rust Reference - Unsafety](https://doc.rust-lang.org/stable/reference/unsafety.html)
- [Safe Bindings in Rust - Russell Johnston](https://www.abubalay.com/blog/2020/08/22/safe-bindings-in-rust)
diff --git a/docs/developer_guide/testing.md b/docs/developer_guide/testing.md
index 5da230b42a6c..85419640594c 100644
--- a/docs/developer_guide/testing.md
+++ b/docs/developer_guide/testing.md
@@ -15,11 +15,13 @@ If you’re using PyCharm then tests should run directly by right clicking on th
Alternatively you can use the `pytest .` command from the root level tests directory, or the other subdirectories.
## Mocks
+
Unit tests will often include other components acting as mocks. The intent of this is to simplify
the test suite to avoid extensive use of a mocking framework, although `MagicMock` objects are
currently used in particular cases.
## Code Coverage
+
Code coverage output is generated using `coverage` and reported using [codecov](https://about.codecov.io/).
High test coverage is a goal for the project however not at the expense of appropriate error
@@ -33,6 +35,7 @@ Other design-time exceptions may also be impossible to test for, and so 100% tes
the ultimate goal.
## Excluded code coverage
+
The `pragma: no cover` comments found throughout the codebase [exclude code from test coverage](https://coverage.readthedocs.io/en/coverage-4.3.3/excluding.html).
The reason for their use is to reduce redundant/needless tests just to keep coverage high, such as:
diff --git a/docs/tutorials/backtest_high_level.md b/docs/getting_started/backtest_high_level.md
similarity index 97%
rename from docs/tutorials/backtest_high_level.md
rename to docs/getting_started/backtest_high_level.md
index bd3db45b4029..c932232b0f7a 100644
--- a/docs/tutorials/backtest_high_level.md
+++ b/docs/getting_started/backtest_high_level.md
@@ -1,7 +1,7 @@
# Backtest (high-level API)
-**This tutorial walks through how to use a `BacktestNode` to backtest a simple EMA cross strategy
-on a simulated FX ECN venue using historical quote tick data.**
+This tutorial walks through how to use a `BacktestNode` to backtest a simple EMA cross strategy
+on a simulated FX ECN venue using historical quote tick data.
The following points will be covered:
- How to load raw data (external to Nautilus) into the data catalog
diff --git a/docs/tutorials/backtest_low_level.md b/docs/getting_started/backtest_low_level.md
similarity index 95%
rename from docs/tutorials/backtest_low_level.md
rename to docs/getting_started/backtest_low_level.md
index f0c2c104e1bd..5de497eea655 100644
--- a/docs/tutorials/backtest_low_level.md
+++ b/docs/getting_started/backtest_low_level.md
@@ -1,7 +1,7 @@
# Backtest (low-level API)
-**This tutorial walks through how to use a `BacktestEngine` to backtest a simple EMA cross strategy
-with a TWAP execution algorithm on a simulated Binance Spot exchange using historical trade tick data.**
+This tutorial walks through how to use a `BacktestEngine` to backtest a simple EMA cross strategy
+with a TWAP execution algorithm on a simulated Binance Spot exchange using historical trade tick data.
The following points will be covered:
- How to load raw data (external to Nautilus) using data loaders and wranglers
@@ -116,21 +116,18 @@ engine.add_data(ticks)
```
-```{note}
+:::note
The amount of and variety of data types is only limited by machine resources and your imagination (custom types are possible).
-```
-
-```{note}
-Multiple venues can be used for backtesting, only limited by machine resources.
-```
+Also, multiple venues can be used for backtesting, again only limited by machine resources.
+:::
## Adding strategies
-Now we can add the trading strategies we'd like to run as part of our system.
+Now we can add the trading strategies we’d like to run as part of our system.
-```{note}
+:::note
Multiple strategies and instruments can be used for backtesting, only limited by machine resources.
-```
+:::
Firstly, initialize a strategy configuration, then use this to initialize a strategy which we can add to the engine:
```python
@@ -161,9 +158,9 @@ and add the actual `ExecAlgorithm` component which will execute the algorithm -
NautilusTrader allows us to build up very complex systems of custom components. Here we show just one of the custom components
available, in this case a built-in TWAP execution algorithm. It is configured and added to the engine in generally the same pattern as for strategies:
-```{note}
+:::note
Multiple execution algorithms can be used for backtesting, only limited by machine resources.
-```
+:::
```python
# Instantiate and add your execution algorithm
diff --git a/docs/getting_started/index.md b/docs/getting_started/index.md
index 685e63731e09..3bc295ecfa8a 100644
--- a/docs/getting_started/index.md
+++ b/docs/getting_started/index.md
@@ -1,22 +1,30 @@
# Getting Started
-```{eval-rst}
-.. toctree::
- :maxdepth: 2
- :glob:
- :titlesonly:
- :hidden:
-
- installation.md
- quickstart.md
-```
-
To get started with NautilusTrader you will need the following:
- A Python environment with the `nautilus_trader` package installed
-- A way to launch Python scripts for backtesting and/or live trading (either from the command line, or jupyter notebook etc)
+- A way to launch Python scripts for backtesting and/or live trading (either from the command line, or Jupyter notebook etc)
## [Installation](installation.md)
The **Installation** guide will help to ensure that NautilusTrader is properly installed on your machine.
## [Quickstart](quickstart.md)
The **Quickstart** provides a step-by-step walk through for setting up your first backtest.
+
+## Backtesting API levels
+
+Backtesting involves running simulated trading systems on historical data.
+
+To get started backtesting with NautilusTrader you need to first understand the two different API
+levels which are provided, and which one may be more suitable for your intended use case.
+
+:::info
+For more information on which API level to choose, refer to the [Backtesting](../concepts/backtesting.md) guide.
+:::
+
+### [Backtest (low-level API)](backtest_low_level.md)
+This tutorial runs through how to load raw data (external to Nautilus) using data loaders and wranglers,
+and then use this data with a `BacktestEngine` to run a single backtest.
+
+### [Backtest (high-level API)](backtest_high_level.md)
+This tutorial runs through how to load raw data (external to Nautilus) into the data catalog,
+and then use this data with a `BacktestNode` to run a single backtest.
diff --git a/docs/getting_started/installation.md b/docs/getting_started/installation.md
index da54d16885c3..5bf116d521a7 100644
--- a/docs/getting_started/installation.md
+++ b/docs/getting_started/installation.md
@@ -8,11 +8,12 @@ NautilusTrader is tested and supported for Python 3.10-3.12 on the following 64-
| macOS | 12 or later | x86_64, ARM64 |
| Windows Server | 2022 or later | x86_64 |
-```{tip}
-We recommend running the platform with the latest supported stable version of Python, and in a virtual environment to isolate the dependencies.
-```
+:::tip
+We recommend running the platform with the latest stable version of Python, and in a virtual environment to isolate the dependencies.
+:::
## From PyPI
+
To install the latest binary wheel (or sdist package) from PyPI using Pythons _pip_ package manager:
pip install -U nautilus_trader
@@ -46,11 +47,13 @@ as specified in the `pyproject.toml`. However, we highly recommend installing us
1. Install [rustup](https://rustup.rs/) (the Rust toolchain installer):
- Linux and macOS:
```bash
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+ curl https://sh.rustup.rs -sSf | sh
```
- Windows:
- Download and install [`rustup-init.exe`](https://win.rustup.rs/x86_64)
- Install "Desktop development with C++" with [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16)
+ - Verify (any system):
+ from a terminal session run: `rustc --version`
2. Enable `cargo` in the current shell:
- Linux and macOS:
@@ -60,11 +63,26 @@ as specified in the `pyproject.toml`. However, we highly recommend installing us
- Windows:
- Start a new PowerShell
-3. Install poetry (or follow the installation guide on their site):
+3. Install [clang](https://clang.llvm.org/) (a C language frontend for LLVM):
+ - Linux:
+ ```bash
+ sudo apt-get install clang
+ ```
+ - Windows:
+ 1. Add Clang to your [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16):
+ - Start | Visual Studio Installer | Modify | C++ Clang tools for Windows (12.0.0 - x64…) = checked | Modify
+ 2. Enable `clang` in the current shell:
+ ```powershell
+ [System.Environment]::SetEnvironmentVariable('path', "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\Llvm\x64\bin\;" + $env:Path,"User")
+ ```
+ - Verify (any system):
+ from a terminal session run: `clang --version`
+
+4. Install poetry (or follow the installation guide on their site):
curl -sSL https://install.python-poetry.org | python3 -
-4. Clone the source with `git`, and install from the projects root directory:
+5. Clone the source with `git`, and install from the projects root directory:
git clone https://github.com/nautechsystems/nautilus_trader
cd nautilus_trader
diff --git a/examples/notebooks/quick_start.ipynb b/docs/getting_started/quickstart.ipynb
similarity index 98%
rename from examples/notebooks/quick_start.ipynb
rename to docs/getting_started/quickstart.ipynb
index 3a05d67bc0ee..54aca4067a16 100644
--- a/examples/notebooks/quick_start.ipynb
+++ b/docs/getting_started/quickstart.ipynb
@@ -10,7 +10,7 @@
"This tutorial steps through how to get up and running with NautilusTrader backtesting using FX data.\n",
"The Nautilus maintainers have pre-loaded some test data using the standard Nautilus persistence format (Parquet) for this guide.\n",
"\n",
- "For more details on how to load data into Nautilus, see [Backtest Example]((https://docs.nautilustrader.io/guides/backtest_example.html) and [Loading External Data](https://docs.nautilustrader.io/guides/loading_external_data.html).)."
+ "For more details on how to load data into Nautilus, see [Backtest Example]((https://nautilustrader.io/docs/guides/backtest_example.html) and [Loading External Data](https://nautilustrader.io/docs/guides/loading_external_data.html).)."
]
},
{
diff --git a/docs/getting_started/quickstart.md b/docs/getting_started/quickstart.md
index 8542d94466e0..08a339a71c51 100644
--- a/docs/getting_started/quickstart.md
+++ b/docs/getting_started/quickstart.md
@@ -1,13 +1,13 @@
# Quickstart
This guide explains how to get up and running with NautilusTrader backtesting with some
-FX data. The Nautilus maintainers have pre-loaded some test data using the standard Nautilus persistence
+FX data. The Nautilus maintainers have pre-loaded some test data using the standard Nautilus persistence
format (Parquet) for this guide.
-For more details on how to load data into Nautilus, see the [Backtest](../tutorials/backtest_high_level.md) tutorial.
+For more details on how to load data into Nautilus, see the [Backtest](backtest_high_level.md) tutorial.
## Running in docker
-A self-contained dockerized jupyter notebook server is available for download, which does not require any setup or
+A self-contained dockerized Jupyter notebook server is available for download, which does not require any setup or
installation. This is the fastest way to get up and running to try out Nautilus. Bear in mind that any data will be
deleted when the container is deleted.
@@ -20,7 +20,7 @@ deleted when the container is deleted.
- Open your web browser to `localhost:{port}`
- https://localhost:8888
-```{warning}
+:::warning
NautilusTrader currently exceeds the rate limit for Jupyter notebook logging (stdout output),
this is why `log_level` in the examples is set to "ERROR". If you lower this level to see
more logging then the notebook will hang during cell execution. A fix is currently
@@ -28,7 +28,7 @@ being investigated which involves either raising the configured rate limits for
Jupyter, or throttling the log flushing from Nautilus.
https://github.com/jupyterlab/jupyterlab/issues/12845
https://github.com/deshaw/jupyterlab-limit-output
-```
+:::
## Getting the sample data
@@ -186,9 +186,9 @@ First, we create a venue configuration. For this example we will create a simula
A venue needs a name which acts as an ID (in this case `SIM`), as well as some basic configuration, e.g.
the account type (`CASH` vs `MARGIN`), an optional base currency, and starting balance(s).
-```{note}
+:::note
FX trading is typically done on margin with Non-Deliverable Forward, Swap or CFD type instruments.
-```
+:::
```python
from nautilus_trader.config import BacktestVenueConfig
@@ -269,7 +269,6 @@ engine = BacktestEngineConfig(
We can now pass our various config pieces to the `BacktestRunConfig`. This object now contains the
full configuration for our backtest.
-
```python
from nautilus_trader.config import BacktestRunConfig
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 68c5abffa4d4..000000000000
--- a/docs/index.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# NautilusTrader Documentation
-
-```{eval-rst}
-.. toctree::
- :maxdepth: 1
- :glob:
- :titlesonly:
- :hidden:
-
- getting_started/index.md
- concepts/index.md
- tutorials/index.md
- integrations/index.md
- api_reference/index.md
- rust.md
- developer_guide/index.md
-
-```
-
-Welcome to the official documentation for NautilusTrader!
-
-**NautilusTrader is an open-source, high-performance, production-grade algorithmic trading platform,
-providing quantitative traders with the ability to backtest portfolios of automated trading strategies
-on historical data with an event-driven engine, and also deploy those same strategies live, with no code changes.**
-
-The platform provides an extensive array of features and capabilities, coupled with open-ended flexibility for assembling
-trading systems using the framework. Given the breadth of information, and required pre-requisite knowledge, both beginners and experts alike may find the learning curve steep.
-However, this documentation aims to assist you in learning and understanding NautilusTrader, so that you can then leverage it to achieve your algorithmic trading goals.
-
-If you have any questions or need further assistance, please reach out to the NautilusTrader community for support.
-
-The following is a brief summary of what you'll find in the documentation, and how to use each section.
-
-## [Getting Started](getting_started/index.md)
-
-The **Getting Started** section offers an introductory overview of the platform,
-a step-by-step guide to installing NautilusTrader, and a tutorial on setting up and running your first backtest.
-This section is crafted for those who are hands-on learners and are eager to see results quickly.
-
-## [Concepts](concepts/index.md)
-
-The **Concepts** section breaks down the fundamental ideas, terminologies, and components of the platform, ensuring you have a solid grasp before diving deeper.
-
-## [Tutorials](tutorials/index.md)
-
-The **Tutorials** section offers a guided learning experience with a series of comprehensive step-by-step walkthroughs.
-Each tutorial targets specific features or workflows, allowing you to learn by doing.
-From basic tasks to more advanced operations, these tutorials cater to a wide range of skill levels.
-
-## [Integrations](integrations/index.md)
-
-The **Integrations** guides for the platform, covers adapter differences in configuration, available features and capabilities,
-as well as providing tips for a smoother trading experience.
-
-## [API Reference](api_reference/index.md)
-
-The **API Reference** provides comprehensive technical information on available modules, functions, classes, methods, and other components for both the Python and Rust APIs.
-
-## [Developer Guide](developer_guide/index.md)
-
-The **Developer Guide** is tailored for those who wish to delve further into and potentially modify the codebase.
-It provides insights into the architectural decisions, coding standards, and best practices, helping to ensuring a pleasant and productive development experience.
-
-```{note}
-The terms "NautilusTrader", "Nautilus" and "platform" are used interchageably throughout the documentation.
-```
diff --git a/docs/integrations/betfair.md b/docs/integrations/betfair.md
index 259e83658293..abeb0261f5fd 100644
--- a/docs/integrations/betfair.md
+++ b/docs/integrations/betfair.md
@@ -59,6 +59,7 @@ node.build()
```
### API credentials
+
There are two options for supplying your credentials to the Betfair clients.
Either pass the corresponding `api_key` and `api_secret` values to the config dictionaries, or
set the following environment variables:
diff --git a/docs/integrations/binance.md b/docs/integrations/binance.md
index d4696c53b4a2..44bae77181f0 100644
--- a/docs/integrations/binance.md
+++ b/docs/integrations/binance.md
@@ -19,10 +19,10 @@ which can be used together or separately depending on the users needs.
- `BinanceLiveDataClientFactory` - Factory for Binance data clients (used by the trading node builder)
- `BinanceLiveExecClientFactory` - Factory for Binance execution clients (used by the trading node builder)
-```{note}
+:::info
Most users will simply define a configuration for a live trading node (as below),
and won't need to necessarily work with these lower level components directly.
-```
+:::
## Data types
@@ -56,18 +56,22 @@ E.g. for Binance Futures, the said instruments symbol is `BTCUSDT-PERP` within t
### Trailing stops
-Binance use the concept of an *activation price* for trailing stops ([see docs](https://www.binance.com/en-AU/support/faq/what-is-a-trailing-stop-order-360042299292)).
-To get trailing stop orders working for Binance we need to use the `trigger_price` value to set the *activation price*.
+Binance uses the concept of an activation price for trailing stops, as detailed in their [documentation](https://www.binance.com/en-AU/support/faq/what-is-a-trailing-stop-order-360042299292).
+This approach is somewhat unconventional. For trailing stop orders to function on Binance, the activation price can optionally be set using the `trigger_price` value.
+
+Note that the activation price is **not** the same as the trigger/STOP price. Binance will always calculate the trigger price for the order based on the current market price and the callback rate provided by `trailing_offset`.
+The activated price is simply the price at which the order will begin trailing based on the callback rate.
+
+When submitting trailing stop orders from your strategy, you have two options:
-For `TRAILING_STOP_MARKET` orders to be submitted successfully, you must define the following:
-- Specify a `trailing_offet_type` of either `DEFAULT` or `BASIS_POINTS`
-- Specify the `trailing_offset` in basis points (% * 100) e.g. for a callback rate of 1% use 100
+1. Use the `trigger_price` to manually set the activation price.
+2. Leave the `trigger_price` as `None`, making the trailing action immediately "active".
You must also have at least *one* of the following:
- The `trigger_price` for the order is set (this will act as the Binance *activation_price*)
-- You have subscribed to quote ticks for the instrument you're submitting the order for (used to infer activation price)
-- You have subscribed to trade ticks for the instrument you're submitting the order for (used to infer activation price)
+- (or) you have subscribed to quote ticks for the instrument you're submitting the order for (used to infer activation price)
+- (or) you have subscribed to trade ticks for the instrument you're submitting the order for (used to infer activation price)
## Configuration
@@ -195,7 +199,7 @@ config = TradingNodeConfig(
)
```
-### Aggregated Trades
+### Aggregated trades
Binance provide aggregated trade data endpoints as an alternative source of trade ticks.
In comparison to the default trade endpoints, aggregated trade data endpoints can return all
@@ -226,9 +230,9 @@ instrument_provider=InstrumentProviderConfig(
## Order books
-```{note}
+:::note
The Nautilus team is currently working on this section.
-```
+:::
Order books can be maintained at full or partial depths depending on the
subscription options. WebSocket stream throttling is different between
@@ -265,11 +269,11 @@ where the former does not provide an event timestamp, so the `ts_init` is used (
It's possible to subscribe to Binance specific data streams as they become available to the
adapter over time.
-```{note}
+:::note
Bars are not considered 'Binance specific' and can be subscribed to in the normal way.
However, as more adapters are built out which need for example mark price and funding rate updates, then these
methods may eventually become first-class (not requiring custom/generic subscriptions as below).
-```
+:::
### BinanceFuturesMarkPriceUpdate
diff --git a/docs/integrations/bybit.md b/docs/integrations/bybit.md
index 86c2dfd6d9d3..b1d69fde60c3 100644
--- a/docs/integrations/bybit.md
+++ b/docs/integrations/bybit.md
@@ -1,8 +1,8 @@
# Bybit
-```{note}
+:::note
We are currently working on this integration guide.
-```
+:::
Founded in 2018, Bybit is one of the largest cryptocurrency exchanges in terms
of daily trading volume, and open interest of crypto assets and crypto
@@ -23,23 +23,23 @@ which can be used together or separately depending on the users needs.
- `BybitLiveDataClientFactory` - Factory for Bybit data clients (used by the trading node builder)
- `BybitLiveExecClientFactory` - Factory for Bybit execution clients (used by the trading node builder)
-```{note}
+:::note
Most users will simply define a configuration for a live trading node (as below),
and won't need to necessarily work with these lower level components directly.
-```
+:::
## Bybit documentation
Bybit provides extensive documentation for users which can be found in the [Bybit help center](https://www.bybit.com/en/help-center).
-It's recommended you also refer to the Bybit documentation in conjunction with this NautilusTrader integration guide.
+It’s recommended you also refer to the Bybit documentation in conjunction with this NautilusTrader integration guide.
## Products
A product is an umberalla term for a group of related instrument types.
-```{note}
+:::note
Product is also referred to as `category` in the Bybit v5 API.
-```
+:::
The following product types are supported on Bybit:
@@ -53,7 +53,7 @@ Options contracts are not currently supported (will be implemented in a future v
## Symbology
-To distinguish between different product types on Bybit, the following instrument ID suffix's are used:
+To distinguish between different product types on Bybit, the following instrument ID suffix’s are used:
- `-SPOT`: spot cryptocurrencies
- `-LINEAR`: perpeutal and futures contracts
@@ -75,10 +75,10 @@ The BTCUSD inverse perpetual futures contract is identified with:
## Order types
-```{warning}
+:::warning
Only Market and Limit orders have been tested and are available.
The remaining order types will be added on a best effort basis going forward.
-```
+:::
| | Spot | Derivatives (Linear, Inverse, Options) |
|------------------------|----------------------|-----------------------------------------|
diff --git a/docs/integrations/databento.md b/docs/integrations/databento.md
index 49d00a787ffa..95fd0f6794a7 100644
--- a/docs/integrations/databento.md
+++ b/docs/integrations/databento.md
@@ -1,9 +1,5 @@
# Databento
-```{note}
-We are currently working on this integration guide.
-```
-
NautilusTrader provides an adapter for integrating with the Databento API and [Databento Binary Encoding (DBN)](https://databento.com/docs/knowledge-base/new-users/dbn-encoding) format data.
As Databento is purely a market data provider, there is no execution client provided - although a sandbox environment with simulated execution could still be set up.
It's also possible to match Databento data with Interactive Brokers execution, or to calculate traditional asset class signals for crypto trading.
@@ -12,23 +8,22 @@ The capabilities of this adapter include:
- Loading historical data from DBN files and decoding into Nautilus objects for backtesting or writing to the data catalog
- Requesting historical data which is decoded to Nautilus objects to support live trading and backtesting
- Subscribing to real-time data feeds which are decoded to Nautilus objects to support live trading and sandbox environments
-
-```{tip}
+:::tip
[Databento](https://databento.com/signup) currently offers 125 USD in free data credits (historical data only) for new account sign-ups.
With careful requests, this is more than enough for testing and evaluation purposes.
It's recommended you make use of the [/metadata.get_cost](https://databento.com/docs/api-reference-historical/metadata/metadata-get-cost) endpoint.
-```
+:::
## Overview
The adapter implementation takes the [databento-rs](https://crates.io/crates/databento) crate as a dependency,
which is the official Rust client library provided by Databento. There are actually no Databento Python dependencies.
-```{note}
+:::info
There is no optional extra installation for `databento`, at this stage the core components of the adapter are compiled
as static libraries and linked during the build by default.
-```
+:::
The following adapter classes are available:
- `DatabentoDataLoader` - Loads Databento Binary Encoding (DBN) data from files
@@ -37,10 +32,10 @@ The following adapter classes are available:
- `DatabentoLiveClient` - Integrates with the Databento API (raw TCP) for subscribing to real-time data feeds
- `DatabentoDataClient` - Provides a `LiveMarketDataClient` implementation for running a trading node in real time
-```{note}
+:::info
As with the other integration adapters, most users will simply define a configuration for a live trading node (covered below),
and won't need to necessarily work with these lower level components directly.
-```
+:::
## Databento documentation
@@ -96,17 +91,17 @@ as a venue identifier. You can read more about Databento dataset naming conventi
Of particular note is for CME Globex MDP 3.0 data (`GLBX.MDP3` dataset code), the following
exchanges are all grouped under the `GLBX` venue. These mappings can be determined from the
instruments `exchange` field:
-- `CBCM` - **XCME-XCBT inter-exchange spread**
-- `NYUM` - **XNYM-DUMX inter-exchange spread**
-- `XCBT` - **Chicago Board of Trade (CBOT)**
-- `XCEC` - **Commodities Exchange Center (COMEX)**
-- `XCME` - **Chicago Mercantile Exchange (CME)**
-- `XFXS` - **CME FX Link spread**
-- `XNYM` - **New York Mercantile Exchange (NYMEX)**
-
-```{note}
+- `CBCM` - XCME-XCBT inter-exchange spread
+- `NYUM` - XNYM-DUMX inter-exchange spread
+- `XCBT` - Chicago Board of Trade (CBOT)
+- `XCEC` - Commodities Exchange Center (COMEX)
+- `XCME` - Chicago Mercantile Exchange (CME)
+- `XFXS` - CME FX Link spread**
+- `XNYM` - New York Mercantile Exchange (NYMEX)
+
+:::info
Other venue MICs can be found in the `venue` field of responses from the [metadata.list_publishers](https://databento.com/docs/api-reference-historical/metadata/metadata-list-publishers?historical=http&live=python) endpoint.
-```
+:::
## Timestamps
@@ -127,20 +122,20 @@ When decoding and normalizing Databento to Nautilus we generally assign the Data
The exception to this are the `DatabentoImbalance` and `DatabentoStatistics` data types, which have fields for all timestamps
- as the types are defined specifically for the adapter.
-```{note}
+:::info
See the following Databento docs for further information:
- [Databento standards and conventions - timestamps](https://databento.com/docs/knowledge-base/new-users/standards-conventions/timestamps)
- [Databento timestamping guide](https://databento.com/docs/knowledge-base/data-integrity/timestamping/timestamps-on-databento-and-how-to-use-them)
-```
+:::
## Data types
The following section discusses Databento schema -> Nautilus data type equivalence
and considerations.
-```{note}
+:::info
See the Databento [list of fields by schema guide](https://databento.com/docs/knowledge-base/new-users/fields-by-schema).
-```
+:::
### Instrument definitions
@@ -249,9 +244,9 @@ objects to the data catalog, which performs the decoding step once.
the Nautilus Parquet data from disk, which achieves extremely high through-put (at least an order of magnitude faster
than converting DBN -> Nautilus on the fly for every backtest run).
-```{note}
+:::note
Performance benchmarks are currently under development.
-```
+:::
## Loading DBN data
@@ -312,9 +307,9 @@ trades = loader.from_dbn_file(
catalog.write_data(trades)
```
-```{note}
+:::info
See also the [Data concepts guide](../concepts/data.md).
-```
+:::
## Real-time client architecture
@@ -323,13 +318,13 @@ There are two `DatabentoLiveClient`s per Databento dataset:
- One for MBO (order book deltas) real-time feeds
- One for all other real-time feeds
-```{note}
+:::warning
There is currently a limitation that all MBO (order book deltas) subscriptions for a dataset have to be made at
node startup, to then be able to replay data from the beginning of the session. If subsequent subscriptions
arrive after start, then an error will be logged (and the subscription ignored).
There is no such limitation for any of the other Databento schemas.
-```
+:::
A single `DatabentoHistoricalClient` instance is reused between the `DatabentoInstrumentProvider` and `DatabentoDataClient`,
which makes historical instrument definitions and data requests.
diff --git a/docs/integrations/ib.md b/docs/integrations/ib.md
index aa34049b0930..8dc28d5b4f55 100644
--- a/docs/integrations/ib.md
+++ b/docs/integrations/ib.md
@@ -6,9 +6,9 @@ The TWS API serves as an interface to IB's standalone trading applications: TWS
Alternatively, you can start with a [dockerized version](https://github.com/gnzsnz/ib-gateway-docker) of the IB Gateway, which is particularly useful when deploying trading strategies on a hosted cloud platform. This requires having [Docker](https://www.docker.com/) installed on your machine, along with the [docker](https://pypi.org/project/docker/) Python package, which NautilusTrader conveniently includes as an extra package.
-```{note}
+:::note
The standalone TWS and IB Gateway applications require manually inputting username, password, and trading mode (live or paper) at startup. The dockerized version of the IB Gateway handles these steps programmatically.
-```
+:::
## Installation
@@ -24,30 +24,38 @@ For installation via poetry, use:
poetry add "nautilus_trader[ib,docker]"
```
-```{note}
-Because IB does not provide wheels for `ibapi`, NautilusTrader [repackages]( https://pypi.org/project/nautilus-ibapi/) it for release on PyPI.
-```
-
+:::note
+Because IB does not provide wheels for `ibapi`, NautilusTrader [repackages](https://pypi.org/project/nautilus-ibapi/) it for release on PyPI.
+:::
## Getting Started
-Before deploying strategies, ensure that TWS / IB Gateway is running. Launch one of the standalone applications and log in with your credentials, or start the dockerized IB Gateway using `InteractiveBrokersGateway`:
+Before implementing your trading strategies, please ensure that either TWS (Trader Workstation) or IB Gateway is currently running. You have the option to log in to one of these standalone applications using your personal credentials or alternatively, via `DockerizedIBGateway`.
-```python
-from nautilus_trader.adapters.interactive_brokers.gateway import InteractiveBrokersGateway
+### Establish Connection to an Existing Gateway or TWS:
+Should you choose to connect to a pre-existing Gateway or TWS, it is crucial that you specify the `host` and `port` parameters in both the `InteractiveBrokersDataClientConfig` and `InteractiveBrokersExecClientConfig` to guarantee a successful connection.
-gateway_config = InteractiveBrokersGatewayConfig(
+### Establish Connection to DockerizedIBGateway:
+
+In this case, it's essential to supply `dockerized_gateway` with an instance of `DockerizedIBGatewayConfig` in both the `InteractiveBrokersDataClientConfig` and `InteractiveBrokersExecClientConfig`. It's important to stress, however, that `host` and `port` parameters aren't necessary in this context.
+The following example provides a clear illustration of how to establish a connection to a Dockerized Gateway, which is judiciously managed internally by the Factories.
+
+```python
+from nautilus_trader.adapters.interactive_brokers.config import DockerizedIBGatewayConfig
+from nautilus_trader.adapters.interactive_brokers.gateway import DockerizedIBGateway
+
+gateway_config = DockerizedIBGatewayConfig(
username="test",
password="test",
trading_mode="paper",
- start=True
)
# This may take a short while to start up, especially the first time
-gateway = InteractiveBrokersGateway(
+gateway = DockerizedIBGateway(
config=gateway_config
)
+gateway.start()
# Confirm you are logged in
print(gateway.is_logged_in(gateway.container))
@@ -56,7 +64,7 @@ print(gateway.is_logged_in(gateway.container))
print(gateway.container.logs())
```
-**Note:** To supply credentials to the Interactive Brokers Gateway, either pass the `username` and `password` to the config dictionaries, or set the following environment variables:
+**Note:** To supply credentials to the Interactive Brokers Gateway, either pass the `username` and `password` to the `DockerizedIBGatewayConfig`, or set the following environment variables:
- `TWS_USERNAME`
- `TWS_PASSWORD`
@@ -81,9 +89,33 @@ To ensure efficient management of these diverse responsibilities, the `Interacti
- `InteractiveBrokersClientMarketDataMixin` - Handles market data requests, subscriptions and data processing
- `InteractiveBrokersClientOrderMixin` - Oversees all aspects of order placement and management.
-```{tip}
+:::tip
To troubleshoot TWS API incoming message issues, consider starting at the `InteractiveBrokersClient._process_message` method, which acts as the primary gateway for processing all messages received from the API.
-```
+:::
+
+## Symbology
+
+The InteractiveBrokersInstrumentProvider supports two methods for constructing InstrumentId instances, which can be configured via the strict_symbology flag in InteractiveBrokersInstrumentProviderConfig.
+
+### Simplified Symbology
+
+When strict_symbology is set to False (the default setting), the system utilizes the following parsing rules for symbology:
+
+- Forex: The format is `{symbol}/{currency}.{exchange}`, where the currency pair is constructed as `EUR/USD.IDEALPRO`.
+- Stocks: The format is `{localSymbol}.{primaryExchange}`. Any spaces in localSymbol are replaced with -, e.g., `BF-B.NYSE`.
+- Futures: The format is `{localSymbol}.{exchange}`. Single digit years are expanded to two digits, e.g., `ESM24.CME`.
+- Options: The format is `{localSymbol}.{exchange}`, with all spaces removed from localSymbol, e.g., `AAPL230217P00155000.SMART`.
+- Index: The format is `^{localSymbol}.{exchange}`, e.g., `^SPX.CBOE`.
+
+### Strict Symbology
+
+Setting strict_symbology to True enforces stricter parsing rules that align directly with the fields defined in the ibapi. The format for each security type is as follows:
+
+- CFDs: `{localSymbol}={secType}.IBCFD`
+- Commodities: `{localSymbol}={secType}.IBCMDTY`
+- Default for Other Types: `{localSymbol}={secType}.{exchange}`
+
+This configuration ensures that the symbology is explicitly defined and matched with the Interactive Brokers API requirements, providing clear and consistent instrument identification.
## Instruments & Contracts
@@ -91,7 +123,31 @@ In IB, a NautilusTrader `Instrument` is equivalent to a [Contract](https://ibkrc
To search for contract information, use the [IB Contract Information Center](https://pennies.interactivebrokers.com/cstools/contract_info/).
-Examples of `IBContracts`:
+It's typically suggested to utilize `strict_symbology=False` (which is the default setting). This allows for a cleaner and more intuitive use of InstrumentId by employing `load_ids` in the `InteractiveBrokersInstrumentProviderConfig`, following the guidelines established in the Simplified Symbology section.
+Nonetheless, in order to load multiple Instruments, such as Options Instrument without having to specify each strike explicitly, you would need to utilize `load_contracts` with provided instances of `IBContract`.
+
+```python
+for_loading_instrument_expiry = IBContract(
+ secType="IND",
+ symbol="SPX",
+ exchange="CBOE",
+ build_options_chain=True,
+ lastTradeDateOrContractMonth='20240718',
+)
+
+for_loading_instrument_range = IBContract(
+ secType="IND",
+ symbol="SPX",
+ exchange="CBOE",
+ build_options_chain=True,
+ min_expiry_days=0,
+ max_expiry_days=30,
+)
+```
+
+> **Note:** The `secType` and `symbol` should be specified for the Underlying Contract.
+
+Some more examples of building IBContracts:
```python
from nautilus_trader.adapters.interactive_brokers.common import IBContract
@@ -210,7 +266,7 @@ data_client_config = InteractiveBrokersDataClientConfig(
use_regular_trading_hours=True,
market_data_type=IBMarketDataTypeEnum.DELAYED_FROZEN, # Default is REALTIME if not set
instrument_provider=instrument_provider_config,
- gateway=gateway_config,
+ dockerized_gateway=dockerized_gateway_config,
)
```
@@ -226,7 +282,7 @@ from nautilus_trader.config import RoutingConfig
exec_client_config = InteractiveBrokersExecClientConfig(
ibg_port=4002,
account_id="DU123456", # Must match the connected IB Gateway/TWS
- gateway=gateway_config,
+ dockerized_gateway=dockerized_gateway_config,
instrument_provider=instrument_provider_config,
routing=RoutingConfig(
default=True,
diff --git a/docs/integrations/index.md b/docs/integrations/index.md
index e92037bfe50e..a83028ae2482 100644
--- a/docs/integrations/index.md
+++ b/docs/integrations/index.md
@@ -1,37 +1,24 @@
# Integrations
-```{eval-rst}
-.. toctree::
- :maxdepth: 2
- :glob:
- :titlesonly:
- :hidden:
-
- betfair.md
- binance.md
- bybit.md
- databento.md
- ib.md
-```
-
NautilusTrader is designed in a modular way to work with *adapters* which provide
connectivity to trading venues and data providers - converting their raw API
into a unified interface. The following integrations are currently supported:
| Name | ID | Type | Status | Docs |
| :-------------------------------------------------------- | :-------------------- | :---------------------- | :------------------------------------------------------ | :------------------------------------------------------------------ |
-| [Betfair](https://betfair.com) | `BETFAIR` | Sports Betting Exchange | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://docs.nautilustrader.io/integrations/betfair.html) |
-| [Binance](https://binance.com) | `BINANCE` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://docs.nautilustrader.io/integrations/binance.html) |
-| [Binance US](https://binance.us) | `BINANCE` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://docs.nautilustrader.io/integrations/binance.html) |
-| [Binance Futures](https://www.binance.com/en/futures) | `BINANCE` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://docs.nautilustrader.io/integrations/binance.html) |
-| [Bybit](https://www.bybit.com) | `BYBIT` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/beta-yellow) | [Guide](https://docs.nautilustrader.io/integrations/bybit.html) |
-| [Databento](https://databento.com) | `DATABENTO` | Data Provider | ![status](https://img.shields.io/badge/beta-yellow) | [Guide](https://docs.nautilustrader.io/integrations/databento.html) |
-| [Interactive Brokers](https://www.interactivebrokers.com) | `INTERACTIVE_BROKERS` | Brokerage (multi-venue) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://docs.nautilustrader.io/integrations/ib.html) |
+| [Betfair](https://betfair.com) | `BETFAIR` | Sports Betting Exchange | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://nautilustrader.io/docs/integrations/betfair.html) |
+| [Binance](https://binance.com) | `BINANCE` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://nautilustrader.io/docs/integrations/binance.html) |
+| [Binance US](https://binance.us) | `BINANCE` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://nautilustrader.io/docs/integrations/binance.html) |
+| [Binance Futures](https://www.binance.com/en/futures) | `BINANCE` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://nautilustrader.io/docs/integrations/binance.html) |
+| [Bybit](https://www.bybit.com) | `BYBIT` | Crypto Exchange (CEX) | ![status](https://img.shields.io/badge/beta-yellow) | [Guide](https://nautilustrader.io/docs/integrations/bybit.html) |
+| [Databento](https://databento.com) | `DATABENTO` | Data Provider | ![status](https://img.shields.io/badge/beta-yellow) | [Guide](https://nautilustrader.io/docs/integrations/databento.html) |
+| [Interactive Brokers](https://www.interactivebrokers.com) | `INTERACTIVE_BROKERS` | Brokerage (multi-venue) | ![status](https://img.shields.io/badge/stable-green) | [Guide](https://nautilustrader.io/docs/integrations/ib.html) |
- `ID:` The default client ID for the integrations adapter clients
- `Type:` The type of integration (often the venue type)
### Status
+
- `building` - Under construction and likely not in a usable state
- `beta` - Completed to a minimally working state and in a 'beta' testing phase
- `stable` - Stabilized feature set and API, the integration has been tested by both developers and users to a reasonable level (some bugs may still remain)
@@ -59,6 +46,7 @@ The implementation of each integration aims to meet the following criteria:
a warning or error when a user attempts to perform said action
## API unification
+
All integrations must be compatible with the NautilusTrader API at the system boundary,
this means there is some normalization and standardization needed.
diff --git a/docs/rust.md b/docs/rust.md
deleted file mode 100644
index 83a1c86bbc5e..000000000000
--- a/docs/rust.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Rust API
-
-The core of NautilusTrader is written in Rust, and one day it will be possible to run systems
-entirely programmed and compiled from Rust.
-
-The API reference provides detailed technical documentation for the core NautilusTrader crates,
-the docs are generated from source code using `cargo doc`.
-
-```{note}
-Note the docs are generated using the _nightly_ toolchain (to be able to compile docs for the entire workspace).
-However, we target the _stable_ toolchain for all releases.
-```
-
-Use the following links to explore the Rust docs API references for two different versions of the codebase:
-
-## [Latest Rust docs](https://docs.nautilustrader.io/core)
-This API reference is built from the HEAD of the `master` branch and represents the latest stable release.
-
-## [Nightly Rust docs](https://docs.nautilustrader.io/nightly/core)
-This API reference is built from the HEAD of the `nightly` branch and represents bleeding edge and experimental changes/features currently in development.
-
-## What is Rust?
-[Rust](https://www.rust-lang.org/) is a multi-paradigm programming language designed for performance and safety, especially safe
-concurrency. Rust is blazingly fast and memory-efficient (comparable to C and C++) with no runtime or
-garbage collector. It can power mission-critical systems, run on embedded devices, and easily
-integrates with other languages.
-
-Rust’s rich type system and ownership model guarantees memory-safety and thread-safety deterministically —
-eliminating many classes of bugs at compile-time.
-
-The project increasingly utilizes Rust for core performance-critical components. Python language binding is handled through
-Cython, with static libraries linked at compile-time before the wheel binaries are packaged, so a user
-does not need to have Rust installed to run NautilusTrader. In the future as more Rust code is introduced,
-[PyO3](https://pyo3.rs/latest) will be leveraged for easier Python bindings.
-
-This project makes the [Soundness Pledge](https://raphlinus.github.io/rust/2020/01/18/soundness-pledge.html):
-
-> “The intent of this project is to be free of soundness bugs.
-> The developers will do their best to avoid them, and welcome help in analyzing and fixing them.”
diff --git a/examples/notebooks/backtest_binance_orderbook.ipynb b/docs/tutorials/backtest_binance_orderbook.ipynb
similarity index 100%
rename from examples/notebooks/backtest_binance_orderbook.ipynb
rename to docs/tutorials/backtest_binance_orderbook.ipynb
diff --git a/examples/notebooks/backtest_example.ipynb b/docs/tutorials/backtest_example.ipynb
similarity index 100%
rename from examples/notebooks/backtest_example.ipynb
rename to docs/tutorials/backtest_example.ipynb
diff --git a/examples/notebooks/backtest_fx_usdjpy.ipynb b/docs/tutorials/backtest_fx_usdjpy.ipynb
similarity index 100%
rename from examples/notebooks/backtest_fx_usdjpy.ipynb
rename to docs/tutorials/backtest_fx_usdjpy.ipynb
diff --git a/examples/notebooks/databento_data_catalog.ipynb b/docs/tutorials/databento_data_catalog.ipynb
similarity index 100%
rename from examples/notebooks/databento_data_catalog.ipynb
rename to docs/tutorials/databento_data_catalog.ipynb
diff --git a/examples/notebooks/external_data_backtest.ipynb b/docs/tutorials/external_data_backtest.ipynb
similarity index 100%
rename from examples/notebooks/external_data_backtest.ipynb
rename to docs/tutorials/external_data_backtest.ipynb
diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md
index 046c9fa9b4e5..01e6f0d5a766 100644
--- a/docs/tutorials/index.md
+++ b/docs/tutorials/index.md
@@ -1,15 +1,8 @@
# Tutorials
-```{eval-rst}
-.. toctree::
- :maxdepth: 1
- :glob:
- :titlesonly:
- :hidden:
-
- backtest_low_level.md
- backtest_high_level.md
-```
+:::warning
+We are currently working on the tutorials.
+:::
Welcome to the tutorials for NautilusTrader!
@@ -17,23 +10,13 @@ This section offers a guided learning experience with a series of comprehensive
Each tutorial targets specific features or workflows, allowing you to learn by doing.
From basic tasks to more advanced operations, these tutorials cater to a wide range of skill levels.
-```{tip}
+:::info
+Each tutorial is generated from a Jupyter notebook located in the docs [tutorials directory](https://github.com/nautechsystems/nautilus_trader/tree/develop/docs/tutorials).
+These notebooks not only serve as valuable learning aids but also allow you to execute the code.
+:::
+
+:::tip
Make sure you are following the tutorial docs which match the version of NautilusTrader you are running:
- **Latest:** These docs are built from the HEAD of the `master` branch and work with the latest stable release.
-- **Develop:** These docs are built from the HEAD of the `develop` branch and work with bleeding edge and experimental changes/features currently in development.
-```
-
-## Backtesting
-Backtesting involves running simulated trading systems on historical data. The backtesting tutorials will
-begin with the general basics, then become more specific.
-
-### Which API level?
-For more information on which API level to choose, refer to the [Backtesting](../concepts/backtesting.md) guide.
-
-### [Backtest (low-level API)](backtest_low_level.md)
-This tutorial runs through how to load raw data (external to Nautilus) using data loaders and wranglers,
-and then use this data with a `BacktestEngine` to run a single backtest.
-
-### [Backtest (high-level API)](backtest_high_level.md)
-This tutorial runs through how to load raw data (external to Nautilus) into the data catalog,
-and then use this data with a `BacktestNode` to run a single backtest.
+- **Nightly:** These docs are built from the HEAD of the `nightly` branch and work with bleeding edge and experimental changes/features currently in development.
+:::
diff --git a/examples/notebooks/parquet_explorer.ipynb b/docs/tutorials/parquet_explorer.ipynb
similarity index 100%
rename from examples/notebooks/parquet_explorer.ipynb
rename to docs/tutorials/parquet_explorer.ipynb
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 000000000000..0527d0cc1ac2
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,17 @@
+# Examples
+
+The following code examples are organized by system environment context:
+- **Backtest:** Historical data with simulated venues
+- **Sandbox:** Real-time data with simulated venues
+- **Live:** Real-time data with live venues (paper trading or real accounts)
+
+Within each environment context directory, are scripts organized by integration.
+
+Ensure that the `nautilus_trader` package is either compiled from source or installed via pip before
+running the examples. See the [installation guide](https://nautilustrader.io/docs/getting_started/installation)
+for more information.
+
+To execute an example script from the `examples` directory, use a command similar to the following:
+```
+python backtest/crypto_ema_cross_ethusdt_trade_ticks.py
+```
diff --git a/examples/live/binance/binance_futures_testnet_ema_cross_with_trailing_stop.py b/examples/live/binance/binance_futures_testnet_ema_cross_with_trailing_stop.py
index 65b988300492..a2d8c1eb671a 100644
--- a/examples/live/binance/binance_futures_testnet_ema_cross_with_trailing_stop.py
+++ b/examples/live/binance/binance_futures_testnet_ema_cross_with_trailing_stop.py
@@ -40,7 +40,7 @@
# Configure the trading node
config_node = TradingNodeConfig(
trader_id=TraderId("TESTER-001"),
- logging=LoggingConfig(log_level="INFO"),
+ logging=LoggingConfig(log_level="INFO", use_pyo3=True),
exec_engine=LiveExecEngineConfig(
reconciliation=True,
reconciliation_lookback_mins=1440,
@@ -80,10 +80,11 @@
node = TradingNode(config=config_node)
# Configure your strategy
+symbol = "ETHUSDT-PERP"
strat_config = EMACrossTrailingStopConfig(
- instrument_id=InstrumentId.from_str("ETHUSDT-PERP.BINANCE"),
- external_order_claims=[InstrumentId.from_str("ETHUSDT-PERP.BINANCE")],
- bar_type=BarType.from_str("ETHUSDT-PERP.BINANCE-1-MINUTE-LAST-EXTERNAL"),
+ instrument_id=InstrumentId.from_str(f"{symbol}.BINANCE"),
+ external_order_claims=[InstrumentId.from_str(f"{symbol}.BINANCE")],
+ bar_type=BarType.from_str(f"{symbol}.BINANCE-1-MINUTE-LAST-EXTERNAL"),
fast_ema_period=10,
slow_ema_period=20,
atr_period=20,
diff --git a/examples/live/bybit/bybit_ema_cross_stop_entry.py b/examples/live/bybit/bybit_ema_cross_stop_entry.py
new file mode 100644
index 000000000000..b5f9df2793bd
--- /dev/null
+++ b/examples/live/bybit/bybit_ema_cross_stop_entry.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python3
+# -------------------------------------------------------------------------------------------------
+# Copyright (C) 2015-2024 Nautech Systems Pty Ltd. All rights reserved.
+# https://nautechsystems.io
+#
+# Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
+# You may not use this file except in compliance with the License.
+# You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# -------------------------------------------------------------------------------------------------
+
+from decimal import Decimal
+
+from nautilus_trader.adapters.bybit.common.enums import BybitProductType
+from nautilus_trader.adapters.bybit.config import BybitDataClientConfig
+from nautilus_trader.adapters.bybit.config import BybitExecClientConfig
+from nautilus_trader.adapters.bybit.factories import BybitLiveDataClientFactory
+from nautilus_trader.adapters.bybit.factories import BybitLiveExecClientFactory
+from nautilus_trader.config import InstrumentProviderConfig
+from nautilus_trader.config import LiveExecEngineConfig
+from nautilus_trader.config import LoggingConfig
+from nautilus_trader.config import TradingNodeConfig
+from nautilus_trader.examples.strategies.ema_cross_stop_entry import EMACrossStopEntry
+from nautilus_trader.examples.strategies.ema_cross_stop_entry import EMACrossStopEntryConfig
+from nautilus_trader.live.node import TradingNode
+from nautilus_trader.model.data import BarType
+from nautilus_trader.model.identifiers import InstrumentId
+from nautilus_trader.model.identifiers import TraderId
+
+
+# *** THIS IS A TEST STRATEGY WITH NO ALPHA ADVANTAGE WHATSOEVER. ***
+# *** IT IS NOT INTENDED TO BE USED TO TRADE LIVE WITH REAL MONEY. ***
+
+# SPOT/LINEAR
+product_type = BybitProductType.LINEAR
+symbol = f"ETHUSDT-{product_type.value.upper()}"
+trade_size = Decimal("0.010")
+
+# Configure the trading node
+config_node = TradingNodeConfig(
+ trader_id=TraderId("TESTER-001"),
+ logging=LoggingConfig(log_level="INFO", use_pyo3=True),
+ exec_engine=LiveExecEngineConfig(
+ reconciliation=True,
+ reconciliation_lookback_mins=1440,
+ ),
+ data_clients={
+ "BYBIT": BybitDataClientConfig(
+ api_key=None, # 'BYBIT_API_KEY' env var
+ api_secret=None, # 'BYBIT_API_SECRET' env var
+ base_url_http=None, # Override with custom endpoint
+ instrument_provider=InstrumentProviderConfig(load_all=True),
+ product_types=[product_type],
+ testnet=False, # If client uses the testnet
+ ),
+ },
+ exec_clients={
+ "BYBIT": BybitExecClientConfig(
+ api_key=None, # 'BYBIT_API_KEY' env var
+ api_secret=None, # 'BYBIT_API_SECRET' env var
+ base_url_http=None, # Override with custom endpoint
+ base_url_ws=None, # Override with custom endpoint
+ instrument_provider=InstrumentProviderConfig(load_all=True),
+ product_types=[product_type],
+ testnet=False, # If client uses the testnet
+ ),
+ },
+ timeout_connection=30.0,
+ timeout_reconciliation=10.0,
+ timeout_portfolio=10.0,
+ timeout_disconnection=10.0,
+ timeout_post_stop=5.0,
+)
+
+# Instantiate the node with a configuration
+node = TradingNode(config=config_node)
+
+# Configure your strategy
+strat_config = EMACrossStopEntryConfig(
+ instrument_id=InstrumentId.from_str(f"{symbol}.BYBIT"),
+ external_order_claims=[InstrumentId.from_str(f"{symbol}.BYBIT")],
+ bar_type=BarType.from_str(f"{symbol}.BYBIT-1-MINUTE-LAST-EXTERNAL"),
+ fast_ema_period=10,
+ slow_ema_period=20,
+ atr_period=20,
+ trailing_atr_multiple=3.0,
+ trailing_offset=Decimal("0.010"),
+ trailing_offset_type="BASIS_POINTS",
+ trigger_type="LAST_TRADE",
+ trade_size=Decimal("0.010"),
+)
+# Instantiate your strategy
+strategy = EMACrossStopEntry(config=strat_config)
+
+# Add your strategies and modules
+node.trader.add_strategy(strategy)
+
+# Register your client factories with the node (can take user defined factories)
+node.add_data_client_factory("BYBIT", BybitLiveDataClientFactory)
+node.add_exec_client_factory("BYBIT", BybitLiveExecClientFactory)
+node.build()
+
+
+# Stop and dispose of the node with SIGINT/CTRL+C
+if __name__ == "__main__":
+ try:
+ node.run()
+ finally:
+ node.dispose()
diff --git a/examples/live/bybit/bybit_ema_cross_with_trailing_stop.py b/examples/live/bybit/bybit_ema_cross_with_trailing_stop.py
new file mode 100644
index 000000000000..73f9036b2217
--- /dev/null
+++ b/examples/live/bybit/bybit_ema_cross_with_trailing_stop.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+# -------------------------------------------------------------------------------------------------
+# Copyright (C) 2015-2024 Nautech Systems Pty Ltd. All rights reserved.
+# https://nautechsystems.io
+#
+# Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
+# You may not use this file except in compliance with the License.
+# You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# -------------------------------------------------------------------------------------------------
+
+from decimal import Decimal
+
+from nautilus_trader.adapters.bybit.common.enums import BybitProductType
+from nautilus_trader.adapters.bybit.config import BybitDataClientConfig
+from nautilus_trader.adapters.bybit.config import BybitExecClientConfig
+from nautilus_trader.adapters.bybit.factories import BybitLiveDataClientFactory
+from nautilus_trader.adapters.bybit.factories import BybitLiveExecClientFactory
+from nautilus_trader.config import InstrumentProviderConfig
+from nautilus_trader.config import LiveExecEngineConfig
+from nautilus_trader.config import LoggingConfig
+from nautilus_trader.config import TradingNodeConfig
+from nautilus_trader.examples.strategies.ema_cross_trailing_stop import EMACrossTrailingStop
+from nautilus_trader.examples.strategies.ema_cross_trailing_stop import EMACrossTrailingStopConfig
+from nautilus_trader.live.node import TradingNode
+from nautilus_trader.model.data import BarType
+from nautilus_trader.model.identifiers import InstrumentId
+from nautilus_trader.model.identifiers import TraderId
+
+
+# *** THIS IS A TEST STRATEGY WITH NO ALPHA ADVANTAGE WHATSOEVER. ***
+# *** IT IS NOT INTENDED TO BE USED TO TRADE LIVE WITH REAL MONEY. ***
+
+# SPOT/LINEAR
+product_type = BybitProductType.LINEAR
+symbol = f"ETHUSDT-{product_type.value.upper()}"
+trade_size = Decimal("0.010")
+
+# Configure the trading node
+config_node = TradingNodeConfig(
+ trader_id=TraderId("TESTER-001"),
+ logging=LoggingConfig(log_level="INFO", use_pyo3=True),
+ exec_engine=LiveExecEngineConfig(
+ reconciliation=True,
+ reconciliation_lookback_mins=1440,
+ ),
+ data_clients={
+ "BYBIT": BybitDataClientConfig(
+ api_key=None, # 'BYBIT_API_KEY' env var
+ api_secret=None, # 'BYBIT_API_SECRET' env var
+ base_url_http=None, # Override with custom endpoint
+ instrument_provider=InstrumentProviderConfig(load_all=True),
+ product_types=[product_type],
+ testnet=False, # If client uses the testnet
+ ),
+ },
+ exec_clients={
+ "BYBIT": BybitExecClientConfig(
+ api_key=None, # 'BYBIT_API_KEY' env var
+ api_secret=None, # 'BYBIT_API_SECRET' env var
+ base_url_http=None, # Override with custom endpoint
+ base_url_ws=None, # Override with custom endpoint
+ instrument_provider=InstrumentProviderConfig(load_all=True),
+ product_types=[product_type],
+ testnet=False, # If client uses the testnet
+ ),
+ },
+ timeout_connection=30.0,
+ timeout_reconciliation=10.0,
+ timeout_portfolio=10.0,
+ timeout_disconnection=10.0,
+ timeout_post_stop=5.0,
+)
+
+# Instantiate the node with a configuration
+node = TradingNode(config=config_node)
+
+# Configure your strategy
+strat_config = EMACrossTrailingStopConfig(
+ instrument_id=InstrumentId.from_str(f"{symbol}.BYBIT"),
+ external_order_claims=[InstrumentId.from_str(f"{symbol}.BYBIT")],
+ bar_type=BarType.from_str(f"{symbol}.BYBIT-1-MINUTE-LAST-EXTERNAL"),
+ fast_ema_period=10,
+ slow_ema_period=20,
+ atr_period=20,
+ trailing_atr_multiple=3.0,
+ trailing_offset_type="BASIS_POINTS",
+ trigger_type="LAST_TRADE",
+ trade_size=Decimal("0.010"),
+)
+# Instantiate your strategy
+strategy = EMACrossTrailingStop(config=strat_config)
+
+# Add your strategies and modules
+node.trader.add_strategy(strategy)
+
+# Register your client factories with the node (can take user defined factories)
+node.add_data_client_factory("BYBIT", BybitLiveDataClientFactory)
+node.add_exec_client_factory("BYBIT", BybitLiveExecClientFactory)
+node.build()
+
+
+# Stop and dispose of the node with SIGINT/CTRL+C
+if __name__ == "__main__":
+ try:
+ node.run()
+ finally:
+ node.dispose()
diff --git a/examples/live/bybit/bybit_market_maker.py b/examples/live/bybit/bybit_market_maker.py
index 9cafd7ff3f91..5c0107838f1e 100644
--- a/examples/live/bybit/bybit_market_maker.py
+++ b/examples/live/bybit/bybit_market_maker.py
@@ -22,7 +22,6 @@
from nautilus_trader.adapters.bybit.factories import BybitLiveDataClientFactory
from nautilus_trader.adapters.bybit.factories import BybitLiveExecClientFactory
from nautilus_trader.cache.config import CacheConfig
-from nautilus_trader.common.config import DatabaseConfig
from nautilus_trader.config import InstrumentProviderConfig
from nautilus_trader.config import LiveExecEngineConfig
from nautilus_trader.config import LoggingConfig
@@ -60,7 +59,7 @@
reconciliation_lookback_mins=1440,
),
cache=CacheConfig(
- database=DatabaseConfig(),
+ # database=DatabaseConfig(),
timestamps_as_iso8601=True,
buffer_interval_ms=100,
),
@@ -83,7 +82,7 @@
api_secret=None, # 'BYBIT_API_SECRET' env var
base_url_http=None, # Override with custom endpoint
instrument_provider=InstrumentProviderConfig(load_all=True),
- # product_types=[product_type], # Will load all instruments
+ product_types=[product_type], # Will load all instruments
testnet=False, # If client uses the testnet
),
},
diff --git a/examples/live/interactive_brokers/interactive_brokers_example.py b/examples/live/interactive_brokers/connect_with_dockerized_gateway.py
similarity index 94%
rename from examples/live/interactive_brokers/interactive_brokers_example.py
rename to examples/live/interactive_brokers/connect_with_dockerized_gateway.py
index fb0700ba110b..e4f67c4b4b25 100644
--- a/examples/live/interactive_brokers/interactive_brokers_example.py
+++ b/examples/live/interactive_brokers/connect_with_dockerized_gateway.py
@@ -16,12 +16,14 @@
# fmt: off
+import os
+
from nautilus_trader.adapters.interactive_brokers.common import IB_VENUE
from nautilus_trader.adapters.interactive_brokers.common import IBContract
+from nautilus_trader.adapters.interactive_brokers.config import DockerizedIBGatewayConfig
from nautilus_trader.adapters.interactive_brokers.config import IBMarketDataTypeEnum
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersDataClientConfig
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersExecClientConfig
-from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersGatewayConfig
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersInstrumentProviderConfig
from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveDataClientFactory
from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveExecClientFactory
@@ -62,10 +64,9 @@
IBContract(secType="FUT", exchange="NYMEX", localSymbol="CLV3", build_futures_chain=False),
]
-gateway = InteractiveBrokersGatewayConfig(
- start=False,
- username=None,
- password=None,
+dockerized_gateway = DockerizedIBGatewayConfig(
+ username=os.environ["TWS_USERNAME"],
+ password=os.environ["TWS_PASSWORD"],
trading_mode="paper",
read_only_api=True,
)
@@ -96,23 +97,19 @@
logging=LoggingConfig(log_level="INFO"),
data_clients={
"IB": InteractiveBrokersDataClientConfig(
- ibg_host="127.0.0.1",
- ibg_port=7497,
ibg_client_id=1,
handle_revised_bars=False,
use_regular_trading_hours=True,
market_data_type=IBMarketDataTypeEnum.DELAYED_FROZEN, # If unset default is REALTIME
instrument_provider=instrument_provider,
- gateway=gateway,
+ dockerized_gateway=dockerized_gateway,
),
},
exec_clients={
"IB": InteractiveBrokersExecClientConfig(
- ibg_host="127.0.0.1",
- ibg_port=7497,
ibg_client_id=1,
account_id="DU123456", # This must match with the IB Gateway/TWS node is connecting to
- gateway=gateway,
+ dockerized_gateway=dockerized_gateway,
instrument_provider=instrument_provider,
routing=RoutingConfig(
default=True,
diff --git a/examples/live/interactive_brokers/connect_with_tws.py b/examples/live/interactive_brokers/connect_with_tws.py
new file mode 100644
index 000000000000..5f819f1ff3e5
--- /dev/null
+++ b/examples/live/interactive_brokers/connect_with_tws.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+# -------------------------------------------------------------------------------------------------
+# Copyright (C) 2015-2024 Nautech Systems Pty Ltd. All rights reserved.
+# https://nautechsystems.io
+#
+# Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
+# You may not use this file except in compliance with the License.
+# You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# -------------------------------------------------------------------------------------------------
+
+# fmt: off
+
+from nautilus_trader.adapters.interactive_brokers.config import IBMarketDataTypeEnum
+from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersDataClientConfig
+from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersExecClientConfig
+from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersInstrumentProviderConfig
+from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveDataClientFactory
+from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveExecClientFactory
+from nautilus_trader.config import LiveDataEngineConfig
+from nautilus_trader.config import LoggingConfig
+from nautilus_trader.config import RoutingConfig
+from nautilus_trader.config import TradingNodeConfig
+from nautilus_trader.examples.strategies.subscribe import SubscribeStrategy
+from nautilus_trader.examples.strategies.subscribe import SubscribeStrategyConfig
+from nautilus_trader.live.node import TradingNode
+from nautilus_trader.model.identifiers import InstrumentId
+
+
+# fmt: on
+
+# *** THIS IS A TEST STRATEGY WITH NO ALPHA ADVANTAGE WHATSOEVER. ***
+# *** IT IS NOT INTENDED TO BE USED TO TRADE LIVE WITH REAL MONEY. ***
+
+# *** THIS INTEGRATION IS STILL UNDER CONSTRUCTION. ***
+# *** CONSIDER IT TO BE IN AN UNSTABLE BETA PHASE AND EXERCISE CAUTION. ***
+
+
+instrument_provider = InteractiveBrokersInstrumentProviderConfig(
+ load_ids=frozenset(
+ [
+ "EUR/USD.IDEALPRO",
+ "BTC/USD.PAXOS",
+ "SPY.ARCA",
+ "AAPL.NASDAQ",
+ "V.NYSE",
+ "CLZ28.NYMEX",
+ "ESZ28.CME",
+ ],
+ ),
+)
+
+# Configure the trading node
+
+config_node = TradingNodeConfig(
+ trader_id="TESTER-001",
+ logging=LoggingConfig(log_level="INFO"),
+ data_clients={
+ "IB": InteractiveBrokersDataClientConfig(
+ ibg_host="127.0.0.1",
+ ibg_port=7497,
+ ibg_client_id=1,
+ handle_revised_bars=False,
+ use_regular_trading_hours=True,
+ market_data_type=IBMarketDataTypeEnum.DELAYED_FROZEN, # If unset default is REALTIME
+ instrument_provider=instrument_provider,
+ ),
+ },
+ exec_clients={
+ "IB": InteractiveBrokersExecClientConfig(
+ ibg_host="127.0.0.1",
+ ibg_port=7497,
+ ibg_client_id=1,
+ account_id="DU123456", # This must match with the IB Gateway/TWS node is connecting to
+ instrument_provider=instrument_provider,
+ routing=RoutingConfig(
+ default=True,
+ ),
+ ),
+ },
+ data_engine=LiveDataEngineConfig(
+ time_bars_timestamp_on_close=False, # Will use opening time as `ts_event` (same like IB)
+ validate_data_sequence=True, # Will make sure DataEngine discards any Bars received out of sequence
+ ),
+ timeout_connection=90.0,
+ timeout_reconciliation=5.0,
+ timeout_portfolio=5.0,
+ timeout_disconnection=5.0,
+ timeout_post_stop=2.0,
+)
+
+
+# Instantiate the node with a configuration
+node = TradingNode(config=config_node)
+
+# Configure your strategy
+strategy_config = SubscribeStrategyConfig(
+ instrument_id=InstrumentId.from_str("EUR/USD.IDEALPRO"),
+ trade_ticks=False,
+ quote_ticks=True,
+ bars=True,
+)
+# Instantiate your strategy
+strategy = SubscribeStrategy(config=strategy_config)
+
+# Add your strategies and modules
+node.trader.add_strategy(strategy)
+
+# Register your client factories with the node (can take user defined factories)
+node.add_data_client_factory("IB", InteractiveBrokersLiveDataClientFactory)
+node.add_exec_client_factory("IB", InteractiveBrokersLiveExecClientFactory)
+node.build()
+
+
+# Stop and dispose of the node with SIGINT/CTRL+C
+if __name__ == "__main__":
+ try:
+ node.run()
+ finally:
+ node.dispose()
diff --git a/examples/live/interactive_brokers/historic_download.py b/examples/live/interactive_brokers/historic_download.py
index 1b0e2c1b0d30..91dfa5e51469 100644
--- a/examples/live/interactive_brokers/historic_download.py
+++ b/examples/live/interactive_brokers/historic_download.py
@@ -19,20 +19,33 @@
import os
from nautilus_trader.adapters.interactive_brokers.common import IBContract
-from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersGatewayConfig
-from nautilus_trader.adapters.interactive_brokers.gateway import InteractiveBrokersGateway
+from nautilus_trader.adapters.interactive_brokers.config import DockerizedIBGatewayConfig
+from nautilus_trader.adapters.interactive_brokers.gateway import DockerizedIBGateway
from nautilus_trader.adapters.interactive_brokers.historic import HistoricInteractiveBrokersClient
+from nautilus_trader.core.correctness import PyCondition
from nautilus_trader.persistence.catalog import ParquetDataCatalog
-async def main():
- gateway_config = InteractiveBrokersGatewayConfig(
- username=os.environ["TWS_USERNAME"],
- password=os.environ["TWS_PASSWORD"],
- port=4002,
- )
- gateway = InteractiveBrokersGateway(config=gateway_config)
- gateway.start()
+async def main(
+ host: str | None = None,
+ port: int | None = None,
+ dockerized_gateway: DockerizedIBGatewayConfig | None = None,
+) -> None:
+ if dockerized_gateway:
+ PyCondition.none(host, "Ensure `host` is set to None when using DockerizedIBGatewayConfig.")
+ PyCondition.none(port, "Ensure `port` is set to None when using DockerizedIBGatewayConfig.")
+ PyCondition.type(dockerized_gateway, DockerizedIBGatewayConfig, "dockerized_gateway")
+ gateway = DockerizedIBGateway(config=dockerized_gateway)
+ gateway.start(dockerized_gateway.timeout)
+ host = gateway.host
+ port = gateway.port
+ else:
+ gateway = None
+ PyCondition.not_none(
+ host,
+ "Please provide the `host` IP address for the IB TWS or Gateway.",
+ )
+ PyCondition.not_none(port, "Please provide the `port` for the IB TWS or Gateway.")
contract = IBContract(
secType="STK",
@@ -42,8 +55,8 @@ async def main():
)
instrument_id = "TSLA.NASDAQ"
- client = HistoricInteractiveBrokersClient(port=4002, client_id=5)
- await client._connect()
+ client = HistoricInteractiveBrokersClient(host=host, port=port, client_id=5)
+ await client.connect()
await asyncio.sleep(2)
instruments = await client.request_instruments(
@@ -78,7 +91,8 @@ async def main():
instrument_ids=[instrument_id],
)
- gateway.stop()
+ if gateway:
+ gateway.stop()
catalog = ParquetDataCatalog("./catalog")
catalog.write_data(instruments)
@@ -88,4 +102,13 @@ async def main():
if __name__ == "__main__":
- asyncio.run(main())
+ gateway_config = DockerizedIBGatewayConfig(
+ username=os.environ["TWS_USERNAME"],
+ password=os.environ["TWS_PASSWORD"],
+ trading_mode="paper",
+ )
+ asyncio.run(main(dockerized_gateway=gateway_config))
+
+ # To connect to an existing TWS or Gateway instance without the use of automated dockerized gateway,
+ # follow this format:
+ # asyncio.run(main(host="127.0.0.1", port=7497))
diff --git a/examples/sandbox/interactive_brokers_sandbox.py b/examples/sandbox/interactive_brokers_sandbox.py
index 2895783c1e05..dcc2668d9ae5 100644
--- a/examples/sandbox/interactive_brokers_sandbox.py
+++ b/examples/sandbox/interactive_brokers_sandbox.py
@@ -16,9 +16,10 @@
from decimal import Decimal
+from nautilus_trader.adapters.interactive_brokers.config import DockerizedIBGatewayConfig
+
# fmt: off
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersDataClientConfig
-from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersGatewayConfig
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersInstrumentProviderConfig
from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveDataClientFactory
from nautilus_trader.adapters.sandbox.config import SandboxExecutionClientConfig
@@ -41,8 +42,7 @@
SANDBOX_INSTRUMENTS = catalog.instruments(instrument_ids=["EUR/USD.IDEALPRO"])
# Set up the Interactive Brokers gateway configuration, this is applicable only when using Docker.
-gateway = InteractiveBrokersGatewayConfig(
- start=False,
+dockerized_gateway = DockerizedIBGatewayConfig(
username=None,
password=None,
trading_mode="paper",
@@ -80,7 +80,7 @@
ibg_client_id=1,
use_regular_trading_hours=True,
instrument_provider=instrument_provider,
- gateway=gateway,
+ dockerized_gateway=dockerized_gateway,
),
},
exec_clients=exec_clients, # type: ignore
diff --git a/nautilus_core/Cargo.lock b/nautilus_core/Cargo.lock
index 61ef3ca14afa..3298d5afb35f 100644
--- a/nautilus_core/Cargo.lock
+++ b/nautilus_core/Cargo.lock
@@ -125,9 +125,9 @@ dependencies = [
[[package]]
name = "anstyle-query"
-version = "1.0.3"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
+checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
dependencies = [
"windows-sys 0.52.0",
]
@@ -162,9 +162,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "arrow"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "219d05930b81663fd3b32e3bde8ce5bff3c4d23052a99f11a8fa50a3b47b2658"
+checksum = "7ae9728f104939be6d8d9b368a354b4929b0569160ea1641f0721b55a861ce38"
dependencies = [
"arrow-arith",
"arrow-array",
@@ -184,9 +184,9 @@ dependencies = [
[[package]]
name = "arrow-arith"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0272150200c07a86a390be651abdd320a2d12e84535f0837566ca87ecd8f95e0"
+checksum = "a7029a5b3efbeafbf4a12d12dc16b8f9e9bff20a410b8c25c5d28acc089e1043"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -199,9 +199,9 @@ dependencies = [
[[package]]
name = "arrow-array"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8010572cf8c745e242d1b632bd97bd6d4f40fefed5ed1290a8f433abaa686fea"
+checksum = "d33238427c60271710695f17742f45b1a5dc5bcfc5c15331c25ddfe7abf70d97"
dependencies = [
"ahash 0.8.11",
"arrow-buffer",
@@ -216,9 +216,9 @@ dependencies = [
[[package]]
name = "arrow-buffer"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d0a2432f0cba5692bf4cb757469c66791394bac9ec7ce63c1afe74744c37b27"
+checksum = "fe9b95e825ae838efaf77e366c00d3fc8cca78134c9db497d6bda425f2e7b7c1"
dependencies = [
"bytes",
"half",
@@ -227,9 +227,9 @@ dependencies = [
[[package]]
name = "arrow-cast"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9abc10cd7995e83505cc290df9384d6e5412b207b79ce6bdff89a10505ed2cba"
+checksum = "87cf8385a9d5b5fcde771661dd07652b79b9139fea66193eda6a88664400ccab"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -248,9 +248,9 @@ dependencies = [
[[package]]
name = "arrow-csv"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95cbcba196b862270bf2a5edb75927380a7f3a163622c61d40cbba416a6305f2"
+checksum = "cea5068bef430a86690059665e40034625ec323ffa4dd21972048eebb0127adc"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -267,9 +267,9 @@ dependencies = [
[[package]]
name = "arrow-data"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2742ac1f6650696ab08c88f6dd3f0eb68ce10f8c253958a18c943a68cd04aec5"
+checksum = "cb29be98f987bcf217b070512bb7afba2f65180858bca462edf4a39d84a23e10"
dependencies = [
"arrow-buffer",
"arrow-schema",
@@ -279,9 +279,9 @@ dependencies = [
[[package]]
name = "arrow-ipc"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a42ea853130f7e78b9b9d178cb4cd01dee0f78e64d96c2949dc0a915d6d9e19d"
+checksum = "ffc68f6523970aa6f7ce1dc9a33a7d9284cfb9af77d4ad3e617dbe5d79cc6ec8"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -294,9 +294,9 @@ dependencies = [
[[package]]
name = "arrow-json"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaafb5714d4e59feae964714d724f880511500e3569cc2a94d02456b403a2a49"
+checksum = "2041380f94bd6437ab648e6c2085a045e45a0c44f91a1b9a4fe3fed3d379bfb1"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -314,9 +314,9 @@ dependencies = [
[[package]]
name = "arrow-ord"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3e6b61e3dc468f503181dccc2fc705bdcc5f2f146755fa5b56d0a6c5943f412"
+checksum = "fcb56ed1547004e12203652f12fe12e824161ff9d1e5cf2a7dc4ff02ba94f413"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -329,9 +329,9 @@ dependencies = [
[[package]]
name = "arrow-row"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "848ee52bb92eb459b811fb471175ea3afcf620157674c8794f539838920f9228"
+checksum = "575b42f1fc588f2da6977b94a5ca565459f5ab07b60545e17243fb9a7ed6d43e"
dependencies = [
"ahash 0.8.11",
"arrow-array",
@@ -344,18 +344,18 @@ dependencies = [
[[package]]
name = "arrow-schema"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02d9483aaabe910c4781153ae1b6ae0393f72d9ef757d38d09d450070cf2e528"
+checksum = "32aae6a60458a2389c0da89c9de0b7932427776127da1a738e2efc21d32f3393"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "arrow-select"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "849524fa70e0e3c5ab58394c770cb8f514d0122d20de08475f7b472ed8075830"
+checksum = "de36abaef8767b4220d7b4a8c2fe5ffc78b47db81b03d77e2136091c3ba39102"
dependencies = [
"ahash 0.8.11",
"arrow-array",
@@ -367,9 +367,9 @@ dependencies = [
[[package]]
name = "arrow-string"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9373cb5a021aee58863498c37eb484998ef13377f69989c6c5ccfbd258236cdb"
+checksum = "e435ada8409bcafc910bc3e0077f532a4daa20e99060a496685c0e3e53cc2597"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -379,7 +379,7 @@ dependencies = [
"memchr",
"num",
"regex",
- "regex-syntax 0.8.3",
+ "regex-syntax 0.8.4",
]
[[package]]
@@ -500,9 +500,9 @@ dependencies = [
[[package]]
name = "backtrace"
-version = "0.3.72"
+version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11"
+checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
@@ -578,9 +578,9 @@ dependencies = [
[[package]]
name = "borsh"
-version = "1.5.0"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77"
+checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
dependencies = [
"borsh-derive",
"cfg_aliases",
@@ -588,9 +588,9 @@ dependencies = [
[[package]]
name = "borsh-derive"
-version = "1.5.0"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d"
+checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
dependencies = [
"once_cell",
"proc-macro-crate",
@@ -602,9 +602,9 @@ dependencies = [
[[package]]
name = "brotli"
-version = "3.5.0"
+version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
+checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -613,9 +613,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
-version = "2.5.1"
+version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
+checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -715,9 +715,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.98"
+version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
+checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
dependencies = [
"jobserver",
"libc",
@@ -732,9 +732,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
-version = "0.1.1"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
@@ -752,9 +752,9 @@ dependencies = [
[[package]]
name = "chrono-tz"
-version = "0.8.6"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e"
+checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
dependencies = [
"chrono",
"chrono-tz-build",
@@ -763,9 +763,9 @@ dependencies = [
[[package]]
name = "chrono-tz-build"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f"
+checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
dependencies = [
"parse-zoneinfo",
"phf",
@@ -816,9 +816,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.4"
+version = "4.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
+checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
dependencies = [
"clap_builder",
"clap_derive",
@@ -826,21 +826,21 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.2"
+version = "4.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
+checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
dependencies = [
"anstream",
"anstyle",
- "clap_lex 0.7.0",
+ "clap_lex 0.7.1",
"strsim 0.11.1",
]
[[package]]
name = "clap_derive"
-version = "4.5.4"
+version = "4.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
+checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -859,9 +859,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
+checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
[[package]]
name = "colorchoice"
@@ -994,7 +994,7 @@ dependencies = [
"anes",
"cast",
"ciborium",
- "clap 4.5.4",
+ "clap 4.5.7",
"criterion-plot",
"is-terminal",
"itertools 0.10.5",
@@ -1148,9 +1148,9 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
[[package]]
name = "databento"
-version = "0.10.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "958e83b1f051563971485b8b8acf6de4fe016ec5d4e9cf3e10aa810416b7d160"
+checksum = "ce919531f297649bd016e1febbac94d33a2d9fd75c35ec5f1925f7cb813c93fc"
dependencies = [
"dbn",
"futures",
@@ -1169,9 +1169,9 @@ dependencies = [
[[package]]
name = "datafusion"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05fb4eeeb7109393a0739ac5b8fd892f95ccef691421491c85544f7997366f68"
+checksum = "2f92d2d7a9cba4580900b32b009848d9eb35f1028ac84cdd6ddcf97612cd0068"
dependencies = [
"ahash 0.8.11",
"arrow",
@@ -1192,6 +1192,7 @@ dependencies = [
"datafusion-functions-aggregate",
"datafusion-optimizer",
"datafusion-physical-expr",
+ "datafusion-physical-expr-common",
"datafusion-physical-plan",
"datafusion-sql",
"flate2",
@@ -1206,6 +1207,7 @@ dependencies = [
"object_store",
"parking_lot",
"parquet",
+ "paste",
"pin-project-lite",
"rand",
"sqlparser",
@@ -1220,9 +1222,9 @@ dependencies = [
[[package]]
name = "datafusion-common"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "741aeac15c82f239f2fc17deccaab19873abbd62987be20023689b15fa72fa09"
+checksum = "effed030d2c1667eb1e11df5372d4981eaf5d11a521be32220b3985ae5ba6971"
dependencies = [
"ahash 0.8.11",
"arrow",
@@ -1231,6 +1233,7 @@ dependencies = [
"arrow-schema",
"chrono",
"half",
+ "hashbrown 0.14.5",
"instant",
"libc",
"num_cpus",
@@ -1242,18 +1245,18 @@ dependencies = [
[[package]]
name = "datafusion-common-runtime"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e8ddfb8d8cb51646a30da0122ecfffb81ca16919ae9a3495a9e7468bdcd52b8"
+checksum = "d0091318129dad1359f08e4c6c71f855163c35bba05d1dbf983196f727857894"
dependencies = [
"tokio",
]
[[package]]
name = "datafusion-execution"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282122f90b20e8f98ebfa101e4bf20e718fd2684cf81bef4e8c6366571c64404"
+checksum = "8385aba84fc4a06d3ebccfbcbf9b4f985e80c762fac634b49079f7cc14933fb1"
dependencies = [
"arrow",
"chrono",
@@ -1272,13 +1275,14 @@ dependencies = [
[[package]]
name = "datafusion-expr"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5478588f733df0dfd87a62671c7478f590952c95fa2fa5c137e3ff2929491e22"
+checksum = "ebb192f0055d2ce64e38ac100abc18e4e6ae9734d3c28eee522bbbd6a32108a3"
dependencies = [
"ahash 0.8.11",
"arrow",
"arrow-array",
+ "arrow-buffer",
"chrono",
"datafusion-common",
"paste",
@@ -1290,9 +1294,9 @@ dependencies = [
[[package]]
name = "datafusion-functions"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4afd261cea6ac9c3ca1192fd5e9f940596d8e9208c5b1333f4961405db53185"
+checksum = "27c081ae5b7edd712b92767fb8ed5c0e32755682f8075707666cd70835807c0b"
dependencies = [
"arrow",
"base64 0.22.1",
@@ -1313,11 +1317,13 @@ dependencies = [
[[package]]
name = "datafusion-functions-aggregate"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b36a6c4838ab94b5bf8f7a96ce6ce059d805c5d1dcaa6ace49e034eb65cd999"
+checksum = "feb28a4ea52c28a26990646986a27c4052829a2a2572386258679e19263f8b78"
dependencies = [
+ "ahash 0.8.11",
"arrow",
+ "arrow-schema",
"datafusion-common",
"datafusion-execution",
"datafusion-expr",
@@ -1329,9 +1335,9 @@ dependencies = [
[[package]]
name = "datafusion-optimizer"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54f2820938810e8a2d71228fd6f59f33396aebc5f5f687fcbf14de5aab6a7e1a"
+checksum = "12172f2a6c9eb4992a51e62d709eeba5dedaa3b5369cce37ff6c2260e100ba76"
dependencies = [
"arrow",
"async-trait",
@@ -1343,14 +1349,14 @@ dependencies = [
"indexmap 2.2.6",
"itertools 0.12.1",
"log",
- "regex-syntax 0.8.3",
+ "regex-syntax 0.8.4",
]
[[package]]
name = "datafusion-physical-expr"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9adf8eb12716f52ddf01e09eb6c94d3c9b291e062c05c91b839a448bddba2ff8"
+checksum = "7a3fce531b623e94180f6cd33d620ef01530405751b6ddd2fd96250cdbd78e2e"
dependencies = [
"ahash 0.8.11",
"arrow",
@@ -1379,20 +1385,21 @@ dependencies = [
[[package]]
name = "datafusion-physical-expr-common"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d5472c3230584c150197b3f2c23f2392b9dc54dbfb62ad41e7e36447cfce4be"
+checksum = "046400b6a2cc3ed57a7c576f5ae6aecc77804ac8e0186926b278b189305b2a77"
dependencies = [
"arrow",
"datafusion-common",
"datafusion-expr",
+ "rand",
]
[[package]]
name = "datafusion-physical-plan"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18ae750c38389685a8b62e5b899bbbec488950755ad6d218f3662d35b800c4fe"
+checksum = "4aed47f5a2ad8766260befb375b201592e86a08b260256e168ae4311426a2bff"
dependencies = [
"ahash 0.8.11",
"arrow",
@@ -1424,9 +1431,9 @@ dependencies = [
[[package]]
name = "datafusion-sql"
-version = "38.0.0"
+version = "39.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "befc67a3cdfbfa76853f43b10ac27337821bb98e519ab6baf431fcc0bcfcafdb"
+checksum = "7fa92bb1fd15e46ce5fb6f1c85f3ac054592560f294429a28e392b5f9cd4255e"
dependencies = [
"arrow",
"arrow-array",
@@ -1434,15 +1441,16 @@ dependencies = [
"datafusion-common",
"datafusion-expr",
"log",
+ "regex",
"sqlparser",
"strum",
]
[[package]]
name = "dbn"
-version = "0.18.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f78191ea0a044d346c1d05b11325414bc6d615c6bfdda4934634b19291295b92"
+checksum = "1d08c21b96290a94678c4bfacef7510ed96e5d12e32e542983dd5bf471bc075d"
dependencies = [
"async-compression",
"csv",
@@ -1460,9 +1468,9 @@ dependencies = [
[[package]]
name = "dbn-macros"
-version = "0.18.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a1fea28cc8c78a5626ea0d4965f896ef65466237c497f5373d2264eac803011"
+checksum = "a4f55029b42eb3420e023909bbf16a5664193fa01d3579136478ce49b7103b0a"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1540,6 +1548,17 @@ dependencies = [
"subtle",
]
+[[package]]
+name = "displaydoc"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
[[package]]
name = "doc-comment"
version = "0.3.3"
@@ -1645,9 +1664,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flatbuffers"
-version = "23.5.26"
+version = "24.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640"
+checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f"
dependencies = [
"bitflags 1.3.2",
"rustc_version",
@@ -2002,12 +2021,12 @@ dependencies = [
[[package]]
name = "http-body-util"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
- "futures-core",
+ "futures-util",
"http",
"http-body",
"pin-project-lite",
@@ -2015,9 +2034,9 @@ dependencies = [
[[package]]
name = "httparse"
-version = "1.8.0"
+version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545"
[[package]]
name = "httpdate"
@@ -2117,6 +2136,124 @@ dependencies = [
"cc",
]
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -2125,12 +2262,14 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
-version = "0.5.0"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed"
dependencies = [
- "unicode-bidi",
- "unicode-normalization",
+ "icu_normalizer",
+ "icu_properties",
+ "smallvec",
+ "utf8_iter",
]
[[package]]
@@ -2355,6 +2494,12 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+[[package]]
+name = "litemap"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704"
+
[[package]]
name = "lock_api"
version = "0.4.12"
@@ -2422,9 +2567,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.7.2"
+version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memoffset"
@@ -2486,10 +2631,11 @@ dependencies = [
[[package]]
name = "nautilus-accounting"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"cbindgen",
+ "log",
"nautilus-common",
"nautilus-core",
"nautilus-model",
@@ -2502,7 +2648,7 @@ dependencies = [
[[package]]
name = "nautilus-adapters"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"chrono",
@@ -2511,12 +2657,11 @@ dependencies = [
"fallible-streaming-iterator",
"indexmap 2.2.6",
"itoa",
- "log",
"nautilus-common",
"nautilus-core",
"nautilus-model",
"pyo3",
- "pyo3-asyncio",
+ "pyo3-asyncio-0-21",
"rand",
"rstest",
"rust_decimal",
@@ -2533,7 +2678,7 @@ dependencies = [
[[package]]
name = "nautilus-backtest"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"cbindgen",
@@ -2550,10 +2695,10 @@ dependencies = [
[[package]]
name = "nautilus-cli"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
- "clap 4.5.4",
+ "clap 4.5.7",
"clap_derive",
"dotenvy",
"log",
@@ -2567,7 +2712,7 @@ dependencies = [
[[package]]
name = "nautilus-common"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"cbindgen",
@@ -2578,7 +2723,7 @@ dependencies = [
"nautilus-core",
"nautilus-model",
"pyo3",
- "pyo3-asyncio",
+ "pyo3-asyncio-0-21",
"rstest",
"rust_decimal",
"rust_decimal_macros",
@@ -2595,7 +2740,7 @@ dependencies = [
[[package]]
name = "nautilus-core"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"cbindgen",
@@ -2615,7 +2760,7 @@ dependencies = [
[[package]]
name = "nautilus-execution"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"criterion",
@@ -2626,7 +2771,7 @@ dependencies = [
"nautilus-core",
"nautilus-model",
"pyo3",
- "pyo3-asyncio",
+ "pyo3-asyncio-0-21",
"rstest",
"rust_decimal",
"rust_decimal_macros",
@@ -2634,15 +2779,15 @@ dependencies = [
"serde_json",
"strum",
"thiserror",
- "tracing",
"ustr",
]
[[package]]
name = "nautilus-indicators"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
+ "log",
"nautilus-core",
"nautilus-model",
"pyo3",
@@ -2652,7 +2797,7 @@ dependencies = [
[[package]]
name = "nautilus-infrastructure"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"log",
@@ -2675,7 +2820,7 @@ dependencies = [
[[package]]
name = "nautilus-model"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"cbindgen",
@@ -2703,7 +2848,7 @@ dependencies = [
[[package]]
name = "nautilus-network"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"axum",
@@ -2716,7 +2861,7 @@ dependencies = [
"nautilus-core",
"nonzero_ext",
"pyo3",
- "pyo3-asyncio",
+ "pyo3-asyncio-0-21",
"reqwest",
"rstest",
"serde_json",
@@ -2728,7 +2873,7 @@ dependencies = [
[[package]]
name = "nautilus-persistence"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"anyhow",
"binary-heap-plus",
@@ -2737,6 +2882,7 @@ dependencies = [
"datafusion",
"dotenv",
"futures",
+ "log",
"nautilus-core",
"nautilus-model",
"procfs",
@@ -2751,7 +2897,7 @@ dependencies = [
[[package]]
name = "nautilus-pyo3"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"nautilus-accounting",
"nautilus-adapters",
@@ -2939,18 +3085,18 @@ dependencies = [
[[package]]
name = "object"
-version = "0.35.0"
+version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
+checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
dependencies = [
"memchr",
]
[[package]]
name = "object_store"
-version = "0.9.1"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8718f8b65fdf67a45108d1548347d4af7d71fb81ce727bbf9e3b2535e079db3"
+checksum = "fbebfd32c213ba1907fa7a9c9138015a8de2b43e30c5aa45b18f7deb46786ad6"
dependencies = [
"async-trait",
"bytes",
@@ -3013,9 +3159,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
-version = "300.3.0+3.3.0"
+version = "300.3.1+3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eba8804a1c5765b18c4b3f907e6897ebabeedebc9830e1a0046c4a4cf44663e1"
+checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91"
dependencies = [
"cc",
]
@@ -3083,16 +3229,16 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.5.1",
+ "redox_syscall 0.5.2",
"smallvec",
"windows-targets 0.52.5",
]
[[package]]
name = "parquet"
-version = "51.0.0"
+version = "52.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "096795d4f47f65fd3ee1ec5a98b77ab26d602f2cc785b0e4be5443add17ecc32"
+checksum = "29c3b5322cc1bbf67f11c079c42be41a55949099b78732f7dba9e15edde40eab"
dependencies = [
"ahash 0.8.11",
"arrow-array",
@@ -3121,6 +3267,7 @@ dependencies = [
"tokio",
"twox-hash",
"zstd",
+ "zstd-sys",
]
[[package]]
@@ -3351,9 +3498,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
+checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
@@ -3406,9 +3553,9 @@ dependencies = [
[[package]]
name = "pyo3"
-version = "0.20.3"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233"
+checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8"
dependencies = [
"cfg-if",
"indoc",
@@ -3424,24 +3571,24 @@ dependencies = [
]
[[package]]
-name = "pyo3-asyncio"
-version = "0.20.0"
+name = "pyo3-asyncio-0-21"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ea6b68e93db3622f3bb3bf363246cf948ed5375afe7abff98ccbdd50b184995"
+checksum = "8fde289486f7d5cee0ac7c20b2637a0657654681079cc5eedc90d9a2a79af1e5"
dependencies = [
"futures",
"once_cell",
"pin-project-lite",
"pyo3",
- "pyo3-asyncio-macros",
+ "pyo3-asyncio-macros-0-21",
"tokio",
]
[[package]]
-name = "pyo3-asyncio-macros"
-version = "0.20.0"
+name = "pyo3-asyncio-macros-0-21"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56c467178e1da6252c95c29ecf898b133f742e9181dca5def15dc24e19d45a39"
+checksum = "2e5ffc4e987e866bf54b781235a6c3b91e7e67df14f73ce716625ee78728554a"
dependencies = [
"proc-macro2",
"quote",
@@ -3450,9 +3597,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
-version = "0.20.3"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7"
+checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50"
dependencies = [
"once_cell",
"target-lexicon",
@@ -3460,9 +3607,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
-version = "0.20.3"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa"
+checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403"
dependencies = [
"libc",
"pyo3-build-config",
@@ -3470,9 +3617,9 @@ dependencies = [
[[package]]
name = "pyo3-macros"
-version = "0.20.3"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158"
+checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
@@ -3482,9 +3629,9 @@ dependencies = [
[[package]]
name = "pyo3-macros-backend"
-version = "0.20.3"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185"
+checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c"
dependencies = [
"heck 0.4.1",
"proc-macro2",
@@ -3595,7 +3742,7 @@ dependencies = [
"itoa",
"percent-encoding",
"pin-project-lite",
- "rustls",
+ "rustls 0.22.4",
"rustls-native-certs",
"rustls-pemfile",
"rustls-pki-types",
@@ -3621,23 +3768,23 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "regex"
-version = "1.10.4"
+version = "1.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
dependencies = [
"aho-corasick",
"memchr",
- "regex-automata 0.4.6",
- "regex-syntax 0.8.3",
+ "regex-automata 0.4.7",
+ "regex-syntax 0.8.4",
]
[[package]]
@@ -3651,13 +3798,13 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
- "regex-syntax 0.8.3",
+ "regex-syntax 0.8.4",
]
[[package]]
@@ -3668,9 +3815,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "relative-path"
@@ -3819,9 +3966,9 @@ dependencies = [
[[package]]
name = "rstest"
-version = "0.19.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d5316d2a1479eeef1ea21e7f9ddc67c191d497abc8fc3ba2467857abbb68330"
+checksum = "9afd55a67069d6e434a95161415f5beeada95a01c7b815508a82dcb0e1593682"
dependencies = [
"futures",
"futures-timer",
@@ -3831,12 +3978,13 @@ dependencies = [
[[package]]
name = "rstest_macros"
-version = "0.19.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04a9df72cc1f67020b0d63ad9bfe4a323e459ea7eb68e03bd9824db49f9a4c25"
+checksum = "4165dfae59a39dd41d8dec720d3cbfbc71f69744efb480a3920f5d4e0cc6798d"
dependencies = [
"cfg-if",
"glob",
+ "proc-macro-crate",
"proc-macro2",
"quote",
"regex",
@@ -3914,6 +4062,19 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "rustls"
+version = "0.23.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
+dependencies = [
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "rustls-native-certs"
version = "0.7.0"
@@ -4284,20 +4445,19 @@ dependencies = [
[[package]]
name = "sqlformat"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c"
+checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f"
dependencies = [
- "itertools 0.12.1",
"nom",
"unicode_categories",
]
[[package]]
name = "sqlparser"
-version = "0.45.0"
+version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7bbffee862a796d67959a89859d6b1046bb5016d63e23835ad0da182777bbe0"
+checksum = "295e9930cd7a97e58ca2a070541a3ca502b17f5d1fa7157376d0fabd85324f25"
dependencies = [
"log",
"sqlparser_derive",
@@ -4508,6 +4668,12 @@ dependencies = [
"urlencoding",
]
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
[[package]]
name = "static_assertions"
version = "1.1.0"
@@ -4548,11 +4714,11 @@ dependencies = [
[[package]]
name = "strum_macros"
-version = "0.26.2"
+version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
- "heck 0.4.1",
+ "heck 0.5.0",
"proc-macro2",
"quote",
"rustversion",
@@ -4611,6 +4777,17 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
[[package]]
name = "sysinfo"
version = "0.30.12"
@@ -4799,6 +4976,16 @@ dependencies = [
"crunchy",
]
+[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
[[package]]
name = "tinytemplate"
version = "1.2.1"
@@ -4881,7 +5068,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
dependencies = [
- "rustls",
+ "rustls 0.22.4",
"rustls-pki-types",
"tokio",
]
@@ -4899,12 +5086,12 @@ dependencies = [
[[package]]
name = "tokio-tungstenite"
-version = "0.21.0"
+version = "0.23.0"
dependencies = [
"futures-util",
"log",
"native-tls",
- "rustls",
+ "rustls 0.22.4",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
@@ -5045,11 +5232,10 @@ dependencies = [
[[package]]
name = "tracing-test"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a2c0ff408fe918a94c428a3f2ad04e4afd5c95bbc08fcf868eff750c15728a4"
+checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68"
dependencies = [
- "lazy_static",
"tracing-core",
"tracing-subscriber",
"tracing-test-macro",
@@ -5057,13 +5243,12 @@ dependencies = [
[[package]]
name = "tracing-test-macro"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bc1c4f8e2e73a977812ab339d503e6feeb92700f6d07a6de4d321522d5c08"
+checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568"
dependencies = [
- "lazy_static",
"quote",
- "syn 1.0.109",
+ "syn 2.0.66",
]
[[package]]
@@ -5074,9 +5259,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tungstenite"
-version = "0.21.0"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
+checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8"
dependencies = [
"byteorder",
"bytes",
@@ -5086,11 +5271,10 @@ dependencies = [
"log",
"native-tls",
"rand",
- "rustls",
+ "rustls 0.23.10",
"rustls-pki-types",
"sha1",
"thiserror",
- "url",
"utf-8",
]
@@ -5165,9 +5349,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "unicode-width"
-version = "0.1.12"
+version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]]
name = "unicode_categories"
@@ -5189,9 +5373,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
-version = "2.5.0"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
+checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56"
dependencies = [
"form_urlencoded",
"idna",
@@ -5223,11 +5407,23 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
[[package]]
name = "utf8parse"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
@@ -5384,9 +5580,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
-version = "0.26.1"
+version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009"
+checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3"
dependencies = [
"rustls-pki-types",
]
@@ -5609,6 +5805,18 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
[[package]]
name = "wyz"
version = "0.5.1"
@@ -5633,6 +5841,30 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+[[package]]
+name = "yoke"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+ "synstructure",
+]
+
[[package]]
name = "zerocopy"
version = "0.7.34"
@@ -5653,35 +5885,78 @@ dependencies = [
"syn 2.0.66",
]
+[[package]]
+name = "zerofrom"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+ "synstructure",
+]
+
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+[[package]]
+name = "zerovec"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
[[package]]
name = "zstd"
-version = "0.13.1"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
+checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
-version = "7.1.0"
+version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
+checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
-version = "2.0.10+zstd.1.5.6"
+version = "2.0.9+zstd.1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
+checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
dependencies = [
"cc",
"pkg-config",
diff --git a/nautilus_core/Cargo.toml b/nautilus_core/Cargo.toml
index a43a67496d70..632d87f7c401 100644
--- a/nautilus_core/Cargo.toml
+++ b/nautilus_core/Cargo.toml
@@ -18,12 +18,12 @@ members = [
]
[workspace.package]
-rust-version = "1.78.0"
-version = "0.24.0"
+rust-version = "1.79.0"
+version = "0.25.0"
edition = "2021"
authors = ["Nautech Systems "]
description = "A high-performance algorithmic trading platform and event-driven backtester"
-documentation = "https://docs.nautilustrader.io"
+documentation = "https://nautilustrader.io/docs"
[workspace.dependencies]
anyhow = "1.0.86"
@@ -35,8 +35,8 @@ itertools = "0.12.1"
itoa = "1.0.11"
once_cell = "1.19.0"
log = { version = "0.4.21", features = ["std", "kv_unstable", "serde", "release_max_level_debug"] }
-pyo3 = { version = "0.20.3", features = ["rust_decimal"] }
-pyo3-asyncio = { version = "0.20.0", features = ["tokio-runtime", "tokio", "attributes"] }
+pyo3 = { version = "0.21.2", features = ["rust_decimal"] }
+pyo3-asyncio-0-21 = { version = "0.21.0", features = ["tokio-runtime", "tokio", "attributes"] }
rand = "0.8.5"
rmp-serde = "1.3.0"
rust_decimal = "1.35.0"
@@ -57,7 +57,7 @@ criterion = "0.5.1"
float-cmp = "0.9.0"
iai = "0.1.1"
pretty_assertions = "1.4.0"
-rstest = "0.19.0"
+rstest = "0.21.0"
tempfile = "3.10.1"
# build-dependencies
diff --git a/nautilus_core/accounting/Cargo.toml b/nautilus_core/accounting/Cargo.toml
index f81d62c9e488..7ff79f711ad1 100644
--- a/nautilus_core/accounting/Cargo.toml
+++ b/nautilus_core/accounting/Cargo.toml
@@ -15,6 +15,7 @@ nautilus-common = { path = "../common", features = ["stubs"] }
nautilus-model = { path = "../model", features = ["stubs"] }
nautilus-core = { path = "../core" }
anyhow = { workspace = true }
+log = { workspace = true }
pyo3 = { workspace = true, optional = true }
rust_decimal = { workspace = true }
serde = { workspace = true }
diff --git a/nautilus_core/accounting/src/account/base.rs b/nautilus_core/accounting/src/account/base.rs
index b7a52d2e4e2d..fc3c5889874a 100644
--- a/nautilus_core/accounting/src/account/base.rs
+++ b/nautilus_core/accounting/src/account/base.rs
@@ -18,7 +18,7 @@ use std::collections::HashMap;
use nautilus_model::{
enums::{AccountType, LiquiditySide, OrderSide},
events::{account::state::AccountState, order::filled::OrderFilled},
- identifiers::account_id::AccountId,
+ identifiers::AccountId,
instruments::any::InstrumentAny,
position::Position,
types::{
diff --git a/nautilus_core/accounting/src/account/cash.rs b/nautilus_core/accounting/src/account/cash.rs
index 0fc53797b12b..d222ee528fe8 100644
--- a/nautilus_core/accounting/src/account/cash.rs
+++ b/nautilus_core/accounting/src/account/cash.rs
@@ -23,7 +23,7 @@ use nautilus_common::interface::account::Account;
use nautilus_model::{
enums::{AccountType, LiquiditySide, OrderSide},
events::{account::state::AccountState, order::filled::OrderFilled},
- identifiers::account_id::AccountId,
+ identifiers::AccountId,
instruments::any::InstrumentAny,
position::Position,
types::{
@@ -155,8 +155,8 @@ impl Account for CashAccount {
fn calculate_pnls(
&self,
- instrument: InstrumentAny,
- fill: OrderFilled,
+ instrument: InstrumentAny, // TODO: Make this a reference
+ fill: OrderFilled, // TODO: Make this a reference
position: Option,
) -> anyhow::Result> {
self.base_calculate_pnls(instrument, fill, position)
@@ -228,12 +228,12 @@ mod tests {
use nautilus_model::{
enums::{AccountType, LiquiditySide, OrderSide},
events::account::{state::AccountState, stubs::*},
- identifiers::{account_id::AccountId, position_id::PositionId, strategy_id::StrategyId},
+ identifiers::{position_id::PositionId, AccountId},
instruments::{
- crypto_perpetual::CryptoPerpetual, currency_pair::CurrencyPair, equity::Equity,
- stubs::*, Instrument,
+ any::InstrumentAny, crypto_perpetual::CryptoPerpetual, currency_pair::CurrencyPair,
+ equity::Equity, stubs::*, Instrument,
},
- orders::{market::MarketOrder, stubs::TestOrderEventStubs},
+ orders::stubs::TestOrderEventStubs,
position::Position,
types::{currency::Currency, money::Money, price::Price, quantity::Quantity},
};
@@ -441,8 +441,9 @@ mod tests {
mut order_factory: OrderFactory,
audusd_sim: CurrencyPair,
) {
+ let audusd_sim = InstrumentAny::CurrencyPair(audusd_sim);
let order = order_factory.market(
- audusd_sim.id,
+ audusd_sim.id(),
OrderSide::Buy,
Quantity::from("1000000"),
None,
@@ -452,10 +453,9 @@ mod tests {
None,
None,
);
- let fill = TestOrderEventStubs::order_filled::(
+ let fill = TestOrderEventStubs::order_filled(
&order,
&audusd_sim,
- Some(StrategyId::new("S-001").unwrap()),
None,
Some(PositionId::new("P-123456").unwrap()),
Some(Price::from("0.8")),
@@ -463,11 +463,10 @@ mod tests {
None,
None,
Some(AccountId::from("SIM-001")),
- )
- .unwrap();
- let position = Position::new(audusd_sim, fill).unwrap();
+ );
+ let position = Position::new(&audusd_sim, fill.clone().into()).unwrap();
let pnls = cash_account_million_usd
- .calculate_pnls(audusd_sim.into_any(), fill, Some(position))
+ .calculate_pnls(audusd_sim, fill.into(), Some(position)) // TODO: Remove clone
.unwrap();
assert_eq!(pnls, vec![Money::from("-800000 USD")]);
}
@@ -478,6 +477,7 @@ mod tests {
mut order_factory: OrderFactory,
currency_pair_btcusdt: CurrencyPair,
) {
+ let btcusdt = InstrumentAny::CurrencyPair(currency_pair_btcusdt);
let order1 = order_factory.market(
currency_pair_btcusdt.id,
OrderSide::Sell,
@@ -489,10 +489,9 @@ mod tests {
None,
None,
);
- let fill1 = TestOrderEventStubs::order_filled::(
+ let fill1 = TestOrderEventStubs::order_filled(
&order1,
- ¤cy_pair_btcusdt,
- Some(StrategyId::new("S-001").unwrap()),
+ &btcusdt,
None,
Some(PositionId::new("P-123456").unwrap()),
Some(Price::from("45500.00")),
@@ -500,13 +499,12 @@ mod tests {
None,
None,
Some(AccountId::from("SIM-001")),
- )
- .unwrap();
- let position = Position::new(currency_pair_btcusdt, fill1).unwrap();
+ );
+ let position = Position::new(&btcusdt, fill1.clone().into()).unwrap();
let result1 = cash_account_multi
.calculate_pnls(
currency_pair_btcusdt.into_any(),
- fill1,
+ fill1.into(), // TODO: This doesn't need to be owned
Some(position.clone()),
)
.unwrap();
@@ -521,10 +519,9 @@ mod tests {
None,
None,
);
- let fill2 = TestOrderEventStubs::order_filled::(
+ let fill2 = TestOrderEventStubs::order_filled(
&order2,
- ¤cy_pair_btcusdt,
- Some(StrategyId::new("S-001").unwrap()),
+ &btcusdt,
None,
Some(PositionId::new("P-123456").unwrap()),
Some(Price::from("45500.00")),
@@ -532,10 +529,13 @@ mod tests {
None,
None,
Some(AccountId::from("SIM-001")),
- )
- .unwrap();
+ );
let result2 = cash_account_multi
- .calculate_pnls(currency_pair_btcusdt.into_any(), fill2, Some(position))
+ .calculate_pnls(
+ currency_pair_btcusdt.into_any(),
+ fill2.into(),
+ Some(position),
+ )
.unwrap();
// use hash set to ignore order of results
let result1_set: HashSet = result1.into_iter().collect();
diff --git a/nautilus_core/accounting/src/account/margin.rs b/nautilus_core/accounting/src/account/margin.rs
index cbad02117d07..e2bace16958d 100644
--- a/nautilus_core/accounting/src/account/margin.rs
+++ b/nautilus_core/accounting/src/account/margin.rs
@@ -26,7 +26,7 @@ use nautilus_common::interface::account::Account;
use nautilus_model::{
enums::{AccountType, LiquiditySide, OrderSide},
events::{account::state::AccountState, order::filled::OrderFilled},
- identifiers::{account_id::AccountId, instrument_id::InstrumentId},
+ identifiers::{AccountId, InstrumentId},
instruments::{any::InstrumentAny, Instrument},
position::Position,
types::{
@@ -415,7 +415,7 @@ mod tests {
use nautilus_common::interface::account::Account;
use nautilus_model::{
events::account::{state::AccountState, stubs::*},
- identifiers::{instrument_id::InstrumentId, stubs::*},
+ identifiers::{stubs::*, InstrumentId},
instruments::{crypto_perpetual::CryptoPerpetual, currency_pair::CurrencyPair, stubs::*},
types::{currency::Currency, money::Money, price::Price, quantity::Quantity},
};
diff --git a/nautilus_core/accounting/src/python/cash.rs b/nautilus_core/accounting/src/python/cash.rs
index 3f415f2e5156..33ee49d1dcc3 100644
--- a/nautilus_core/accounting/src/python/cash.rs
+++ b/nautilus_core/accounting/src/python/cash.rs
@@ -20,7 +20,7 @@ use nautilus_core::python::to_pyvalue_err;
use nautilus_model::{
enums::{AccountType, LiquiditySide, OrderSide},
events::{account::state::AccountState, order::filled::OrderFilled},
- identifiers::account_id::AccountId,
+ identifiers::AccountId,
position::Position,
python::instruments::pyobject_to_instrument_any,
types::{currency::Currency, money::Money, price::Price, quantity::Quantity},
diff --git a/nautilus_core/accounting/src/python/margin.rs b/nautilus_core/accounting/src/python/margin.rs
index 5471dfb43fb6..8e26d8d676c2 100644
--- a/nautilus_core/accounting/src/python/margin.rs
+++ b/nautilus_core/accounting/src/python/margin.rs
@@ -16,7 +16,7 @@
use nautilus_core::python::to_pyvalue_err;
use nautilus_model::{
events::account::state::AccountState,
- identifiers::{account_id::AccountId, instrument_id::InstrumentId},
+ identifiers::{AccountId, InstrumentId},
instruments::any::InstrumentAny,
python::instruments::pyobject_to_instrument_any,
types::{money::Money, price::Price, quantity::Quantity},
diff --git a/nautilus_core/accounting/src/stubs.rs b/nautilus_core/accounting/src/stubs.rs
index 0156eabde7e7..61bd9fee3934 100644
--- a/nautilus_core/accounting/src/stubs.rs
+++ b/nautilus_core/accounting/src/stubs.rs
@@ -16,9 +16,9 @@
use nautilus_common::{factories::OrderFactory, stubs::*};
use nautilus_model::{
enums::OrderSide,
- identifiers::instrument_id::InstrumentId,
- instruments::{currency_pair::CurrencyPair, stubs::audusd_sim},
- orders::{market::MarketOrder, stubs::TestOrderEventStubs},
+ identifiers::InstrumentId,
+ instruments::{any::InstrumentAny, currency_pair::CurrencyPair, stubs::audusd_sim},
+ orders::stubs::TestOrderEventStubs,
position::Position,
types::{price::Price, quantity::Quantity},
};
@@ -26,6 +26,7 @@ use rstest::fixture;
#[fixture]
pub fn test_position_long(mut order_factory: OrderFactory, audusd_sim: CurrencyPair) -> Position {
+ let audusd_sim = InstrumentAny::CurrencyPair(audusd_sim);
let order = order_factory.market(
InstrumentId::from("AUD/USD.SIM"),
OrderSide::Buy,
@@ -37,24 +38,23 @@ pub fn test_position_long(mut order_factory: OrderFactory, audusd_sim: CurrencyP
None,
None,
);
- let order_filled = TestOrderEventStubs::order_filled::(
+ let filled = TestOrderEventStubs::order_filled(
&order,
&audusd_sim,
None,
None,
- None,
Some(Price::from("1.0002")),
None,
None,
None,
None,
- )
- .unwrap();
- Position::new(audusd_sim, order_filled).unwrap()
+ );
+ Position::new(&audusd_sim, filled.into()).unwrap()
}
#[fixture]
pub fn test_position_short(mut order_factory: OrderFactory, audusd_sim: CurrencyPair) -> Position {
+ let audusd_sim = InstrumentAny::CurrencyPair(audusd_sim);
let order = order_factory.market(
InstrumentId::from("AUD/USD.SIM"),
OrderSide::Sell,
@@ -66,18 +66,16 @@ pub fn test_position_short(mut order_factory: OrderFactory, audusd_sim: Currency
None,
None,
);
- let order_filled = TestOrderEventStubs::order_filled::(
+ let filled = TestOrderEventStubs::order_filled(
&order,
&audusd_sim,
None,
None,
- None,
Some(Price::from("22000.0")),
None,
None,
None,
None,
- )
- .unwrap();
- Position::new(audusd_sim, order_filled).unwrap()
+ );
+ Position::new(&audusd_sim, filled.into()).unwrap()
}
diff --git a/nautilus_core/adapters/Cargo.toml b/nautilus_core/adapters/Cargo.toml
index 11c6da6dd099..00e41a0b01b9 100644
--- a/nautilus_core/adapters/Cargo.toml
+++ b/nautilus_core/adapters/Cargo.toml
@@ -22,20 +22,19 @@ anyhow = { workspace = true }
chrono = { workspace = true }
indexmap = { workspace = true }
itoa = { workspace = true }
-log = { workspace = true }
pyo3 = { workspace = true, optional = true }
-pyo3-asyncio = { workspace = true, optional = true }
+pyo3-asyncio-0-21 = { workspace = true, optional = true }
rand = { workspace = true }
rust_decimal = { workspace = true }
rust_decimal_macros = { workspace = true }
-tracing = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
strum = { workspace = true }
tokio = { workspace = true }
+tracing = { workspace = true }
thiserror = { workspace = true }
ustr = { workspace = true }
-databento = { version = "0.10.0", optional = true }
+databento = { version = "0.11.1", optional = true }
fallible-streaming-iterator = "0.1.9"
time = "0.3.36"
@@ -59,7 +58,7 @@ ffi = [
]
python = [
"pyo3",
- "pyo3-asyncio",
+ "pyo3-asyncio-0-21",
"nautilus-common/python",
"nautilus-core/python",
"nautilus-model/python",
diff --git a/nautilus_core/adapters/src/databento/decode.rs b/nautilus_core/adapters/src/databento/decode.rs
index 796fc2d17a33..764f4f905986 100644
--- a/nautilus_core/adapters/src/databento/decode.rs
+++ b/nautilus_core/adapters/src/databento/decode.rs
@@ -16,7 +16,6 @@
use std::{
cmp,
ffi::{c_char, CStr},
- i64,
str::FromStr,
};
@@ -36,7 +35,7 @@ use nautilus_model::{
AggregationSource, AggressorSide, AssetClass, BarAggregation, BookAction, FromU8,
InstrumentClass, OptionKind, OrderSide, PriceType,
},
- identifiers::{instrument_id::InstrumentId, trade_id::TradeId},
+ identifiers::{InstrumentId, TradeId},
instruments::{
any::InstrumentAny, equity::Equity, futures_contract::FuturesContract,
futures_spread::FuturesSpread, options_contract::OptionsContract,
diff --git a/nautilus_core/adapters/src/databento/live.rs b/nautilus_core/adapters/src/databento/live.rs
index da2700b4e090..3b47ff3e7c63 100644
--- a/nautilus_core/adapters/src/databento/live.rs
+++ b/nautilus_core/adapters/src/databento/live.rs
@@ -32,7 +32,7 @@ use nautilus_model::{
Data,
},
enums::RecordFlag,
- identifiers::{instrument_id::InstrumentId, symbol::Symbol, venue::Venue},
+ identifiers::{InstrumentId, Symbol, Venue},
instruments::any::InstrumentAny,
};
use tokio::{
diff --git a/nautilus_core/adapters/src/databento/loader.rs b/nautilus_core/adapters/src/databento/loader.rs
index d4a95ea0dabb..fea88bcf3d35 100644
--- a/nautilus_core/adapters/src/databento/loader.rs
+++ b/nautilus_core/adapters/src/databento/loader.rs
@@ -24,7 +24,7 @@ use fallible_streaming_iterator::FallibleStreamingIterator;
use indexmap::IndexMap;
use nautilus_model::{
data::Data,
- identifiers::{instrument_id::InstrumentId, symbol::Symbol, venue::Venue},
+ identifiers::{InstrumentId, Symbol, Venue},
instruments::any::InstrumentAny,
types::currency::Currency,
};
diff --git a/nautilus_core/adapters/src/databento/python/historical.rs b/nautilus_core/adapters/src/databento/python/historical.rs
index c0a960944f70..36a2ae1781ef 100644
--- a/nautilus_core/adapters/src/databento/python/historical.rs
+++ b/nautilus_core/adapters/src/databento/python/historical.rs
@@ -27,7 +27,7 @@ use nautilus_core::{
use nautilus_model::{
data::{bar::Bar, quote::QuoteTick, trade::TradeTick, Data},
enums::BarAggregation,
- identifiers::{instrument_id::InstrumentId, symbol::Symbol, venue::Venue},
+ identifiers::{InstrumentId, Symbol, Venue},
python::instruments::instrument_any_to_pyobject,
types::currency::Currency,
};
@@ -89,17 +89,21 @@ impl DatabentoHistoricalClient {
}
#[pyo3(name = "get_dataset_range")]
- fn py_get_dataset_range<'py>(&self, py: Python<'py>, dataset: String) -> PyResult<&'py PyAny> {
+ fn py_get_dataset_range<'py>(
+ &self,
+ py: Python<'py>,
+ dataset: String,
+ ) -> PyResult> {
let client = self.inner.clone();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let response = client.metadata().get_dataset_range(&dataset).await;
match response {
Ok(res) => Python::with_gil(|py| {
let dict = PyDict::new(py);
- dict.set_item("start_date", res.start_date.to_string())?;
- dict.set_item("end_date", res.end_date.to_string())?;
+ dict.set_item("start", res.start.to_string())?;
+ dict.set_item("end", res.end.to_string())?;
Ok(dict.to_object(py))
}),
Err(e) => Err(PyErr::new::(format!(
@@ -114,14 +118,15 @@ impl DatabentoHistoricalClient {
&self,
py: Python<'py>,
dataset: String,
- symbols: Vec<&str>,
+ symbols: Vec,
start: u64,
end: Option,
limit: Option,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
let client = self.inner.clone();
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let end = end.unwrap_or(self.clock.get_time_ns().as_u64());
let time_range = get_date_time_range(start.into(), end.into()).map_err(to_pyvalue_err)?;
@@ -137,7 +142,7 @@ impl DatabentoHistoricalClient {
let publisher_venue_map = self.publisher_venue_map.clone();
let ts_init = self.clock.get_time_ns();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let mut decoder = client
.timeseries()
@@ -182,14 +187,15 @@ impl DatabentoHistoricalClient {
&self,
py: Python<'py>,
dataset: String,
- symbols: Vec<&str>,
+ symbols: Vec,
start: u64,
end: Option,
limit: Option,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
let client = self.inner.clone();
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let end = end.unwrap_or(self.clock.get_time_ns().as_u64());
let time_range = get_date_time_range(start.into(), end.into()).map_err(to_pyvalue_err)?;
@@ -206,7 +212,7 @@ impl DatabentoHistoricalClient {
let publisher_venue_map = self.publisher_venue_map.clone();
let ts_init = self.clock.get_time_ns();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let mut decoder = client
.timeseries()
@@ -249,14 +255,15 @@ impl DatabentoHistoricalClient {
&self,
py: Python<'py>,
dataset: String,
- symbols: Vec<&str>,
+ symbols: Vec,
start: u64,
end: Option,
limit: Option,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
let client = self.inner.clone();
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let end = end.unwrap_or(self.clock.get_time_ns().as_u64());
let time_range = get_date_time_range(start.into(), end.into()).map_err(to_pyvalue_err)?;
@@ -273,7 +280,7 @@ impl DatabentoHistoricalClient {
let publisher_venue_map = self.publisher_venue_map.clone();
let ts_init = self.clock.get_time_ns();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let mut decoder = client
.timeseries()
@@ -317,15 +324,16 @@ impl DatabentoHistoricalClient {
&self,
py: Python<'py>,
dataset: String,
- symbols: Vec<&str>,
+ symbols: Vec,
aggregation: BarAggregation,
start: u64,
end: Option,
limit: Option,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
let client = self.inner.clone();
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let schema = match aggregation {
BarAggregation::Second => dbn::Schema::Ohlcv1S,
@@ -349,7 +357,7 @@ impl DatabentoHistoricalClient {
let publisher_venue_map = self.publisher_venue_map.clone();
let ts_init = self.clock.get_time_ns();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let mut decoder = client
.timeseries()
@@ -393,14 +401,15 @@ impl DatabentoHistoricalClient {
&self,
py: Python<'py>,
dataset: String,
- symbols: Vec<&str>,
+ symbols: Vec,
start: u64,
end: Option,
limit: Option,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
let client = self.inner.clone();
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let end = end.unwrap_or(self.clock.get_time_ns().as_u64());
let time_range = get_date_time_range(start.into(), end.into()).map_err(to_pyvalue_err)?;
@@ -417,7 +426,7 @@ impl DatabentoHistoricalClient {
let publisher_venue_map = self.publisher_venue_map.clone();
let ts_init = self.clock.get_time_ns();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let mut decoder = client
.timeseries()
@@ -450,14 +459,15 @@ impl DatabentoHistoricalClient {
&self,
py: Python<'py>,
dataset: String,
- symbols: Vec<&str>,
+ symbols: Vec,
start: u64,
end: Option,
limit: Option,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
let client = self.inner.clone();
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let end = end.unwrap_or(self.clock.get_time_ns().as_u64());
let time_range = get_date_time_range(start.into(), end.into()).map_err(to_pyvalue_err)?;
@@ -474,7 +484,7 @@ impl DatabentoHistoricalClient {
let publisher_venue_map = self.publisher_venue_map.clone();
let ts_init = self.clock.get_time_ns();
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let mut client = client.lock().await; // TODO: Use a client pool
let mut decoder = client
.timeseries()
diff --git a/nautilus_core/adapters/src/databento/python/live.rs b/nautilus_core/adapters/src/databento/python/live.rs
index 4e14c26069e1..8efbb72e53be 100644
--- a/nautilus_core/adapters/src/databento/python/live.rs
+++ b/nautilus_core/adapters/src/databento/python/live.rs
@@ -19,7 +19,7 @@ use databento::{dbn, live::Subscription};
use indexmap::IndexMap;
use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
use nautilus_model::{
- identifiers::venue::Venue,
+ identifiers::Venue,
python::{data::data_to_pycapsule, instruments::instrument_any_to_pyobject},
};
use pyo3::prelude::*;
@@ -150,10 +150,11 @@ impl DatabentoLiveClient {
fn py_subscribe(
&mut self,
schema: String,
- symbols: Vec<&str>,
+ symbols: Vec,
start: Option,
) -> PyResult<()> {
let stype_in = infer_symbology_type(symbols.first().unwrap());
+ let symbols: Vec<&str> = symbols.iter().map(|s| s.as_str()).collect();
check_consistent_symbology(symbols.as_slice()).map_err(to_pyvalue_err)?;
let mut sub = Subscription::builder()
.symbols(symbols)
@@ -176,7 +177,7 @@ impl DatabentoLiveClient {
py: Python<'py>,
callback: PyObject,
callback_pyo3: PyObject,
- ) -> PyResult<&'py PyAny> {
+ ) -> PyResult> {
if self.is_closed {
return Err(to_pyruntime_err("Client already closed"));
};
@@ -205,7 +206,7 @@ impl DatabentoLiveClient {
self.send_command(LiveCommand::Start)?;
- pyo3_asyncio::tokio::future_into_py(py, async move {
+ pyo3_asyncio_0_21::tokio::future_into_py(py, async move {
let (proc_handle, feed_handle) = tokio::join!(
Self::process_messages(msg_rx, callback, callback_pyo3),
feed_handler.run(),
diff --git a/nautilus_core/adapters/src/databento/python/loader.rs b/nautilus_core/adapters/src/databento/python/loader.rs
index 71f2a2c0b777..6cc51e357383 100644
--- a/nautilus_core/adapters/src/databento/python/loader.rs
+++ b/nautilus_core/adapters/src/databento/python/loader.rs
@@ -22,7 +22,7 @@ use nautilus_model::{
bar::Bar, delta::OrderBookDelta, depth::OrderBookDepth10, quote::QuoteTick,
trade::TradeTick, Data,
},
- identifiers::{instrument_id::InstrumentId, venue::Venue},
+ identifiers::{InstrumentId, Venue},
python::instruments::instrument_any_to_pyobject,
};
use pyo3::{
@@ -421,7 +421,7 @@ fn exhaust_data_iter_to_pycapsule(
}
let cvec: CVec = data.into();
- let capsule = PyCapsule::new::(py, cvec, None)?;
+ let capsule = PyCapsule::new_bound::(py, cvec, None)?;
Ok(capsule.into_py(py))
}
diff --git a/nautilus_core/adapters/src/databento/python/types.rs b/nautilus_core/adapters/src/databento/python/types.rs
index 575533d400f5..047d64f2a42a 100644
--- a/nautilus_core/adapters/src/databento/python/types.rs
+++ b/nautilus_core/adapters/src/databento/python/types.rs
@@ -21,7 +21,7 @@ use std::{
use nautilus_core::python::serialization::from_dict_pyo3;
use nautilus_model::{
enums::OrderSide,
- identifiers::instrument_id::InstrumentId,
+ identifiers::InstrumentId,
types::{price::Price, quantity::Quantity},
};
use pyo3::{basic::CompareOp, prelude::*, types::PyDict};
diff --git a/nautilus_core/adapters/src/databento/symbology.rs b/nautilus_core/adapters/src/databento/symbology.rs
index 3c9d5bfad3aa..1c10dacf6bcd 100644
--- a/nautilus_core/adapters/src/databento/symbology.rs
+++ b/nautilus_core/adapters/src/databento/symbology.rs
@@ -17,7 +17,7 @@ use databento::dbn;
use dbn::Record;
use indexmap::IndexMap;
use nautilus_core::correctness::check_slice_not_empty;
-use nautilus_model::identifiers::{instrument_id::InstrumentId, symbol::Symbol, venue::Venue};
+use nautilus_model::identifiers::{InstrumentId, Symbol, Venue};
use super::types::PublisherId;
diff --git a/nautilus_core/adapters/src/databento/types.rs b/nautilus_core/adapters/src/databento/types.rs
index da3ed8aca2b5..008cb192daaa 100644
--- a/nautilus_core/adapters/src/databento/types.rs
+++ b/nautilus_core/adapters/src/databento/types.rs
@@ -19,7 +19,7 @@ use databento::dbn;
use nautilus_core::nanos::UnixNanos;
use nautilus_model::{
enums::OrderSide,
- identifiers::instrument_id::InstrumentId,
+ identifiers::InstrumentId,
types::{price::Price, quantity::Quantity},
};
use serde::Deserialize;
diff --git a/nautilus_core/backtest/src/engine.rs b/nautilus_core/backtest/src/engine.rs
index 669259b12b3d..a3f1c417f892 100644
--- a/nautilus_core/backtest/src/engine.rs
+++ b/nautilus_core/backtest/src/engine.rs
@@ -115,7 +115,7 @@ mod tests {
use nautilus_common::timer::TimeEvent;
use nautilus_core::uuid::UUID4;
- use pyo3::{types::PyList, Py, Python};
+ use pyo3::{prelude::*, types::PyList, Py, Python};
use rstest::*;
use ustr::Ustr;
@@ -126,7 +126,7 @@ mod tests {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
- let py_list = PyList::empty(py);
+ let py_list = PyList::empty_bound(py);
let py_append = Py::from(py_list.getattr("append").unwrap());
let mut accumulator = TimeEventAccumulator::new();
diff --git a/nautilus_core/backtest/src/matching_engine.rs b/nautilus_core/backtest/src/matching_engine.rs
index 10da49cc3bb8..a27b45596ba3 100644
--- a/nautilus_core/backtest/src/matching_engine.rs
+++ b/nautilus_core/backtest/src/matching_engine.rs
@@ -31,10 +31,7 @@ use nautilus_model::{
delta::OrderBookDelta,
},
enums::{AccountType, BookType, MarketStatus, OmsType},
- identifiers::{
- account_id::AccountId, client_order_id::ClientOrderId, instrument_id::InstrumentId,
- trader_id::TraderId, venue::Venue,
- },
+ identifiers::{AccountId, ClientOrderId, InstrumentId, TraderId, Venue},
instruments::Instrument,
orderbook::book::OrderBook,
orders::{
diff --git a/nautilus_core/cli/Cargo.toml b/nautilus_core/cli/Cargo.toml
index 928e18caa8ab..1299c6ca3556 100644
--- a/nautilus_core/cli/Cargo.toml
+++ b/nautilus_core/cli/Cargo.toml
@@ -16,9 +16,9 @@ nautilus-model = { path = "../model" }
nautilus-core = { path = "../core" }
nautilus-infrastructure = { path = "../infrastructure" , features = ["postgres"] }
anyhow = { workspace = true }
-tokio = {workspace = true}
log = { workspace = true }
-clap = { version = "4.5.4", features = ["derive", "env"] }
-clap_derive = { version = "4.5.4" }
+tokio = {workspace = true}
+clap = { version = "4.5.7", features = ["derive", "env"] }
+clap_derive = { version = "4.5.5" }
dotenvy = { version = "0.15.7" }
simple_logger = "5.0.0"
diff --git a/nautilus_core/common/Cargo.toml b/nautilus_core/common/Cargo.toml
index 1c4be86600ac..180849e768a2 100644
--- a/nautilus_core/common/Cargo.toml
+++ b/nautilus_core/common/Cargo.toml
@@ -19,7 +19,7 @@ indexmap = { workspace = true }
itertools = { workspace = true }
log = { workspace = true }
pyo3 = { workspace = true, optional = true }
-pyo3-asyncio = { workspace = true, optional = true }
+pyo3-asyncio-0-21 = { workspace = true, optional = true }
rstest = { workspace = true , optional = true}
rust_decimal = { workspace = true }
rust_decimal_macros = { workspace = true }
@@ -48,5 +48,5 @@ extension-module = [
"nautilus-model/extension-module",
]
ffi = ["cbindgen", "nautilus-core/ffi", "nautilus-model/ffi"]
-python = ["pyo3", "pyo3-asyncio", "nautilus-core/python", "nautilus-model/python"]
+python = ["pyo3", "pyo3-asyncio-0-21", "nautilus-core/python", "nautilus-model/python"]
stubs = ["rstest", "nautilus-model/stubs"]
diff --git a/nautilus_core/common/src/cache/core.rs b/nautilus_core/common/src/cache/core.rs
index 015962e38d8a..4d641ab120b0 100644
--- a/nautilus_core/common/src/cache/core.rs
+++ b/nautilus_core/common/src/cache/core.rs
@@ -30,19 +30,12 @@ use nautilus_model::{
},
enums::{AggregationSource, OmsType, OrderSide, PositionSide, PriceType, TriggerType},
identifiers::{
- account_id::AccountId, client_id::ClientId, client_order_id::ClientOrderId,
- component_id::ComponentId, exec_algorithm_id::ExecAlgorithmId, instrument_id::InstrumentId,
- order_list_id::OrderListId, position_id::PositionId, strategy_id::StrategyId, venue::Venue,
- venue_order_id::VenueOrderId,
+ AccountId, ClientId, ClientOrderId, ComponentId, ExecAlgorithmId, InstrumentId,
+ OrderListId, PositionId, StrategyId, Venue, VenueOrderId,
},
instruments::{any::InstrumentAny, synthetic::SyntheticInstrument},
orderbook::book::OrderBook,
orders::{any::OrderAny, list::OrderList},
- polymorphism::{
- GetClientOrderId, GetEmulationTrigger, GetExecAlgorithmId, GetExecSpawnId, GetInstrumentId,
- GetOrderFilledQty, GetOrderLeavesQty, GetOrderQuantity, GetOrderSide, GetPositionId,
- GetStrategyId, GetVenueOrderId, IsClosed, IsInflight, IsOpen,
- },
position::Position,
types::{currency::Currency, price::Price, quantity::Quantity},
};
@@ -862,7 +855,6 @@ impl Cache {
}
}
- // Finally
let total_us = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
@@ -2412,10 +2404,10 @@ impl Cache {
/// Returns references to all instrument IDs for the given `venue`.
#[must_use]
- pub fn instrument_ids(&self, venue: &Venue) -> Vec<&InstrumentId> {
+ pub fn instrument_ids(&self, venue: Option<&Venue>) -> Vec<&InstrumentId> {
self.instruments
.keys()
- .filter(|i| &i.venue == venue)
+ .filter(|i| venue.is_none() || &i.venue == venue.unwrap())
.collect()
}
@@ -2514,24 +2506,16 @@ impl Cache {
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
- use nautilus_core::{nanos::UnixNanos, uuid::UUID4};
use nautilus_model::{
data::{bar::Bar, quote::QuoteTick, trade::TradeTick},
enums::{OrderSide, OrderStatus},
- events::order::{accepted::OrderAccepted, event::OrderEventAny, submitted::OrderSubmitted},
- identifiers::{
- account_id::AccountId, client_order_id::ClientOrderId, position_id::PositionId,
- venue_order_id::VenueOrderId,
- },
+ events::order::{OrderAccepted, OrderEventAny, OrderRejected, OrderSubmitted},
+ identifiers::{ClientOrderId, PositionId},
instruments::{
any::InstrumentAny, currency_pair::CurrencyPair, stubs::*,
synthetic::SyntheticInstrument,
},
- orders::{any::OrderAny, stubs::TestOrderStubs},
- polymorphism::{
- ApplyOrderEventAny, GetAccountId, GetClientOrderId, GetInstrumentId, GetOrderStatus,
- GetStrategyId, GetTraderId, GetVenueOrderId, IsOpen,
- },
+ orders::stubs::{TestOrderEventStubs, TestOrderStubs},
types::{price::Price, quantity::Quantity},
};
use rstest::*;
@@ -2548,6 +2532,18 @@ mod tests {
cache.build_index();
}
+ #[rstest]
+ fn test_check_integrity_when_empty(mut cache: Cache) {
+ let result = cache.check_integrity();
+ assert!(result);
+ }
+
+ #[rstest]
+ fn test_check_residuals_when_empty(cache: Cache) {
+ let result = cache.check_residuals();
+ assert!(!result);
+ }
+
#[rstest]
fn test_clear_index_when_empty(mut cache: Cache) {
cache.clear_index();
@@ -2571,23 +2567,17 @@ mod tests {
}
#[rstest]
- fn test_check_residuals_when_empty(cache: Cache) {
- let result = cache.check_residuals();
- assert!(!result);
- }
-
- #[rstest]
- fn test_cache_general_load_when_no_database(mut cache: Cache) {
+ fn test_cache_general_when_no_database(mut cache: Cache) {
assert!(cache.cache_general().is_ok());
}
#[rstest]
- fn test_cache_currencies_load_when_no_database(mut cache: Cache) {
+ fn test_cache_currencies_when_no_database(mut cache: Cache) {
assert!(cache.cache_currencies().is_ok());
}
#[rstest]
- fn test_cache_instruments_load_when_no_database(mut cache: Cache) {
+ fn test_cache_instruments_when_no_database(mut cache: Cache) {
assert!(cache.cache_instruments().is_ok());
}
@@ -2596,6 +2586,11 @@ mod tests {
assert!(cache.cache_synthetics().is_ok());
}
+ #[rstest]
+ fn test_cache_accounts_when_no_database(mut cache: Cache) {
+ assert!(cache.cache_accounts().is_ok());
+ }
+
#[rstest]
fn test_cache_orders_when_no_database(mut cache: Cache) {
assert!(cache.cache_orders().is_ok());
@@ -2606,21 +2601,6 @@ mod tests {
assert!(cache.cache_positions().is_ok());
}
- #[rstest]
- fn test_get_general_when_empty(cache: Cache) {
- let result = cache.get("A").unwrap();
- assert!(result.is_none());
- }
-
- #[rstest]
- fn test_add_general_when_value(mut cache: Cache) {
- let key = "A";
- let value = vec![0_u8];
- cache.add(key, value.clone()).unwrap();
- let result = cache.get(key).unwrap();
- assert_eq!(result, Some(&value.as_slice()).copied());
- }
-
#[rstest]
fn test_order_when_empty(cache: Cache) {
let client_order_id = ClientOrderId::default();
@@ -2638,12 +2618,11 @@ mod tests {
None,
None,
);
- let order = OrderAny::Limit(order);
- cache.add_order(order.clone(), None, None, false).unwrap();
- let result = cache.order(&order.client_order_id()).unwrap();
+ let client_order_id = order.client_order_id();
+ cache.add_order(order, None, None, false).unwrap();
- assert_eq!(result, &order);
- assert_eq!(cache.orders(None, None, None, None), vec![&order]);
+ let order = cache.order(&client_order_id).unwrap();
+ assert_eq!(cache.orders(None, None, None, None), vec![order]);
assert!(cache.orders_open(None, None, None, None).is_empty());
assert!(cache.orders_closed(None, None, None, None).is_empty());
assert!(cache.orders_emulated(None, None, None, None).is_empty());
@@ -2664,7 +2643,7 @@ mod tests {
#[rstest]
fn test_order_when_submitted(mut cache: Cache, audusd_sim: CurrencyPair) {
- let order = TestOrderStubs::limit_order(
+ let mut order = TestOrderStubs::limit_order(
audusd_sim.id,
OrderSide::Buy,
Price::from("1.00000"),
@@ -2672,20 +2651,10 @@ mod tests {
None,
None,
);
- let mut order = OrderAny::Limit(order);
+ let client_order_id = order.client_order_id();
cache.add_order(order.clone(), None, None, false).unwrap();
- let submitted = OrderSubmitted::new(
- order.trader_id(),
- order.strategy_id(),
- order.instrument_id(),
- order.client_order_id(),
- AccountId::default(),
- UUID4::new(),
- UnixNanos::default(),
- UnixNanos::default(),
- )
- .unwrap(); // TODO: Should event generation be fallible?
+ let submitted = OrderSubmitted::default();
order.apply(OrderEventAny::Submitted(submitted)).unwrap();
cache.update_order(&order).unwrap();
@@ -2713,8 +2682,49 @@ mod tests {
}
#[rstest]
- fn test_order_when_accepted_open(mut cache: Cache, audusd_sim: CurrencyPair) {
- let order = TestOrderStubs::limit_order(
+ fn test_order_when_rejected(mut cache: Cache, audusd_sim: CurrencyPair) {
+ let mut order = TestOrderStubs::market_order(
+ audusd_sim.id,
+ OrderSide::Buy,
+ Quantity::from(100_000),
+ None,
+ None,
+ );
+ cache.add_order(order.clone(), None, None, false).unwrap();
+
+ let submitted = OrderSubmitted::default();
+ order.apply(OrderEventAny::Submitted(submitted)).unwrap();
+ cache.update_order(&order).unwrap();
+
+ let rejected = OrderRejected::default();
+ order.apply(OrderEventAny::Rejected(rejected)).unwrap();
+ cache.update_order(&order).unwrap();
+
+ let result = cache.order(&order.client_order_id()).unwrap();
+
+ assert!(order.is_closed());
+ assert_eq!(result, &order);
+ assert_eq!(cache.orders(None, None, None, None), vec![&order]);
+ assert!(cache.orders_open(None, None, None, None).is_empty());
+ assert_eq!(cache.orders_closed(None, None, None, None), vec![&order]);
+ assert!(cache.orders_emulated(None, None, None, None).is_empty());
+ assert!(cache.orders_inflight(None, None, None, None).is_empty());
+ assert!(cache.order_exists(&order.client_order_id()));
+ assert!(!cache.is_order_open(&order.client_order_id()));
+ assert!(cache.is_order_closed(&order.client_order_id()));
+ assert!(!cache.is_order_emulated(&order.client_order_id()));
+ assert!(!cache.is_order_inflight(&order.client_order_id()));
+ assert!(!cache.is_order_pending_cancel_local(&order.client_order_id()));
+ assert_eq!(cache.orders_open_count(None, None, None, None), 0);
+ assert_eq!(cache.orders_closed_count(None, None, None, None), 1);
+ assert_eq!(cache.orders_emulated_count(None, None, None, None), 0);
+ assert_eq!(cache.orders_inflight_count(None, None, None, None), 0);
+ assert_eq!(cache.orders_total_count(None, None, None, None), 1);
+ }
+
+ #[rstest]
+ fn test_order_when_accepted(mut cache: Cache, audusd_sim: CurrencyPair) {
+ let mut order = TestOrderStubs::limit_order(
audusd_sim.id,
OrderSide::Buy,
Price::from("1.00000"),
@@ -2722,36 +2732,13 @@ mod tests {
None,
None,
);
- let mut order = OrderAny::Limit(order);
cache.add_order(order.clone(), None, None, false).unwrap();
- let submitted = OrderSubmitted::new(
- order.trader_id(),
- order.strategy_id(),
- order.instrument_id(),
- order.client_order_id(),
- AccountId::default(),
- UUID4::new(),
- UnixNanos::default(),
- UnixNanos::default(),
- )
- .unwrap(); // TODO: Should event generation be fallible?
+ let submitted = OrderSubmitted::default();
order.apply(OrderEventAny::Submitted(submitted)).unwrap();
cache.update_order(&order).unwrap();
- let accepted = OrderAccepted::new(
- order.trader_id(),
- order.strategy_id(),
- order.instrument_id(),
- order.client_order_id(),
- VenueOrderId::default(),
- order.account_id().unwrap(),
- UUID4::new(),
- UnixNanos::default(),
- UnixNanos::default(),
- false,
- )
- .unwrap();
+ let accepted = OrderAccepted::default();
order.apply(OrderEventAny::Accepted(accepted)).unwrap();
cache.update_order(&order).unwrap();
@@ -2785,6 +2772,85 @@ mod tests {
);
}
+ #[rstest]
+ fn test_order_when_filled(mut cache: Cache, audusd_sim: CurrencyPair) {
+ let audusd_sim = InstrumentAny::CurrencyPair(audusd_sim);
+ let mut order = TestOrderStubs::market_order(
+ audusd_sim.id(),
+ OrderSide::Buy,
+ Quantity::from(100_000),
+ None,
+ None,
+ );
+ cache.add_order(order.clone(), None, None, false).unwrap();
+
+ let submitted = OrderSubmitted::default();
+ order.apply(OrderEventAny::Submitted(submitted)).unwrap();
+ cache.update_order(&order).unwrap();
+
+ let accepted = OrderAccepted::default();
+ order.apply(OrderEventAny::Accepted(accepted)).unwrap();
+ cache.update_order(&order).unwrap();
+
+ let filled = TestOrderEventStubs::order_filled(
+ &order,
+ &audusd_sim,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ );
+ order.apply(filled).unwrap();
+ cache.update_order(&order).unwrap();
+
+ let result = cache.order(&order.client_order_id()).unwrap();
+
+ assert!(order.is_closed());
+ assert_eq!(result, &order);
+ assert_eq!(cache.orders(None, None, None, None), vec![&order]);
+ assert_eq!(cache.orders_closed(None, None, None, None), vec![&order]);
+ assert!(cache.orders_open(None, None, None, None).is_empty());
+ assert!(cache.orders_emulated(None, None, None, None).is_empty());
+ assert!(cache.orders_inflight(None, None, None, None).is_empty());
+ assert!(cache.order_exists(&order.client_order_id()));
+ assert!(!cache.is_order_open(&order.client_order_id()));
+ assert!(cache.is_order_closed(&order.client_order_id()));
+ assert!(!cache.is_order_emulated(&order.client_order_id()));
+ assert!(!cache.is_order_inflight(&order.client_order_id()));
+ assert!(!cache.is_order_pending_cancel_local(&order.client_order_id()));
+ assert_eq!(cache.orders_open_count(None, None, None, None), 0);
+ assert_eq!(cache.orders_closed_count(None, None, None, None), 1);
+ assert_eq!(cache.orders_emulated_count(None, None, None, None), 0);
+ assert_eq!(cache.orders_inflight_count(None, None, None, None), 0);
+ assert_eq!(cache.orders_total_count(None, None, None, None), 1);
+ assert_eq!(
+ cache.client_order_id(&order.venue_order_id().unwrap()),
+ Some(&order.client_order_id())
+ );
+ assert_eq!(
+ cache.venue_order_id(&order.client_order_id()),
+ Some(&order.venue_order_id().unwrap())
+ );
+ }
+
+ #[rstest]
+ fn test_get_general_when_empty(cache: Cache) {
+ let result = cache.get("A").unwrap();
+ assert!(result.is_none());
+ }
+
+ #[rstest]
+ fn test_add_general_when_value(mut cache: Cache) {
+ let key = "A";
+ let value = vec![0_u8];
+ cache.add(key, value.clone()).unwrap();
+ let result = cache.get(key).unwrap();
+ assert_eq!(result, Some(&value.as_slice()).copied());
+ }
+
#[rstest]
fn test_orders_for_position(mut cache: Cache, audusd_sim: CurrencyPair) {
let order = TestOrderStubs::limit_order(
@@ -2795,7 +2861,6 @@ mod tests {
None,
None,
);
- let order = OrderAny::Limit(order);
let position_id = PositionId::default();
cache
.add_order(order.clone(), Some(position_id), None, false)
diff --git a/nautilus_core/common/src/cache/database.rs b/nautilus_core/common/src/cache/database.rs
index 62477d7ca19b..10fa6709679d 100644
--- a/nautilus_core/common/src/cache/database.rs
+++ b/nautilus_core/common/src/cache/database.rs
@@ -24,9 +24,8 @@ use std::collections::HashMap;
use nautilus_core::nanos::UnixNanos;
use nautilus_model::{
identifiers::{
- account_id::AccountId, client_id::ClientId, client_order_id::ClientOrderId,
- component_id::ComponentId, instrument_id::InstrumentId, position_id::PositionId,
- strategy_id::StrategyId, venue_order_id::VenueOrderId,
+ AccountId, ClientId, ClientOrderId, ComponentId, InstrumentId, PositionId, StrategyId,
+ VenueOrderId,
},
instruments::{any::InstrumentAny, synthetic::SyntheticInstrument},
orders::any::OrderAny,
@@ -60,18 +59,21 @@ pub trait CacheDatabaseAdapter {
fn load_index_order_client(&mut self) -> anyhow::Result>;
- fn load_currency(&mut self, code: &Ustr) -> anyhow::Result;
+ fn load_currency(&mut self, code: &Ustr) -> anyhow::Result