Metadata-Version: 2.1
Name: chartpipe
Version: 0.1.2
Summary: Chart visualization toolkit for quantitative trading analysis
Home-page: https://github.com/yourusername/chartpipe
Author: Your Name
Author-email: your.email@example.com
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: pandas>=2.0.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: click>=8.0.0
Requires-Dist: matplotlib>=3.7.0
Requires-Dist: mplfinance>=0.12.10b0
Requires-Dist: seaborn>=0.12.0

# ChartPipe

A professional chart visualization toolkit for quantitative trading analysis. Seamlessly integrates with seamflux CLI and quantpipe via Unix pipes.

**Pipeline contract** (CLI flags, JSON envelope, exit codes, `runs/<runId>/` layout) is defined in the repo root [`rule.md`](../rule.md). ChartPipe uses **`schemaVersion`: 1** on stdout when `--json` is set.

## Features overview

| Area | What ChartPipe does |
|------|---------------------|
| **OHLCV** | Candlestick charts with optional moving averages and volume (mplfinance) |
| **Indicators** | RSI, MACD, Bollinger Bands (single or `--indicator all`) |
| **Backtest** | Equity curve, drawdown, trade markers from JSON or `runs/<id>/` CSVs |
| **Stats** | Returns distribution, price distribution, monthly returns heatmap |
| **Volatility** | Historical vol, rolling vol, volatility cone |
| **Compare** | Multi-asset price overlay, correlation matrix, relative strength vs benchmark |
| **Volume** | VWAP with bands, volume profile, on-balance volume (OBV) |
| **Drawdown** | Underwater curve, recovery-time distribution, top-N drawdowns on price |
| **Calendar** | Returns by weekday, month, or intraday hour |
| **Regime** | Trend (ADX), volatility regime, MA-cross bull/bear |
| **Themes** | Dark and light |
| **Pipelines** | `--json` single-line envelope; optional `--dry-run`; global or per-command `-o` / `--json` / `--dry-run` |
| **Input** | Auto-detects Binance-style klines, wrapped JSON (`data`, `result`, `ohlcv`, `candles`), Polymarket-style price history, generic OHLCV |

## Installation

### From source (development)

```bash
cd chartpipe
pip install -e .
```

### Using requirements.txt

```bash
pip install -r requirements.txt
```

## Quick start

### Integration with seamflux

```bash
# OHLCV candlestick
seamflux invoke binance fetchOhlcv --pipe -p symbol=BTC/USDT -p interval=1h -p limit=200 | chartpipe ohlcv --stdin

# RSI
seamflux invoke binance fetchOhlcv --pipe -p symbol=BTC/USDT -p interval=1h -p limit=200 | chartpipe indicators --indicator rsi --stdin

# Returns distribution
seamflux invoke binance fetchOhlcv --pipe -p symbol=BTC/USDT -p interval=1h -p limit=500 | chartpipe stats --type returns --stdin

# JSON output (one line on stdout; parse with jq)
seamflux invoke binance fetchOhlcv --pipe -p symbol=BTC/USDT -p interval=1h -p limit=200 | chartpipe ohlcv --stdin --json
```

### Integration with quantpipe

```bash
# Recommended (rule.md): quantpipe writes equity.csv / trades.csv under runs/<id>/
quantpipe backtest --data btc_history.json --strategy ma_cross --run-dir runs/my-run --json
chartpipe backtest --run-dir runs/my-run --json

# Stdin: quantpipe JSON line that includes artifacts.equity (paths from --run-dir/--run-id)
quantpipe backtest --data btc_history.json --strategy ma_cross --run-dir runs/my-run --json | chartpipe backtest --stdin --json
```

**Note:** quantpipe `--json` without `--run-dir` / `--run-id` does not emit `equity.csv`; chartpipe `backtest --stdin` then fails with a clear error—use `--run-dir` on quantpipe or `chartpipe backtest --run-dir`.

## Global CLI

### Options (group level)

| Option | Description |
|--------|-------------|
| `--version` | Show version and exit |
| `--json` | Machine-readable JSON envelope on stdout (single line); debug on stderr |
| `-o, --output-dir PATH` | Directory for charts (default: `./charts`). Works as `chartpipe -o DIR <cmd>` or `chartpipe <cmd> -o DIR`. |
| `-v, --verbose` | Debug logs on stderr |
| `--dry-run` | Validate input only; do not write chart files |

