Compare commits
	
		
			4 Commits 
		
	
	
		
			82174d01c5
			...
			96c70ee542
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 96c70ee542 | |
|  | 118d0afc39 | |
|  | 21baee4da9 | |
|  | 291cc9f148 | 
|  | @ -0,0 +1,174 @@ | |||
| provider "spec" (aka backends) | ||||
| ============================== | ||||
| ``piker`` abstracts and encapsulates real-time data feeds across a slew | ||||
| of providers covering many (pretty much any) instrument class. | ||||
| 
 | ||||
| This doc is shoddy attempt as specifying what a backend must provide as | ||||
| a basic api, per functionality-feature set, in order to be supported for | ||||
| bny of real-time and historical data feeds and order control via the | ||||
| ``emsd`` clearing system. | ||||
| 
 | ||||
| "providers" must offer a top plevel namespace (normally exposed as | ||||
| a python module) which offers to a certain set of (async) functions | ||||
| to deliver info through a real-time, normalized data layer. | ||||
| 
 | ||||
| Generally speaking we break each ``piker.brokers.<backend_name>`` into | ||||
| a python package containing 3 sub-modules: | ||||
| 
 | ||||
| - ``.api`` containing lowest level client code used to interact | ||||
|   specifically with the APIs of the exchange, broker or data provider. | ||||
| - ``.feed`` which provides historical and real-time quote stream data | ||||
|   provider endpoints called by piker's data layer in | ||||
|   ``piker.data.feed``. | ||||
| - ``.broker`` which defines endpoints expected by | ||||
|   ``pikerd.clearing._ems`` and which are expected to adhere to the msg | ||||
|   protocol defined in ``piker.clrearing._messages``. | ||||
| 
 | ||||
| 
 | ||||
| Our current set of "production" grade backends includes: | ||||
| 
 | ||||
| - ``kraken`` | ||||
| - ``ib`` | ||||
| 
 | ||||
| 
 | ||||
| data feeds | ||||
| ---------- | ||||
| 
 | ||||
| real-time quotes and tick streaming: | ||||
| 
 | ||||
| .. code:: python | ||||
| 
 | ||||
|     async def stream_quotes( | ||||
| 
 | ||||
|         send_chan: trio.abc.SendChannel, | ||||
|         symbols: List[str], | ||||
|         shm: ShmArray, | ||||
|         feed_is_live: trio.Event, | ||||
|         loglevel: str = None,  # log level passed in from user config | ||||
| 
 | ||||
|         # startup sync via ``trio`` | ||||
|         task_status: TaskStatus[Tuple[Dict, Dict]] = trio.TASK_STATUS_IGNORED, | ||||
| 
 | ||||
|     ) -> None: | ||||
| 
 | ||||
| 
 | ||||
| this routine must eventually deliver realt-time quote messages by sending them on | ||||
| the passed in ``send_chan``; these messages must have specific format. | ||||
| there is a very simple but required startup sequence: | ||||
| 
 | ||||
| 
 | ||||
| message starup sequence: | ||||
| ************************ | ||||
| at a minimum, and asap, a first quote message should be returned for | ||||
| each requested symbol in ``symbols``. the message should have a minimum | ||||
| format: | ||||
| 
 | ||||
| .. code:: python | ||||
| 
 | ||||
|     quote_msg: dict[str, Any] = { | ||||
|         'symbol': 'xbtusd',  # or wtv symbol was requested | ||||
| 
 | ||||
|         # this field is required in the initial first quote only (though | ||||
|         # is recommended in all follow up quotes) but can be  | ||||
|         'last': <last clearing price>,  # float | ||||
| 
 | ||||
|         # tick stream fields (see below for schema/format) | ||||
|         'ticks': list[dict[str, Any]], | ||||
|     } | ||||
| 
 | ||||
| further streamed quote messages should be in this same format. | ||||
| ``ticks`` is an optional sequence | ||||
| 
 | ||||
| 
 | ||||
| historical OHLCV sampling | ||||
| ------------------------- | ||||
| Example endpoint copyed from the ``binance`` backend: | ||||
| 
 | ||||
