mirror of
https://github.com/NicolasBohn/NexQuant.git
synced 2026-07-30 00:47:43 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d97d84100 | |||
| 9bc525a264 | |||
| 7cb6531c2a | |||
| 44c8af572e |
@@ -1,3 +1,3 @@
|
||||
{
|
||||
".": "1.3.10"
|
||||
".": "1.4.0"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [1.4.0](https://github.com/TPTBusiness/Predix/compare/v1.3.11...v1.4.0) (2026-05-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **optimizer:** add max_positions parameter to Optuna search space ([fdb4be3](https://github.com/TPTBusiness/Predix/commit/fdb4be3b3ebd93325e7821f4251148424184a40d))
|
||||
|
||||
## [1.3.11](https://github.com/TPTBusiness/Predix/compare/v1.3.10...v1.3.11) (2026-05-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** lazy import logger in predix.py and cli.py to avoid ImportError in test env ([60763e8](https://github.com/TPTBusiness/Predix/commit/60763e8eae34f41865ba8e5e65bdfde13b564b4b))
|
||||
|
||||
## [1.3.10](https://github.com/TPTBusiness/Predix/compare/v1.3.9...v1.3.10) (2026-05-01)
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,12 @@ load_dotenv(Path(__file__).parent / ".env")
|
||||
import typer
|
||||
from rich.console import Console
|
||||
|
||||
from rdagent.utils.env import logger
|
||||
try:
|
||||
from rdagent.utils.env import logger
|
||||
except ImportError:
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = typer.Typer(help="Predix - AI Quantitative Trading Agent")
|
||||
console = Console()
|
||||
|
||||
+6
-1
@@ -27,7 +27,12 @@ import typer
|
||||
from rich.console import Console
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from rdagent.utils.env import logger
|
||||
try:
|
||||
from rdagent.utils.env import logger
|
||||
except ImportError:
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from rdagent.app.data_science.loop import main as data_science
|
||||
from rdagent.app.finetune.llm.loop import main as llm_finetune
|
||||
|
||||
@@ -292,6 +292,7 @@ class OptunaOptimizer:
|
||||
"volatility_lookback": trial.suggest_int("volatility_lookback", 5, 500, step=5),
|
||||
"signal_bias": trial.suggest_float("signal_bias", -1.0, 1.0, step=0.05),
|
||||
"max_hold_bars": trial.suggest_int("max_hold_bars", 5, 1000, step=5),
|
||||
"max_positions": trial.suggest_int("max_positions", 1, 5, step=1),
|
||||
}
|
||||
|
||||
# Parameters that are allowed to be negative (not clamped to 0).
|
||||
@@ -308,6 +309,7 @@ class OptunaOptimizer:
|
||||
"volatility_lookback": 1.0,
|
||||
"signal_bias": -1.0,
|
||||
"max_hold_bars": 1.0,
|
||||
"max_positions": 1.0,
|
||||
}
|
||||
|
||||
def _suggest_bounded(
|
||||
@@ -357,6 +359,7 @@ class OptunaOptimizer:
|
||||
"volatility_lookback": (center.get("volatility_lookback", 100), 30),
|
||||
"signal_bias": (center.get("signal_bias", 0.0), 0.2),
|
||||
"max_hold_bars": (center.get("max_hold_bars", 100), 50),
|
||||
"max_positions": (center.get("max_positions", 1), 2),
|
||||
}
|
||||
return {key: self._suggest_bounded(trial, key, c, hw) for key, (c, hw) in ranges.items()}
|
||||
|
||||
@@ -388,6 +391,7 @@ class OptunaOptimizer:
|
||||
"volatility_lookback": (center.get("volatility_lookback", 100), 10),
|
||||
"signal_bias": (center.get("signal_bias", 0.0), 0.07),
|
||||
"max_hold_bars": (center.get("max_hold_bars", 100), 17),
|
||||
"max_positions": (center.get("max_positions", 1), 1),
|
||||
}
|
||||
return {key: self._suggest_bounded(trial, key, c, hw) for key, (c, hw) in ranges.items()}
|
||||
|
||||
@@ -467,6 +471,9 @@ class OptunaOptimizer:
|
||||
|
||||
# Max holding periods (in bars)
|
||||
"max_hold_bars": trial.suggest_int("max_hold_bars", 10, 500, step=10),
|
||||
|
||||
# Max concurrent positions (1 = no pyramiding, 2-5 = scale-in)
|
||||
"max_positions": trial.suggest_int("max_positions", 1, 5, step=1),
|
||||
}
|
||||
|
||||
return params
|
||||
@@ -597,6 +604,13 @@ class OptunaOptimizer:
|
||||
if signal_bias != 0.0:
|
||||
signal = (signal.astype(float) + signal_bias).round().astype(int).clip(-1, 1)
|
||||
|
||||
# Apply max_positions: scale signal by position_size_pct and cap exposure
|
||||
max_positions = int(params.get("max_positions", 1))
|
||||
position_size_pct = float(params.get("position_size_pct", 1.0))
|
||||
# Each "position" is position_size_pct of equity; total exposure capped at max_positions × size
|
||||
effective_size = min(position_size_pct * max_positions, 1.0)
|
||||
signal = (signal.astype(float) * effective_size).clip(-1.0, 1.0)
|
||||
|
||||
# Build a synthetic close from the factor-mean so we can route
|
||||
# through the same unified engine as every other backtest path.
|
||||
# Backtest formulas must match the orchestrator's real-OHLCV path.
|
||||
|
||||
Reference in New Issue
Block a user