Work in progress / independent research system
QAP Crypto CLI
Work-in-progress Python CLI that compares spot crypto pairs, checks whether the data and setup are trustworthy, and uses copula-based dependency evidence before paper-run decision workflows.
QAP Crypto CLI
Summary: Most crypto tools make it easy to chase a signal. QAP asks a harder question first: which pairs are actually worth trusting, and which only look good on a chart?
QAP is a work-in-progress Python CLI that compares spot crypto pairs, checks the data behind them, tests whether the relationship holds up, and uses advanced dependency models before moving into paper-run decision workflows. It is the most complex independent research system I have taken on because it turns research papers, market data, pair comparison, validation rules, and proof artifacts into one command-line workflow.
Why I built it
Crypto has been my longest-running technical interest. I have followed the market for more than 10 years, first as curiosity, then as a deeper attempt to understand why some strategies sound convincing but fail once costs, volatility, missing data, and execution reality are included.
At some point I wanted to move past chart-watching and indicator stacking. I started reading and decoding research papers around pairs trading, cointegration, z-score diagnostics, copulas, tail dependence, walk-forward validation, and portfolio-style accumulation.
QAP came from that decision: if I care about crypto this much, I should build a system that tells me when an idea is weak, not just when it looks exciting.
What it does
QAP is a Python CLI for spot crypto pair analysis and forward-proof preparation. It is not just a research notebook in terminal form. The tool helps answer practical questions:
- Which pairs are worth comparing?
- Is the market data fresh enough to trust?
- Does the pair relationship survive validation?
- Is the current setup actionable, or blocked?
- Does copula-based dependency evidence support the signal?
- Can the result be exported into a paper-run decision workflow?
The current direction is not live order routing. QAP is the decision and proof layer before any external execution path.
The workflow is deliberately phase-based:
discoverscreens and compares structurally interesting spot pairs.data freshnesschecks whether cached and provider data are trustworthy enough for a run.validateproduces backtest, walk-forward, blocker, and current-actionability diagnostics.run shadowsimulates signal and execution behavior without routing live orders.campaignruns manifest-driven validation, paper-export, and evaluation flows.
Pipeline Architecture
$ qap validate BTC-USDT --freshness-check
┌──────────────┐
│ 1. DISCOVER │ ──➔ (Spot pair correlation & eligibility)
└──────┬───────┘
▼
┌──────────────┐
│ 2. INGEST │ ──➔ (Freshness audit: cached & live provider sync)
└──────┬───────┘
▼
┌──────────────┐
│ 3. COPULA │ ──➔ (Tail dependence & Mispricing Index model)
└──────┬───────┘
▼
┌──────────────┐
│ 4. VETO GATE │ ──➔ (Checks z-score, cointegration & risk rules)
└──────┬───────┘
▼
[Actionable / Blocked report + Paper-run bundle manifest]
Terminal Session Output
$ qap validate BTC-USDT --freshness-check
[INFO] Loading config from ~/.qap/config.json
[DATA] Cache age: 4m (freshness limit: 15m) -> Ingestion skipped.
[COPULA] Fitting Student-t Copula for BTC-USDT tail correlation...
[COPULA] Tail-dependence parameter: 0.81 (Signal: mispriced / candidate)
[VETO] Cointegration p-value: 0.12 (limit: 0.05) -> [VETO TRIGGERED]
[VETO] Relationship non-stationary; high probability of random walk divergence.
[REPORT] Validation completed.
Pair status: BLOCKED
Veto matches: 1 (Stationarity test failure)
Action: No trade allowed. Saved manifest to ~/.qap/runs/blocked_BTC-USDT.json
The goal is not a flashy win-rate screenshot. QAP is built around a more useful question: after fees and slippage, did the system accumulate more coin pieces than simply holding?
Tech stack
QAP is a Python 3.11+ CLI managed with uv. The command surface uses Typer, while the domain logic sits under a core layer for models, validation, backtests, risk gates, configuration, ledgers, registries, reporting, and paper execution contracts.
The testing surface is a major part of the project. The repo includes unit, CLI, integration, invariant, architecture, ops, performance, reference, stress, and characterization tests. That matters because this project is easy to make impressive-looking and wrong. The tests are there to defend boundaries such as copula-only signal authority, simulation-only execution, and thin CLI adapters.
Key engineering decisions
The biggest decision is that Student-t Copula Mispricing Index is the canonical signal authority. In simpler terms: QAP does not let a basic chart signal decide by itself.
It still studies spreads, hedge ratios, z-score diagnostics, cointegration, tail behavior, and pair eligibility, but those mechanisms have different jobs. Z-score and spread diagnostics can help explain structure, but they are not allowed to become the trade trigger.
That choice forced the architecture to separate responsibilities clearly:
- Discovery can find candidates, but it cannot decide trades.
- Pair comparison can rank and diagnose candidates, but it cannot bypass validation.
- Validation can produce evidence, but it cannot silently promote weak results.
- Copula-derived probability can drive signal authority.
- Veto gates can block entries, but they cannot create entries.
- Shadow and paper workflows can produce auditable artifacts, but the repo does not hide live exchange execution.
This is why QAP has phase enforcement, explicit no-trade explanations, paper-only bundles, pair eligibility rules, and governance checks. The goal is to make the system honest when it says no.
Problems I ran into
The hardest part is that every useful idea adds another way to be wrong.
Student-t copula work needs enough aligned data and careful probability handling. Z-score diagnostics are useful, but dangerous if they leak into signal authority. Pair eligibility needs structure, not just correlation. Backtests need fees, slippage, warmup behavior, and walk-forward checks. Shadow runs need provenance. Paper artifacts need enough metadata to be evaluated later. Tests need to catch architecture drift before the CLI becomes a pile of command adapters.
That is why this project has been difficult: it is not one algorithm. It is many integrations that have to agree with each other.
Engineering Notes & Lessons Learned
- Domain Rigidity: Quantitative tooling exposes how different software feels when the domain itself pushes back. A mathematical approach can look polished but be functionally invalid without rigorous validation boundaries.
- Auditable Execution Trails: Separating signal generation, veto evaluation, and shadow routing is the only way to build trust. Every phase must produce deterministic, auditable JSON manifests.
Validation Notes
- Veto Gate Coverage: Verified trade blocker flags under validation vetoes (such as non-stationarity, low tail-dependence, and high volume deviation) during local backtests.
- Local Ingestion Caching: Verified cache behavior to prevent redundant external API calls when cached data is under the 15-minute freshness limit.
- Backtest Validation: Compared walk-forward backtest outputs against historical fee schedules to ensure correct parameter calculations.
What I would improve next
The next work is to keep tightening the forward paper-run path, improve copula readiness reporting, expand deterministic test coverage around edge cases, and make the CLI output clearer for the difference between structural eligibility, signal evidence, and current actionability.
I also want to keep translating the research-paper side into practical engineering notes, because this project is partly a tool and partly my way of learning crypto market structure with real code.
Links
- Private work-in-progress repository