deeptrade-quant 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. deeptrade/__init__.py +8 -0
  2. deeptrade/channels_builtin/__init__.py +0 -0
  3. deeptrade/channels_builtin/stdout/__init__.py +0 -0
  4. deeptrade/channels_builtin/stdout/deeptrade_plugin.yaml +25 -0
  5. deeptrade/channels_builtin/stdout/migrations/20260429_001_init.sql +13 -0
  6. deeptrade/channels_builtin/stdout/stdout_channel/__init__.py +0 -0
  7. deeptrade/channels_builtin/stdout/stdout_channel/channel.py +180 -0
  8. deeptrade/cli.py +214 -0
  9. deeptrade/cli_config.py +396 -0
  10. deeptrade/cli_data.py +33 -0
  11. deeptrade/cli_plugin.py +176 -0
  12. deeptrade/core/__init__.py +8 -0
  13. deeptrade/core/config.py +344 -0
  14. deeptrade/core/config_migrations.py +138 -0
  15. deeptrade/core/db.py +176 -0
  16. deeptrade/core/llm_client.py +591 -0
  17. deeptrade/core/llm_manager.py +174 -0
  18. deeptrade/core/logging_config.py +61 -0
  19. deeptrade/core/migrations/__init__.py +0 -0
  20. deeptrade/core/migrations/core/20260427_001_init.sql +121 -0
  21. deeptrade/core/migrations/core/20260501_002_drop_llm_calls_stage.sql +10 -0
  22. deeptrade/core/migrations/core/__init__.py +0 -0
  23. deeptrade/core/notifier.py +302 -0
  24. deeptrade/core/paths.py +49 -0
  25. deeptrade/core/plugin_manager.py +616 -0
  26. deeptrade/core/run_status.py +29 -0
  27. deeptrade/core/secrets.py +152 -0
  28. deeptrade/core/tushare_client.py +824 -0
  29. deeptrade/plugins_api/__init__.py +44 -0
  30. deeptrade/plugins_api/base.py +66 -0
  31. deeptrade/plugins_api/channel.py +42 -0
  32. deeptrade/plugins_api/events.py +61 -0
  33. deeptrade/plugins_api/llm.py +46 -0
  34. deeptrade/plugins_api/metadata.py +84 -0
  35. deeptrade/plugins_api/notify.py +67 -0
  36. deeptrade/strategies_builtin/__init__.py +0 -0
  37. deeptrade/strategies_builtin/limit_up_board/__init__.py +0 -0
  38. deeptrade/strategies_builtin/limit_up_board/deeptrade_plugin.yaml +101 -0
  39. deeptrade/strategies_builtin/limit_up_board/limit_up_board/__init__.py +0 -0
  40. deeptrade/strategies_builtin/limit_up_board/limit_up_board/calendar.py +65 -0
  41. deeptrade/strategies_builtin/limit_up_board/limit_up_board/cli.py +269 -0
  42. deeptrade/strategies_builtin/limit_up_board/limit_up_board/config.py +76 -0
  43. deeptrade/strategies_builtin/limit_up_board/limit_up_board/data.py +1191 -0
  44. deeptrade/strategies_builtin/limit_up_board/limit_up_board/pipeline.py +869 -0
  45. deeptrade/strategies_builtin/limit_up_board/limit_up_board/plugin.py +30 -0
  46. deeptrade/strategies_builtin/limit_up_board/limit_up_board/profiles.py +85 -0
  47. deeptrade/strategies_builtin/limit_up_board/limit_up_board/prompts.py +485 -0
  48. deeptrade/strategies_builtin/limit_up_board/limit_up_board/render.py +890 -0
  49. deeptrade/strategies_builtin/limit_up_board/limit_up_board/runner.py +1087 -0
  50. deeptrade/strategies_builtin/limit_up_board/limit_up_board/runtime.py +172 -0
  51. deeptrade/strategies_builtin/limit_up_board/limit_up_board/schemas.py +178 -0
  52. deeptrade/strategies_builtin/limit_up_board/migrations/20260430_001_init.sql +150 -0
  53. deeptrade/strategies_builtin/limit_up_board/migrations/20260501_002_lub_stage_results_llm_provider.sql +8 -0
  54. deeptrade/strategies_builtin/limit_up_board/migrations/20260508_001_lub_lhb_tables.sql +36 -0
  55. deeptrade/strategies_builtin/limit_up_board/migrations/20260508_002_lub_cyq_perf.sql +18 -0
  56. deeptrade/strategies_builtin/limit_up_board/migrations/20260508_003_lub_lhb_pk_fix.sql +46 -0
  57. deeptrade/strategies_builtin/limit_up_board/migrations/20260508_004_lub_lhb_drop_pk.sql +53 -0
  58. deeptrade/strategies_builtin/limit_up_board/migrations/20260508_005_lub_config.sql +17 -0
  59. deeptrade/strategies_builtin/volume_anomaly/__init__.py +0 -0
  60. deeptrade/strategies_builtin/volume_anomaly/deeptrade_plugin.yaml +59 -0
  61. deeptrade/strategies_builtin/volume_anomaly/migrations/20260430_001_init.sql +94 -0
  62. deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_001_realized_returns.sql +44 -0
  63. deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_002_dimension_scores.sql +13 -0
  64. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/__init__.py +0 -0
  65. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/calendar.py +52 -0
  66. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/cli.py +247 -0
  67. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/data.py +2154 -0
  68. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/pipeline.py +327 -0
  69. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/plugin.py +22 -0
  70. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/profiles.py +49 -0
  71. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts.py +187 -0
  72. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts_examples.py +84 -0
  73. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/render.py +906 -0
  74. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runner.py +772 -0
  75. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runtime.py +90 -0
  76. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/schemas.py +97 -0
  77. deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/stats.py +174 -0
  78. deeptrade/theme.py +48 -0
  79. deeptrade_quant-0.0.2.dist-info/METADATA +166 -0
  80. deeptrade_quant-0.0.2.dist-info/RECORD +83 -0
  81. deeptrade_quant-0.0.2.dist-info/WHEEL +4 -0
  82. deeptrade_quant-0.0.2.dist-info/entry_points.txt +2 -0
  83. deeptrade_quant-0.0.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,90 @@
