# Data Access

Price series, OHLC columns, TBBO tick fields, composite prices, and time components.

<a id="close"></a>
## close

Closing price for each bar as a pandas Series.

The most commonly used price input and the default for most indicator calculations. Supports all standard pandas operations.

On TBBO files (when read from Python), `close` is the per-bar last mid-price after the WASM aggregator builds bars at the active timeframe.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import close

sma_20 = close.rolling(20).mean()
ema_12 = close.ewm(span=12, adjust=False).mean()
daily_return = close.pct_change()
```

### Output

```text
>>> close.head()
0    100.578931
1    100.436809
2    102.385924
3    105.363522
4    104.579579
dtype: float64
```

<a id="open"></a>
## open

Opening price for each bar as a pandas Series.

The opening price of each bar. Useful for gap analysis (comparing current `open` to previous `close`) and candlestick pattern detection.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import open, close
gap = open - close.shift(1)
```

<a id="high"></a>
## high

Highest price reached during each bar.

Used for channel indicators, range calculations, true range, and resistance level detection.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import high, low
bar_range = high - low
highest_20 = high.rolling(20).max()
```

<a id="low"></a>
## low

Lowest price reached during each bar.

Used alongside `high` for volatility measures, channel indicators, and support level detection.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import high, low
lowest_20 = low.rolling(20).min()
```

<a id="column-resolvers-volume_series-delta_series-vwap_series-df_col_or"></a>
## Column resolvers (volume_series / delta_series / vwap_series / df_col_or)

Helpers that resolve volume / delta / VWAP across different parquet shapes via priority chains.

Different parquets ship different columns. Native OHLC files often carry `volume` / `delta` / `vwap`; TBBO-aggregated bars carry `bid_vol` / `ask_vol` / `tickCount`; some older files only have `tickCount`. Hard-coding column names breaks portability across data files. The four helpers below resolve a single concept (the volume signal, the signed delta signal, etc.) with an explicit fallback chain so your indicator/strategy works on every parquet shape:

