feat: add alphaview tool to show alpha weights alongside bar data
Joins the bar dataset with one or more alpha parquet files on (symbol, date) for a given symbol and date range. Standalone tools/alphaview.py wired as `cli.py alphaview`, plus README docs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -179,6 +179,31 @@ ln -sf "$(pwd)/tools/pqcat.py" ~/.local/bin/pqcat # ~/.local/bin must be on PA
|
|||||||
pqcat alphas/reversal_5d.pq --info
|
pqcat alphas/reversal_5d.pq --info
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `alphaview` — alpha weight(s) alongside bar data for one symbol
|
||||||
|
|
||||||
|
Join the bar dataset and one or more alpha parquet files on `(symbol, date)` and
|
||||||
|
print them side by side, so you can eyeball how a weight moves against price /
|
||||||
|
volume over a time range.
|
||||||
|
|
||||||
|
| Option | Default | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `--data-path` | (required) | Bar dataset dir or parquet file |
|
||||||
|
| `--alpha-path` | (required) | Comma-separated alpha parquet path(s) — each `alpha_name` becomes a column |
|
||||||
|
| `--symbol` | (required) | Symbol id, e.g. `sh600000` |
|
||||||
|
| `--start-date` | — | `YYYY-MM-DD` (inclusive) |
|
||||||
|
| `--end-date` | — | `YYYY-MM-DD` (inclusive) |
|
||||||
|
| `-c, --columns` | `close,volume` | Comma-separated bar columns to show |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 cli.py alphaview \
|
||||||
|
--data-path data/daily_bars/csi500 \
|
||||||
|
--alpha-path alphas/reversal_5d.pq,alphas/momentum_5d.pq \
|
||||||
|
--symbol sh600000 --start-date 2024-01-01 --end-date 2024-03-31 \
|
||||||
|
-c close,volume,vwap
|
||||||
|
```
|
||||||
|
|
||||||
|
Also standalone like `pqcat` — `ln -sf "$(pwd)/tools/alphaview.py" ~/.local/bin/alphaview`.
|
||||||
|
|
||||||
## Alphas: the factory / plugin interface
|
## Alphas: the factory / plugin interface
|
||||||
|
|
||||||
An **alpha** is a class that maps a wide close matrix (date index × `symbol_id`
|
An **alpha** is a class that maps a wide close matrix (date index × `symbol_id`
|
||||||
@@ -272,6 +297,7 @@ directory yields an extra `month` (`YYYY-MM`) partition column on top of
|
|||||||
- `pipeline/common/schema.py` — parquet column contracts
|
- `pipeline/common/schema.py` — parquet column contracts
|
||||||
- `data/downloader.py`, `data/universe.py` — baostock/akshare download + constituents
|
- `data/downloader.py`, `data/universe.py` — baostock/akshare download + constituents
|
||||||
- `tools/pqcat.py` — standalone parquet inspector (`pqcat`), also wired as `cli.py pqcat`
|
- `tools/pqcat.py` — standalone parquet inspector (`pqcat`), also wired as `cli.py pqcat`
|
||||||
|
- `tools/alphaview.py` — standalone alpha-vs-bar viewer (`alphaview`), also wired as `cli.py alphaview`
|
||||||
- `examples/alphas/` — example external alpha(s)
|
- `examples/alphas/` — example external alpha(s)
|
||||||
|
|
||||||
## Roadmap (not yet implemented)
|
## Roadmap (not yet implemented)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from pipeline.data.cli import data
|
|||||||
from pipeline.alpha.cli import alpha
|
from pipeline.alpha.cli import alpha
|
||||||
from pipeline.combo.cli import combo
|
from pipeline.combo.cli import combo
|
||||||
from tools.pqcat import pqcat
|
from tools.pqcat import pqcat
|
||||||
|
from tools.alphaview import alphaview
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
@@ -39,6 +40,7 @@ cli.add_command(data)
|
|||||||
cli.add_command(alpha)
|
cli.add_command(alpha)
|
||||||
cli.add_command(combo)
|
cli.add_command(combo)
|
||||||
cli.add_command(pqcat)
|
cli.add_command(pqcat)
|
||||||
|
cli.add_command(alphaview)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Executable
+58
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Show alpha weight(s) alongside daily bar data for a single symbol.
|
||||||
|
|
||||||
|
Joins the bar dataset and one or more alpha parquet files on (symbol, date) so
|
||||||
|
you can eyeball how a weight moves against price/volume over a time range.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import click
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
|
def _filter_dates(df, start_date, end_date):
|
||||||
|
if start_date:
|
||||||
|
df = df[df["date"] >= pd.Timestamp(start_date)]
|
||||||
|
if end_date:
|
||||||
|
df = df[df["date"] <= pd.Timestamp(end_date)]
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
@click.command(name="alphaview")
|
||||||
|
@click.option("--data-path", required=True, type=click.Path(exists=True), help="Bar dataset dir or parquet file")
|
||||||
|
@click.option("--alpha-path", "alpha_paths", required=True, help="Comma-separated alpha parquet path(s)")
|
||||||
|
@click.option("--symbol", required=True, help="Symbol id, e.g. sh600000")
|
||||||
|
@click.option("--start-date", default=None, help="YYYY-MM-DD (inclusive)")
|
||||||
|
@click.option("--end-date", default=None, help="YYYY-MM-DD (inclusive)")
|
||||||
|
@click.option("-c", "--columns", default="close,volume", help="Comma-separated bar columns to show")
|
||||||
|
def alphaview(data_path, alpha_paths, symbol, start_date, end_date, columns):
|
||||||
|
"""Print bar columns + alpha weight(s) for SYMBOL over a date range."""
|
||||||
|
bar_cols = [c.strip() for c in columns.split(",") if c.strip()]
|
||||||
|
|
||||||
|
bars = pd.read_parquet(data_path)
|
||||||
|
bars = bars[bars["symbol_id"] == symbol]
|
||||||
|
if bars.empty:
|
||||||
|
raise click.ClickException(f"Symbol {symbol!r} not found in {data_path}")
|
||||||
|
missing = [c for c in bar_cols if c not in bars.columns]
|
||||||
|
if missing:
|
||||||
|
raise click.ClickException(f"Bar columns not found: {', '.join(missing)}")
|
||||||
|
bars = _filter_dates(bars, start_date, end_date)
|
||||||
|
out = bars[["date", *bar_cols]].set_index("date").sort_index()
|
||||||
|
|
||||||
|
for path in (p.strip() for p in alpha_paths.split(",") if p.strip()):
|
||||||
|
adf = pd.read_parquet(path)
|
||||||
|
adf = adf[adf["symbol_id"] == symbol]
|
||||||
|
adf = _filter_dates(adf, start_date, end_date)
|
||||||
|
# One alpha file may carry multiple alpha_name values; spread to columns.
|
||||||
|
wide = adf.pivot_table(index="date", columns="alpha_name", values="weight")
|
||||||
|
out = out.join(wide, how="left")
|
||||||
|
|
||||||
|
if out.empty:
|
||||||
|
raise click.ClickException("No rows in the requested date range")
|
||||||
|
|
||||||
|
with pd.option_context("display.max_rows", None, "display.max_columns", None, "display.width", None):
|
||||||
|
click.echo(f"symbol: {symbol} rows: {len(out):,}")
|
||||||
|
click.echo(out.to_string())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
alphaview()
|
||||||
Reference in New Issue
Block a user