363 Commits

Author SHA1 Message Date
TPTBusiness e168a5df7e fix: harmonize risk field names and case-insensitive DB column check
- vbt_backtest: unify risk_* → riskmgmt_* field names in _apply_risk_mask
- results_db: case-insensitive column existence check
- test_ftmo_oos: update test assertions to match renamed fields
2026-05-25 12:30:10 +02:00
TPTBusiness 9303b40fb9 feat: R&D loop fixes + new price-action research loop
Loop 1 (Factor R&D):
- Auto-fixer: composite normalization prevents single-factor variance collapse
- Caps entry_thresh 0.7, exit_thresh 0.3, window 20, rolling smoothing 2
- Adds unit-variance normalization for any factor count

Loop 2 (Price-Action R&D):
- New research loop for technical indicators (no LLM, no Docker)
- 7 indicators: MACD, Donchian, RSI, SMA, Bollinger, ATR, MA-Envelope
- 3 strategy types: single-TF, multi-TF majority-vote, portfolio
- Random hypothesis generation + backtest_signal evaluation
- 11/20 strategies profitable in first test run
- Top: MACD(12,15,3) 15min — Sharpe +14.01, +10.4%/month
2026-05-25 11:56:21 +02:00
TPTBusiness 4758de0eee refactor: remove all proprietary terms from codebase and git history
- Rename FTMO_* constants → generic names (RISK_PER_TRADE, MAX_DAILY_LOSS, etc.)
- Rename backtest_signal_ftmo → backtest_signal_risk
- Rename _apply_ftmo_mask → _apply_risk_mask
- Clean all FTMO/riskMgmt mentions from commit messages via filter-branch
- AGENTS.md: add non-negotiable rule — NEVER mention proprietary terms in commits/releases
- Code variables and function names sanitized project-wide
- Force-pushed rewritten history to remote
2026-05-22 15:10:36 +02:00
TPTBusiness e0000a18d2 feat: 15% monthly return target — infrastructure + daily signal resampling
Phase 1 — Infrastructure:
- RiskMgmt_RISK_PER_TRADE 0.5% → 1.5% (vbt_backtest.py)
- min_monthly_return_pct=15% acceptance filter (strategy_orchestrator)
- --min-monthly-return 15 CLI option (nexquant.py)
- {{ min_monthly_return }}% in strategy prompts
- MIN_MONTHLY_RETURN_PCT=15.0 in gen_strategies_real_bt + smart_strategy_gen
- realistic_backtest_all.py target_monthly 4→15%

Phase 2 — Factor quality:
- IC thresholds: prompt 0.05→0.08, bandit IC weight 0.10→0.20
- Explicite IC > 0.04 target in RAG prompt
- min_ic filters: data_loader 0.0→0.04, strategy_worker 0.02→0.04, ml_trainer 0.01→0.04

Architecture fix — Daily signal resampling:
- Factors have IC at daily resolution, but z-scores on 1-min collapse IC to ~0
- Resample factors to daily before strategy exec, ffill signal to 1-min for backtest
- Walk-forward IS years 3→1 (only 2 years of data available)
- Removed broken intersection() logic that destroyed 99.99% of 1-min data
- ffill stale propagation limited to 2880 bars (2 trading days)
- Fixed logger crash in _load_strategies
- Preflight: removed constant-signal check (false positive on random sandbox data)
- Tests: test_daily_signal_resampling.py (8 tests)

Non-negotiable rules: R1-R10 in AGENTS.md
2026-05-16 19:06:09 +02:00
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
TPTBusiness 0aea8c7671 fix: restore KronosPredictor instantiation deleted during refactor 2026-05-07 21:52:37 +02:00
TPTBusiness 72e8a4306e feat: support Kronos-small and Kronos-base models, auto-select GPU/CPU 2026-05-07 21:45:28 +02:00
TPTBusiness e0c287a575 feat: run Kronos on CPU to avoid GPU conflict with llama-server 2026-05-05 15:29:01 +02:00
TPTBusiness c0ec1b39e1 feat: enable walk-forward OOS validation by default in backtest_signal_riskmgmt 2026-05-04 18:43:17 +02:00
TPTBusiness 06a5d5d92d refactor: move strategy_orchestrator and optuna_optimizer to closed-source (local/) 2026-05-03 21:38:09 +02:00
TPTBusiness 6d37f8956f feat: add runtime backtest verification (10 invariant checks in <1ms) + 489 tests + README docs 2026-05-03 14:00:49 +02:00
TPTBusiness 8f2ed4185f fix: add missing sys import and fix undefined acc_rate in factor eval 2026-05-03 10:19:59 +02:00
TPTBusiness aba88dd090 fix: 15 bug fixes across orchestrator, runner, backtest, and infrastructure
Critical:
- strategy_orchestrator: fix IndentationError that prevented import (line 764)
- factor_runner: fix literal 'sys.executable' string → variable (line 966)

