Metadata-Version: 2.4
Name: wos-rfq
Version: 0.4.3
Summary: The Wolverine tick-quote add-on client: read, convert, import, check and remove tick quotes over the add-on's storage master and upload web.
Author: Wolverine
License-Expression: Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: wos-py>=0.0.8
Dynamic: license-file

# wos-rfq

The client of the Wolverine tick-quote add-on. The add-on stores
`private::RealFutureQuote` at granularity 0, one row per tick, under the
DATED contract code. This package is pure Python and works from any host with
Python 3.9 or newer — and inside the Wolverine ring images, on the image's own
binding.

```
pip install wos-rfq          # also installs wos-py (the native pycaitlyn binding) >= 0.0.8
wos-rfq --help
```

## Endpoints

The add-on has no login. The client talks to two endpoints:

- **The storage master**, raw TCP — the binary protocol, the default and fast
  route for reads. Pass `--master HOST:PORT`, or set `WOS_RFQ_MASTER`.
- **The add-on's web.** Pass `--web http://HOST:PORT`, or set `WOS_RFQ_WEB`.
  It carries the upload API and a JSON read API (`/rfq/api/structs`, `/ticks`,
  `/bars`, `/main`) for inspection and debugging. Reads use it only when asked:
  `--via web` (`--via master` is the default; `--via auto` = web when it answers). JSON is much slower than the binary route; no binding is needed
  for it.

## Commands

| Command | What it does |
|---|---|
| `structs` | Lists the storage master's catalog. |
| `read` | Reads stored ticks. `--bars N` folds them into N-second bars by the ring sampler's rules (below); the sections come from the ring's market metadata (`--sessions-from-master HOST:PORT`, a master serving `global::Market/Commodity/Holiday`), or `--manual-trade-period` + `--manual-time-zone` as a marked debugging override. |
| `sessions` | Prints a commodity's trade-day sections (China time) from the ring's singularity (`--sessions-from-master` / `--sessions-from-web`, or the manual override); `--format json` prints the full document. |
| `main` | The trade day's main (dated) contract of a commodity, as the add-on knows it: the futures metadata mapping when a meta upstream answers it, else the dated code holding the most ticks that day; lists every code holding ticks that day. |
| `sniff` | Inspects a foreign tick file set and suggests a mapping. |
| `convert` | Converts a file set to the canonical upload zip and writes a summary. |
| `mapping-help` | Prints the mapping reference. |
| `upload` | Uploads a converted zip. |
| `list` | Lists the uploads. |
| `status` | Gives the true outcome of one upload. |
| `artifact` | Shows an upload's processing log. |
| `delete-upload` | Removes an upload record. |
| `check` | Compares the stored ticks with the converted rows. |
| `remove` | Deletes the stored ticks in a time window (storage master only). |

The same features are available from Python as `wos_rfq.master`,
`wos_rfq.reads`, `wos_rfq.ticks`, `wos_rfq.convert` and `wos_rfq.web`
(`ReadWeb` is the JSON read client).

## Bars — the sampler's rules

`wos_rfq.ticks.fold` (and `read --bars`, `read_bars`, the web's `/bars`)
builds by default the bars the ring's own sampler stores for the contract
(`global::SampleQuote`), traded minute for traded minute:

1. **OHLC from traded ticks only** — a tick whose cumulative volume advanced
   over the previous tick of its trade day. A tick that only moved the book
   adds no price; it is still counted in `ticks` and kept in the vectors
   (`tick_time_tags`, `prices`, `tick_volumes`, `bid1`, `ask1`, …). `traded`
   counts the traded ticks of the bar.
2. **The pre-open auction** (a tick before the trade day's first section)
   belongs to the **first** bar, its volume included.
3. **A tick between two sections, or after the close**, belongs to the
   **last bar of the preceding section** — never forward.
4. **No trade, no bar** — the sampler stores no bar for a slot in which nothing
   traded. `quiet_bars=True` (`--quiet-bars`, `/bars?quiet_bars=1`) returns a
   dense grid instead: those slots too, `traded` 0, prices empty.

`volume`/`turnover` are sums of per-tick deltas of the cumulative fields over
every tick of the bar. `outside="drop"` (a tick outside every section is in no
bar) and `outside="next"` (to the first bar of the following section) remain
as explicit choices; rules 1 and 4 apply in every mode. Bar bounds are the
binding's `tradeday_sections` / `sampler_tm_bound` on the singularity's rows.

**A day the singularity has no row for** fails with one stable prefix,
`no singularity sections for <market> <commodity> on <day>:`, followed by the
case, read from the same master: `holiday/weekend`, `a gap on the global ring
(the neighbours <d1>, <d2> answer; use their sections as the manual override …)`
or `a day not yet reached`.

## Bindings

The storage-master route needs a `pycaitlyn` binding; it is imported at the
first connect, not at `import wos_rfq`:

- **the `wos-py` wheel** (>= 0.0.8) — the declared dependency, for every pip user;
- **a ring image's own binding** — the SWIG build the ring's workers import.
  `wos_rfq` detects it by its surface and does the raw ring frames, the delete
  body and the error body in pure Python.

`wos_rfq.binding()` says which one is in use. Without either, `import wos_rfq`
and the JSON read route still work; a storage-master call stops with one line
naming what is missing (exit 1 from the command).

**Inside a ring image install with `--no-deps`:**

```
pip install --no-deps wos-rfq
```

The image already has its binding; installing the `wos-py` dependency there
would put a second `pycaitlyn` in the venv and, for any process that does not
put the image's directory first, shadow the one the ring's workers depend on.
The ring images built by the regular pipeline ship this package that way.
