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.
- deeptrade/__init__.py +8 -0
- deeptrade/channels_builtin/__init__.py +0 -0
- deeptrade/channels_builtin/stdout/__init__.py +0 -0
- deeptrade/channels_builtin/stdout/deeptrade_plugin.yaml +25 -0
- deeptrade/channels_builtin/stdout/migrations/20260429_001_init.sql +13 -0
- deeptrade/channels_builtin/stdout/stdout_channel/__init__.py +0 -0
- deeptrade/channels_builtin/stdout/stdout_channel/channel.py +180 -0
- deeptrade/cli.py +214 -0
- deeptrade/cli_config.py +396 -0
- deeptrade/cli_data.py +33 -0
- deeptrade/cli_plugin.py +176 -0
- deeptrade/core/__init__.py +8 -0
- deeptrade/core/config.py +344 -0
- deeptrade/core/config_migrations.py +138 -0
- deeptrade/core/db.py +176 -0
- deeptrade/core/llm_client.py +591 -0
- deeptrade/core/llm_manager.py +174 -0
- deeptrade/core/logging_config.py +61 -0
- deeptrade/core/migrations/__init__.py +0 -0
- deeptrade/core/migrations/core/20260427_001_init.sql +121 -0
- deeptrade/core/migrations/core/20260501_002_drop_llm_calls_stage.sql +10 -0
- deeptrade/core/migrations/core/__init__.py +0 -0
- deeptrade/core/notifier.py +302 -0
- deeptrade/core/paths.py +49 -0
- deeptrade/core/plugin_manager.py +616 -0
- deeptrade/core/run_status.py +29 -0
- deeptrade/core/secrets.py +152 -0
- deeptrade/core/tushare_client.py +824 -0
- deeptrade/plugins_api/__init__.py +44 -0
- deeptrade/plugins_api/base.py +66 -0
- deeptrade/plugins_api/channel.py +42 -0
- deeptrade/plugins_api/events.py +61 -0
- deeptrade/plugins_api/llm.py +46 -0
- deeptrade/plugins_api/metadata.py +84 -0
- deeptrade/plugins_api/notify.py +67 -0
- deeptrade/strategies_builtin/__init__.py +0 -0
- deeptrade/strategies_builtin/limit_up_board/__init__.py +0 -0
- deeptrade/strategies_builtin/limit_up_board/deeptrade_plugin.yaml +101 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/__init__.py +0 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/calendar.py +65 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/cli.py +269 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/config.py +76 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/data.py +1191 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/pipeline.py +869 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/plugin.py +30 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/profiles.py +85 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/prompts.py +485 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/render.py +890 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/runner.py +1087 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/runtime.py +172 -0
- deeptrade/strategies_builtin/limit_up_board/limit_up_board/schemas.py +178 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260430_001_init.sql +150 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260501_002_lub_stage_results_llm_provider.sql +8 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260508_001_lub_lhb_tables.sql +36 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260508_002_lub_cyq_perf.sql +18 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260508_003_lub_lhb_pk_fix.sql +46 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260508_004_lub_lhb_drop_pk.sql +53 -0
- deeptrade/strategies_builtin/limit_up_board/migrations/20260508_005_lub_config.sql +17 -0
- deeptrade/strategies_builtin/volume_anomaly/__init__.py +0 -0
- deeptrade/strategies_builtin/volume_anomaly/deeptrade_plugin.yaml +59 -0
- deeptrade/strategies_builtin/volume_anomaly/migrations/20260430_001_init.sql +94 -0
- deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_001_realized_returns.sql +44 -0
- deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_002_dimension_scores.sql +13 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/__init__.py +0 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/calendar.py +52 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/cli.py +247 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/data.py +2154 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/pipeline.py +327 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/plugin.py +22 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/profiles.py +49 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts.py +187 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts_examples.py +84 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/render.py +906 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runner.py +772 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runtime.py +90 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/schemas.py +97 -0
- deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/stats.py +174 -0
- deeptrade/theme.py +48 -0
- deeptrade_quant-0.0.2.dist-info/METADATA +166 -0
- deeptrade_quant-0.0.2.dist-info/RECORD +83 -0
- deeptrade_quant-0.0.2.dist-info/WHEEL +4 -0
- deeptrade_quant-0.0.2.dist-info/entry_points.txt +2 -0
- 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
|
+
[](#) [](#) [](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,,
|