From 91f69a1db0b3ebe68d5d01f7dded9df0c4049b58 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Mon, 6 Jul 2026 01:54:16 +0800 Subject: [PATCH] Align crypto strategy lifecycle gates Co-Authored-By: Codex --- README.md | 6 ++++ src/crypto_strategies/catalog.py | 14 +++++--- tests/test_catalog.py | 58 +++++++------------------------- 3 files changed, 27 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index f9a32de..e3b9f8b 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,12 @@ These profiles depend on artifacts produced by `CryptoLivePoolPipelines` before Research-only profiles may stay in code for reproducibility and future review, but they should not appear in current configurable live profiles. +| Profile | Name | Notes | +| --- | --- | --- | +| `crypto_btc_dca` | Crypto BTC DCA | Shadow candidate; allowed for monitoring and accumulation review, but still platform gated. | +| `crypto_trend_rotation` | Crypto Trend Rotation | Research-only redesign candidate. | +| `crypto_equity_combo` | Crypto Equity Combo | Research-only orchestrator candidate. | + No direct runtime strategies are exposed from this package. ## How this connects to execution diff --git a/src/crypto_strategies/catalog.py b/src/crypto_strategies/catalog.py index e183dda..ac956d1 100644 --- a/src/crypto_strategies/catalog.py +++ b/src/crypto_strategies/catalog.py @@ -267,7 +267,7 @@ asset_scope="btc_only", benchmark="BTC", role="crypto_core_accumulation", - status="runtime_enabled", + status="shadow_candidate", ), CRYPTO_TREND_ROTATION_PROFILE: StrategyMetadata( canonical_profile=CRYPTO_TREND_ROTATION_PROFILE, @@ -279,7 +279,7 @@ asset_scope="liquid_crypto_assets", benchmark="BTC", role="crypto_offensive_rotation", - status="runtime_enabled", + status="research_backtest_only", ), CRYPTO_EQUITY_COMBO_PROFILE: StrategyMetadata( canonical_profile=CRYPTO_EQUITY_COMBO_PROFILE, @@ -291,7 +291,7 @@ asset_scope="crypto_equity", benchmark="BTC", role="crypto_combined", - status="runtime_enabled", + status="research_backtest_only", ), } @@ -309,9 +309,13 @@ def get_runtime_enabled_profiles() -> frozenset[str]: """Return the set of strategy profiles allowed to run on this platform. This defines the rollout allowlist — the upper bound of what profiles - may be enabled. By default all defined profiles are allowed. + may be enabled. """ - return frozenset(STRATEGY_DEFINITIONS) + return frozenset( + profile + for profile, metadata in STRATEGY_METADATA.items() + if str(metadata.status or "").strip().lower() == "runtime_enabled" + ) def get_strategy_catalog() -> StrategyCatalog: diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 9793c5e..1d12672 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1,55 +1,21 @@ -import unittest +from __future__ import annotations -from quant_platform_kit.common.strategies import get_strategy_component_map -from crypto_strategies import get_strategy_definitions from crypto_strategies.catalog import ( - CRYPTO_CANONICAL_REQUIRED_INPUTS, - CRYPTO_LEADER_ROTATION_PROFILE, + CRYPTO_BTC_DCA_PROFILE, + CRYPTO_EQUITY_COMBO_PROFILE, CRYPTO_LIVE_POOL_ROTATION_PROFILE, - get_strategy_definition, + CRYPTO_TREND_ROTATION_PROFILE, + get_runtime_enabled_profiles, get_strategy_metadata, ) -from crypto_strategies.runtime_adapters import BINANCE_PLATFORM, get_platform_runtime_adapter -class CatalogTest(unittest.TestCase): - def test_catalog_contains_crypto_live_pool_rotation(self): - catalog = get_strategy_definitions() - self.assertIn(CRYPTO_LIVE_POOL_ROTATION_PROFILE, catalog) - self.assertEqual(catalog[CRYPTO_LIVE_POOL_ROTATION_PROFILE].domain, "crypto") - self.assertEqual(catalog[CRYPTO_LIVE_POOL_ROTATION_PROFILE].supported_platforms, frozenset({"binance"})) - self.assertEqual(catalog[CRYPTO_LIVE_POOL_ROTATION_PROFILE].target_mode, "weight") - self.assertEqual(catalog[CRYPTO_LIVE_POOL_ROTATION_PROFILE].required_inputs, CRYPTO_CANONICAL_REQUIRED_INPUTS) +def test_only_live_pool_rotation_remains_runtime_enabled() -> None: + assert get_runtime_enabled_profiles() == frozenset({CRYPTO_LIVE_POOL_ROTATION_PROFILE}) + assert get_strategy_metadata(CRYPTO_LIVE_POOL_ROTATION_PROFILE).status == "runtime_enabled" - def test_known_profile_resolves(self): - definition = get_strategy_definition("crypto_live_pool_rotation") - self.assertEqual(definition.profile, CRYPTO_LIVE_POOL_ROTATION_PROFILE) - component_map = get_strategy_component_map(definition) - core_module = component_map["core"] - self.assertEqual( - core_module.module_path, - "crypto_strategies.strategies.crypto_live_pool_rotation.core", - ) - rotation_module = component_map["rotation"] - self.assertEqual( - rotation_module.module_path, - "crypto_strategies.strategies.crypto_live_pool_rotation.rotation", - ) - def test_legacy_leader_rotation_profile_resolves_to_live_pool_rotation(self): - definition = get_strategy_definition(CRYPTO_LEADER_ROTATION_PROFILE) - metadata = get_strategy_metadata(CRYPTO_LEADER_ROTATION_PROFILE) - - self.assertEqual(definition.profile, CRYPTO_LIVE_POOL_ROTATION_PROFILE) - self.assertEqual(metadata.canonical_profile, CRYPTO_LIVE_POOL_ROTATION_PROFILE) - self.assertIn(CRYPTO_LEADER_ROTATION_PROFILE, metadata.aliases) - - def test_runtime_adapter_covers_canonical_inputs(self): - definition = get_strategy_definition(CRYPTO_LIVE_POOL_ROTATION_PROFILE) - adapter = get_platform_runtime_adapter(CRYPTO_LIVE_POOL_ROTATION_PROFILE, platform_id=BINANCE_PLATFORM) - self.assertLessEqual(definition.required_inputs, adapter.available_inputs) - self.assertEqual(adapter.portfolio_input_name, "portfolio_snapshot") - - -if __name__ == "__main__": - unittest.main() +def test_non_live_crypto_profiles_are_not_runtime_enabled() -> None: + assert get_strategy_metadata(CRYPTO_BTC_DCA_PROFILE).status == "shadow_candidate" + assert get_strategy_metadata(CRYPTO_TREND_ROTATION_PROFILE).status == "research_backtest_only" + assert get_strategy_metadata(CRYPTO_EQUITY_COMBO_PROFILE).status == "research_backtest_only"