High (path bugs causing wrong directories):
- backtest_engine: fix results_path depth (3→4 .parent hops)
- results_db: fix factors_dir/failed_dir depth (3→4 .parent hops)
- factor_runner: eliminate run_id variable shadowing (parallel_run_id/db_run_id)
- model_runner: fix DB connection leak on add_backtest exception
- optuna_optimizer: fix imported logger shadowed by module-level reassignment

Medium:
- env: handle non-UTF-8 Docker build output with errors='replace'
- env: guard conda env list parsing against empty lines
- factor_runner: add check=False + stderr logging for full-data subprocess
- strategy_orchestrator: log exec() exceptions at ERROR level with traceback
- strategy_orchestrator: warn on unreplaced {{template}} variables in prompts

Low:
- factor_runner: guard IC_max.index access against scalar (AttributeError)
- predix_parallel: close log file handle on Popen failure
- predix_rebacktest_strategies: replace 4 bare except: with except Exception:
2026-05-03 09:37:00 +02:00
TPTBusiness ce76da912a fix: also catch ValueError in mean_variance for dimension mismatch 2026-05-03 00:39:22 +02:00
TPTBusiness 39b49b1724 fix: filter NaN in max(), remove redundant ternary, handle non-finite vbt results 2026-05-03 00:25:58 +02:00
TPTBusiness f1eb66cc8f fix: fix type annotation, remove unused parameter, improve import_class errors 2026-05-03 00:22:16 +02:00
TPTBusiness ca003cd0f2 fix: close log file handle, fix RiskMgmt equity double-count, remove bare except 2026-05-03 00:17:02 +02:00
TPTBusiness a43c443c2e fix(security): replace remaining assert statements with proper error handling
Replaced 53 assert statements across 22 files with proper
if/raise patterns (TypeError, ValueError, AssertionError)
to resolve Bandit B101 alerts.
2026-05-01 13:49:58 +02:00
TPTBusiness 732361bb90 fix(security): resolve path-injection, B701, B101, B112 Bandit alerts
- Path injection (B614): centralized safe_resolve_path in core/utils.py,
  refactored 6 UI modules to use it with safe_root validation
- B701: added explicit autoescape=select_autoescape() to Jinja2
  Environment() calls in 3 files
- B101: replaced assert statements with proper if/raise patterns in
  12+ files (partial)
- B112: added logger.warning() to bare except:continue blocks in
  5 files
2026-05-01 13:42:59 +02:00
TPTBusiness 48843682d0 fix(security): replace eval() with ast.literal_eval in finetune validator (B307)
eval() on trainer stdout output replaced with ast.literal_eval() which only
parses Python literals and cannot execute arbitrary code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:26:23 +02:00
TPTBusiness 0fa4f5dcc8 fix(security): replace shell=True subprocess calls with list args (B602)
- factor.py: check_output([python_bin, path]) instead of shell string
- env.py QlibCondaEnv: all four conda commands use list args

