xQuant is a local, single-user quantitative research application for historical stock data. It combines iTick REST ingestion, durable DuckDB storage, pandas/NumPy and QuantLib analytics, Plotly charts, Streamlit workflows, and JupyterLab research.
Current development release: v0.2. Its versioned product definition is in
design/v0.2/; design/v0.1/ remains the immutable
first-release baseline.
xQuant requires Python 3.14 and installs its Python dependencies from
pyproject.toml:
- duckdb — durable local market-data storage and SQL analytics.
- httpx[socks] — iTick REST requests, including optional SOCKS proxy support.
- pandas, numpy, PyArrow, and pytz — tabular analytics, numerical calculations, CSV/Parquet reference data, and time-zone support.
- QuantLib — pricing, calendars, curves, and risk analytics.
- Streamlit — local application interface.
- Plotly and Kaleido — interactive financial charts and figure export.
- Pydantic, pydantic-settings, and PyYAML — models and configuration.
- JupyterLab and ipykernel — notebook-based research.
Development and verification additionally use pytest, pytest-cov, respx, and Ruff. The installation command below installs both runtime and development dependencies; users do not need to install DuckDB or the other packages individually.
Python 3.14 is required. The existing environment can be used:
git clone git@github.com:xtcyclist/xQuant.git
cd xQuant
python3.14 -m venv xQuantEnv
source xQuantEnv/bin/activate
python -m pip install -e ".[dev]"
cp .env.example .env
cp configs.example.json configs.jsonEdit the ignored local configs.json and replace the placeholder with your own
iTick token:
{"service": "iTick", "token": "replace-with-your-token"}An exported shell ITICK_TOKEN takes priority over configs.json; configs.json
takes priority over .env. Then initialize storage:
xquant init-dbxQuant has one durable data universe: the market_bars table in DuckDB. Data Manager
adds to or removes from that universe through explicit tasks filtered by market,
exchange, stock IDs, temporal frequencies, and inclusive date ranges. Overlapping
loads are idempotent and never create duplicate datasets.
xquant sync-metadatasync-metadata downloads iTick's supported stock IDs, names, regions, and exchanges
into DuckDB. Data Manager can perform the same refresh and then provides dependent
Region → Exchange → searchable Stock selectors. Cached metadata remains available
offline, and failed region refreshes retain their previous catalog.
The virtual China market combines Shanghai (SH/SSE), Shenzhen (SZ/SZSE),
Beijing (BJ/BSE), and Hong Kong (HK/HKEX) selections while preserving the source
region required by iTick requests. iTick currently returns no Beijing stock symbols;
the UI reports this explicitly and will include them automatically if the API adds
support. A large filtered task is split into source-specific API requests and may
consume substantial API quota.
The Data Manager header reports total DuckDB storage, bar count, stock count, frequency series count, and overall date coverage. Removal tasks preview their matching bar count and require confirmation before permanently deleting data.
The Reference data tab validates and imports the supplied
config/sector_classifications.csv snapshot into DuckDB. It reports catalog matches,
unclassified rows, market/sector coverage, import provenance, and rejected records.
Provider-neutral CSV or Parquet fundamental facts can be added with point-in-time
availability timestamps.
Stock Selector can build a market-wide, resumable Parquet snapshot without filling the
main DuckDB universe. Snapshots retain complete normalized OHLCV, turnover, source, and
ingestion fields under data/selector_snapshots/market=.../interval=.../as_of=.../.
Each snapshot freezes its classification mapping, records per-stock progress in DuckDB,
and remains available until explicitly removed. Building China-wide history can consume
substantial iTick quota; the UI estimates requests and size and requires confirmation.
Failed or rate-limited stocks can be resumed without refetching completed members.
Screening reads the selected snapshot with DuckDB Parquet predicate pushdown. Choosing
results and selecting Add selected stocks to data universe copies their full bars
locally and idempotently into market_bars; this promotion makes no additional iTick
request. Selector snapshots and the durable data universe remain separate until that
explicit action.
xquant appOpen the Streamlit URL shown in the terminal. The application provides:
- Data Manager for filtered add/remove tasks, storage status, coverage, and logs.
- Stock Selector for sector-rotation visualization, strict metric screening, DuckDB-backed versioned filter sets, and handoffs to other workflows.
- Market Explorer for filtering up to five stock IDs at one common frequency, with separate candlesticks, indicators, metrics, and exports for each stock.
- Research Lab for opening project notebooks in a separate JupyterLab browser tab.
- Named workspace snapshots for restoring UI, chart, and research-reference state.
Register this environment once and start JupyterLab:
python -m ipykernel install --user --name xquant --display-name "xQuant (Python 3.14)"
xquant jupyterOpen either starter notebook from Research Lab. Notebook code uses the same
xquant package and DuckDB file as the application. Save durable research in cells or
move reusable functions into src/xquant; live kernel variables are not part of
workspace snapshots.
The default data/xquant.duckdb is file-backed and durable across restarts. DuckDB
uses transactional storage and recovery, but durability is not a backup strategy.
xquant backup
xquant export --directory data/exportsRun a backup when no other xQuant process is writing. Keep external backup copies outside the project machine as appropriate.
ruff check .
pytestTests use temporary DuckDB files and mocked iTick responses. A live iTick smoke test is skipped unless explicitly enabled with credentials.
Every user must provide their own iTick token. Real tokens are loaded from environment
variables or ignored local configs.json and never belong in source control, example
files, workspace state, logs, or notebook URLs. v0.1 covers historical stocks only.
Real-time WebSockets, order execution, portfolio accounting, multi-user deployment,
and live Jupyter kernel persistence are outside this release.