- [`volume_series(df)`](https://quantchartsllc.com/docs/python/py-column-resolvers.md#volume_series) -> `volume` -> `bid_vol+ask_vol` -> `tickCount` -> zeros
- [`delta_series(df)`](https://quantchartsllc.com/docs/python/py-column-resolvers.md#delta_series) -> `delta` -> `ask_vol-bid_vol` -> `sign(close-open)` -> zeros
- [`vwap_series(df)`](https://quantchartsllc.com/docs/python/py-column-resolvers.md#vwap_series) -> precomputed `vwap` column -> session-cumulative typical price * `volume_series(df)`
- [`df_col_or(df, "name1", "name2", default=None)`](https://quantchartsllc.com/docs/python/py-column-resolvers.md#df_col_or) -> first column that exists, or the default

All resolvers return numpy arrays of length `len(df)` (or `default` for `df_col_or`). NaN entries are coerced to 0 inside `volume_series` and `delta_series` so cumulative sums stay finite.

Declare `required_columns=[...]` only for columns your math truly needs (typically `high`/`low`/`close`); leave optional columns out and read them via the resolvers so the validator does not reject parquets that lack the optional columns.

### Returns

numpy.ndarray of float64

### Example

```python
from quant_charts import indicator, plot, volume_series, delta_series, vwap_series, cvd, df_col_or

@indicator(name="Order-Flow Light", overlay=False, required_columns=["close"])
class OrderFlowLight:
    def calculate(self, df):
        vol = volume_series(df)        # works on any parquet shape
        cvd_arr = cvd(delta_series(df))
        vwap = vwap_series(df)         # uses precomputed column or builds session VWAP
        custom = df_col_or(df, "trade_size", "tickCount", default=vol)
        plot(cvd_arr, "CVD", color="#7AA2F7")
```

<a id="volume"></a>
## volume

Trading volume for each bar.

Total traded volume within each bar. May be zero if volume data is unavailable. Used for VWAP, volume analysis, and liquidity filtering.

On TBBO data (Python execution path) this is the per-bar sum of trade volume aggregated by `scripts/strategy_executor.py`.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import close, volume
vwap = (close * volume).cumsum() / volume.cumsum()
```

### Output

```text
>>> volume.head()
0    18702.0
1    10384.0
2    10404.0
3    50943.0
4    57926.0
dtype: float64
```

<a id="delta"></a>
## delta

Per-bar signed volume delta (buyer minus seller).

Positive when buyers lift the offer, negative when sellers hit the bid. Pair with the [`cvd()`](https://quantchartsllc.com/docs/python/py-signals.md#cvd) helper for cumulative volume delta.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import delta, cvd
cumdelta = cvd(delta)
```

<a id="vwap"></a>
## vwap

Session volume-weighted average price.

Available where the parquet provides it (or computed from volume + close otherwise). Pair with [`vwap_band(vwap, atr, mult)`](https://quantchartsllc.com/docs/python/py-signals.md#vwap_band) for mean-reversion envelopes.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import vwap, ta, high, low, close, vwap_band
atr = ta.atr(high, low, close, 14)
upper, lower = vwap_band(vwap, atr, mult=1.5)
```

<a id="bid_vol-ask_vol"></a>
## bid_vol / ask_vol

Per-bar sum of bid_size / ask_size on TBBO bars.

Aggregated by `scripts/strategy_executor.py` from raw tick `bid_size`/`ask_size`. Pair with [`imbalance(bid_vol, ask_vol)`](https://quantchartsllc.com/docs/python/py-signals.md#imbalance) for an order-book pressure ratio.

Note: the WASM chart aggregator only emits 6 fields per bar; bid_vol/ask_vol live on the strategy-execution DataFrame, not the chart bar.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import bid_vol, ask_vol, imbalance
imb = imbalance(bid_vol, ask_vol)
buy_pressure = imb > 0.6
```

<a id="bid_price-ask_price-mid_price"></a>
## bid_price / ask_price / mid_price

TBBO best bid/ask/mid prices per bar.

Available on TBBO files; fall back to `close` on OHLC-only sources so cross-mode code stays symmetric.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import bid_price, ask_price, mid_price
spread_pct = (ask_price - bid_price) / mid_price * 100
```

<a id="bid_size-ask_size"></a>
## bid_size / ask_size

TBBO per-tick resting size at best bid / ask.

Tick-mode quantity. Fall back to `bid_vol` / `ask_vol` on OHLC-aggregated TBBO bars so `imbalance(bid_size, ask_size)` works at any execution timeframe.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import bid_size, ask_size, imbalance
imb = imbalance(bid_size, ask_size)
```

<a id="hl2"></a>
## hl2

Median price: (high + low) / 2

Midpoint of `high` and `low`. Less noisy than `close` alone and often used as a smoothed input for oscillators and moving averages.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import hl2
smoothed = hl2.rolling(14).mean()
```

### Notes

- Formula: `(high + low) / 2`

<a id="hlc3"></a>
## hlc3

Typical price: (high + low + close) / 3

Incorporates `close` for more weight toward the final traded price. Commonly used in VWAP-like calculations.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import hlc3
typical = hlc3.rolling(20).mean()
```

### Notes

- Formula: `(high + low + close) / 3`

<a id="ohlc4"></a>
## ohlc4

Average price: (open + high + low + close) / 4

The most balanced representation of each bar's price action, weighting all four components equally.

### Returns

pandas Series of float64

### Example

```python
from quant_charts import ohlc4
balanced = ohlc4.ewm(span=20).mean()
```

### Notes

- Formula: `(open + high + low + close) / 4`

<a id="tbbo-vs-ohlc"></a>
## TBBO vs OHLC

Two source-data types. Python only runs on OHLC bars; tick-level TBBO uses Rust.

Quant Charts ingests two parquet shapes:

- **OHLC files** (e.g. `MNQ_OHLC.parquet`): pre-aggregated bars with open/high/low/close/volume and optional delta/vwap. Python strategies and indicators run directly on these.
- **TBBO files** (e.g. `TBBO_Converted.parquet`): tick-level bid/ask/bid_size/ask_size/volume/delta. Python execution uses an in-memory aggregator (`scripts/strategy_executor.py`) to produce OHLC bars at the active timeframe before calling `calculate(self, df)`. Tick-level access (per-tick bid/ask/microprice) is **only** available in Rust.

If you need per-tick decisions (microprice, spread compression, large-trade detection at tick granularity), write a Rust .rs file and use the [`#[strategy]`](https://quantchartsllc.com/docs/rust/rust-strategy.md#strategy) or [`#[indicator]`](https://quantchartsllc.com/docs/rust/rust-indicator.md#indicator) macro.

### Example

```python
# Python (OHLC bar path):
@indicator("VWAP Bands", overlay=True, data_mode='ohlc')
class VwapBands:
    def calculate(self, df):
        plot(df['vwap'], "VWAP")

# Rust (TBBO tick path):
#[indicator(name = "Spread Heatmap", overlay = false)]
pub struct SpreadHeatmap { /* ... */ }
```

### Notes

- Python `data_mode` accepts `'ohlc'` only. Tick mode for Python was removed.
- TBBO files still render in the chart via the WASM aggregator (6 fields per bar).
- On TBBO data, Python strategies see `bid_vol`/`ask_vol` columns produced by the bar aggregator.

<a id="price"></a>
## price

```python
price(source?)
```

Get the active price series for the chart.

Returns the appropriate price Series for OHLC bars. Pass `"open"`, `"high"`, `"low"`, `"close"`, `"hl2"`, `"hlc3"`, or `"ohlc4"` to pick a specific source.

### Parameters

- `source` (`str`, default `"close"`): OHLC source name

### Returns

pandas Series

### Example

```python
src = price()           # close by default
mid = price("hl2")      # explicit hl2
```

<a id="is_ohlc_mode"></a>
## is_ohlc_mode

```python
is_ohlc_mode()
```

Returns `True` if the chart is showing OHLC candles.

### Returns

bool

### Example

```python
if is_ohlc_mode():
    true_range = high - low
```

<a id="is_tick_mode"></a>
## is_tick_mode

```python
is_tick_mode()
```

Returns `True` if the chart is showing tick data (TBBO files in tick view).

Python strategies always receive aggregated bars, but indicators that render directly on a tick-mode chart can branch on this. For tick-level computation use a Rust indicator.

### Returns

bool

### Example

```python
if is_tick_mode():
    spread = price("ask") - price("bid")
```

<a id="is_native_ohlc"></a>
## is_native_ohlc

```python
is_native_ohlc()
```

Returns `True` if the source is native OHLC (real intra-bar variation).

Distinguishes native OHLC files (real open/high/low/close) from tick-derived OHLC (O=H=L=C=mid_price). Use this to gate calculations that need true range.

### Returns

bool

### Example

```python
if is_native_ohlc():
    tr = high - low
else:
    tr = price().rolling(2).apply(lambda x: abs(x[1] - x[0]))
```

<a id="get_source_data_type"></a>
## get_source_data_type

```python
get_source_data_type()
```

Returns "TBBO", "OHLC", or None.

### Returns

Optional[str]

### Example

```python
kind = get_source_data_type()
if kind == "TBBO":
    log("running on tick-derived bars")
```

<a id="on_tick"></a>
## on_tick

```python
on_tick(func)
```

Decorator: wrapped function only runs in tick mode.

Returns the decorated function unchanged but short-circuits to None when the chart is in OHLC mode. Use to keep tick-only logic out of OHLC code paths without an explicit `if`.

### Returns

callable

### Example

```python
from quant_charts import on_tick

@on_tick
def microprice_drift():
    return (ask_price + bid_price) * 0.5

drift = microprice_drift()  # None in OHLC mode
```

<a id="on_ohlc"></a>
## on_ohlc

```python
on_ohlc(func)
```

Decorator: wrapped function only runs in OHLC mode.

### Returns

callable

### Example

```python
@on_ohlc
def true_range():
    return (high - low).rolling(14).mean()
```

<a id="either"></a>
## either

```python
either(tick_func, ohlc_func)
```

Run `tick_func()` in tick mode, `ohlc_func()` in OHLC mode.

Convenience for two-implementation indicators where the tick path differs structurally from the OHLC path.

### Returns

Any

### Example

```python
from quant_charts import either

result = either(
    lambda: (ask_price - bid_price).rolling(20).mean(),
    lambda: (high - low).rolling(20).mean(),
)
```

<a id="hour"></a>
## hour

Hour of day (0-23) in US/Eastern time.

Lazy proxy that extracts the hour from each bar's timestamp. Works like a numpy array in comparisons.

**Important**: Futures sessions cross midnight. A "Monday" session starts Sunday 6pm ET.

### Returns

TimeSeries (int)

### Example

```python
from quant_charts import hour, minute

rth = (hour >= 9) & (hour < 16)
asian = (hour >= 19) | (hour < 1)
market_open = (hour == 9) & (minute == 30)
```

<a id="minute"></a>
## minute

Minute of hour (0-59).

Lazy proxy that extracts the minute from each bar's timestamp. Converted to US/Eastern time.

### Returns

TimeSeries (int)

### Example

```python
from quant_charts import hour, minute

first_half = minute < 30
market_open = (hour == 9) & (minute == 30)
```

<a id="second"></a>
## second

Second of minute (0-59). Useful for tick-level timing.

Lazy proxy, converted to US/Eastern time.

### Returns

TimeSeries (int)

### Example

```python
from quant_charts import second
on_the_minute = second == 0
```

<a id="day_of_week"></a>
## day_of_week

Day of week (0=Monday, 6=Sunday).

US/Eastern time. Remember: futures Sunday session = day_of_week == 6.

### Returns

TimeSeries (int)

### Example

```python
from quant_charts import day_of_week

is_monday = day_of_week == 0
is_friday = day_of_week == 4
weekday = day_of_week < 5
```