Most subcommands also accept their own `--json`, `--dry-run`, and `-o`. **`--json` and `--dry-run` are enabled if either the global or the subcommand flag is set** (logical OR). **`-o` on the subcommand wins** when provided; otherwise the global `--output-dir` applies.

### Exit codes

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | General failure (I/O, plot error, bad args) |
| 2 | Input / schema mismatch |
| 3 | Missing optional dependency (e.g. mplfinance for OHLCV) |

Run `chartpipe --help` for the full epilog.

### Headless rendering

[`charts.py`](src/chartpipe/core/charts.py) sets matplotlib to the **Agg** backend by default so charts run without a display. You may set `MPLBACKEND=Agg` in the environment if needed.

## Commands (complete reference)

Common input pattern for OHLCV-based commands:

- `--data PATH` / `-d` or `--input` (alias): JSON file
- `--stdin`: read JSON from stdin
- If neither file nor `--stdin` is given, stdin is still read when used in a pipe (same as `--stdin` behavior in implementations that treat “no path” as stdin)

### `chartpipe ohlcv` — candlestick charts

Professional OHLCV charts with optional moving averages and volume.

| Option | Description |
|--------|-------------|
| `--data PATH`, `-d` | OHLCV JSON file |
| `--input PATH` | Alias for `--data` |
| `--stdin` | Read from stdin |
| `--title`, `-t` | Title (default: `Price Chart`) |
| `--volume` / `--no-volume` | Volume subplot (default: on) |
| `--ma INT` | Moving average period (repeatable; default periods: 20, 50) |
| `--theme` | `dark` or `light` |
| `-o`, `--output-dir` | Output directory (overrides global) |
| `--json` | JSON line on stdout |
| `--dry-run` | Validate only |

```bash
chartpipe ohlcv --data ohlcv.json --title "BTC/USDT" --ma 20 --ma 50 --volume
seamflux invoke binance fetchOhlcv --pipe ... | chartpipe ohlcv --stdin --theme dark
```

### `chartpipe indicators` — RSI, MACD, Bollinger Bands

| Option | Description |
|--------|-------------|
| `--indicator`, `-i` | `rsi`, `macd`, `bb`, or `all` |
| `--period`, `-p` | RSI period (default: 14) |
| `--data`, `--input`, `--stdin` | Same as ohlcv |
| `--title`, `-t` | Title |
| `--theme` | `dark` / `light` |
| `-o`, `--output-dir`, `--json`, `--dry-run` | As above |

`--indicator all` produces three charts; JSON `artifacts` uses keys `rsi`, `macd`, `bb`.

### `chartpipe backtest` — equity, drawdown, trades

Sources:

- **`--run-dir`**: `equity.csv`, optional `trades.csv`, optional `summary.json` (quantpipe layout)
- **`--data` / `--stdin`**: JSON envelope or legacy backtest JSON (parsed by [`backtest_input.py`](src/chartpipe/core/backtest_input.py))

| Option | Description |
|--------|-------------|
| `--run-dir PATH` | Load CSVs from a run directory |
| `--data`, `--input`, `--stdin` | JSON file or stdin |
| `--title`, `-t` | Override title (else from `summary.json` or default) |
| `--theme` | `dark` / `light` |
| `-o`, `--output-dir`, `--json`, `--dry-run` | As above |

Requires a valid **equity** series (`equity` column after load).

### `chartpipe stats` — statistical charts

| Option | Description |
|--------|-------------|
| `--type` | `returns`, `distribution`, `monthly`, or `all` |
| `--data`, `--input`, `--stdin` | OHLCV JSON |
| `--title`, `-t`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

`--type all` → artifact keys `returns`, `distribution`, `monthly`.

### `chartpipe volatility` — volatility analysis

| Option | Description |
|--------|-------------|
| `--type` | `history`, `rolling`, `cone`, or `all` |
| `--window`, `-w` | Rolling window (default: 20) |
| `--annualize`, `-a` | Annualization factor (default: 252, daily) |
| `--data`, `--input`, `--stdin` | OHLCV JSON (needs `close`) |
| `--title`, `-t`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

`--type all` → artifact keys `history`, `rolling`, `cone`.

### `chartpipe compare` — multi-asset comparison

**Input formats:**

