Skip to content

Commit 9ab2eed

Browse files
authored
Merge pull request #6 from QuantStrategyLab/codex/ues-shared-strategy-catalog
[codex] refactor shared strategy catalog access
2 parents d645d86 + 8b0c59f commit 9ab2eed

4 files changed

Lines changed: 72 additions & 116 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description = "Shared US equity strategy catalog and implementations"
99
readme = "README.md"
1010
requires-python = ">=3.11"
1111
dependencies = [
12-
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@v0.6.0",
12+
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@6e8cc058b821aea8a54015d4b39e02fbdd3dc198",
1313
]
1414

1515
[tool.setuptools]

src/us_equity_strategies/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
__all__ = [
2+
"STRATEGY_CATALOG",
23
"STRATEGY_DEFINITIONS",
34
"get_compatible_platforms",
45
"get_profile_aliases",
6+
"get_strategy_catalog",
57
"get_strategy_index_rows",
68
"get_strategy_definition",
79
"get_strategy_definitions",
@@ -14,9 +16,11 @@
1416

1517
def __getattr__(name: str):
1618
if name in {
19+
"STRATEGY_CATALOG",
1720
"STRATEGY_DEFINITIONS",
1821
"get_profile_aliases",
1922
"get_compatible_platforms",
23+
"get_strategy_catalog",
2024
"get_strategy_index_rows",
2125
"get_strategy_definition",
2226
"get_strategy_definitions",

src/us_equity_strategies/catalog.py

Lines changed: 26 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
from __future__ import annotations
22

3-
from dataclasses import dataclass
4-
53
from quant_platform_kit.common.strategies import (
4+
StrategyCatalog,
65
StrategyComponentDefinition,
76
StrategyDefinition,
7+
StrategyMetadata,
88
US_EQUITY_DOMAIN,
9+
build_strategy_catalog,
10+
build_strategy_index_rows,
11+
get_catalog_compatible_platforms,
12+
get_catalog_strategy_definition,
13+
get_catalog_strategy_metadata,
14+
normalize_profile_name as qpk_normalize_profile_name,
15+
resolve_catalog_profile,
916
)
1017

1118
GLOBAL_ETF_ROTATION_PROFILE = "global_etf_rotation"
@@ -23,20 +30,6 @@
2330
CASH_BUFFER_BRANCH_DEFAULT_PROFILE: frozenset({"ibkr"}),
2431
}
2532

26-
27-
@dataclass(frozen=True)
28-
class StrategyMetadata:
29-
canonical_profile: str
30-
display_name: str
31-
description: str
32-
aliases: tuple[str, ...] = ()
33-
cadence: str | None = None
34-
asset_scope: str | None = None
35-
benchmark: str | None = None
36-
role: str | None = None
37-
status: str | None = None
38-
39-
4033
# `supported_platforms` 仍保留为兼容镜像,避免一次性改动所有平台 runtime。
4134
# 平台真正的启用状态由各自 runtime 仓库维护;UES 这里只表达策略层兼容性。
4235
def _build_strategy_definition(
@@ -151,68 +144,45 @@ def _build_strategy_definition(
151144
for alias in metadata.aliases
152145
}
153146

147+
STRATEGY_CATALOG: StrategyCatalog = build_strategy_catalog(
148+
strategy_definitions=STRATEGY_DEFINITIONS,
149+
metadata=STRATEGY_METADATA,
150+
compatible_platforms=STRATEGY_PLATFORM_COMPATIBILITY,
151+
profile_aliases=PROFILE_ALIASES,
152+
)
153+
154154

155155
def normalize_profile_name(profile: str | None) -> str:
156-
return str(profile or "").strip().lower()
156+
return qpk_normalize_profile_name(profile)
157157

158158

159159
def resolve_canonical_profile(profile: str | None) -> str:
160-
normalized = normalize_profile_name(profile)
161-
return PROFILE_ALIASES.get(normalized, normalized)
160+
return resolve_catalog_profile(profile, strategy_catalog=STRATEGY_CATALOG)
162161

163162

164163
def get_strategy_definitions() -> dict[str, StrategyDefinition]:
165164
return dict(STRATEGY_DEFINITIONS)
166165

167166

167+
def get_strategy_catalog() -> StrategyCatalog:
168+
return STRATEGY_CATALOG
169+
170+
168171
def get_strategy_platform_compatibility_map() -> dict[str, frozenset[str]]:
169172
return dict(STRATEGY_PLATFORM_COMPATIBILITY)
170173

171174

172175
def get_compatible_platforms(profile: str) -> frozenset[str]:
173-
canonical = resolve_canonical_profile(profile)
174-
if canonical not in STRATEGY_PLATFORM_COMPATIBILITY:
175-
supported = ", ".join(sorted(STRATEGY_PLATFORM_COMPATIBILITY)) or "<none>"
176-
aliases = ", ".join(sorted(PROFILE_ALIASES)) or "<none>"
177-
raise ValueError(
178-
f"Unknown us_equity strategy profile={profile!r}; supported canonical values: {supported}; aliases: {aliases}"
179-
)
180-
return STRATEGY_PLATFORM_COMPATIBILITY[canonical]
176+
return get_catalog_compatible_platforms(STRATEGY_CATALOG, profile)
181177

182178

183179
def get_strategy_definition(profile: str) -> StrategyDefinition:
184-
canonical = resolve_canonical_profile(profile)
185-
if canonical not in STRATEGY_DEFINITIONS:
186-
supported = ", ".join(sorted(STRATEGY_DEFINITIONS)) or "<none>"
187-
aliases = ", ".join(sorted(PROFILE_ALIASES)) or "<none>"
188-
raise ValueError(
189-
f"Unknown us_equity strategy profile={profile!r}; supported canonical values: {supported}; aliases: {aliases}"
190-
)
191-
return STRATEGY_DEFINITIONS[canonical]
180+
return get_catalog_strategy_definition(STRATEGY_CATALOG, profile)
192181

193182

194183

195184
def get_strategy_index_rows() -> list[dict[str, object]]:
196-
rows: list[dict[str, object]] = []
197-
for canonical_profile in sorted(STRATEGY_METADATA):
198-
metadata = STRATEGY_METADATA[canonical_profile]
199-
definition = STRATEGY_DEFINITIONS[canonical_profile]
200-
rows.append(
201-
{
202-
"canonical_profile": metadata.canonical_profile,
203-
"display_name": metadata.display_name,
204-
"aliases": metadata.aliases,
205-
"description": metadata.description,
206-
"cadence": metadata.cadence,
207-
"asset_scope": metadata.asset_scope,
208-
"benchmark": metadata.benchmark,
209-
"role": metadata.role,
210-
"status": metadata.status,
211-
"component_names": tuple(component.name for component in definition.components),
212-
"compatible_platforms": STRATEGY_PLATFORM_COMPATIBILITY[canonical_profile],
213-
}
214-
)
215-
return rows
185+
return build_strategy_index_rows(STRATEGY_CATALOG)
216186

217187

218188

@@ -221,14 +191,7 @@ def get_strategy_metadata_map() -> dict[str, StrategyMetadata]:
221191

222192

223193
def get_strategy_metadata(profile: str) -> StrategyMetadata:
224-
canonical = resolve_canonical_profile(profile)
225-
if canonical not in STRATEGY_METADATA:
226-
supported = ", ".join(sorted(STRATEGY_METADATA)) or "<none>"
227-
aliases = ", ".join(sorted(PROFILE_ALIASES)) or "<none>"
228-
raise ValueError(
229-
f"Unknown us_equity strategy profile={profile!r}; supported canonical values: {supported}; aliases: {aliases}"
230-
)
231-
return STRATEGY_METADATA[canonical]
194+
return get_catalog_strategy_metadata(STRATEGY_CATALOG, profile)
232195

233196

234197
def get_profile_aliases() -> dict[str, str]:
Lines changed: 41 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
from __future__ import annotations
22

3-
from quant_platform_kit.common.strategies import StrategyDefinition
4-
5-
from .catalog import (
6-
get_strategy_definition,
7-
get_strategy_metadata,
8-
resolve_canonical_profile,
3+
from quant_platform_kit.common.strategies import (
4+
PlatformStrategyPolicy,
5+
StrategyDefinition,
6+
build_platform_profile_matrix as qpk_build_platform_profile_matrix,
7+
get_enabled_profiles_for_platform as qpk_get_enabled_profiles_for_platform,
8+
resolve_platform_strategy_definition as qpk_resolve_platform_strategy_definition,
99
)
1010

11+
from .catalog import STRATEGY_CATALOG
12+
1113

1214
def get_enabled_profiles_for_platform(
1315
platform_id: str,
1416
*,
1517
expected_platform_id: str,
1618
enabled_profiles: frozenset[str],
1719
) -> frozenset[str]:
18-
if platform_id != expected_platform_id:
19-
return frozenset()
20-
return enabled_profiles
20+
return qpk_get_enabled_profiles_for_platform(
21+
platform_id,
22+
policy=PlatformStrategyPolicy(
23+
platform_id=expected_platform_id,
24+
supported_domains=frozenset(),
25+
enabled_profiles=enabled_profiles,
26+
default_profile="",
27+
rollback_profile="",
28+
),
29+
)
2130

2231

2332
def build_platform_profile_matrix(
@@ -27,23 +36,16 @@ def build_platform_profile_matrix(
2736
default_profile: str,
2837
rollback_profile: str,
2938
) -> list[dict[str, object]]:
30-
rows: list[dict[str, object]] = []
31-
for profile in sorted(enabled_profiles):
32-
definition = get_strategy_definition(profile)
33-
metadata = get_strategy_metadata(profile)
34-
rows.append(
35-
{
36-
"platform": platform_id,
37-
"canonical_profile": definition.profile,
38-
"display_name": metadata.display_name,
39-
"aliases": metadata.aliases,
40-
"enabled": True,
41-
"is_default": definition.profile == default_profile,
42-
"is_rollback": definition.profile == rollback_profile,
43-
"domain": definition.domain,
44-
}
45-
)
46-
return rows
39+
return qpk_build_platform_profile_matrix(
40+
STRATEGY_CATALOG,
41+
policy=PlatformStrategyPolicy(
42+
platform_id=platform_id,
43+
supported_domains=frozenset(),
44+
enabled_profiles=enabled_profiles,
45+
default_profile=default_profile,
46+
rollback_profile=rollback_profile,
47+
),
48+
)
4749

4850

4951
def resolve_platform_strategy_definition(
@@ -56,29 +58,16 @@ def resolve_platform_strategy_definition(
5658
default_profile: str | None = None,
5759
require_explicit: bool = False,
5860
) -> StrategyDefinition:
59-
if platform_id != expected_platform_id:
60-
raise ValueError(f"Unsupported platform_id={platform_id!r}")
61-
62-
normalized = str(raw_value or "").strip()
63-
if require_explicit and not normalized:
64-
raise EnvironmentError("STRATEGY_PROFILE is required")
65-
66-
candidate = normalized or str(default_profile or "").strip()
67-
if not candidate:
68-
raise EnvironmentError("STRATEGY_PROFILE is required")
69-
70-
canonical_profile = resolve_canonical_profile(candidate)
71-
supported = ", ".join(sorted(enabled_profiles))
72-
73-
if canonical_profile not in enabled_profiles:
74-
raise ValueError(
75-
f"Unsupported STRATEGY_PROFILE={raw_value!r}; supported values: {supported}"
76-
)
77-
78-
definition = get_strategy_definition(canonical_profile)
79-
if definition.domain not in platform_supported_domains.get(platform_id, frozenset()):
80-
raise ValueError(
81-
f"Unsupported strategy domain {definition.domain!r} for platform {platform_id!r}"
82-
)
83-
84-
return definition
61+
return qpk_resolve_platform_strategy_definition(
62+
raw_value,
63+
platform_id=platform_id,
64+
strategy_catalog=STRATEGY_CATALOG,
65+
policy=PlatformStrategyPolicy(
66+
platform_id=expected_platform_id,
67+
supported_domains=platform_supported_domains.get(expected_platform_id, frozenset()),
68+
enabled_profiles=enabled_profiles,
69+
default_profile=default_profile or "",
70+
rollback_profile=default_profile or "",
71+
require_explicit_profile=require_explicit,
72+
),
73+
)

0 commit comments

Comments
 (0)