Skip to content

Commit

Permalink
Add pyo3 object conversion methods
Browse files Browse the repository at this point in the history
  • Loading branch information
cjdsellers committed Aug 9, 2023
1 parent b1ed581 commit 7de008e
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 0 deletions.
44 changes: 44 additions & 0 deletions nautilus_trader/model/data/bar.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# -------------------------------------------------------------------------------------------------

from cpython.datetime cimport timedelta
from libc.stdint cimport uint8_t
from libc.stdint cimport uint64_t

from nautilus_trader.core.correctness cimport Condition
Expand Down Expand Up @@ -915,6 +916,49 @@ cdef class Bar(Data):
"""
return Bar.to_dict_c(obj)

@staticmethod
def from_pyo3(list pyo3_bars) -> list[Bar]:
"""
Return bars converted from the given pyo3 provided objects.

Parameters
----------
pyo3_bars : list[RustBar]
The Rust pyo3 bars to convert from.

Returns
-------
list[Bar]

"""
cdef list output = []

cdef BarType bar_type = None
cdef uint8_t price_prec = 0
cdef uint8_t volume_prec = 0

cdef:
Bar bar
for pyo3_bar in pyo3_bars:
if bar_type is None:
bar_type = BarType.from_str_c(str(pyo3_bar.bar_type))
price_prec = pyo3_bar.open.precision
volume_prec = pyo3_bar.volume.precision

bar = Bar(
bar_type,
Price.from_raw_c(pyo3_bar.open.raw, price_prec),
Price.from_raw_c(pyo3_bar.high.raw, price_prec),
Price.from_raw_c(pyo3_bar.low.raw, price_prec),
Price.from_raw_c(pyo3_bar.close.raw, price_prec),
Quantity.from_raw_c(pyo3_bar.volume.raw, volume_prec),
pyo3_bar.ts_event,
pyo3_bar.ts_init,
)
output.append(bar)

return output

cpdef bint is_single_price(self):
"""
If the OHLC are all equal to a single price.
Expand Down
50 changes: 50 additions & 0 deletions nautilus_trader/model/data/book.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,56 @@ cdef class OrderBookDelta(Data):
"""
return OrderBookDelta.clear_c(instrument_id, ts_event, ts_init, sequence)

@staticmethod
def from_pyo3(list pyo3_deltas) -> list[OrderBookDelta]:
"""
Return order book deltas converted from the given pyo3 provided objects.

Parameters
----------
pyo3_deltas : list[RustOrderBookDelta]
The Rust pyo3 order book deltas to convert from.

Returns
-------
list[OrderBookDelta]

"""
cdef list output = []

cdef InstrumentId instrument_id = None
cdef uint8_t price_prec = 0
cdef uint8_t size_prec = 0

cdef:
OrderBookDelta delta
BookOrder book_order
for pyo3_delta in pyo3_deltas:
if instrument_id is None:
instrument_id = InstrumentId.from_str_c(pyo3_delta.instrument_id.value)
price_prec = pyo3_delta.order.price.precision
size_prec = pyo3_delta.order.size.precision

book_order = BookOrder(
pyo3_delta.order.side.value,
Price.from_raw_c(pyo3_delta.order.price.raw, price_prec),
Quantity.from_raw_c(pyo3_delta.order.size.raw, size_prec),
pyo3_delta.order.order_id,
)

delta = OrderBookDelta(
instrument_id,
pyo3_delta.action.value,
book_order,
pyo3_delta.ts_event,
pyo3_delta.ts_init,
pyo3_delta.sequence,
pyo3_delta.flags,
)
output.append(delta)

return output


cdef class OrderBookDeltas(Data):
"""
Expand Down
97 changes: 97 additions & 0 deletions nautilus_trader/model/data/tick.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# limitations under the License.
# -------------------------------------------------------------------------------------------------

from nautilus_trader.core.nautilus_pyo3.model import QuoteTick as RustQuoteTick
from nautilus_trader.core.nautilus_pyo3.model import TradeTick as RustTradeTick

from libc.stdint cimport int64_t
from libc.stdint cimport uint8_t
from libc.stdint cimport uint64_t
Expand Down Expand Up @@ -440,6 +443,56 @@ cdef class QuoteTick(Data):
"""
return QuoteTick.to_dict_c(obj)

@staticmethod
def from_pyo3(list pyo3_ticks) -> list[QuoteTick]:
"""
Return quote ticks converted from the given pyo3 provided objects.

