Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Check QPK pin consistency
run: |
set -euo pipefail
QPK_EXPECTED_PIN=a90937621a7a05c9f72d0ca8a29be3fcb18a327c uv run --no-sync python scripts/check_qpk_pin_consistency.py
QPK_EXPECTED_PIN=0f2fde65023906f9f813fd1149a8dd6fbadbdd7f uv run --no-sync python scripts/check_qpk_pin_consistency.py

- name: Ensure uv.lock matches pyproject.toml
run: uv lock --check
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dependencies = [
"google-cloud-secret-manager",
"google-cloud-storage",
"yfinance",
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@a90937621a7a05c9f72d0ca8a29be3fcb18a327c",
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@0f2fde65023906f9f813fd1149a8dd6fbadbdd7f",
"us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@4a3943883cd6b5bbfe32a559e56a91b40a81b7ce",
"hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@709e5e1cde7841aed538d94eb26b552b46cb7806",
]
Expand Down Expand Up @@ -64,5 +64,5 @@ include = [

[tool.uv]
override-dependencies = [
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@a90937621a7a05c9f72d0ca8a29be3fcb18a327c",
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@0f2fde65023906f9f813fd1149a8dd6fbadbdd7f",
]
2 changes: 1 addition & 1 deletion qsl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ upgrade_ring = "ring_d"
allow_legacy = false

[qsl.requires]
quant_platform_kit = "a90937621a7a05c9f72d0ca8a29be3fcb18a327c"
quant_platform_kit = "0f2fde65023906f9f813fd1149a8dd6fbadbdd7f"
us_equity_strategies = "4a3943883cd6b5bbfe32a559e56a91b40a81b7ce"
hk_equity_strategies = "709e5e1cde7841aed538d94eb26b552b46cb7806"

Expand Down
46 changes: 46 additions & 0 deletions strategy_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,45 @@ def _parse_small_account_hold_policy(raw: Any) -> SmallAccountRiskHoldPolicy | N
return None


def _verified_nav_from_capabilities(capabilities: Mapping[str, Any]) -> float | None:
capital_base = capabilities.get("capital_base")
if capital_base is None:
return None
try:
nav = float(getattr(capital_base, "target_equity"))
except (TypeError, ValueError, AttributeError):
return None
if nav <= 0.0:
return None
return nav


def _portfolio_weight_map_from_snapshot(
portfolio_snapshot: Any,
*,
verified_nav: float | None,
) -> dict[str, float] | None:
if portfolio_snapshot is None or verified_nav is None or verified_nav <= 0.0:
return None
positions = getattr(portfolio_snapshot, "positions", None)
if positions is None:
return None
weights: dict[str, float] = {}
try:
for position in positions:
symbol = str(getattr(position, "symbol", "") or "").strip().upper()
try:
market_value = float(getattr(position, "market_value"))
except (TypeError, ValueError, AttributeError):
continue
if not symbol or market_value <= 0.0:
continue
weights[symbol] = weights.get(symbol, 0.0) + market_value / verified_nav
except TypeError:
return None
return weights or None


def _installed_ues_revision() -> str | None:
"""Read the VCS revision of the installed UES distribution."""
candidates: list[str] = []
Expand Down Expand Up @@ -534,6 +573,13 @@ def _build_runtime_risk_capabilities(
"runtime_risk_limits": object(),
}, "unavailable:small_account_hold_cash_only"
capability_payload["small_account_hold_policy"] = hold_policy
# Always expose book weights for default/opt-in hold non-worsening checks.
current_weights = _portfolio_weight_map_from_snapshot(
snapshot,
verified_nav=_verified_nav_from_capabilities(capabilities),
)
if current_weights is not None:
capability_payload["current_portfolio_weights"] = current_weights
return capability_payload, "verified:runtime_risk_limits"

def _build_context_capabilities(
Expand Down
6 changes: 3 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.