Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
cjdsellers committed Oct 29, 2023
1 parent 1f59991 commit fe7b8a5
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 45 deletions.
25 changes: 25 additions & 0 deletions docs/concepts/orders.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,31 @@ is not available, then the system will not submit the order and an error will be
a clear explanatory message.
```

### Terminology

- An order is **aggressive** if the type is `MARKET` or if its executing like a `MARKET` order (taking liquidity).
- An order is **passive** if the type is not `MARKET` (providing liquidity).
- An order is **active local** if it is still within the local system boundary in one of the following three (non-terminal) status:
- `INITIALIZED`
- `EMULATED`
- `RELEASED`
- An order is **in-flight** when in one of the following status:
- `SUBMITTED`
- `PENDING_UPDATE`
- `PENDING_CANCEL`
- An order is **open** when in one of the following (non-terminal) status:
- `ACCEPTED`
- `TRIGGERED`
- `PENDING_UPDATE`
- `PENDING_CANCEL`
- `PARTIALLY_FILLED`
- An order is **closed** when in one of the following (terminal) status:
- `DENIED`
- `REJECTED`
- `CANCELED`
- `EXPIRED`
- `FILLED`

## Execution Instructions

Certain exchanges allow a trader to specify conditions and restrictions on
Expand Down
171 changes: 127 additions & 44 deletions docs/concepts/strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,21 +219,22 @@ Strategies have access to a comprehensive `Clock` which provides a number of met
different timestamps, as well as setting time alerts or timers.

```{note}
See the `Clock` [API reference](../api_reference/common.md#Clock) for a complete list of available methods.
See the `Clock` [API reference](../api_reference/common.md) for a complete list of available methods.
```

#### Current timestamps

While there are multiple ways to obtain current timestamps, here are two commonly used methods as examples:

**UTC Timestamp:** This method returns a timezone-aware (UTC) timestamp:
To get the current UTC timestamp as a tz-aware `pd.Timestamp`:
```python
import pandas as pd


now: pd.Timestamp = self.clock.utc_now()
```

**Unix Nanoseconds:** This method provides the current timestamp in nanoseconds since the UNIX epoch:
To get the current UTC timestamp as nanoseconds since the UNIX epoch:
```python
unix_nanos: int = self.clock.timestamp_ns()
```
Expand Down Expand Up @@ -338,7 +339,7 @@ metrics and statistics.
Refer to the `PortfolioAnalyzer` in the [API Reference](../api_reference/analysis.md) for a complete description
of all available methods.

```{tip}
```{note}
Also see the [Porfolio statistics](../concepts/advanced/portfolio_statistics.md) guide.
```

Expand All @@ -349,39 +350,42 @@ 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}
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

An `OrderFactory` is provided on the base class for every `Strategy` as a convenience, reducing
the amount of boilerplate required to create different `Order` objects (although these objects
can still be initialized directly with the `Order.__init__(...)` constructor if the trader prefers).

The component an order flows to when submitted for execution depends on the following:

- If an `emulation_trigger` is specified, the order will _firstly_ be sent to the `OrderEmulator`
- If an `exec_algorithm_id` is specified (with no `emulation_trigger`), the order will _firstly_ be sent to the relevant `ExecAlgorithm` (assuming it exists and has been registered correctly)
- Otherwise, the order will _firstly_ be sent to the `RiskEngine`
The component a `SubmitOrder` or `SubmitOrderList` command will flow to for execution depends on the following:

The following examples show method implementations for a `Strategy`.
- If an `emulation_trigger` is specified, the command will _firstly_ be sent to the `OrderEmulator`
- If an `exec_algorithm_id` is specified (with no `emulation_trigger`), the command will _firstly_ be sent to the relevant `ExecAlgorithm`
- Otherwise, the command will _firstly_ be sent to the `RiskEngine`

