예제 #1
0
    def test_to_dict_returns_expected_dict(self):
        # Arrange
        tick = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("1.00000"),
            size=Quantity.from_int(10000),
            aggressor_side=AggressorSide.BUY,
            trade_id=TradeId("123456789"),
            ts_event=0,
            ts_init=0,
        )

        # Act
        result = TradeTick.to_dict(tick)

        # Assert
        assert result == {
            "type": "TradeTick",
            "instrument_id": "AUD/USD.SIM",
            "price": "1.00000",
            "size": "10000",
            "aggressor_side": "BUY",
            "trade_id": "123456789",
            "ts_event": 0,
            "ts_init": 0,
        }
    def test_handle_trade_tick_when_volume_at_threshold_sends_bar_to_handler(
            self):
        # Arrange
        bar_store = ObjectStorer()
        handler = bar_store.store
        instrument = AUDUSD_SIM
        bar_spec = BarSpecification(10000, BarAggregation.VOLUME,
                                    PriceType.LAST)
        bar_type = BarType(instrument.id, bar_spec)
        aggregator = VolumeBarAggregator(
            instrument,
            bar_type,
            handler,
            Logger(TestClock()),
        )

        tick1 = TradeTick(
            instrument_id=instrument.id,
            price=Price.from_str("1.00001"),
            size=Quantity.from_int(3000),
            aggressor_side=AggressorSide.BUY,
            trade_id="123456",
            ts_event=0,
            ts_init=0,
        )

        tick2 = TradeTick(
            instrument_id=instrument.id,
            price=Price.from_str("1.00002"),
            size=Quantity.from_int(4000),
            aggressor_side=AggressorSide.BUY,
            trade_id="123457",
            ts_event=0,
            ts_init=0,
        )

        tick3 = TradeTick(
            instrument_id=instrument.id,
            price=Price.from_str("1.00000"),
            size=Quantity.from_int(3000),
            aggressor_side=AggressorSide.BUY,
            trade_id="123458",
            ts_event=0,
            ts_init=0,
        )

        # Act
        aggregator.handle_trade_tick(tick1)
        aggregator.handle_trade_tick(tick2)
        aggregator.handle_trade_tick(tick3)

        # Assert
        assert len(bar_store.get_store()) == 1
        assert bar_store.get_store()[0].open == Price.from_str("1.00001")
        assert bar_store.get_store()[0].high == Price.from_str("1.00002")
        assert bar_store.get_store()[0].low == Price.from_str("1.00000")
        assert bar_store.get_store()[0].close == Price.from_str("1.00000")
        assert bar_store.get_store()[0].volume == Quantity.from_int(10000)
예제 #3
0
    def test_passive_fill_on_trade_tick(self):
        # Arrange: Prepare market
        # Market is 10 @ 15
        snapshot = TestDataStubs.order_book_snapshot(
            instrument_id=USDJPY_SIM.id, bid_volume=1000, ask_volume=1000)
        self.data_engine.process(snapshot)
        self.exchange.process_order_book(snapshot)

        order = self.strategy.order_factory.limit(
            instrument_id=USDJPY_SIM.id,
            order_side=OrderSide.SELL,
            quantity=Quantity.from_int(2000),
            price=Price.from_str("14"),
            post_only=False,
        )
        self.strategy.submit_order(order)

        # Act
        tick1 = TradeTick(
            instrument_id=USDJPY_SIM.id,
            price=Price.from_str("14.0"),
            size=Quantity.from_int(1000),
            aggressor_side=AggressorSide.SELL,
            trade_id=TradeId("123456789"),
            ts_event=0,
            ts_init=0,
        )
        self.exchange.process_tick(tick1)

        # Assert
        assert order.status == OrderStatus.PARTIALLY_FILLED
        assert order.filled_qty == Quantity.from_int(1000.0)  # No slippage
        assert order.avg_px == Decimal("14.0")
    def test_handle_trade_tick_when_value_below_threshold_updates(self):
        # Arrange
        bar_store = ObjectStorer()
        handler = bar_store.store
        instrument_id = TestStubs.audusd_id()
        bar_spec = BarSpecification(100000, BarAggregation.VALUE,
                                    PriceType.LAST)
        bar_type = BarType(instrument_id, bar_spec)
        aggregator = ValueBarAggregator(
            AUDUSD_SIM,
            bar_type,
            handler,
            Logger(TestClock()),
        )

        tick1 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("15000.00"),
            size=Quantity.from_str("3.5"),
            aggressor_side=AggressorSide.BUY,
            trade_id="123456",
            ts_event=0,
            ts_init=0,
        )

        # Act
        aggregator.handle_trade_tick(tick1)

        # Assert
        assert len(bar_store.get_store()) == 0
        assert aggregator.get_cumulative_value() == Decimal("52500.000")