- Object whose values are OHLCV lists: `{"BTCUSDT": [...], "ETHUSDT": [...]}`
- Or `{"data": { "SYM": [...], ... } }`
- Single-asset list or dict is treated as one series (symbol `unknown` or `symbol` field if present)

| Option | Description |
|--------|-------------|
| `--type` | `price`, `correlation`, `rs`, or `all` |
| `--benchmark`, `-b` | Benchmark symbol for relative strength (for `rs`, defaults to first asset if omitted) |
| `--normalize`, `-n` | Normalize series to start at 100 (price charts) |
| `--data`, `--input`, `--stdin` | Multi-asset or single-asset JSON |
| `--title`, `-t`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

**Rules:** `correlation` and `all` require **at least two assets**. For `--type all`, correlation is included only if ≥2 assets; `rs` only if `--benchmark` is in the asset set (or defaulted and present).

### `chartpipe volume` — VWAP, profile, OBV

| Option | Description |
|--------|-------------|
| `--type` | `vwap`, `profile`, `obv`, or `all` |
| `--bands`, `-b` | VWAP standard-deviation bands count (default: 3) |
| `--session`, `-s` | `daily`, `weekly`, or `none` — session reset for VWAP |
| `--data`, `--input`, `--stdin` | OHLCV JSON |
| `--title`, `-t`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

**Columns:** `close` and `volume` always; `high` and `low` also required for `vwap` and `profile`.

### `chartpipe drawdown` — drawdown analytics

| Option | Description |
|--------|-------------|
| `--type` | `underwater`, `recovery`, `top`, or `all` |
| `--top`, `-t` | Number of top drawdowns for `top` type (default: 5) |
| `--from-equity` | Input is already an equity curve (use `equity` or `close` column) |
| `--data`, `--input`, `--stdin` | OHLCV (default) or equity series with `--from-equity` |
| `--title`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

Without `--from-equity`, equity is synthesized from `close` returns (cumulative, starting at 100).

### `chartpipe calendar` — calendar effects

| Option | Description |
|--------|-------------|
| `--type` | `weekday`, `month`, `intraday`, or `all` |
| `--agg` | `mean`, `sum`, or `median` — aggregation for returns |
| `--data`, `--input`, `--stdin` | OHLCV with parseable datetime index |
| `--title`, `-t`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

**Note:** Data must normalize to a **datetime index** after timestamp parsing. For `--type all`, `intraday` is included only if the index has hour components and there are more than 24 rows.

### `chartpipe regime` — market regime

| Option | Description |
|--------|-------------|
| `--type` | `trend`, `volatility`, `ma-cross`, or `all` |
| `--period`, `-p` | Period for ADX / related (default: 14) |
| `--fast` / `--slow` | Fast/slow MA for `ma-cross` (default: 20 / 50) |
| `--data`, `--input`, `--stdin` | OHLCV JSON |
| `--title`, `-t`, `--theme`, `-o`, `--json`, `--dry-run` | As above |

**Columns:** `close` always; `high` and `low` required for `trend` and `ma-cross`.

**Semantics:** `trend` — ADX-style trend strength; `volatility` — high/low vol classification; `ma-cross` — bull/bear from MA crossovers.

## Data formats

ChartPipe accepts **JSON** parsed from a string, file, or stdin. [`parse_input_text`](src/chartpipe/core/input_data.py) loads JSON; nested shapes are unwrapped by [`json_payload_to_dataframe`](src/chartpipe/core/input_data.py).

### Wrapper objects (single series)

If the root is a dict, the table rows may come from:

| Key | Use |
|-----|-----|
| `data` | `pd.DataFrame(data["data"])` |
| `result` | Recurse into `result` (also used by `unwrap_upstream_json` in pipeline code) |
| `ohlcv` | `pd.DataFrame(data["ohlcv"])` |
| `candles` | Binance-style **array rows** (first six columns → timestamp, open, high, low, close, volume) |
| `history` | Polymarket-style list of points (e.g. `{t, p}`) → DataFrame |

### Standard OHLCV list

```json
[
  {"timestamp": "2024-01-01", "open": 42000, "high": 43000, "low": 41000, "close": 42500, "volume": 1000}
]
```

### Binance-style objects

```json
[
  {"t": 1704067200000, "o": "42000.00", "h": "43000.00", "l": "41000.00", "c": "42500.00", "v": "1000.00"}
]
```