1
+ """VaRuntime — context bundle the volume-anomaly plugin's pipeline runs against.
2
+
3
+ v0.6 — ``llm: DeepSeekClient`` field removed. ``llms: LLMManager`` is the
4
+ new framework hand-off; runner / pipeline pull a per-provider ``LLMClient``
5
+ via ``rt.llms.get_client(name, plugin_id=, run_id=)``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from dataclasses import dataclass
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ from deeptrade.plugins_api.events import EventLevel, EventType, StrategyEvent
15
+
16
+ if TYPE_CHECKING: # pragma: no cover
17
+ from deeptrade.core.config import ConfigService
18
+ from deeptrade.core.db import Database
19
+ from deeptrade.core.llm_manager import LLMManager
20
+ from deeptrade.core.tushare_client import TushareClient
21
+ from deeptrade.plugins_api.notify import NotificationPayload
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ PLUGIN_ID = "volume-anomaly"
26
+
27
+
28
+ @dataclass
29
+ class VaRuntime:
30
+ db: Database
31
+ config: ConfigService
32
+ llms: LLMManager
33
+ plugin_id: str = PLUGIN_ID
34
+ run_id: str | None = None
35
+ is_intraday: bool = False
36
+ tushare: TushareClient | None = None
37
+
38
+ def emit(
39
+ self,
40
+ event_type: EventType,
41
+ message: str,
42
+ *,
43
+ level: EventLevel = EventLevel.INFO,
44
+ **payload: object,
45
+ ) -> StrategyEvent:
46
+ return StrategyEvent(type=event_type, level=level, message=message, payload=dict(payload))
47
+
48
+ def notify(self, payload: NotificationPayload) -> bool:
49
+ from deeptrade import notify as _notify
50
+
51
+ try:
52
+ _notify(self.db, payload)
53
+ return True
54
+ except Exception as e: # noqa: BLE001
55
+ logger.warning("notify dispatch failed: %s", e)
56
+ return False
57
+
58
+
59
+ def build_tushare_client(rt: VaRuntime, *, intraday: bool = False, event_cb: Any = None):
60
+ from deeptrade.core.tushare_client import TushareClient, TushareSDKTransport
61
+
62
+ token = rt.config.get("tushare.token")
63
+ if not token:
64
+ raise RuntimeError("tushare.token not configured; run `deeptrade config set-tushare`")
65
+ cfg = rt.config.get_app_config()
66
+ return TushareClient(
67
+ rt.db,
68
+ TushareSDKTransport(str(token)),
69
+ plugin_id=rt.plugin_id,
70
+ rps=cfg.tushare_rps,
71
+ intraday=intraday,
72
+ event_cb=event_cb,
73
+ )
74
+
75
+
76
+ def pick_llm_provider(rt: VaRuntime) -> str:
77
+ """Pick which configured LLM provider to use for this run.
78
+
79
+ See ``limit_up_board.runtime.pick_llm_provider`` for the policy rationale
80
+ — kept duplicated here so each plugin can later diverge (per-plugin
81
+ default LLM in v0.7).
82
+ """
83
+ available = rt.llms.list_providers()
84
+ if not available:
85
+ raise RuntimeError(
86
+ "No LLM provider configured; run `deeptrade config set-llm`"
87
+ )
88
+ if "deepseek" in available:
89
+ return "deepseek"
90
+ return available[0]
@@ -0,0 +1,97 @@
1
+ """Pydantic schemas for the volume-anomaly LLM stage.
2
+
3
+ Hard constraints (mirrors limit_up_board conventions):
4
+ * extra='forbid' on every model
5
+ * candidate_id round-trips verbatim from input
6
+ * rank is a dense permutation 1..N within each batch
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Literal
12
+
13
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
14
+
15
+
16
+ class VAEvidenceItem(BaseModel):
17
+ """One field-level fact the LLM is using to reason.
18
+
19
+ `field` MUST refer to a key actually present in the input prompt; `unit`
20
+ is REQUIRED so prompt and model speak the same units.
21
+ """
22
+
23
+ model_config = ConfigDict(extra="forbid")
24
+ field: str = Field(..., min_length=1, max_length=64)
25
+ value: str | int | float | None
26
+ unit: str = Field(..., min_length=1, max_length=16)
27
+ interpretation: str = Field(..., min_length=1, max_length=120)
28
+
29
+
30
+ class VADimensionScores(BaseModel):
31
+ """v0.6.0 P1-2 — per-dimension explicit scoring (0–100).
32
+
33
+ `risk` is reverse-polarity — a higher score means greater risk; every
34
+ other dimension is positive-polarity (higher = more bullish). The
35
+ relationship between this sub-object and ``launch_score`` is left to the
36
+ LLM's own consistency (F3 / F14 — soft constraint via prompt, no formula).
37
+ """
38
+
39
+ model_config = ConfigDict(extra="forbid")
40
+ washout: int = Field(ge=0, le=100) # 洗盘充分度
41
+ pattern: int = Field(ge=0, le=100) # 形态突破有效性
42
+ capital: int = Field(ge=0, le=100) # 资金验证(moneyflow / volume)
43
+ sector: int = Field(ge=0, le=100) # 板块强度 + 大盘相对(与 P1-1 合流)
44
+ historical: int = Field(ge=0, le=100) # 历史浪型位置(越早越好)
45
+ risk: int = Field(ge=0, le=100) # 风险(reverse-polarity — 高分 = 高风险)
46
+
47
+
48
+ class VATrendCandidate(BaseModel):
49
+ """One LLM verdict per input candidate."""
50
+
51
+ model_config = ConfigDict(extra="forbid")
52
+ candidate_id: str
53
+ ts_code: str
54
+ name: str
55
+ rank: int = Field(ge=1)
56
+ launch_score: float = Field(ge=0, le=100)
57
+ confidence: Literal["high", "medium", "low"]
58
+ prediction: Literal["imminent_launch", "watching", "not_yet"]
59
+ pattern: Literal[
60
+ "breakout",
61
+ "consolidation_break",
62
+ "first_wave",
63
+ "second_leg",
64
+ "unclear",
65
+ ]
66
+ washout_quality: Literal["sufficient", "partial", "insufficient", "unclear"]
67
+ rationale: str = Field(..., max_length=200)
68
+ # v0.6.0 P1-2 — required field (F8). Old persisted responses live in
69
+ # va_stage_results.raw_response_json so the strict schema is safe.
70
+ dimension_scores: VADimensionScores
71
+ key_evidence: list[VAEvidenceItem] = Field(min_length=1, max_length=5)
72
+ next_session_watch: list[str] = Field(min_length=1, max_length=4)
73
+ invalidation_triggers: list[str] = Field(min_length=1, max_length=4)
74
+ risk_flags: list[str] = Field(default_factory=list, max_length=5)
75
+ missing_data: list[str] = Field(default_factory=list)
76
+
77
+
78
+ class VATrendResponse(BaseModel):
79
+ model_config = ConfigDict(extra="forbid")
80
+ stage: Literal["continuation_prediction"]
81
+ trade_date: str
82
+ next_trade_date: str
83
+ batch_no: int = Field(ge=1)
84
+ batch_total: int = Field(ge=1)
85
+ market_context_summary: str = Field(..., max_length=200)
86
+ risk_disclaimer: str = Field(..., max_length=160)
87
+ candidates: list[VATrendCandidate]
88
+
89
+ @field_validator("candidates")
90
+ @classmethod
91
+ def ranks_must_be_dense_1_to_n(cls, v: list[VATrendCandidate]) -> list[VATrendCandidate]:
92
+ """Per-batch rank must be a dense permutation 1..N."""
93
+ ranks = sorted(c.rank for c in v)
94
+ expected = list(range(1, len(ranks) + 1))
95
+ if ranks != expected:
96
+ raise ValueError(f"candidate ranks must be a dense permutation 1..N; got {ranks}")
97
+ return v
@@ -0,0 +1,174 @@
1
+ """volume-anomaly v0.4.0 — Stats query layer.
2
+
3
+ Pure read-only SQL aggregation over ``va_stage_results`` JOIN
4
+ ``va_realized_returns``. Consumed by the ``stats`` CLI subcommand and any
5
+ future LightGBM / Multi-Agent feature pipeline.
6
+
7
+ The shape returned to the renderer is:
8
+ [{bucket: str, n_samples: int, t3_mean: float | None,
9
+ t3_winrate: float | None, t5_max_ret_mean: float | None}, ...]
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Any
15
+
16
+ # G4 — default launch_score bins. v0.7+ may expose a `--bins` flag.
17
+ LAUNCH_SCORE_BINS: list[tuple[str, float, float]] = [
18
+ ("0-40", 0.0, 40.0),
19
+ ("40-60", 40.0, 60.0),
20
+ ("60-80", 60.0, 80.0),
21
+ ("80-100", 80.0, 100.0),
22
+ ]
23
+
24
+
25
+ DIMENSION_COLS: tuple[str, ...] = (
26
+ "washout", "pattern", "capital", "sector", "historical", "risk",
27
+ )
28
+
29
+
30
+ def run_stats_query(
31
+ db: Any,
32
+ *,
33
+ from_date: str | None,
34
+ to_date: str | None,
35
+ by: str,
36
+ ) -> tuple[list[dict[str, Any]], str]:
37
+ """Execute the aggregation; return (rows, table_title)."""
38
+ if by not in {"prediction", "pattern", "launch_score_bin", "dimension_scores"}:
39
+ raise ValueError(
40
+ f"unknown --by={by!r}; choose from prediction | pattern | "
41
+ f"launch_score_bin | dimension_scores"
42
+ )
43
+
44
+ # Build WHERE clause for date range. We bind via parameters to avoid SQL
45
+ # injection even though these are user-supplied YYYYMMDD strings.
46
+ where_clauses = ["s.trade_date = r.anomaly_date"]
47
+ params: list[Any] = []
48
+ if from_date:
49
+ where_clauses.append("r.anomaly_date >= ?")
50
+ params.append(from_date)
51
+ if to_date:
52
+ where_clauses.append("r.anomaly_date <= ?")
53
+ params.append(to_date)
54
+ where_sql = " AND ".join(where_clauses)
55
+
56
+ if by == "launch_score_bin":
57
+ return _by_launch_score_bin(db, where_sql=where_sql, params=params), (
58
+ f"按 launch_score_bin 维度({from_date or '*'}–{to_date or '*'})"
59
+ )
60
+
61
+ if by == "dimension_scores":
62
+ return _by_dimension_scores(db, where_sql=where_sql, params=params), (
63
+ f"按 dimension_scores 维度与 ret_t3 的 Pearson 相关系数"
64
+ f"({from_date or '*'}–{to_date or '*'})"
65
+ )
66
+
67
+ # Generic group-by for prediction / pattern.
68
+ group_col = f"s.{by}"
69
+ sql = f"""
70
+ SELECT {group_col} AS bucket,
71
+ COUNT(*) AS n_samples,
72
+ AVG(r.ret_t3) AS t3_mean,
73
+ AVG(CASE WHEN r.ret_t3 > 0 THEN 100.0 ELSE 0.0 END) AS t3_winrate,
74
+ AVG(r.max_ret_5d) AS t5_max_ret_mean
75
+ FROM va_stage_results s
76
+ JOIN va_realized_returns r
77
+ ON s.ts_code = r.ts_code AND {where_sql}
78
+ WHERE r.ret_t3 IS NOT NULL
79
+ GROUP BY {group_col}
80
+ ORDER BY {group_col}
81
+ """
82
+ rows = db.fetchall(sql, tuple(params))
83
+ title = f"按 {by} 维度({from_date or '*'}–{to_date or '*'})"
84
+ return [_row_to_dict(r) for r in rows], title
85
+
86
+
87
+ def _by_launch_score_bin(
88
+ db: Any, *, where_sql: str, params: list[Any]
89
+ ) -> list[dict[str, Any]]:
90
+ """Bin launch_score into LAUNCH_SCORE_BINS and aggregate per bucket.
91
+
92
+ Implemented with a CASE expression to keep the query fully SQL-side
93
+ (DuckDB executes faster than fetching everything to Python and binning).
94
+ """
95
+ case_lines = []
96
+ for label, lo, hi in LAUNCH_SCORE_BINS:
97
+ # Half-open low, closed high — inclusive of upper bound for the last bin
98
+ is_last = label == LAUNCH_SCORE_BINS[-1][0]
99
+ op_hi = "<=" if is_last else "<"
100
+ case_lines.append(
101
+ f"WHEN s.launch_score >= {lo} AND s.launch_score {op_hi} {hi} THEN '{label}'"
102
+ )
103
+ case_expr = "CASE " + " ".join(case_lines) + " ELSE 'oob' END"
104
+
105
+ sql = f"""
106
+ SELECT {case_expr} AS bucket,
107
+ COUNT(*) AS n_samples,
108
+ AVG(r.ret_t3) AS t3_mean,
109
+ AVG(CASE WHEN r.ret_t3 > 0 THEN 100.0 ELSE 0.0 END) AS t3_winrate,
110
+ AVG(r.max_ret_5d) AS t5_max_ret_mean
111
+ FROM va_stage_results s
112
+ JOIN va_realized_returns r
113
+ ON s.ts_code = r.ts_code AND {where_sql}
114
+ WHERE r.ret_t3 IS NOT NULL AND s.launch_score IS NOT NULL
115
+ GROUP BY bucket
116
+ ORDER BY bucket
117
+ """
118
+ rows = db.fetchall(sql, tuple(params))
119
+ return [_row_to_dict(r) for r in rows]
120
+
121
+
122
+ def _row_to_dict(r: tuple[Any, ...]) -> dict[str, Any]:
123
+ return {
124
+ "bucket": r[0],
125
+ "n_samples": int(r[1] or 0),
126
+ "t3_mean": float(r[2]) if r[2] is not None else None,
127
+ "t3_winrate": float(r[3]) if r[3] is not None else None,
128
+ "t5_max_ret_mean": float(r[4]) if r[4] is not None else None,
129
+ }
130
+
131
+
132
+ def _by_dimension_scores(
133
+ db: Any, *, where_sql: str, params: list[Any]
134
+ ) -> list[dict[str, Any]]:
135
+ """Compute Pearson correlation between each dim_<X> column and ret_t3.
136
+
137
+ Pearson formula in pure SQL:
138
+ corr(x, y) = (n*Σxy − Σx Σy) /
139
+ √((n*Σx² − (Σx)²)(n*Σy² − (Σy)²))
140
+
141
+ DuckDB has a built-in `CORR(x, y)` aggregate which is even simpler — use it
142
+ when available. (DuckDB ≥ 0.7.0 supports CORR.)
143
+ """
144
+ rows: list[dict[str, Any]] = []
145
+ for dim in DIMENSION_COLS:
146
+ col = f"dim_{dim}"
147
+ sql = f"""
148
+ SELECT COUNT(*) AS n_samples,
149
+ AVG(CASE WHEN s.{col} > 50 AND r.ret_t3 > 0 THEN 100.0 ELSE 0.0 END)
150
+ AS hit_rate_above_50,
151
+ CORR(s.{col}, r.ret_t3) AS corr_t3,
152
+ AVG(r.ret_t3) AS t3_mean,
153
+ AVG(r.max_ret_5d) AS t5_max_ret_mean
154
+ FROM va_stage_results s
155
+ JOIN va_realized_returns r
156
+ ON s.ts_code = r.ts_code AND {where_sql}
157
+ WHERE r.ret_t3 IS NOT NULL AND s.{col} IS NOT NULL
158
+ """
159
+ row = db.fetchone(sql, tuple(params))
160
+ if not row:
161
+ continue
162
+ n, _hit, corr, t3_mean, t5_max = row
163
+ rows.append(
164
+ {
165
+ "bucket": dim,
166
+ "n_samples": int(n or 0),
167
+ # Repurpose t3_mean column to show the correlation coefficient
168
+ # so the existing renderer doesn't need a special-case branch.
169
+ "t3_mean": float(corr) if corr is not None else None,
170
+ "t3_winrate": None,
171
+ "t5_max_ret_mean": float(t5_max) if t5_max is not None else None,
172
+ }
173
+ )
174
+ return rows
deeptrade/theme.py ADDED
@@ -0,0 +1,48 @@
1
+ """EVA-themed Rich design tokens.
2
+
3
+ V0.0: tokens defined but not yet applied to a Console.
4
+ V0.6: full Theme integration into the Live dashboard (DESIGN §9.2).
5
+
6
+ Naming convention: tokens use semantic role names (status.running, panel.border.error)
7
+ so callers reference styles by meaning, not raw color literals.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from rich.theme import Theme
13
+
14
+ # === EVA-01 design tokens (truecolor) ===
15
+ EVA_BG = "#0B0B10" # 黑底
16
+ EVA_PANEL = "#15131D"
17
+ EVA_PURPLE = "#6B2FBF" # EVA-01 紫,主框线
18
+ EVA_DEEP_PURPLE = "#3B0764"
19
+ EVA_LIME = "#78D64B" # 终端绿,正常 / 成功
20
+ EVA_ORANGE = "#FF8A00" # NERV 橙,进行中
21
+ EVA_RED = "#E53935" # 错误
22
+ EVA_YELLOW = "#FFB000" # 警告
23
+ EVA_TEXT = "#E8E6F0"
24
+ EVA_DIM = "#8C8799"
25
+ EVA_STOCK_UP = "#E53935" # A 股约定红涨
26
+ EVA_STOCK_DOWN = "#78D64B" # 绿跌
27
+
28
+ EVA_THEME = Theme(
29
+ {
30
+ "title": f"bold {EVA_LIME}",
31
+ "subtitle": f"italic {EVA_DIM}",
32
+ "panel.border.primary": EVA_PURPLE,
33
+ "panel.border.warn": EVA_YELLOW,
34
+ "panel.border.error": EVA_RED,
35
+ "panel.border.ok": EVA_LIME,
36
+ "status.pending": EVA_DIM,
37
+ "status.running": EVA_ORANGE,
38
+ "status.success": EVA_LIME,
39
+ "status.error": EVA_RED,
40
+ "k.value": EVA_LIME,
41
+ "k.label": EVA_DIM,
42
+ "stock.up": EVA_STOCK_UP,
43
+ "stock.down": EVA_STOCK_DOWN,
44
+ "spinner": EVA_ORANGE,
45
+ "headline.alert": f"bold {EVA_YELLOW} on {EVA_DEEP_PURPLE}",
46
+ "headline.fatal": f"bold {EVA_RED} on {EVA_DEEP_PURPLE}",
47
+ }
48
+ )
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: deeptrade-quant
3
+ Version: 0.0.2
4
+ Summary: LLM-driven A-share (Shanghai/Shenzhen main board) stock screening CLI
5
+ Project-URL: Homepage, https://github.com/ty19880929/deeptrade
6
+ Project-URL: Repository, https://github.com/ty19880929/deeptrade
7
+ Project-URL: Issues, https://github.com/ty19880929/deeptrade/issues
8
+ Author: DeepTrade
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: a-share,cli,deepseek,duckdb,llm,stock,tushare
12
+ Requires-Python: >=3.11
13
+ Requires-Dist: click>=8.1
14
+ Requires-Dist: duckdb>=1.0
15
+ Requires-Dist: keyring>=25.0
16
+ Requires-Dist: openai>=1.0
17
+ Requires-Dist: pandas>=2.2
18
+ Requires-Dist: pydantic>=2.7
19
+ Requires-Dist: pyyaml>=6.0
20
+ Requires-Dist: questionary>=2.0
21
+ Requires-Dist: rich>=13.7
22
+ Requires-Dist: tenacity>=8.0
23
+ Requires-Dist: tushare>=1.4
24
+ Requires-Dist: typer>=0.12
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.10; extra == 'dev'
27
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
28
+ Requires-Dist: pytest-mock>=3.12; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.5; extra == 'dev'
31
+ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # DeepTrade
35
+
36
+ > 本地运行的 A 股(沪深主板)选股 CLI 工具:tushare 行情 + OpenAI 兼容 LLM(DeepSeek / Qwen / Kimi …)+ DuckDB 单机仓库 + 插件式 CLI 框架。
37
+
38
+ [![tests](https://img.shields.io/badge/tests-passing-brightgreen)](#) [![python](https://img.shields.io/badge/python-3.11+-blue)](#) [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
39
+
40
+ ## ✨ 主要特性
41
+
42
+ - **轻量本地化**:单文件 DuckDB + uv,一条命令跑完,无需服务进程或容器。
43
+ - **纯透传式插件 CLI**:框架命令面**封闭**——只管 `init / config / plugin / data`;其余命令一律按 `deeptrade <plugin_id> <argv...>` 透传给插件,插件自管 `--help`、子命令、参数、持久化。新增插件类型(皮肤、新数据源、回测、IM 渠道……)零框架改动。
44
+ - **数据隔离(Plan A)**:每个插件在自己的 migrations 里声明并拥有自己的表(含 tushare 派生数据),框架不持有任何业务表。`tushare_sync_state` / `tushare_calls` / `llm_calls` 都按 `plugin_id` 维度隔离。
45
+ - **顶层通知 API**:`from deeptrade import notify, notification_session` 一行发推送;框架根据已安装的 channel 插件自动路由,无 channel 时自动 noop。
46
+ - **多 LLM Provider 共存**:`llm.providers` 字典化配置,多个 OpenAI 兼容服务并存;插件通过 `LLMManager.get_client(name=...)` 按名取用,单次 run 内可调多家。
47
+ - **LLM 强约束**:JSON 模式 + Pydantic 双层校验;**永远**不传 tools / function calls。
48
+ - **盘中数据隔离**:`--allow-intraday` 模式下同步的不完整数据写入 `data_completeness='intraday'`,日终模式严格拒绝命中。
49
+
50
+ ## 🚀 5 分钟上手
51
+
52
+ ### 安装
53
+
54
+ ```bash
55
+ # 推荐
56
+ uv sync --all-extras
57
+ uv run pre-commit install
58
+
59
+ # 兜底(无 uv)
60
+ python -m venv .venv && source .venv/bin/activate # Windows: .\.venv\Scripts\activate
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ ### 初始化与配置
65
+
66
+ ```bash
67
+ deeptrade init # 建库 + 应用 core migrations
68
+ deeptrade config set-tushare # 交互式输入 tushare token
69
+ deeptrade config set-llm # 交互式增/改/删 LLM provider(deepseek / qwen / kimi …)
70
+ deeptrade config list-llm # 列出已配置且可用的 provider
71
+ deeptrade config test-llm # 对所有 provider 做连通性自检(也可加 <name> 单测)
72
+ deeptrade config show # 表格展示当前配置(密钥脱敏)
73
+ ```
74
+
75
+ ### 安装内置插件并运行
76
+
77
+ ```bash
78
+ # 安装一个 strategy 插件 + 一个 channel 插件
79
+ deeptrade plugin install ./deeptrade/strategies_builtin/limit_up_board -y
80
+ deeptrade plugin install ./deeptrade/channels_builtin/stdout -y
81
+
82
+ deeptrade plugin list # 查看已安装
83
+
84
+ # 运行打板策略(CLI 由插件自管,--help 由插件渲染)
85
+ deeptrade limit-up-board --help
86
+ deeptrade limit-up-board run # 默认日终模式
87
+ deeptrade limit-up-board run --allow-intraday --force-sync
88
+
89
+ # 运行成交量异动策略(三模式)
90
+ deeptrade volume-anomaly screen # 异动筛选 → upsert va_watchlist
91
+ deeptrade volume-anomaly analyze # LLM 主升浪启动预测
92
+ deeptrade volume-anomaly prune --days 30 # 剔除追踪 ≥30 日的标的
93
+
94
+ # 推送链路自检
95
+ deeptrade stdout-channel test
96
+ ```
97
+
98
+ 报告产出在 `~/.deeptrade/reports/<run_id>/`。
99
+
100
+ ## 📦 命令矩阵
101
+
102
+ ### 框架命令(封闭集合)
103
+
104
+ | 命令 | 用途 |
105
+ |---|---|
106
+ | `deeptrade --version` / `-V` | 显示版本 |
107
+ | `deeptrade --help` / `-h` | 框架命令清单(**不**枚举插件子命令) |
108
+ | `deeptrade init [--no-prompts]` | 建库 + 应用 core migrations |
109
+ | `deeptrade config {show, set, set-tushare, set-llm, list-llm, test-llm}` | 全局配置 |
110
+ | `deeptrade plugin install <path> [-y]` | 本地路径安装(绝不联网) |
111
+ | `deeptrade plugin list / info <id>` | 列表 / 详情 |
112
+ | `deeptrade plugin enable <id> / disable <id>` | 启 / 停 |
113
+ | `deeptrade plugin uninstall <id> [--purge]` | 卸载(`--purge` 才 DROP 表) |
114
+ | `deeptrade plugin upgrade <path>` | 升级(增量 migrations) |
115
+ | `deeptrade data sync ...` | (暂停用,下版本恢复) |
116
+
117
+ 保留字(不可作为 plugin_id):`init / config / plugin / data`。
118
+
119
+ ### 插件命令(按 plugin_id 透传,插件自管)
120
+
121
+ | 命令 | 来源 |
122
+ |---|---|
123
+ | `deeptrade limit-up-board {run, sync, history, report}` | 内建打板策略插件 |
124
+ | `deeptrade volume-anomaly {screen, analyze, prune, history, report}` | 内建成交量异动插件 |
125
+ | `deeptrade stdout-channel {test, log}` | 内建 stdout 通知插件 |
126
+ | `deeptrade <你的-plugin-id> ...` | 你自己写的任何插件 |
127
+
128
+ 任意插件子命令的 `--help` 都由插件自身渲染——框架不感知动词语义。
129
+
130
+ ## 🧱 架构
131
+
132
+ ```
133
+ ┌──────────────────────── deeptrade CLI (custom click.Group) ────────────────────────┐
134
+ │ │
135
+ │ framework commands (closed): │
136
+ │ init │ config │ plugin │ data │
137
+ │ │
138
+ │ plugin pass-through (open): │
139
+ │ <plugin_id> ──argv──→ Plugin.dispatch(argv) → int (plugin owns the rest) │
140
+ └──────────────────────────────────┬─────────────────────────────────────────────────┘
141
+
142
+ ┌──────────────────────┼──────────────────────────┐
143
+ ▼ ▼ ▼
144
+ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
145
+ │ Core services │ │ deeptrade.notify │ │ Plugins (any type)│
146
+ │ DuckDB · Config │ │ → routes to all │ │ • metadata │
147
+ │ Tushare · LLM │ │ enabled │ │ • validate_static │
148
+ │ Notifier │ │ channel plugins│ │ • dispatch(argv) │
149
+ └─────────────────┘ └──────────────────┘ │ (channel: + push) │
150
+ └────────────────────┘
151
+ ```
152
+
153
+ 设计决策见 [docs/plugin_cli_dispatch_evaluation.md](docs/plugin_cli_dispatch_evaluation.md)。
154
+
155
+ ## 📖 文档
156
+
157
+ - [DESIGN.md](DESIGN.md) — 设计文档
158
+ - [docs/plugin_cli_dispatch_evaluation.md](docs/plugin_cli_dispatch_evaluation.md) — 当前架构的评估与决策记录(v0.3)
159
+ - [docs/quick-start.md](docs/quick-start.md) — 上手指南
160
+ - [docs/plugin-development.md](docs/plugin-development.md) — 写一个新插件
161
+ - [docs/limit-up-board.md](docs/limit-up-board.md) — 打板策略说明
162
+ - [CHANGELOG.md](CHANGELOG.md) — 版本变更
163
+
164
+ ## ⚖️ 免责声明
165
+
166
+ 本工具仅用于策略研究、数据整理与候选标的分析,**不构成投资建议**,**不进行自动交易**。所有 LLM 输出基于提交的结构化数据,不引用任何外部信息源;用户应自行核验候选标的的最新状态后再做决策。
@@ -0,0 +1,83 @@
1
+ deeptrade/__init__.py,sha256=dsqgIyXg1efLfeZuoNwVqk4FPU8FcPsrCxL8I-4J9jo,245
2
+ deeptrade/cli.py,sha256=YiPdrCj8LE5N5uo6yu4jTPr6SUQZV456QGy35JNZgWs,7020
3
+ deeptrade/cli_config.py,sha256=nDlE1GG_NPJaZRn1fbyXJffz6PglXBiAYZPnS0cubO4,13094
4
+ deeptrade/cli_data.py,sha256=d3AbPi9mhrXvnFXMZ4UVyVf0qtY9RH00Y35VQdhZYnQ,1053
5
+ deeptrade/cli_plugin.py,sha256=S4cqhbqytSemYRCiORlT75l4dLse-siJF1PzOK-wxyI,5513
6
+ deeptrade/theme.py,sha256=7ZlrZ9hbJaWKKtEkDyL3pPf2jpY1ckEukQ8RChJ30mk,1549
7
+ deeptrade/channels_builtin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ deeptrade/channels_builtin/stdout/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ deeptrade/channels_builtin/stdout/deeptrade_plugin.yaml,sha256=7XnjIYF2TU8zeOoZMNQvR03PsSgIN6N4I4x7zwUiGF0,692
10
+ deeptrade/channels_builtin/stdout/migrations/20260429_001_init.sql,sha256=cxfSPUrJG5oSWeK6TZkIY0kd6P4RFeGQUrAvg5OTmcw,551
11
+ deeptrade/channels_builtin/stdout/stdout_channel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ deeptrade/channels_builtin/stdout/stdout_channel/channel.py,sha256=2thLzba7npXCMFOarWETX41MpxyohKJ4_iKKljSKJLY,6780
13
+ deeptrade/core/__init__.py,sha256=KV4_3Ge1q8triWpL5pHxi3X7d6nI0r3xzTKMR1gHH9Y,302
14
+ deeptrade/core/config.py,sha256=UEbzczwknlbn_8NDj7gHp-xmyVR3wr7KA9bnT0pi5qc,14201
15
+ deeptrade/core/config_migrations.py,sha256=PY_pStNaFjjEvh7hBYbXudLOe_GVI0BWzOLfR7WWNHo,5288
16
+ deeptrade/core/db.py,sha256=hZyfuCDXZgKZXX2wzH9udaYri4EYLPlCdnBH2T9LMZg,6466
17
+ deeptrade/core/llm_client.py,sha256=yXRw_xduteH0bwdL8dA6DPr7f_zngDZYGhhXzjkMyw0,23496
18
+ deeptrade/core/llm_manager.py,sha256=s2rYeGVmPeNkBby63XW_alyctQIudCH5dWAIWRwr1bs,6477
19
+ deeptrade/core/logging_config.py,sha256=6Ob4-QGae52R4DckW2zb_RfGLXFejll5aykb_ybAq8s,1801
20
+ deeptrade/core/notifier.py,sha256=nYLwUWD46VeFlHfJbK241oq-aA7n9vYnKRdZGKCSGis,10913
21
+ deeptrade/core/paths.py,sha256=_6AUIIADkMx2SrjMgu9YXPVT2Jj2-0UJSwOMabtxSws,1246
22
+ deeptrade/core/plugin_manager.py,sha256=qcNYYoWMPj2EE6exiGk80rMbKBY3s3Mj-lBNwKZdr_8,25267
23
+ deeptrade/core/run_status.py,sha256=QHr0Kk9x32K6qZ9bOudPEzzrbf9VX-fptkYjU7j2BGM,798
24
+ deeptrade/core/secrets.py,sha256=UEeqMAn688EoaqKcGXoNgNcXHjnuTl-_aN1p0lGN49s,5964
25
+ deeptrade/core/tushare_client.py,sha256=NNBjL4lCemhppef_vIecGUUk6UoH-1b77tG6vBJcfS0,31529
26
+ deeptrade/core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ deeptrade/core/migrations/core/20260427_001_init.sql,sha256=KT8-WSpDw97bDLbHcXWpL3kjg2rRGGBAMapKJb4p5-k,4725
28
+ deeptrade/core/migrations/core/20260501_002_drop_llm_calls_stage.sql,sha256=Gsj39v2LuKp2k_Gh-kNqhY31iLYMuCXqZjHDWOBPlRI,512
29
+ deeptrade/core/migrations/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ deeptrade/plugins_api/__init__.py,sha256=QNaWFsHoxuXlhfQanhRU80EpDYc4kQUngRFqcmw60I4,1334
31
+ deeptrade/plugins_api/base.py,sha256=VfHT0EYOY1hzJRniSWMCq32qBj77k1nLGd4yQI_fk98,2538
32
+ deeptrade/plugins_api/channel.py,sha256=Tc6KqPiwhdLyBxEcfkaeOo7aQZ3NWqxgxNtXLJL141E,1638
33
+ deeptrade/plugins_api/events.py,sha256=FVsRmZFsWW-JggnYfbsekQmjmJz9qN4UtoATlCGb1Gc,2013
34
+ deeptrade/plugins_api/llm.py,sha256=wqpblcwsz3UYbDFFlGqhVnADX0PfW_rFgJuK3vtwlvk,1726
35
+ deeptrade/plugins_api/metadata.py,sha256=IH3zz_N-sYLlIXlWT87ih4Cy7_JAUJGlKyKQU0LpmyM,2948
36
+ deeptrade/plugins_api/notify.py,sha256=TMNY6Q_XqW55KV5x_SDEdpGVq_oUh5c0uzzQh7qXul8,1997
37
+ deeptrade/strategies_builtin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ deeptrade/strategies_builtin/limit_up_board/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ deeptrade/strategies_builtin/limit_up_board/deeptrade_plugin.yaml,sha256=PPgili7BaZ3UfNWwAofZ8v0fTnVecjUuVaWuXoRuCw8,3431
40
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/calendar.py,sha256=ODf4Minli8bLyfft_GJX6AaU4cyj_OPLY4GOSWEbKrg,2822
42
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/cli.py,sha256=jFP8qQ9-kDvee3ZWEsEK8jPLZiW911kRZAwc6vBpRsg,9088
43
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/config.py,sha256=cKr76418ZjoDaOvd--FO-NW9CZF4m4r4vQKIgxGpvVY,2476
44
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/data.py,sha256=oqx1gju_DJZTgq3R1ODbR6DWDznTka810sz0ZBx22O0,43535
45
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/pipeline.py,sha256=17ZsSirl_tosVaXKPrNPcXfOr01DBSpdb7pY0KQmxgo,29324
46
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/plugin.py,sha256=jsbzg3AqNkec_zP8Yywn6FLI9u1hIDzRRFYCp-gUDyU,943
47
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/profiles.py,sha256=_pOMF-vwmlGP34EP7ZheYxAj9rmy4fFO7CfhpqmMgFg,3088
48
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/prompts.py,sha256=sRIDZOPnIyhAHlynnfcwA8WJQ5KGWuri9hRDIHNsom8,20980
49
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/render.py,sha256=OEyajTi2EWQWMKWr7DXFuC7wQLIo5dcO6jaZ74-WCVM,34632
50
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/runner.py,sha256=cc8ojhC4QsB9yVDrTh_juXQu55R-kTlu5BIGFpuW1Xo,42317
51
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/runtime.py,sha256=x11CetwK_SByShVdseGKMcexYJs14VMAM9wktscIOO4,6105
52
+ deeptrade/strategies_builtin/limit_up_board/limit_up_board/schemas.py,sha256=1MbiqvLkNWMH0U578cha0V5mUvJY05RvXY0OYuUFWB8,6577
53
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260430_001_init.sql,sha256=YAlGUkJVSEgxX80Fi4FoKRYfH1GAPbAENhmV3fKIFMM,5441
54
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260501_002_lub_stage_results_llm_provider.sql,sha256=nbkkeKeGmEtp-jehQ7gGNX-UC9JHElPXvUkYc1xBaQ8,468
55
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260508_001_lub_lhb_tables.sql,sha256=EuMvoHiHTBt9MGRWRqI-NF2yk38AU0Jp0oIlHJtJfw0,1142
56
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260508_002_lub_cyq_perf.sql,sha256=VVgWnmxfaucr4CbfrFmPml2IbQG3alNWV5am8bVmV3I,609
57
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260508_003_lub_lhb_pk_fix.sql,sha256=pe-vk_E5kTFhDi0O57I7sAhGoK7HKAFYm5HWZpRD8Yc,1625
58
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260508_004_lub_lhb_drop_pk.sql,sha256=GSg3qojzG5hVddc4QKUWcZz2kq4b4NzkR_zZjQ3gZn8,1997
59
+ deeptrade/strategies_builtin/limit_up_board/migrations/20260508_005_lub_config.sql,sha256=WXHwZmbulqI6UpcpDovHJdq2Heu7ZKWJJavMJtiESjw,811
60
+ deeptrade/strategies_builtin/volume_anomaly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ deeptrade/strategies_builtin/volume_anomaly/deeptrade_plugin.yaml,sha256=T1WHuuluBqABtzOpWdZVmjuymmZE900jTu0S6hXgdaw,1886
62
+ deeptrade/strategies_builtin/volume_anomaly/migrations/20260430_001_init.sql,sha256=Ynh8nvZh0N3WBUtlb8wxD14TndnR3-pw3DsDWcMhvV8,3413
63
+ deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_001_realized_returns.sql,sha256=2isagPuHwiYSJMfvsE3p6Vvx0nTbMuq3Om4WK4u5kxw,1938
64
+ deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_002_dimension_scores.sql,sha256=X8U7xN5km4hDNwFLT2yahytBeBc_28jcyfy1axSitbk,746
65
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/calendar.py,sha256=y42-8SHlju5Ewhjrb2FQe7YDp4NLOkXuDoW1vOvoo18,2032
67
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/cli.py,sha256=_BweAIGsGhPKP-8VI5peb73TI4KvDONDWSr3aCO57-c,8186
68
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/data.py,sha256=mfFDY5aH0Pom55ENTAgT0YhT44xAuW1dSNhi_ybVyhI,87298
69
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/pipeline.py,sha256=7HscVxXW36g3EUWGPPxzSXNyHtVpCmLTNAZ74B9YjUs,11392
70
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/plugin.py,sha256=QLU_nDTk7NninXP2n9VKlMfBKzuUQdZuwXVaAyoNVCo,636
71
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/profiles.py,sha256=JU9o9xCiR9fJaVkoTa2QX3YHcPm12FertMT76v6T0zU,1597
72
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts.py,sha256=IGqr2rvU9USkQ7R3xsZn_J2QoHxmFfEvZepHVKB2CL8,9528
73
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts_examples.py,sha256=8jvPD3b7hDZgjG-F9jpdercm_lx5Q7fqBvy4yjRY37g,3891
74
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/render.py,sha256=WCupH4g1-efXEsfQaHkdwV5yTMlkvCc8L8qSis6jCbw,37606
75
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runner.py,sha256=4y1am3vTGN73gfqwwa-6Od00yyaQxqoGwFw-0KLg8m4,29182
76
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runtime.py,sha256=2cVPeCMPqE_PW6KxG_6nZesoL-SG-bZNxJDd_gYFxwA,2833
77
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/schemas.py,sha256=M9misDOqVySxLLvwxSm82OMhNIjdvQm3bIMHjh1_0Yg,3866
78
+ deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/stats.py,sha256=0JFZX0vGrv6Q0DGVwSdrBS01Xuo6p9Gi4iexobmt8g0,6378
79
+ deeptrade_quant-0.0.2.dist-info/METADATA,sha256=k2LduW1rZtBevQwl1jPQsYh9I16r6zuv_FvHP0tBWis,8954
80
+ deeptrade_quant-0.0.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
81
+ deeptrade_quant-0.0.2.dist-info/entry_points.txt,sha256=q2HmNNJeCHq4077h3hpaup7iRX8v-7Y5w0DyKqPJTDw,48
82
+ deeptrade_quant-0.0.2.dist-info/licenses/LICENSE,sha256=4891GSu2Y0gASDZdYvpB5-YX4xP40YAk1HW4ENiIo0c,1066
83
+ deeptrade_quant-0.0.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any