예제 #5
0
    async def test_subscribe_trade_ticks(self, monkeypatch):
        handler = []
        self.msgbus.subscribe(
            topic="data.trades.BINANCE.ETHUSDT",
            handler=handler.append,
        )

        # Act
        self.data_client.subscribe_trade_ticks(ETHUSDT_BINANCE.id)

        raw_trade = pkgutil.get_data(
            package="tests.integration_tests.adapters.binance.resources.ws_messages",
            resource="ws_spot_trade.json",
        )

        # Assert
        self.data_client._handle_ws_message(raw_trade)
        await asyncio.sleep(1)

        assert self.data_engine.data_count == 1
        assert len(handler) == 1  # <-- handler received tick
        assert handler[0] == TradeTick(
            instrument_id=ETHUSDT_BINANCE.id,
            price=Price.from_str("4149.74000000"),
            size=Quantity.from_str("0.43870000"),
            aggressor_side=AggressorSide.SELL,
            trade_id=TradeId("705291099"),
            ts_event=1639351062243000064,
            ts_init=handler[0].ts_init,
        )
    def test_handle_trade_tick_when_volume_below_threshold_updates(self):
        # Arrange
        bar_store = ObjectStorer()
        handler = bar_store.store
        instrument = AUDUSD_SIM
        bar_spec = BarSpecification(10000, BarAggregation.VOLUME,
                                    PriceType.LAST)
        bar_type = BarType(instrument.id, bar_spec)
        aggregator = VolumeBarAggregator(
            instrument,
            bar_type,
            handler,
            Logger(TestClock()),
        )

        tick1 = TradeTick(
            instrument_id=instrument.id,
            price=Price.from_str("1.00001"),
            size=Quantity.from_int(1),
            aggressor_side=AggressorSide.BUY,
            trade_id="123456",
            ts_event=0,
            ts_init=0,
        )

        # Act
        aggregator.handle_trade_tick(tick1)

        # Assert
        assert len(bar_store.get_store()) == 0
예제 #7
0
    def test_data_catalog_instrument_ids_correctly_unmapped(self):
        # Arrange
        catalog = DataCatalog.from_env()
        instrument = TestInstrumentProvider.default_fx_ccy("AUD/USD",
                                                           venue=Venue("SIM"))
        trade_tick = TradeTick(
            instrument_id=instrument.id,
            price=Price.from_str("2.0"),
            size=Quantity.from_int(10),
            aggressor_side=AggressorSide.UNKNOWN,
            trade_id=TradeId("1"),
            ts_event=0,
            ts_init=0,
        )
        write_objects(catalog=catalog, chunk=[instrument, trade_tick])

        # Act
        instrument = catalog.instruments(instrument_ids=["AUD/USD.SIM"],
                                         as_nautilus=True)[0]
        trade_tick = catalog.trade_ticks(instrument_ids=["AUD/USD.SIM"],
                                         as_nautilus=True)[0]

        # Assert
        assert instrument.id.value == "AUD/USD.SIM"
        assert trade_tick.instrument_id.value == "AUD/USD.SIM"
예제 #8
0
    def test_from_dict_returns_expected_tick(self):
        # Arrange
        tick = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("1.00000"),
            size=Quantity.from_int(10000),
            aggressor_side=AggressorSide.BUY,
            trade_id=TradeId("123456789"),
            ts_event=0,
            ts_init=0,
        )

        # Act
        result = TradeTick.from_dict(TradeTick.to_dict(tick))

        # Assert
        assert tick == result
예제 #9
0
def parse_trade_tick_ws(instrument_id: InstrumentId, msg: Dict,
                        ts_init: int) -> TradeTick:
    return TradeTick(
        instrument_id=instrument_id,
        price=Price.from_str(msg["p"]),
        size=Quantity.from_str(msg["q"]),
        aggressor_side=AggressorSide.SELL if msg["m"] else AggressorSide.BUY,
        trade_id=str(msg["t"]),
        ts_event=millis_to_nanos(msg["T"]),
        ts_init=ts_init,
    )
예제 #10
0
def parse_trade_tick_http(instrument_id: InstrumentId, msg: Dict,
                          ts_init: int) -> TradeTick:
    return TradeTick(
        instrument_id=instrument_id,
        price=Price.from_str(msg["price"]),
        size=Quantity.from_str(msg["qty"]),
        aggressor_side=AggressorSide.SELL
        if msg["isBuyerMaker"] else AggressorSide.BUY,
        trade_id=TradeId(str(msg["id"])),
        ts_event=millis_to_nanos(msg["time"]),
        ts_init=ts_init,
    )