Epoch **milliseconds** in `t` / `T` are detected and converted appropriately for plotting.

### Polymarket-style price history

Rows with **`p` / `P` (price)** and no full OHLCV: ChartPipe **synthesizes** `open`/`high`/`low`/`close` from price and sets `volume` to 0 if missing.

### Multi-asset JSON (`compare`)

```json
{
  "BTCUSDT": [{"timestamp": "...", "close": 42000, "open": 41900, "high": 42100, "low": 41800, "volume": 100}],
  "ETHUSDT": [{"timestamp": "...", "close": 2800, "open": 2790, "high": 2810, "low": 2780, "volume": 200}]
}
```

### Backtest JSON (file/stdin)

Legacy or quantpipe-style payloads with equity curve and optional trades—see [`backtest_input.py`](src/chartpipe/core/backtest_input.py). Run directory layout is preferred for quantpipe (`equity.csv`, `trades.csv`, `summary.json`).

### Column name mapping (excerpt)

| Canonical | Aliases |
|-----------|---------|
| `timestamp` | `t`, `T`, `time`, `Time` |
| `open` | `o`, `O`, `Open` |
| `high` | `h`, `H`, `High` |
| `low` | `l`, `L`, `Low` |
| `close` | `c`, `C`, `Close` |
| `volume` | `v`, `V`, `vol`, `Volume` |
| `price` (Polymarket) | `p`, `P` → synthesized OHLCV |

## Output

### Human-readable

```
Chart saved: /path/to/charts/ohlcv_20260317_130405.png
```

### JSON (`--json`)

- **One JSON object per invocation** on stdout (single line by default).
- Success: `schemaVersion`, `tool`, `command`, `ok: true`, optional `artifacts`, `meta` (`startedAt`, `finishedAt`; `dryRun: true` when applicable), optional `data` (dry-run diagnostics).
- Chart paths in `artifacts` are **relative to cwd** unless absolute.
- Single-chart commands use `artifacts.chart` unless noted above (`indicators all`, `stats all`, etc. use multiple keys).
- Failure: `ok: false`, `error: { "code", "message" }` (e.g. `INVALID_INPUT`, `MISSING_FILE`, `MISSING_DEPENDENCY`, `PLOT_ERROR`).

**Migration:** older releases used `{"img": "..."}`; prefer `artifacts.chart` or the multi-key maps for `all` modes.

### Upstream JSON unwrap

If stdin/file is a seamflux-style `{"result": { ... }}`, inner `result` may be unwrapped for pipeline compatibility ([`unwrap_upstream_json`](src/chartpipe/core/pipeline_json.py)).

## Package layout

```
chartpipe/
├── src/chartpipe/
│   ├── cli.py
│   ├── cli_exit.py
│   ├── core/
│   │   ├── backtest_input.py
│   │   ├── charts.py
│   │   ├── input_data.py
│   │   ├── pipeline_json.py
│   │   └── styles.py
│   └── commands/
│       ├── ohlcv.py
│       ├── indicators.py
│       ├── backtest.py
│       ├── stats.py
│       ├── volatility.py
│       ├── compare.py
│       ├── volume.py
│       ├── drawdown.py
│       ├── calendar.py
│       └── regime.py
├── tests/
├── requirements.txt
├── requirements-dev.txt
├── pytest.ini
├── setup.py
└── README.md
```

## Tests

```bash
pip install -r requirements-dev.txt
pytest
```

## Requirements

- Python >= 3.10
- pandas >= 2.0.0
- numpy >= 1.24.0
- matplotlib >= 3.7.0
- mplfinance >= 0.12.10b0
- seaborn >= 0.12.0
- click >= 8.0.0

## License

MIT License

## Contributing

Contributions are welcome. Please open a Pull Request.

## Changelog

### Current (0.1.0+)

- Subcommands: `ohlcv`, `indicators`, `backtest`, `stats`, `volatility`, `compare`, `volume`, `drawdown`, `calendar`, `regime`
- Pipeline JSON, exit codes, dry-run, global/per-command output and JSON flags
- Input normalization: Binance klines, wrappers, Polymarket price history, multi-asset compare

### v0.1.0

- Initial release: OHLCV, indicators, backtest, stats, themes, JSON output
