-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstrategy_registry.py
More file actions
219 lines (190 loc) · 8.54 KB
/
Copy pathstrategy_registry.py
File metadata and controls
219 lines (190 loc) · 8.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
from __future__ import annotations
from us_equity_strategies import (
get_platform_runtime_adapter as get_us_platform_runtime_adapter,
get_runtime_enabled_profiles as get_us_runtime_enabled_profiles,
get_strategy_catalog as get_us_strategy_catalog,
)
from us_equity_strategies.runtime_adapters import (
describe_platform_runtime_requirements as describe_us_platform_runtime_requirements,
)
from hk_equity_strategies import (
get_platform_runtime_adapter as get_hk_platform_runtime_adapter,
get_runtime_enabled_profiles as get_hk_runtime_enabled_profiles,
get_strategy_catalog as get_hk_strategy_catalog,
)
from hk_equity_strategies.runtime_adapters import (
describe_platform_runtime_requirements as describe_hk_platform_runtime_requirements,
)
from quant_platform_kit.common.strategies import (
PlatformCapabilityMatrix,
PlatformStrategyPolicy,
StrategyCatalog,
StrategyDefinition,
StrategyMetadata,
US_EQUITY_DOMAIN,
build_platform_profile_matrix,
build_platform_profile_status_matrix,
derive_enabled_profiles_for_platform,
derive_eligible_profiles_for_platform,
get_catalog_strategy_metadata,
get_enabled_profiles_for_platform,
resolve_platform_strategy_definition,
)
LONGBRIDGE_PLATFORM = "longbridge"
HK_EQUITY_DOMAIN = "hk_equity"
TECH_COMMUNICATION_PULLBACK_PROFILE = "tech_communication_pullback_enhancement"
HK_DIVIDEND_GOLD_DEFENSIVE_ROTATION_PROFILE = "hk_dividend_gold_defensive_rotation"
PLATFORM_SUPPORTED_DOMAINS: dict[str, frozenset[str]] = {
LONGBRIDGE_PLATFORM: frozenset({US_EQUITY_DOMAIN, HK_EQUITY_DOMAIN}),
}
def _merge_strategy_catalogs(*catalogs: StrategyCatalog) -> StrategyCatalog:
definitions: dict[str, StrategyDefinition] = {}
metadata: dict[str, StrategyMetadata] = {}
compatible_platforms: dict[str, frozenset[str]] = {}
profile_aliases: dict[str, str] = {}
for catalog in catalogs:
for profile, definition in catalog.definitions.items():
if profile in definitions and definitions[profile] != definition:
raise ValueError(f"Duplicate strategy definition for profile {profile!r}")
definitions[profile] = definition
for profile, value in catalog.metadata.items():
if profile in metadata and metadata[profile] != value:
raise ValueError(f"Duplicate strategy metadata for profile {profile!r}")
metadata[profile] = value
for profile, platforms in catalog.compatible_platforms.items():
if profile in compatible_platforms and compatible_platforms[profile] != platforms:
raise ValueError(f"Duplicate strategy platform compatibility for profile {profile!r}")
compatible_platforms[profile] = platforms
for alias, profile in catalog.profile_aliases.items():
if alias in profile_aliases and profile_aliases[alias] != profile:
raise ValueError(f"Duplicate strategy alias {alias!r}")
profile_aliases[alias] = profile
return StrategyCatalog(
definitions=definitions,
metadata=metadata,
compatible_platforms=compatible_platforms,
profile_aliases=profile_aliases,
)
def _canonical_profile(profile: str | None) -> str:
normalized = str(profile or "").strip().lower()
return STRATEGY_CATALOG.profile_aliases.get(normalized, normalized)
def get_platform_runtime_adapter(profile: str | None, *, platform_id: str):
canonical_profile = _canonical_profile(profile)
if canonical_profile in HK_STRATEGY_PROFILES:
return get_hk_platform_runtime_adapter(canonical_profile, platform_id=platform_id)
return get_us_platform_runtime_adapter(canonical_profile, platform_id=platform_id)
def describe_platform_runtime_requirements(profile: str | None, *, platform_id: str) -> dict[str, object]:
canonical_profile = _canonical_profile(profile)
if canonical_profile in HK_STRATEGY_PROFILES:
return describe_hk_platform_runtime_requirements(canonical_profile, platform_id=platform_id)
return describe_us_platform_runtime_requirements(canonical_profile, platform_id=platform_id)
US_STRATEGY_CATALOG = get_us_strategy_catalog()
HK_STRATEGY_CATALOG = get_hk_strategy_catalog()
STRATEGY_CATALOG = _merge_strategy_catalogs(US_STRATEGY_CATALOG, HK_STRATEGY_CATALOG)
US_STRATEGY_PROFILES = frozenset(US_STRATEGY_CATALOG.definitions)
HK_STRATEGY_PROFILES = frozenset(HK_STRATEGY_CATALOG.definitions)
LONGBRIDGE_EXCLUDED_LIVE_PROFILES = frozenset(
{
HK_DIVIDEND_GOLD_DEFENSIVE_ROTATION_PROFILE,
TECH_COMMUNICATION_PULLBACK_PROFILE,
}
)
LONGBRIDGE_ROLLOUT_ALLOWLIST = (
get_us_runtime_enabled_profiles() | get_hk_runtime_enabled_profiles()
) - LONGBRIDGE_EXCLUDED_LIVE_PROFILES
PLATFORM_CAPABILITY_MATRIX = PlatformCapabilityMatrix(
platform_id=LONGBRIDGE_PLATFORM,
supported_domains=PLATFORM_SUPPORTED_DOMAINS[LONGBRIDGE_PLATFORM],
supported_target_modes=frozenset({"weight", "value"}),
supported_inputs=frozenset(
{
"benchmark_history",
"market_history",
"portfolio_snapshot",
"derived_indicators",
"feature_snapshot",
"indicators",
"account_state",
"snapshot",
"russell_snapshot",
"current_holdings",
"market_data",
}
),
# LongPort API enforces quantity ≥ 1 (regex ``^([1-9]\d*(\.\d+)?)$``).
# Fractional / notional orders are NOT natively supported.
# DCA profiles (ibit_smart_dca, nasdaq_sp500_smart_dca, etc.) run in
# **compat mode**: each notional buy is converted to a minimum 1‑share
# (US) or 1‑lot (HK) order. Orders below one unit price are deferred.
# Paper-verified 2026-06-29.
supported_capabilities=frozenset(),
)
_STRUCTURALLY_ELIGIBLE_STRATEGY_PROFILES = derive_eligible_profiles_for_platform(
STRATEGY_CATALOG,
capability_matrix=PLATFORM_CAPABILITY_MATRIX,
runtime_adapter_loader=lambda profile: get_platform_runtime_adapter(
profile,
platform_id=LONGBRIDGE_PLATFORM,
),
) - LONGBRIDGE_EXCLUDED_LIVE_PROFILES
# Keep research-only and snapshot-scaffold HK profiles out of platform switch/status output.
ELIGIBLE_STRATEGY_PROFILES = _STRUCTURALLY_ELIGIBLE_STRATEGY_PROFILES & LONGBRIDGE_ROLLOUT_ALLOWLIST
LONGBRIDGE_ENABLED_PROFILES = derive_enabled_profiles_for_platform(
STRATEGY_CATALOG,
capability_matrix=PLATFORM_CAPABILITY_MATRIX,
runtime_adapter_loader=lambda profile: get_platform_runtime_adapter(
profile,
platform_id=LONGBRIDGE_PLATFORM,
),
rollout_allowlist=LONGBRIDGE_ROLLOUT_ALLOWLIST,
)
PLATFORM_POLICY = PlatformStrategyPolicy(
platform_id=LONGBRIDGE_PLATFORM,
supported_domains=PLATFORM_SUPPORTED_DOMAINS[LONGBRIDGE_PLATFORM],
enabled_profiles=LONGBRIDGE_ENABLED_PROFILES,
default_profile="",
rollback_profile="",
require_explicit_profile=True,
)
SUPPORTED_STRATEGY_PROFILES = LONGBRIDGE_ENABLED_PROFILES
_SELECTION_ROLE_FIELDS = frozenset({"is_default", "is_rollback"})
def _without_selection_role_fields(row: dict[str, object]) -> dict[str, object]:
return {key: value for key, value in row.items() if key not in _SELECTION_ROLE_FIELDS}
def get_eligible_profiles_for_platform(platform_id: str) -> frozenset[str]:
if platform_id != LONGBRIDGE_PLATFORM:
return frozenset()
return ELIGIBLE_STRATEGY_PROFILES
def get_supported_profiles_for_platform(platform_id: str) -> frozenset[str]:
return get_enabled_profiles_for_platform(platform_id, policy=PLATFORM_POLICY)
def get_platform_profile_matrix() -> list[dict[str, object]]:
return [
_without_selection_role_fields(row)
for row in build_platform_profile_matrix(STRATEGY_CATALOG, policy=PLATFORM_POLICY)
]
def get_platform_profile_status_matrix() -> list[dict[str, object]]:
return [
_without_selection_role_fields(row)
for row in build_platform_profile_status_matrix(
STRATEGY_CATALOG,
policy=PLATFORM_POLICY,
eligible_profiles=ELIGIBLE_STRATEGY_PROFILES,
)
]
def resolve_strategy_definition(
raw_value: str | None,
*,
platform_id: str,
) -> StrategyDefinition:
return resolve_platform_strategy_definition(
raw_value,
platform_id=platform_id,
strategy_catalog=STRATEGY_CATALOG,
policy=PLATFORM_POLICY,
)
def resolve_strategy_metadata(
raw_value: str | None,
*,
platform_id: str,
) -> StrategyMetadata:
definition = resolve_strategy_definition(raw_value, platform_id=platform_id)
return get_catalog_strategy_metadata(STRATEGY_CATALOG, definition.profile)