This example submits a `LIMIT` BUY order for emulation (see [OrderEmulator](advanced/emulated_orders.md)):
```python
from nautilus_trader.model.enums import OrderSide
from nautilus_trader.model.enums import TriggerType
from nautilus_trader.model.orders import LimitOrder

def buy(self) -> None:
"""
Users simple buy method (example).
"""
order: LimitOrder = self.order_factory.limit(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
price=self.instrument.make_price(5000.00),
emulation_trigger=TriggerType.LAST_TRADE,
)

self.submit_order(order)
def buy(self) -> None:
"""
Users simple buy method (example).
"""
order: LimitOrder = self.order_factory.limit(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
price=self.instrument.make_price(5000.00),
emulation_trigger=TriggerType.LAST_TRADE,
)

self.submit_order(order)
```

```{note}
Expand All @@ -394,34 +398,100 @@ from nautilus_trader.model.enums import OrderSide
from nautilus_trader.model.enums import TimeInForce
from nautilus_trader.model.identifiers import ExecAlgorithmId

def buy(self) -> None:
"""
Users simple buy method (example).
"""
order: MarketOrder = self.order_factory.market(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
time_in_force=TimeInForce.FOK,
exec_algorithm_id=ExecAlgorithmId("TWAP"),
exec_algorithm_params={"horizon_secs": 20, "interval_secs": 2.5},
)

self.submit_order(order)
def buy(self) -> None:
"""
Users simple buy method (example).
"""
order: MarketOrder = self.order_factory.market(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
time_in_force=TimeInForce.FOK,
exec_algorithm_id=ExecAlgorithmId("TWAP"),
exec_algorithm_params={"horizon_secs": 20, "interval_secs": 2.5},
)

self.submit_order(order)
```

#### Managed GTD expiry
#### Canceling orders

It's possible for the strategy to manage expiry for orders with a time in force of GTD (_Good 'till Date_).
This may be desirable if the exchange/broker does not support this time in force option, or for any
reason you prefer the strategy to manage this.
Orders can be canceled individually, as a batch, or all orders for an instrument (with an optional side filter).

To use this option, pass `manage_gtd_expiry=True` to your `StrategyConfig`. When an order is submitted with
a time in force of GTD, the strategy will automatically start an internal time alert.
Once the internal GTD time alert is reached, the order will be canceled (if not already closed).
If the order is already *closed* or already pending cancel, then a warning will be logged.

Some venues (such as Binance Futures) support the GTD time in force, so to avoid conflicts when using
`managed_gtd_expiry` you should set `use_gtd=False` for your execution client config.
If the order is currently *open* then the status will become `PENDING_CANCEL`.

The component a `CancelOrder`, `CancelAllOrders` or `BatchCancelOrders` 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`
- 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}
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

self.cancel_order(order)

```

The following shows how to cancel a batch of orders:
```python
from nautilus_trader.model import Order


my_order_list: list[Order] = [order1, order2, order3]
self.cancel_orders(my_order_list)

```

The following shows how to cancel all orders:

```python

self.cancel_all_orders()

```

#### Modifying orders

Orders can be modified individually when emulated, or *open* on a venue (if supported).

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}
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}
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
from nautilus_trader.model import Quantity


new_quantity: Quantity = Quantity.from_int(5)
self.modify_order(order, new_quantity)

```

```{note}
The price and trigger price can also be modified (when emulated or supported by a venue).

```

## Configuration

Expand Down Expand Up @@ -482,6 +552,19 @@ 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

It's possible for the strategy to manage expiry for orders with a time in force of GTD (_Good 'till Date_).
This may be desirable if the exchange/broker does not support this time in force option, or for any
reason you prefer the strategy to manage this.

To use this option, pass `manage_gtd_expiry=True` to your `StrategyConfig`. When an order is submitted with
a time in force of GTD, the strategy will automatically start an internal time alert.
Once the internal GTD time alert is reached, the order will be canceled (if not already *closed*).

Some venues (such as Binance Futures) support the GTD time in force, so to avoid conflicts when using
`managed_gtd_expiry` you should set `use_gtd=False` for your execution client config.

### Multiple strategies

If you intend running multiple instances of the same strategy, with different
Expand Down
2 changes: 1 addition & 1 deletion nautilus_trader/execution/manager.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ cdef class OrderManager:
Parameters
----------
order : Order
The order the check.
The order to check.
Returns
-------
Expand Down

0 comments on commit fe7b8a5

Please sign in to comment.