Parameters
----------
pyo3_ticks : list[RustQuoteTick]
The Rust pyo3 quote ticks to convert from.

Returns
-------
list[QuoteTick]

"""
cdef list output = []

cdef InstrumentId instrument_id = None
cdef uint8_t bid_prec = 0
cdef uint8_t ask_prec = 0
cdef uint8_t bid_size_prec = 0
cdef uint8_t ask_size_prec = 0

cdef:
QuoteTick tick
for pyo3_tick in pyo3_ticks:
if instrument_id is None:
instrument_id = InstrumentId.from_str_c(pyo3_tick.instrument_id.value)
bid_prec = pyo3_tick.bid.precision
ask_prec = pyo3_tick.ask.precision
bid_size_prec = pyo3_tick.bid_size.precision
ask_size_prec = pyo3_tick.ask_size.precision

tick = QuoteTick.from_raw_c(
instrument_id,
pyo3_tick.bid.raw,
pyo3_tick.ask.raw,
bid_prec,
ask_prec,
pyo3_tick.bid_size.raw,
pyo3_tick.ask_size.raw,
bid_size_prec,
ask_size_prec,
pyo3_tick.ts_event,
pyo3_tick.ts_init,
)
output.append(tick)

return output

cpdef Price extract_price(self, PriceType price_type):
"""
Extract the price for the given price type.
Expand Down Expand Up @@ -848,3 +901,47 @@ cdef class TradeTick(Data):
"""
return TradeTick.to_dict_c(obj)

@staticmethod
def from_pyo3(list pyo3_ticks) -> list[TradeTick]:
"""
Return trade ticks converted from the given pyo3 provided objects.

Parameters
----------
pyo3_ticks : list[RustTradeTick]
The Rust pyo3 trade ticks to convert from.

Returns
-------
list[TradeTick]

"""
cdef list output = []

cdef InstrumentId instrument_id = None
cdef uint8_t price_prec = 0
cdef uint8_t size_prec = 0

cdef:
TradeTick tick
for pyo3_tick in pyo3_ticks:
if instrument_id is None:
instrument_id = InstrumentId.from_str_c(pyo3_tick.instrument_id.value)
price_prec = pyo3_tick.price.precision
size_prec = pyo3_tick.price.precision

tick = TradeTick.from_raw_c(
instrument_id,
pyo3_tick.price.raw,
price_prec,
pyo3_tick.size.raw,
size_prec,
pyo3_tick.aggressor_side.value,
TradeId(pyo3_tick.trade_id.value),
pyo3_tick.ts_event,
pyo3_tick.ts_init,
)
output.append(tick)

return output
10 changes: 10 additions & 0 deletions tests/unit_tests/persistence/test_wranglers_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import pandas as pd
from fsspec.utils import pathlib

from nautilus_trader.model.data import QuoteTick
from nautilus_trader.model.data import TradeTick
from nautilus_trader.persistence.wranglers_v2 import QuoteTickDataWrangler
from nautilus_trader.persistence.wranglers_v2 import TradeTickDataWrangler
from nautilus_trader.test_kit.providers import TestInstrumentProvider
Expand All @@ -36,8 +38,12 @@ def test_quote_tick_data_wrangler() -> None:
wrangler = QuoteTickDataWrangler(AUDUSD_SIM)
ticks = wrangler.from_pandas(df)

cython_ticks = QuoteTick.from_pyo3(ticks)

# Assert
assert len(ticks) == 100_000
assert len(cython_ticks) == 100_000
assert isinstance(cython_ticks[0], QuoteTick)
assert str(ticks[0]) == "AUD/USD.SIM,0.67067,0.67070,1000000,1000000,1580398089820000000"
assert str(ticks[-1]) == "AUD/USD.SIM,0.66934,0.66938,1000000,1000000,1580504394501000000"

Expand All @@ -51,7 +57,11 @@ def test_trade_tick_data_wrangler() -> None:
wrangler = TradeTickDataWrangler(ETHUSDT_BINANCE)
ticks = wrangler.from_pandas(df)

cython_ticks = TradeTick.from_pyo3(ticks)

# Assert
assert len(ticks) == 69806
assert len(cython_ticks) == 69806
assert isinstance(cython_ticks[0], TradeTick)
assert str(ticks[0]) == "ETHUSDT.BINANCE,423.76,2.67900,BUYER,148568980,1597399200223000000"
assert str(ticks[-1]) == "ETHUSDT.BINANCE,426.89,0.16100,BUYER,148638715,1597417198693000000"

0 comments on commit 7de008e

Please sign in to comment.