|
20 | 20 | """ |
21 | 21 | from __future__ import annotations |
22 | 22 | from pathlib import Path |
| 23 | +import time |
| 24 | +from typing import Generator |
23 | 25 | # from typing import TYPE_CHECKING |
24 | 26 |
|
25 | 27 | import polars as pl |
26 | 28 | import numpy as np |
| 29 | +import tractor |
27 | 30 | # import pendulum |
28 | 31 | from rich.console import Console |
29 | 32 | import trio |
|
32 | 35 |
|
33 | 36 | from piker.service import open_piker_runtime |
34 | 37 | from piker.cli import cli |
| 38 | +from piker.config import get_conf_dir |
| 39 | +from piker.data import ( |
| 40 | + maybe_open_shm_array, |
| 41 | + def_iohlcv_fields, |
| 42 | + ShmArray, |
| 43 | +) |
| 44 | +from piker.data.history import ( |
| 45 | + _default_hist_size, |
| 46 | + _default_rt_size, |
| 47 | +) |
35 | 48 | from . import ( |
36 | 49 | log, |
37 | 50 | ) |
@@ -132,8 +145,6 @@ def anal( |
132 | 145 |
|
133 | 146 | ) -> np.ndarray: |
134 | 147 |
|
135 | | - import tractor |
136 | | - |
137 | 148 | async def main(): |
138 | 149 | async with ( |
139 | 150 | open_piker_runtime( |
@@ -171,99 +182,150 @@ async def main(): |
171 | 182 | trio.run(main) |
172 | 183 |
|
173 | 184 |
|
| 185 | +def iter_dfs_from_shms(fqme: str) -> Generator[ |
| 186 | + tuple[Path, ShmArray, pl.DataFrame], |
| 187 | + None, |
| 188 | + None, |
| 189 | +]: |
| 190 | + # shm buffer size table based on known sample rates |
| 191 | + sizes: dict[str, int] = { |
| 192 | + 'hist': _default_hist_size, |
| 193 | + 'rt': _default_rt_size, |
| 194 | + } |
| 195 | + |
| 196 | + # load all detected shm buffer files which have the |
| 197 | + # passed FQME pattern in the file name. |
| 198 | + shmfiles: list[Path] = [] |
| 199 | + shmdir = Path('/dev/shm/') |
| 200 | + |
| 201 | + for shmfile in shmdir.glob(f'*{fqme}*'): |
| 202 | + filename: str = shmfile.name |
| 203 | + |
| 204 | + # skip index files |
| 205 | + if ( |
| 206 | + '_first' in filename |
| 207 | + or '_last' in filename |
| 208 | + ): |
| 209 | + continue |
| 210 | + |
| 211 | + assert shmfile.is_file() |
| 212 | + log.debug(f'Found matching shm buffer file: {filename}') |
| 213 | + shmfiles.append(shmfile) |
| 214 | + |
| 215 | + for shmfile in shmfiles: |
| 216 | + |
| 217 | + # lookup array buffer size based on file suffix |
| 218 | + # being either .rt or .hist |
| 219 | + size: int = sizes[shmfile.name.rsplit('.')[-1]] |
| 220 | + |
| 221 | + # attach to any shm buffer, load array into polars df, |
| 222 | + # write to local parquet file. |
| 223 | + shm, opened = maybe_open_shm_array( |
| 224 | + key=shmfile.name, |
| 225 | + size=size, |
| 226 | + dtype=def_iohlcv_fields, |
| 227 | + readonly=True, |
| 228 | + ) |
| 229 | + assert not opened |
| 230 | + ohlcv = shm.array |
| 231 | + |
| 232 | + start = time.time() |
| 233 | + |
| 234 | + # XXX: thanks to this SO answer for this conversion tip: |
| 235 | + # https://stackoverflow.com/a/72054819 |
| 236 | + df = pl.DataFrame({ |
| 237 | + field_name: ohlcv[field_name] |
| 238 | + for field_name in ohlcv.dtype.fields |
| 239 | + }) |
| 240 | + delay: float = round( |
| 241 | + time.time() - start, |
| 242 | + ndigits=6, |
| 243 | + ) |
| 244 | + log.info( |
| 245 | + f'numpy -> polars conversion took {delay} secs\n' |
| 246 | + f'polars df: {df}' |
| 247 | + ) |
| 248 | + |
| 249 | + yield ( |
| 250 | + shmfile, |
| 251 | + shm, |
| 252 | + df, |
| 253 | + ) |
| 254 | + |
| 255 | + |
174 | 256 | @store.command() |
175 | | -def clone( |
| 257 | +def ldshm( |
176 | 258 | fqme: str, |
| 259 | + |
| 260 | + write_parquet: bool = False, |
| 261 | + |
177 | 262 | ) -> None: |
178 | | - import time |
179 | | - from piker.config import get_conf_dir |
180 | | - from piker.data import ( |
181 | | - maybe_open_shm_array, |
182 | | - def_iohlcv_fields, |
183 | | - ) |
184 | | - import polars as pl |
185 | | - |
186 | | - # TODO: actually look up an existing shm buf (set) from |
187 | | - # an fqme and file name parsing.. |
188 | | - # open existing shm buffer for kucoin backend |
189 | | - key: str = 'piker.brokerd[3595d316-3c15-46].xmrusdt.kucoin.hist' |
190 | | - shmpath: Path = Path('/dev/shm') / key |
191 | | - assert shmpath.is_file() |
| 263 | + ''' |
| 264 | + Linux ONLY: load any fqme file name matching shm buffer from |
| 265 | + /dev/shm/ into an OHLCV numpy array and polars DataFrame, |
| 266 | + optionally write to .parquet file. |
192 | 267 |
|
| 268 | + ''' |
193 | 269 | async def main(): |
194 | 270 | async with ( |
195 | 271 | open_piker_runtime( |
196 | 272 | 'polars_boi', |
197 | 273 | enable_modules=['piker.data._sharedmem'], |
198 | 274 | ), |
199 | 275 | ): |
200 | | - # attach to any shm buffer, load array into polars df, |
201 | | - # write to local parquet file. |
202 | | - shm, opened = maybe_open_shm_array( |
203 | | - key=key, |
204 | | - dtype=def_iohlcv_fields, |
205 | | - ) |
206 | | - assert not opened |
207 | | - ohlcv = shm.array |
208 | | - |
209 | | - start = time.time() |
210 | | - |
211 | | - # XXX: thanks to this SO answer for this conversion tip: |
212 | | - # https://stackoverflow.com/a/72054819 |
213 | | - df = pl.DataFrame({ |
214 | | - field_name: ohlcv[field_name] |
215 | | - for field_name in ohlcv.dtype.fields |
216 | | - }) |
217 | | - delay: float = round( |
218 | | - time.time() - start, |
219 | | - ndigits=6, |
220 | | - ) |
221 | | - print( |
222 | | - f'numpy -> polars conversion took {delay} secs\n' |
223 | | - f'polars df: {df}' |
224 | | - ) |
225 | 276 |
|
226 | | - # compute ohlc properties for naming |
227 | | - times: np.ndarray = ohlcv['time'] |
228 | | - secs: float = times[-1] - times[-2] |
229 | | - if secs < 1.: |
230 | | - breakpoint() |
231 | | - raise ValueError( |
232 | | - f'Something is wrong with time period for {shm}:\n{ohlcv}' |
233 | | - ) |
234 | | - |
235 | | - timeframe: str = f'{secs}s' |
236 | | - |
237 | | - # write to parquet file |
238 | | - datadir: Path = get_conf_dir() / 'parqdb' |
239 | | - if not datadir.is_dir(): |
240 | | - datadir.mkdir() |
241 | | - |
242 | | - path: Path = datadir / f'{fqme}.{timeframe}.parquet' |
243 | | - |
244 | | - # write to fs |
245 | | - start = time.time() |
246 | | - df.write_parquet(path) |
247 | | - delay: float = round( |
248 | | - time.time() - start, |
249 | | - ndigits=6, |
250 | | - ) |
251 | | - print( |
252 | | - f'parquet write took {delay} secs\n' |
253 | | - f'file path: {path}' |
254 | | - ) |
| 277 | + df: pl.DataFrame | None = None |
| 278 | + for shmfile, shm, df in iter_dfs_from_shms(fqme): |
255 | 279 |
|
256 | | - # read back from fs |
257 | | - start = time.time() |
258 | | - read_df: pl.DataFrame = pl.read_parquet(path) |
259 | | - delay: float = round( |
260 | | - time.time() - start, |
261 | | - ndigits=6, |
262 | | - ) |
263 | | - print( |
264 | | - f'parquet read took {delay} secs\n' |
265 | | - f'polars df: {read_df}' |
266 | | - ) |
| 280 | + # compute ohlc properties for naming |
| 281 | + times: np.ndarray = shm.array['time'] |
| 282 | + secs: float = times[-1] - times[-2] |
| 283 | + if secs < 1.: |
| 284 | + breakpoint() |
| 285 | + raise ValueError( |
| 286 | + f'Something is wrong with time period for {shm}:\n{times}' |
| 287 | + ) |
| 288 | + |
| 289 | + # TODO: maybe only optionally enter this depending |
| 290 | + # on some CLI flags and/or gap detection? |
| 291 | + await tractor.breakpoint() |
| 292 | + |
| 293 | + # write to parquet file? |
| 294 | + if write_parquet: |
| 295 | + timeframe: str = f'{secs}s' |
| 296 | + |
| 297 | + datadir: Path = get_conf_dir() / 'nativedb' |
| 298 | + if not datadir.is_dir(): |
| 299 | + datadir.mkdir() |
| 300 | + |
| 301 | + path: Path = datadir / f'{fqme}.{timeframe}.parquet' |
| 302 | + |
| 303 | + # write to fs |
| 304 | + start = time.time() |
| 305 | + df.write_parquet(path) |
| 306 | + delay: float = round( |
| 307 | + time.time() - start, |
| 308 | + ndigits=6, |
| 309 | + ) |
| 310 | + log.info( |
| 311 | + f'parquet write took {delay} secs\n' |
| 312 | + f'file path: {path}' |
| 313 | + ) |
| 314 | + |
| 315 | + # read back from fs |
| 316 | + start = time.time() |
| 317 | + read_df: pl.DataFrame = pl.read_parquet(path) |
| 318 | + delay: float = round( |
| 319 | + time.time() - start, |
| 320 | + ndigits=6, |
| 321 | + ) |
| 322 | + print( |
| 323 | + f'parquet read took {delay} secs\n' |
| 324 | + f'polars df: {read_df}' |
| 325 | + ) |
| 326 | + |
| 327 | + if df is None: |
| 328 | + log.error(f'No matching shm buffers for {fqme} ?') |
267 | 329 |
|
268 | 330 | trio.run(main) |
269 | 331 |
|
|
0 commit comments