예제 #11
0
def parse_trade_tick_ws(
    instrument_id: InstrumentId,
    data: BinanceTradeData,
    ts_init: int,
) -> TradeTick:
    return TradeTick(
        instrument_id=instrument_id,
        price=Price.from_str(data.p),
        size=Quantity.from_str(data.q),
        aggressor_side=AggressorSide.SELL if data.m else AggressorSide.BUY,
        trade_id=TradeId(str(data.t)),
        ts_event=millis_to_nanos(data.T),
        ts_init=ts_init,
    )
예제 #12
0
 def parse_line(d):
     if "status" in d:
         return {}
     elif "close_price" in d:
         # return {'timestamp': d['remote_timestamp'], "close_price": d['close_price']}
         return {}
     if "trade" in d:
         ts = millis_to_nanos(
             pd.Timestamp(d["remote_timestamp"]).timestamp())
         return {
             "timestamp":
             d["remote_timestamp"],
             "op":
             "trade",
             "trade":
             TradeTick(
                 instrument_id=InstrumentId(Symbol("TEST"),
                                            Venue("BETFAIR")),
                 price=Price(d["trade"]["price"], 4),
                 size=Quantity(d["trade"]["volume"], 4),
                 aggressor_side=d["trade"]["side"],
                 trade_id=TradeId(d["trade"]["trade_id"]),
                 ts_event=ts,
                 ts_init=ts,
             ),
         }
     elif "level" in d and d["level"]["orders"][0]["volume"] == 0:
         op = "delete"
     else:
         op = "update"
     order_like = d["level"]["orders"][0] if op != "trade" else d[
         "trade"]
     return {
         "timestamp":
         d["remote_timestamp"],
         "op":
         op,
         "order":
         Order(
             price=Price(order_like["price"], precision=6),
             size=Quantity(abs(order_like["volume"]), precision=4),
             # Betting sides are reversed
             side={
                 2: OrderSide.BUY,
                 1: OrderSide.SELL
             }[order_like["side"]],
             id=str(order_like["order_id"]),
         ),
     }
예제 #13
0
 def trade_tick_3decimal(
     instrument_id=None,
     price=None,
     aggressor_side=None,
     quantity=None,
 ) -> TradeTick:
     return TradeTick(
         instrument_id=instrument_id or TestIdStubs.usdjpy_id(),
         price=price or Price.from_str("1.001"),
         size=quantity or Quantity.from_int(100000),
         aggressor_side=aggressor_side or AggressorSide.BUY,
         trade_id=TradeId("123456"),
         ts_event=0,
         ts_init=0,
     )
예제 #14
0
    def test_hash_str_and_repr(self):
        # Arrange
        tick = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("1.00000"),
            size=Quantity.from_int(50000),
            aggressor_side=AggressorSide.BUY,
            trade_id=TradeId("123456789"),
            ts_event=0,
            ts_init=0,
        )

        # Act, Assert
        assert isinstance(hash(tick), int)
        assert str(tick) == "AUD/USD.SIM,1.00000,50000,BUY,123456789,0"
        assert repr(tick) == "TradeTick(AUD/USD.SIM,1.00000,50000,BUY,123456789,0)"
예제 #15
0
 def _on_trade_ticker_update(self, ticker: Ticker):
     instrument_id = self._instrument_provider.contract_id_to_instrument_id[
         ticker.contract.conId]
     for tick in ticker.ticks:
         price = str(tick.price)
         size = str(tick.size)
         ts_event = dt_to_unix_nanos(tick.time)
         update = TradeTick(
             instrument_id=instrument_id,
             price=Price.from_str(price),
             size=Quantity.from_str(size),
             aggressor_side=AggressorSide.UNKNOWN,
             trade_id=generate_trade_id(symbol=instrument_id.value,
                                        ts_event=ts_event,
                                        price=price,
                                        size=size),
             ts_event=ts_event,
             ts_init=self._clock.timestamp_ns(),
         )
         self._handle_data(update)
예제 #16
0
def parse_trade_ticks_ws(
    instrument: Instrument,
    data: List[Dict[str, Any]],
    ts_init: int,
) -> List[TradeTick]:
    ticks: List[TradeTick] = []
    for trade in data:
        tick: TradeTick = TradeTick(
            instrument_id=instrument.id,
            price=Price(trade["price"], instrument.price_precision),
            size=Quantity(trade["size"], instrument.size_precision),
            aggressor_side=AggressorSide.BUY
            if trade["side"] == "buy" else AggressorSide.SELL,
            trade_id=TradeId(str(trade["id"])),
            ts_event=pd.to_datetime(trade["time"], utc=True).to_datetime64(),
            ts_init=ts_init,
        )
        ticks.append(tick)

    return ticks