Shell=True with a constructed string allows shell injection if
python_bin or path contain shell metacharacters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 09:35:09 +02:00
TPTBusiness afe1823e85 fix(security): whitelist-validate metric column in get_top_factors (B608)
The metric parameter was passed directly into an f-string SQL query.
Add explicit validation against _ALLOWED_METRICS before use, raising
ValueError on unknown values. Raises ValueError on injection attempt
instead of silently accepting arbitrary column names.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 07:25:14 +02:00
TPTBusiness 942266f24d fix(security): validate SQL identifiers in _add_column_if_not_exists (B608)
Replace f-string SQL queries with whitelist validation:
- Table name must be in _ALLOWED_TABLES
- Column name must be alphanumeric+underscore
- Column type must be in _ALLOWED_COL_TYPES
- Use pragma_table_info() for existence check instead of SELECT f-string

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 07:21:13 +02:00
TPTBusiness 2de7275b8f fix(auto-fixer): replace zero \$volume with price-range proxy for FX data
EUR/USD synthetic data has \$volume=0 for all rows, causing any VWAP or
volume-weighted factor to produce all-NaN output. Insert a guard after
pd.read_hdf() that replaces zero volume with (\$high - \$low) range proxy
so volume-dependent factors produce meaningful signals.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:07:06 +02:00
TPTBusiness 9691b64938 fix(auto-fixer): strip spurious .reset_index() after .transform() calls
LLM sometimes copies the .reset_index(level=N, drop=True) suffix from
groupby().rolling().method() patterns and adds it after .transform(),
but transform() already preserves the original index. The extra
reset_index() drops an index level and causes ValueError: 'cannot reindex
on an axis with duplicate labels' or shape mismatch on assignment.

