Files
NexQuant/rdagent/scenarios/qlib/quant_loop_factory.py
T
TPTBusiness cbe1c52e00 refactor: rename project from Predix to NexQuant
Rename all source files, scripts, tests, documentation, and configuration
from Predix/predix to NexQuant/nexquant across the entire codebase.
2026-05-09 17:48:22 +02:00

133 lines
3.7 KiB
Python

"""
NexQuant Quant Loop Factory - Selects appropriate workflow based on available components.
This module is the entry point for the quantitative trading loop.
It automatically selects between:
1. Standard Loop (Open Source) - Factor generation + backtesting
2. Advanced Loop (Local/Closed Source) - Full ML pipeline with portfolio & strategy
The selection is based on:
- Availability of local components (ml_trainer, portfolio_optimizer)
- Number of valid factors (threshold: 5000 for advanced loop)
Usage:
from rdagent.scenarios.qlib.quant_loop_factory import create_quant_loop
loop = create_quant_loop(scenario)
loop.run()
"""
from pathlib import Path
from typing import Optional
from rdagent.log import rdagent_logger as logger
# Threshold for advanced loop activation
ADVANCED_LOOP_FACTOR_THRESHOLD = 5000
def has_local_components() -> bool:
"""
Check if local (closed source) components are available.
Returns True if:
- rdagent/scenarios/qlib/local/ml_trainer.py exists
- rdagent/scenarios/qlib/local/portfolio_optimizer.py exists
"""
local_dir = Path(__file__).parent / "local"
if not local_dir.exists():
return False
required_files = [
"ml_trainer.py",
"portfolio_optimizer.py",
]
for fname in required_files:
if not (local_dir / fname).exists():
return False
return True
def count_valid_factors() -> int:
"""
Count the number of valid (successful) factors in results/factors/.
Returns
-------
int
Number of valid factors
"""
import json
from glob import glob
project_root = Path(__file__).parent.parent.parent.parent
factors_dir = project_root / "results" / "factors"
if not factors_dir.exists():
return 0
count = 0
for json_file in glob(str(factors_dir / "*.json")):
try:
with open(json_file) as f:
data = json.load(f)
if data.get("status") == "success" and data.get("ic") is not None:
count += 1
except Exception:
logger.warning("Failed to load factor file %s", json_file, exc_info=True)
continue
return count
def create_quant_loop(scenario) -> "BaseQuantLoop":
"""
Create the appropriate QuantLoop based on available components.
Priority:
1. Advanced Loop (if local components exist AND 5000+ factors)
2. Standard Loop (always available)
Parameters
----------
scenario : Scenario
The trading scenario
Returns
-------
BaseQuantLoop
The appropriate quant loop instance
"""
local_available = has_local_components()
factor_count = count_valid_factors()
logger.info(
f"Quant Loop Factory: local_components={local_available}, "
f"valid_factors={factor_count}, threshold={ADVANCED_LOOP_FACTOR_THRESHOLD}"
)
if local_available and factor_count >= ADVANCED_LOOP_FACTOR_THRESHOLD:
logger.info("Creating AdvancedQuantLoop (ML + Portfolio + Strategy)")
from rdagent.scenarios.qlib.local.quant_loop_advanced import AdvancedQuantLoop
return AdvancedQuantLoop(scenario)
else:
if not local_available:
logger.info("Local components not found — using StandardQuantLoop")
else:
logger.info(
f"Only {factor_count}/{ADVANCED_LOOP_FACTOR_THRESHOLD} factors — "
f"using StandardQuantLoop (need {ADVANCED_LOOP_FACTOR_THRESHOLD - factor_count} more)"
)
from rdagent.app.qlib_rd_loop.quant import QuantRDLoop
return QuantRDLoop
# Base class for type hints
class BaseQuantLoop:
"""Base class for quant loops."""
pass