예제 #17
0
def parse_historic_trade_ticks(historic_ticks: List[HistoricalTickLast],
                               instrument_id: InstrumentId) -> List[TradeTick]:
    trades = []
    for tick in historic_ticks:
        ts_init = dt_to_unix_nanos(tick.time)
        trade_tick = TradeTick(
            instrument_id=instrument_id,
            price=Price.from_str(str(tick.price)),
            size=Quantity.from_str(str(tick.size)),
            aggressor_side=AggressorSide.UNKNOWN,
            trade_id=generate_trade_id(
                symbol=instrument_id.symbol.value,
                ts_event=ts_init,
                price=tick.price,
                size=tick.size,
            ),
            ts_init=ts_init,
            ts_event=ts_init,
        )
        trades.append(trade_tick)

    return trades
    def test_parse_historic_trade_ticks(self):
        # Arrange
        raw = IBTestStubs.historic_trades()
        instrument_id = IBTestStubs.instrument(symbol="AAPL").id

        # Act
        ticks = parse_historic_trade_ticks(historic_ticks=raw,
                                           instrument_id=instrument_id)

        # Assert
        assert all([isinstance(t, TradeTick) for t in ticks])

        expected = TradeTick.from_dict({
            "type": "TradeTick",
            "instrument_id": "AAPL.NASDAQ",
            "price": "6.2",
            "size": "30.0",
            "aggressor_side": "UNKNOWN",
            "trade_id":
            "2a62fd894bf039d1907675dcaa8d2a64a9022fe3fa4bdd0ef9972c4b40e041d5",
            "ts_event": 1646185673000000000,
            "ts_init": 1646185673000000000,
        })
        assert ticks[0] == expected
예제 #19
0
def _handle_market_trades(
    runner,
    instrument,
    ts_event,
    ts_init,
):
    trade_ticks = []
    for price, volume in runner.get("trd", []):
        if volume == 0:
            continue
        # Betfair doesn't publish trade ids, so we make our own
        # TODO - should we use clk here for ID instead of the hash?
        trade_id = hash_json(data=(ts_event, price, volume))
        tick = TradeTick(
            instrument_id=instrument.id,
            price=price_to_probability(str(price)),
            size=Quantity(volume, precision=4),
            aggressor_side=AggressorSide.UNKNOWN,
            trade_id=TradeId(trade_id),
            ts_event=ts_event,
            ts_init=ts_init,
        )
        trade_ticks.append(tick)
    return trade_ticks
예제 #20
0
 def test_fully_qualified_name(self):
     # Arrange, Act, Assert
     assert TradeTick.fully_qualified_name() == "nautilus_trader.model.data.tick.TradeTick"
    def test_handle_trade_tick_when_volume_beyond_threshold_sends_bars_to_handler(
            self):
        # Arrange
        bar_store = ObjectStorer()
        handler = bar_store.store
        instrument_id = TestStubs.audusd_id()
        bar_spec = BarSpecification(100000, BarAggregation.VALUE,
                                    PriceType.LAST)
        bar_type = BarType(instrument_id, bar_spec)
        aggregator = ValueBarAggregator(
            AUDUSD_SIM,
            bar_type,
            handler,
            Logger(TestClock()),
        )

        tick1 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("20.00001"),
            size=Quantity.from_str("3000.00"),
            aggressor_side=AggressorSide.BUY,
            trade_id="123456",
            ts_event=0,
            ts_init=0,
        )

        tick2 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("20.00002"),
            size=Quantity.from_str("4000.00"),
            aggressor_side=AggressorSide.BUY,
            trade_id="123457",
            ts_event=0,
            ts_init=0,
        )

        tick3 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("20.00000"),
            size=Quantity.from_str("5000.00"),
            aggressor_side=AggressorSide.BUY,
            trade_id="123458",
            ts_event=0,
            ts_init=0,
        )

        # Act
        aggregator.handle_trade_tick(tick1)
        aggregator.handle_trade_tick(tick2)
        aggregator.handle_trade_tick(tick3)

        # Assert
        assert len(bar_store.get_store()) == 2
        assert bar_store.get_store()[0].open == Price.from_str("20.00001")
        assert bar_store.get_store()[0].high == Price.from_str("20.00002")
        assert bar_store.get_store()[0].low == Price.from_str("20.00001")
        assert bar_store.get_store()[0].close == Price.from_str("20.00002")
        assert bar_store.get_store()[0].volume == Quantity.from_str("5000.00")
        assert bar_store.get_store()[1].open == Price.from_str("20.00002")
        assert bar_store.get_store()[1].high == Price.from_str("20.00002")
        assert bar_store.get_store()[1].low == Price.from_str("20.00000")
        assert bar_store.get_store()[1].close == Price.from_str("20.00000")
        assert bar_store.get_store()[1].volume == Quantity.from_str("5000.00")
        assert aggregator.get_cumulative_value() == Decimal("40000.11000")