| .. code:: python | ||||
| 
 | ||||
|    @acm | ||||
|     async def open_history_client( | ||||
|         symbol: str, | ||||
| 
 | ||||
|     ) -> tuple[Callable, int]: | ||||
| 
 | ||||
|         # TODO implement history getter for the new storage layer. | ||||
|         async with open_cached_client('binance') as client: | ||||
| 
 | ||||
|             async def get_ohlc( | ||||
|                 timeframe: float, | ||||
|                 end_dt: datetime | None = None, | ||||
|                 start_dt: datetime | None = None, | ||||
| 
 | ||||
|             ) -> tuple[ | ||||
|                 np.ndarray, | ||||
|                 datetime,  # start | ||||
|                 datetime,  # end | ||||
|             ]: | ||||
|                 if timeframe != 60: | ||||
|                     raise DataUnavailable('Only 1m bars are supported') | ||||
| 
 | ||||
|                 array = await client.bars( | ||||
|                     symbol, | ||||
|                     start_dt=start_dt, | ||||
|                     end_dt=end_dt, | ||||
|                 ) | ||||
|                 times = array['time'] | ||||
|                 if ( | ||||
|                     end_dt is None | ||||
|                 ): | ||||
|                     inow = round(time.time()) | ||||
|                     if (inow - times[-1]) > 60: | ||||
|                         await tractor.breakpoint() | ||||
| 
 | ||||
|                 start_dt = pendulum.from_timestamp(times[0]) | ||||
|                 end_dt = pendulum.from_timestamp(times[-1]) | ||||
| 
 | ||||
|                 return array, start_dt, end_dt | ||||
| 
 | ||||
|             yield get_ohlc, {'erlangs': 3, 'rate': 3} | ||||
| 
 | ||||
| 
 | ||||
| This `@acm` routine is responsible for setting up an async historical | ||||
| data query routine for both charting and any local storage requirements. | ||||
| 
 | ||||
| The returned async func should retreive, normalize and deliver | ||||
| a ``tuple[np.ndarray, pendulum.dateime, pendulum.dateime]`` of the the | ||||
| ``numpy``-ified data, the start and stop datetimes for the delivered | ||||
| history "frame". The history backloading routines inside | ||||
| ``piker.data.feed`` expect this interface for both loading history into | ||||
| ``ShmArrayt`` real-time buffers as well as any configured | ||||
| time-series-database (tsdb) and  normally the format of this data is | ||||
| OHLCV sampled price and volume data but in theory can be high | ||||
| reslolution tick/trades/book times series in the future. | ||||
| 
 | ||||
| Currently sampling routines for charting and fsp processing expects | ||||
| a max resolution of 1s (second) OHLCV sampled data. | ||||
| 
 | ||||
| 
 | ||||
| OHLCV minmal schema | ||||
| ******************** | ||||
| ohlcv at a minimum is normally pushed to local shared memory (shm) | ||||
| numpy compatible arrays which are read by both UI components for display | ||||
| as well auto-strats and algorithmic trading engines. shm is obviously | ||||
| used for speed. we also intend to eventually support pure shm tick | ||||
| streams for ultra low latency processing by external processes/services. | ||||
| 
 | ||||
| the provider module at a minimum must define a ``numpy`` structured | ||||
| array dtype ``ohlc_dtype = np.dtype(_ohlc_dtype)`` where the | ||||
| ``_ohlc_dtype`` is normally defined  in standard list-tuple synatx as: | ||||
| 
 | ||||
| .. code:: python | ||||
| 
 | ||||
|     # Broker specific ohlc schema which includes a vwap field | ||||
|     _ohlc_dtype = [ | ||||
|         ('index', int), | ||||
|         ('time', int), | ||||
|         ('open', float), | ||||
|         ('high', float), | ||||
|         ('low', float), | ||||
|         ('close', float), | ||||
|         ('volume', float), | ||||
|         ('count', int), | ||||
|         ('bar_wap', float), | ||||
|     ] | ||||
		Loading…
	
		Reference in New Issue