Files
A_Share_DP/src/ashare_dp/apps/cli/query_cmd.py
T
jackyu66gitandClaude cc95bbb638 v10: Trading OS — 5-subsystem architecture + Signal Intelligence + Dashboard Command Center
Architecture:
- Restructure into 5 subsystems: data/, features/, market/, signals/, execution/, apps/
- Unified ts_code conversion in core/codes.py (idempotent, kills 4 duplicate copies)
- analytics_conn() + kline_glob() — zero hardcoded DB/Parquet paths
- Fixed double-suffix bug (.SZ.SZ) in backfill pipeline root cause

Signal Intelligence (the moat):
- 14 signal types: EMA52, Vegas, Chan, ORB, Gap, NR7, Inside Bar
- 640K+ historical signal instances across 8 backfilled types
- Multi-signal Expectancy Engine with breadth-similarity matching
- Signal backfill CLI: ashare-dp backfill signals

Market Intelligence:
- 8 engines: State, Leadership, Opportunity, Flow, Sentiment, Memory, Knowledge Graph, Recommendations
- Real limit-up/down sentiment via akshare (108 ZT, 19 DT, 52 broken board)
- Knowledge Graph: 8 themes × 30+ concepts with keyword matching
- Money-flow stock recommendations with entry/stop/target trade plans

Dashboard Command Center:
- Decision-first layout: COMMAND → WHERE → WHY → RISK → EXPECTANCY
- Multi-signal Expectancy comparison table (8 types ranked by WR)
- Theme Map visualization with rotation detection
- Intraday Replay infrastructure (30min state snapshots)
- RECOMMENDATIONS card with actionable trade plans

Trading Memory:
- trade_log table + POST/GET/PUT API for trade recording
- Performance stats aggregation

Code Quality:
- 0 hardcoded DB paths, 0 REPLACE hacks, 0 dead ts_code copies
- EMA52 screening deduplicated (CLI + scheduler share one function)
- read_parquet_sql() helper for 28 duplicate patterns
- 6 bugs fixed from code review (NR7 window, theme matching, column indices, etc.)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 12:11:42 +08:00

105 lines
3.3 KiB
Python

"""Query CLI subcommands for ad-hoc data queries."""
from __future__ import annotations
from datetime import date, datetime
import typer
from ashare_dp.core.models import Freq
from ashare_dp.data.store.database import get_db
from ashare_dp.data.store.repository import KLineRepository
query_app = typer.Typer()
@query_app.command("kline")
def query_kline(
freq: str = typer.Argument(..., help="Frequency: 1m,5m,15m,30m,1h,2h,1d,1w,1M"),
ts_code: str = typer.Argument(..., help="Stock code, e.g. 000001.SZ"),
start: str = typer.Option(None, help="Start date YYYY-MM-DD"),
end: str = typer.Option(None, help="End date YYYY-MM-DD"),
limit: int = typer.Option(100, help="Max records"),
):
"""Query K-line data from the command line."""
freq_enum = Freq(freq)
repo = KLineRepository()
sd = date.fromisoformat(start) if start else None
ed = date.fromisoformat(end) if end else None
df = repo.read_klines(freq=freq_enum, ts_code=ts_code, start_date=sd, end_date=ed, limit=limit)
if df.empty:
typer.echo("No data found")
return
typer.echo(f"\n{freq} K-line for {ts_code}:")
typer.echo(df.to_string(index=False))
typer.echo(f"\n{len(df)} records")
@query_app.command("latest")
def query_latest(
freq: str = typer.Option("1d", help="Frequency"),
ts_code: str = typer.Option(None, help="Stock code (optional)"),
):
"""Show latest K-line data."""
freq_enum = Freq(freq)
repo = KLineRepository()
df = repo.get_latest(freq=freq_enum, ts_code=ts_code)
if df.empty:
typer.echo("No data found")
return
typer.echo(f"\nLatest {freq} K-line:")
typer.echo(df.to_string(index=False))
typer.echo(f"\n{len(df)} records")
@query_app.command("stocks")
def query_stocks(
exchange: str = typer.Option(None, help="Exchange: SH, SZ, BJ"),
limit: int = typer.Option(50, help="Max records"),
):
"""List stocks."""
with get_db(read_only=True) as db:
if exchange:
rows = db.query(
"SELECT ts_code, symbol, name, exchange, market, list_date FROM stock_info WHERE exchange = ? LIMIT ?",
(exchange.upper(), limit),
)
else:
rows = db.query(
"SELECT ts_code, symbol, name, exchange, market, list_date FROM stock_info LIMIT ?",
(limit,),
)
typer.echo(f"\n{'ts_code':<12} {'symbol':<8} {'name':<12} {'exchange':<8} {'market':<10} {'list_date'}")
typer.echo("-" * 60)
for row in rows:
ts, sym, name, ex, mkt, ld = row
ld_str = str(ld) if ld else ""
typer.echo(f"{ts:<12} {sym:<8} {name:<12} {ex:<8} {mkt or '':<10} {ld_str}")
@query_app.command("stats")
def query_stats():
"""Show database statistics."""
repo = KLineRepository()
typer.echo("\nDatabase Statistics:")
typer.echo("-" * 40)
# Stock count
with get_db(read_only=True) as db:
n = db.query("SELECT count(*) FROM stock_info")[0][0]
typer.echo(f" Stocks: {n}")
# Record count and date range per frequency
for freq_repr in [Freq.d1, Freq.w1, Freq.M1, Freq.h1, Freq.m5, Freq.m1]:
count = repo.count_records(freq_repr)
dr = repo.get_date_range(freq_repr)
typer.echo(f" {freq_repr.value}: {count} records, range {dr[0]} ~ {dr[1]}")