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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ It is an execution layer, not a strategy research repository. Strategy logic com
- Handles broker/API connectivity, dry-run checks, notifications, and deployment settings.
- Must keep credentials in GitHub Secrets, cloud secret stores, or the broker-specific secret system, never in Git.
- Should start with dry-run or paper mode before any live order path is enabled.
- The account new-risk gate consumes an explicit account snapshot first and the
current portfolio status second. It does not derive production drift from a
shared research PerformanceStore: absent optional drift is not fabricated,
while missing required account inputs and review, critical, or invalid
evidence remain fail-closed for new buys.

`GET /account-snapshot` is a separate, read-only diagnostic and stays disabled
unless `LONGBRIDGE_ACCOUNT_SNAPSHOT_ENABLED=true` is set exactly. It returns
Expand Down
39 changes: 0 additions & 39 deletions application/account_new_risk_gate_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,45 +127,6 @@ def _resolve_production_drift_status(portfolio: Mapping[str, Any], projection: M
return str(raw).strip()


def maybe_inject_production_drift_status(
portfolio: Mapping[str, Any],
*,
strategy_profile: str | None,
domain: str | None,
store=None,
) -> dict[str, Any]:
"""Return a shallow-copied portfolio with production_drift_status filled from store when absent.

Explicit account_new_risk_snapshot.production_drift_status or portfolio.production_drift_status wins.
Missing profile/domain, parked store, or any exception → leave unchanged (omit; never invent CRITICAL).
Never optimizes or grants live.
"""
out = dict(portfolio)
projection = dict(out.get("account_new_risk_snapshot") or {})
if _resolve_production_drift_status(out, projection) is not None:
return out
profile = str(strategy_profile or "").strip() or None
domain_key = str(domain or "").strip() or None
if not profile or not domain_key:
return out
try:
from quant_platform_kit.risk.production_drift_new_risk import (
resolve_production_drift_status_from_store,
)

status = resolve_production_drift_status_from_store(
strategy_profile=profile,
domain=domain_key,
store=store,
)
except Exception:
return out
if status:
projection["production_drift_status"] = status
out["account_new_risk_snapshot"] = projection
return out


def build_snapshot_from_portfolio(
portfolio: Mapping[str, Any],
*,
Expand Down
23 changes: 0 additions & 23 deletions application/rebalance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,29 +952,6 @@ def submit_claimed_order(order_intent):
_lot_sizes = fetch_lot_sizes(quote_context, _candidates)
except Exception:
_lot_sizes = {}
from application.account_new_risk_gate_support import maybe_inject_production_drift_status
from strategy_registry import LONGBRIDGE_PLATFORM, resolve_strategy_definition

domain = ""
metadata = portfolio.get("metadata") if isinstance(portfolio, dict) else None
if isinstance(metadata, dict):
domain = str(metadata.get("strategy_domain") or "").strip()
if not domain:
try:
domain = str(
resolve_strategy_definition(
getattr(config, "strategy_profile", None),
platform_id=LONGBRIDGE_PLATFORM,
).domain
or ""
)
except Exception:
domain = ""
portfolio = maybe_inject_production_drift_status(
portfolio,
strategy_profile=getattr(config, "strategy_profile", None),
domain=domain or None,
)
execution_result = execute_rebalance_cycle(
trade_context=trade_context,
plan=plan,
Expand Down
84 changes: 23 additions & 61 deletions tests/test_account_new_risk_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
build_account_new_risk_snapshot,
build_snapshot_from_portfolio,
evaluate_portfolio_new_risk_admission,
maybe_inject_production_drift_status,
new_risk_buy_prohibited,
set_cycle_snapshot,
)
Expand Down Expand Up @@ -100,77 +99,40 @@ def test_production_drift_critical_prohibits_new_risk(self) -> None:
self.assertEqual(result.disposition, NewRiskDisposition.NEW_RISK_PROHIBITED)
self.assertIn("PRODUCTION_DRIFT_CRITICAL", result.reason_codes)

def test_invalid_production_drift_status_prohibits_new_risk(self) -> None:
result = evaluate_portfolio_new_risk_admission(
{
"total_strategy_equity": 50_000.0,
"account_new_risk_snapshot": {"production_drift_status": "historical_simulation"},
}
)
self.assertEqual(result.disposition, NewRiskDisposition.NEW_RISK_PROHIBITED)

def test_absent_production_drift_status_still_allows_when_healthy(self) -> None:
portfolio = {"total_strategy_equity": 50_000.0}
result = evaluate_portfolio_new_risk_admission(portfolio)
self.assertEqual(result.disposition, NewRiskDisposition.ALLOW_NEW_RISK)

def test_maybe_inject_fills_production_drift_from_store_resolver(self) -> None:
portfolio = {"total_strategy_equity": 50_000.0}
with patch(
"quant_platform_kit.risk.production_drift_new_risk.resolve_production_drift_status_from_store",
return_value="review",
):
injected = maybe_inject_production_drift_status(
portfolio,
strategy_profile="demo_profile",
domain="us_equity",
)
self.assertEqual(
injected["account_new_risk_snapshot"]["production_drift_status"],
"review",
)
result = evaluate_portfolio_new_risk_admission(injected)
self.assertEqual(result.disposition, NewRiskDisposition.NEW_RISK_PROHIBITED)
self.assertIn("PRODUCTION_DRIFT_REVIEW", result.reason_codes)

def test_maybe_inject_does_not_overwrite_explicit_status(self) -> None:
def test_explicit_snapshot_status_wins_over_portfolio_status(self) -> None:
portfolio = {
"total_strategy_equity": 50_000.0,
"account_new_risk_snapshot": {"production_drift_status": "critical"},
"production_drift_status": "review",
}
with patch(
"quant_platform_kit.risk.production_drift_new_risk.resolve_production_drift_status_from_store",
return_value="review",
) as resolve:
injected = maybe_inject_production_drift_status(
portfolio,
strategy_profile="demo_profile",
domain="us_equity",
)
resolve.assert_not_called()
self.assertEqual(
injected["account_new_risk_snapshot"]["production_drift_status"],
"critical",
)
snapshot = build_snapshot_from_portfolio(portfolio)
self.assertEqual(snapshot.production_drift_status, "critical")
self.assertTrue(new_risk_buy_prohibited(evaluate_portfolio_new_risk_admission(portfolio)))

def test_maybe_inject_leaves_absent_when_resolver_returns_none(self) -> None:
portfolio = {"total_strategy_equity": 50_000.0}
with patch(
"quant_platform_kit.risk.production_drift_new_risk.resolve_production_drift_status_from_store",
return_value=None,
):
injected = maybe_inject_production_drift_status(
portfolio,
strategy_profile="demo_profile",
domain="us_equity",
)
self.assertNotIn("account_new_risk_snapshot", injected)
result = evaluate_portfolio_new_risk_admission(injected)
self.assertEqual(result.disposition, NewRiskDisposition.ALLOW_NEW_RISK)
def test_portfolio_status_is_used_when_snapshot_omits_it(self) -> None:
portfolio = {"total_strategy_equity": 50_000.0, "production_drift_status": "review"}
snapshot = build_snapshot_from_portfolio(portfolio)
self.assertEqual(snapshot.production_drift_status, "review")
self.assertTrue(new_risk_buy_prohibited(evaluate_portfolio_new_risk_admission(portfolio)))

def test_maybe_inject_leaves_absent_when_resolver_raises(self) -> None:
portfolio = {"total_strategy_equity": 50_000.0}
with patch(
"quant_platform_kit.risk.production_drift_new_risk.resolve_production_drift_status_from_store",
side_effect=RuntimeError("store unavailable"),
):
injected = maybe_inject_production_drift_status(
portfolio,
strategy_profile="demo_profile",
domain="us_equity",
)
self.assertNotIn("account_new_risk_snapshot", injected)
def test_rebalance_service_has_no_research_store_drift_injection(self) -> None:
source = (ROOT / "application" / "rebalance_service.py").read_text(encoding="utf-8")
self.assertNotIn("maybe_inject_production_drift_status", source)
self.assertNotIn("resolve_production_drift_status_from_store", source)

def test_unknown_pending_orders_prohibits_new_risk(self) -> None:
portfolio = {"total_strategy_equity": 50_000.0, "unknown_pending_orders": True}
Expand Down
6 changes: 5 additions & 1 deletion tests/test_rebalance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,12 @@ def record_marker(self, *_args, **_kwargs):
notify_no_trade_cycles=False,
)

result = rebalance_service.run_strategy(runtime=runtime, config=config)
with patch(
"quant_platform_kit.risk.production_drift_new_risk.resolve_production_drift_status_from_store"
) as resolver:
result = rebalance_service.run_strategy(runtime=runtime, config=config)

resolver.assert_not_called()
self.assertEqual(result.dry_run_orders, ())
self.assertEqual(observed["submit"], 0)
self.assertEqual(observed["notify"], 0)
Expand Down