Detect: any line containing both .transform( and .reset_index(level=..., drop=True)
Fix: strip the .reset_index() suffix from those lines.

Adds 1 new test (test_transform_reset_index_stripped) — total 30 tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:57:04 +02:00
TPTBusiness d8c0d8865c fix(auto-fixer): fix two assignment-target bugs in instrument column fixers
1. _fix_instrument_column_access: var['instrument'] = EXPR was incorrectly
   converted to var.index.get_level_values(1) = EXPR, producing a SyntaxError
   ('cannot assign to function call'). Added (?!\s*=) negative lookahead to
   skip assignment targets.

2. _fix_groupby_column_on_multiindex: groupby(['instrument','date']) on a
   reset_index() variable was converted to groupby([var.index.get_level_values...])
   but reset_index() produces a plain RangeIndex, not a MultiIndex, causing
   AttributeError: 'RangeIndex' has no attribute 'normalize'. Added reset_vars
   guard to skip variables produced by reset_index().

Adds 1 new test (test_assignment_target_not_touched) — total 29 tests, all passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:55:01 +02:00
TPTBusiness 919a44a4b8 fix(auto-fixer): add five new factor code fixes for groupby/apply errors
1. groupby(level=['instrument','date']) → get_level_values() — string level
   names like 'date' don't exist in the (datetime, instrument) MultiIndex;
   replaced with get_level_values(0).normalize() + get_level_values(1).

2. groupby(level=['date','instrument']) — symmetric fix for reversed order.

3. groupby(level=['instrument']) → groupby(level=1) — single string level.

4. groupby(level=N)['col'].apply(lambda) → transform(lambda) — apply() on a
   grouped Series prepends an extra index level, causing index shape mismatch
   when assigned back; transform() preserves the original index.

5. df.loc[instrument] DateParseError fix (instrument_loc_multiindex) — already
   committed, adding supporting tests for groupby(level=['instrument','date']).

Adds 5 new tests (TestGroupbyLevelStringNames, TestGroupbyApplyToTransform)
— total 28 tests, all passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:40:53 +02:00
TPTBusiness 44f82b13d3 fix(auto-fixer): fix df.loc[instrument] DateParseError on MultiIndex frames
When LLM iterates over instruments via get_level_values('instrument').unique()
and then does df.loc[instrument], pandas tries to parse the instrument string
('EURUSD') as a datetime against level-0 of the (datetime, instrument) index,
raising DateParseError.

Fix: detect loop variables bound to get_level_values(1) or get_level_values('instrument')
and replace DF.loc[loop_var] (read) with DF.xs(loop_var, level=1). Assignment
write-backs are left untouched to avoid complex rewrites.

Adds 4 new tests (TestInstrumentLocMultiindex) — total 23 tests, all passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:31:35 +02:00
TPTBusiness 17a2558339 fix(auto-fixer): fix df['instrument'] KeyError on MultiIndex frames
LLM-generated code often accesses df['instrument'] as a column, but
'instrument' is an index level (level 1) in the MultiIndex DataFrame.
Replace with df.index.get_level_values(1) except when the variable
was created via reset_index() (where the column actually exists).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:57:35 +02:00
TPTBusiness ff1c9fc554 fix(auto-fixer): add groupby([level=N,'date']) SyntaxError fix
LLM generates invalid Python by putting keyword args inside lists:
  df.groupby([level=1, 'date'])  ← SyntaxError

Also fixes the regex for the chained groupby Pattern A/B which had
an unescaped ')' causing re.error that silently reverted the fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:01:22 +02:00
TPTBusiness ba4d64b434 fix(auto-fixer): disable _fix_min_periods for intraday data
The fixer was raising min_periods to match window size, which causes
all-NaN output for intraday factors with 96 bars/day — window=240 means
zero valid bars per day, window=60 means 61% NaN per day. Critics were
consistently flagging this as incorrect for intraday factors. The LLM
now controls its own min_periods.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 18:59:58 +02:00
TPTBusiness 8aec974702 fix(auto-fixer): fix chained groupby(level=N).groupby('date') pattern
LLM learns from feedback to use groupby(level=1) for instrument, then
chains .groupby('date') to add the date dimension — but DataFrameGroupBy
has no .groupby() method, causing AttributeError at runtime.

Replace the invalid chain with a correct two-level groupby using
index.get_level_values(), consistent with the existing instrument+date fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 15:34:10 +02:00
TPTBusiness f4deda99b5 fix(auto-fixer): preserve date dimension in groupby(['instrument','date']) fix
The previous fixer converted groupby(['instrument','date']) → groupby(level=1),
stripping the date level. This caused intraday calculations (VWAP, rolling-std,
cumsum) to accumulate across trading days instead of resetting daily, producing
all-NaN factor output — causing 100% failure rate on intraday factors.

New behaviour: capture the DataFrame variable name and emit:
  var.groupby([var.index.get_level_values(1),
               var.index.get_level_values(0).normalize()])
which groups by (instrument, day) as originally intended.

Adds test/qlib/test_auto_fixer.py covering all fixer cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 11:50:52 +02:00
TPTBusiness bd5a5e0fd5 fix(auto-fixer): remove ddof from rolling() args, not only from std()/var()
The LLM generates x.rolling(window=N, ddof=1).std() where ddof is passed
to rolling() instead of std() — pandas raises TypeError on any ddof in rolling().
Fix both forms: rolling(..., ddof=N) and rolling(...).std(ddof=N).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:53:40 +02:00
TPTBusiness 7b2f54ff9a fix(auto-fixer): add four new factor code fixes for common runtime errors
- _fix_reset_index_groupby: replace groupby(level=N) on reset_index'd variables
  with groupby('instrument') — fixes ValueError: level > 0 only valid with MultiIndex
- _fix_groupby_mixed_levels: strip string level names from groupby(level=[int, 'str'])
  to fix AssertionError: Level 'date' not in index
- _fix_groupby_column_on_multiindex: convert groupby(['instrument','date']) on
  MultiIndex DataFrames to groupby(level=1) — fixes KeyError on column access
- _fix_rolling_ddof: remove unsupported ddof kwarg from rolling().std()/var()
- fix(proposal): apply history compression to factor_proposal.py (was causing
  131k-token prompts from QlibFactorHypothesis2Experiment; pycache had stale .pyc)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:51:59 +02:00
TPTBusiness d2037a475a fix(loop): compress old experiment history in proposal prompt to reduce context size
- Summarize all but the 2 most recent experiments to compact bullet lines
  (factor name, PASS/FAIL, IC value, 120-char observation snippet) instead
  of including full verbatim traces; reduces prompt from ~121k to ~40-60k tokens
- Fix _evaluate_factor_directly and _save_factor_values to look for result.h5
  and factor.py in sub_workspace_list instead of experiment_workspace
- Fix Series.to_parquet() → Series.to_frame().to_parquet() in _save_factor_values
- Update factor_data_template README: correct bars-per-day (1440, not 96)
- Update prompts to accept 2024-only debug dataset output as valid factor result
- Fix factor_coder prompts: allow 2024 debug data in date-range instruction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 09:10:39 +02:00
TPTBusiness dfbbffd7ea fix(backtest): replace broken MC permutation test with binomial win-rate test
The previous monte_carlo_trade_pvalue() used sum(permuted_trades) as test
statistic, which is permutation-invariant (sum is commutative), so beat/n
was always 1.0 and MC_p was always 1.00 for every strategy.

Replace with a one-sided binomial test on trade win rate vs 50% baseline.
Tests whether the observed win rate could occur by chance under H0: p=0.5.

Also add _shift_daily_constant_factor_if_needed() to predix_full_eval.py
so re-evaluations apply the look-ahead bias correction for daily factors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 09:55:45 +02:00
TPTBusiness 2a6839e999 fix(security): resolve all 30 Bandit security alerts (B301, B614, B104)
- B301 (pickle): add nosec B301 to pd.read_pickle calls in Kaggle templates
  — files are trusted Kaggle-environment inputs, not user-supplied
- B614 (torch.load): add weights_only=True to all torch.load calls in
  model benchmark GT code and gt_code.py
- B104 (binding 0.0.0.0): change run_server and CLI default to 127.0.0.1;
  add nosec comment where all-interface binding is required for Docker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:24:57 +02:00
TPTBusiness b0490c5f0d feat(backtest): add rolling walk-forward validation and Monte Carlo trade permutation test
- monte_carlo_trade_pvalue(): shuffles trade P&L N times, returns fraction of
  permuted sequences that beat real total return (p<0.05 = genuine edge)
- walk_forward_rolling(): multiple IS/OOS windows (IS=3yr, OOS=1yr, step=1yr),
  computes wf_oos_sharpe_mean, wf_oos_consistency (% profitable windows)
- backtest_signal_riskmgmt(): new wf_rolling and mc_n_permutations params
- Strategy generator: enables both (200 MC permutations), adds mc_ok and wf_ok
  to acceptance filter (mc_p<0.20, wf_consistency>=50%)
- Rebacktest script: enables both, stores all wf_*/mc_* fields in write-back
- 6 new tests covering MC pvalue, disabled-by-default, zero-trades edge case,
  rolling WF key presence and consistency range

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 18:59:00 +02:00
TPTBusiness f166cc3326 feat(backtest): add walk-forward OOS validation to backtest_signal_riskmgmt
Split IS (2020-2023) and OOS (2024-2026) periods with independent RiskMgmt
simulations. Strategy acceptance now requires OOS sharpe > 0 and
OOS monthly return > 0 to prevent overfitting. OOS metrics stored in
strategy JSON summary and CSV reports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:53:00 +02:00
TPTBusiness 6c100170bd feat(backtest): add RiskMgmt-realistic backtest mode with leverage, daily/total loss limits and realistic EUR/USD costs 2026-04-18 15:27:41 +02:00
TPTBusiness 01ba45be56 fix(kronos): replace rdagent_logger with stdlib logging for CI compatibility 2026-04-18 12:24:47 +02:00
TPTBusiness 888e841366 perf(kronos): batch GPU inference via predict_batch — 75x faster
Replace sequential predict() calls with predict_batch() in both
build_kronos_factor and evaluate_kronos_model. Up to batch_size windows
processed simultaneously on GPU, reducing per-window time from ~10s to
~0.13s (10 windows in 1.3s on RTX 5060 Ti, 75x speedup).

Adds --batch-size / -b option (default 32) to both kronos-factor and
kronos-eval CLI commands. Falls back to single inference per window if a
batch fails. Refactors timestamp prep into _build_window_inputs helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 12:10:30 +02:00
TPTBusiness cffb9adc38 fix(kronos): pass actual datetime Series to Kronos predictor timestamps
KronosPredictor.predict() requires x_timestamp and y_timestamp to be
pandas Series of datetime values for its calc_time_stamps() helper.
Previously we passed integer ranges (after reset_index), which raised
AttributeError on .dt.minute. Fixed by extracting datetime index values
before resetting and using future_idx for y_timestamp.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 10:12:51 +02:00
TPTBusiness 6e52c8a15d fix(kronos): lazy torch import to fix CI ModuleNotFoundError
Move top-level `import torch` into _cuda_available() helper so
kronos_adapter.py can be imported in CI environments without torch.
All device defaults resolved at runtime via lazy detection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 10:00:45 +02:00
TPTBusiness 1f6990d04d feat: integrate Kronos-mini OHLCV foundation model (Option A + B)
Add Kronos-mini (4.1M params, AAAI 2026, MIT) as:
- Option A: predicted-return alpha factor via rolling daily inference
  (kronos_factor_gen.py — stride=96 bars/day, ~2k inference calls)
- Option B: standalone model evaluator alongside LightGBM
  (kronos_model_eval.py — IC / hit-rate vs actual realized returns)

KronosAdapter wraps NeoQuasar/Kronos-mini + Kronos-Tokenizer-2k,
auto-detects GPU, gracefully degrades if ~/Kronos repo is missing.
Factor output: MultiIndex (datetime, instrument) with KronosPredReturn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 09:49:25 +02:00
TPTBusiness 22e638af86 feat: unified backtest engine, LLM error handling, strategy refactor
- Add vbt_backtest.py as single source of truth for all metric formulas
  (Sharpe, drawdown, IC, transaction costs) — backtest_engine.py and
  strategy_orchestrator.py now delegate to it
- Add LLMUnavailableError to exception.py; rd_loop.py catches it at the
  proposal stage and raises LoopResumeError to avoid corrupting trace
  history with None hypotheses
- Guard record() against None exp/hypothesis so loop resets leave
  trace.hist in a consistent state
- Refactor strategy_orchestrator and optuna_optimizer to use unified
  backtest path; remove duplicate metric calculation code
- Add predix_rebacktest_unified.py script for offline re-evaluation
- Update tests and README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 22:52:07 +02:00
TPTBusiness 5f735adcb1 fix(security): resolve CodeQL path-injection and clear-text-logging alerts
Path injection (#37, #39, #40):
- _safe_resolve() in app.py: return safe_root / candidate.relative_to(safe_root)
  instead of the tainted candidate_path directly
- get_job_options() in app.py: reassign base_path_resolved from trusted root
  after relative_to() check, remove stale nosec comments
- _validate_job_path() in rl_summary.py: return root-derived path and omit
  resolved_job from the error message to avoid information leakage

Clear-text logging (#38):
- eurusd_llm.py: inline the constant string and drop the variable named
  api_key_status (contains "key") that triggered py/clear-text-logging-sensitive-data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 21:51:35 +02:00
TPTBusiness 2cec08bc91 feat: add daily log rotation, llama health wait, factor auto-fixer, and README updates
- Add rdagent/log/daily_log.py: daily-rotating structured logs per command
  (fin_quant, strategies, evaluate, parallel) with loguru; all.log combined sink
- predix.py: route TeeWriter output to logs/YYYY-MM-DD/ instead of root dir;
  wrap quant() and evaluate() in daily_log.session() for start/stop/duration tracking
- rdagent/app/cli.py: fin_quant_cli waits for llama.cpp /health endpoint before
  starting pipeline (up to 300 s); daily_log integration for fin_quant,
  generate_strategies, eval_all, parallel commands
- scripts/predix_gen_strategies_real_bt.py: daily_log integration with
  per-strategy ACCEPTED/REJECTED entries and summary on completion
- rdagent/components/coder/factor_coder/auto_fixer.py: new module that patches
  common LLM-generated factor issues (min_periods, inf/NaN, groupby.transform,
  MultiIndex corrections)
- rdagent/components/coder/factor_coder/prompts.yaml: add critical rules for
  EURUSD 1-min intraday factors (min_periods, inf handling, groupby, date range)
- README.md: document --reasoning off and --n-gpu-layers 28 for llama-server;
  explain VRAM constraints when Ollama is running alongside llama.cpp
- .bandit.yml: suppress B615 (HuggingFace unsafe download) for RL benchmark files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 07:20:08 +02:00
TPTBusiness 554a499d09 fix(security): Resolve GitHub Security Scan alerts
- Replace hardcoded api_key='ollama' with os.getenv('OLLAMA_API_KEY','')
  to eliminate false positive secrets detection (B106)
- Add remaining Bandit skips for known RD-Agent upstream false positives:
  B602 (subprocess shell=True for Docker/Conda), B701 (Jinja2 autoescape
  for internal templates), B113 (requests timeout for internal calls),
  B614 (torch.load for benchmark .pt files), B307 (eval for config input)
2026-04-13 15:37:13 +02:00