跳到主要内容

适配器

The NautilusTrader design integrates 数据 providers and/or trading venues through adapter implementations. These can be found in the top-level 适配器 subpackage.

An integration adapter is typically comprised of the following main components:

  • HttpClient
  • WebSocketClient
  • InstrumentProvider
  • DataClient
  • ExecutionClient

Instrument providers

Instrument providers do as their name suggests - instantiating Nautilus Instrument objects by parsing the raw API of the publisher or venue.

The use cases for the 金融工具 available from an InstrumentProvider are either:

  • Used standalone to discover the 金融工具 available for an integration, using these for research or 回测 purposes
  • Used in a sandbox or live environment context for consumption by actors/strategies

Research and 回测

Here is an example of discovering the current 金融工具 for the Binance Futures testnet:

import asyncio
import os

from nautilus_trader.adapters.binance.common.enums import BinanceAccountType
from nautilus_trader.adapters.binance import get_cached_binance_http_client
from nautilus_trader.adapters.binance.futures.providers import BinanceFuturesInstrumentProvider
from nautilus_trader.common.component import LiveClock


clock = LiveClock()
account_type = BinanceAccountType.USDT_FUTURES

client = get_cached_binance_http_client(
loop=asyncio.get_event_loop(),
clock=clock,
account_type=account_type,
key=os.getenv("BINANCE_FUTURES_TESTNET_API_KEY"),
secret=os.getenv("BINANCE_FUTURES_TESTNET_API_SECRET"),
is_testnet=True,
)
await client.connect()

provider = BinanceFuturesInstrumentProvider(
client=client,
account_type=BinanceAccountType.USDT_FUTURES,
)

await provider.load_all_async()

实时交易

Each integration is 实现 specific, and there are generally two options for the behavior of an InstrumentProvider within a TradingNode for 实时交易, as configured:

  • All 金融工具 are automatically loaded on start:
from nautilus_trader.config import InstrumentProviderConfig

InstrumentProviderConfig(load_all=True)
  • Only those 金融工具 explicitly specified in the 配置 are loaded on start:
InstrumentProviderConfig(load_ids=["BTCUSDT-PERP.BINANCE", "ETHUSDT-PERP.BINANCE"])

数据 clients

Requests

An Actor or Strategy can request custom 数据 from a DataClient by sending a DataRequest. If the 客户端 that receives the DataRequest implements a handler for the request, 数据 will be returned to the Actor or Strategy.

Example

An example of this is a DataRequest for an Instrument, which the Actor class implements (copied below). Any Actor or Strategy can call a request_instrument method with an InstrumentId to request the instrument from a DataClient.

In this particular case, the Actor implements a separate method request_instrument. A similar type of DataRequest could be instantiated and called from anywhere and/or anytime in the actor/strategy code.

A simplified 版本 of request_instrument for an actor/strategy is:

# nautilus_trader/common/actor.pyx

cpdef void request_instrument(self, InstrumentId instrument_id, ClientId client_id=None):
"""
Request `Instrument` data for the given instrument ID.

Parameters
----------
instrument_id : InstrumentId
The instrument ID for the request.
client_id : ClientId, optional
The specific client ID for the command.
If ``None`` then will be inferred from the venue in the instrument ID.
"""
Condition.not_none(instrument_id, "instrument_id")

cdef RequestInstrument request = RequestInstrument(
instrument_id=instrument_id,
start=None,
end=None,
client_id=client_id,
venue=instrument_id.venue,
callback=self._handle_instrument_response,
request_id=UUID4(),
ts_init=self._clock.timestamp_ns(),
params=None,
)

self._send_data_req(request)

A simplified 版本 of the request handler implemented in a LiveMarketDataClient that will retrieve the 数据 and send it back to 参与者/策略 is for example:

# nautilus_trader/live/data_client.py

def request_instrument(self, request: RequestInstrument) -> None:
self.create_task(self._request_instrument(request))

# nautilus_trader/adapters/binance/data.py

async def _request_instrument(self, request: RequestInstrument) -> None:
instrument: Instrument | None = self._instrument_provider.find(request.instrument_id)

if instrument is None:
self._log.error(f"Cannot find instrument for {request.instrument_id}")
return

self._handle_instrument(instrument, request.id, request.params)

The DataEngine which is an important 组件 in Nautilus links a request with a DataClient. For example a simplified 版本 of handling an instrument request is:

# nautilus_trader/data/engine.pyx

self._msgbus.register(endpoint="DataEngine.request", handler=self.request)

cpdef void request(self, RequestData request):
self._handle_request(request)

cpdef void _handle_request(self, RequestData request):
cdef DataClient client = self._clients.get(request.client_id)

if client is None:
client = self._routing_map.get(request.venue, self._default_client)

if isinstance(request, RequestInstrument):
self._handle_request_instrument(client, request)

cpdef void _handle_request_instrument(self, DataClient client, RequestInstrument request):
client.request_instrument(request)