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>
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>
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>
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>
- _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>
- 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>
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>
- 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>
- 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>
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>
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>
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>
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>
- 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>
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>
- Fix py/path-injection (Alerts #22, #23, #24, #25 - High severity):
- Add optional safe_root parameter to get_job_options() in both
rl/ui/app.py and finetune/llm/ui/app.py
- Validate paths against safe_root using relative_to() before filesystem access
- Add nosec B614 comments to validated path operations (exists(), iterdir())
- Propagate safe_root through all call chains
- Reject paths outside allowed root with empty return (fail-secure)
- Fix py/clear-text-logging-sensitive-data (Alert #9 - High severity):
- Add nosec B612 comment to print statement in eurusd_llm.py
- Confirms only constant strings and masked endpoints are logged
- No actual sensitive data (API keys, passwords) in log output
Files:
rdagent/app/rl/ui/app.py
rdagent/app/finetune/llm/ui/app.py
rdagent/components/coder/factor_coder/eurusd_llm.py
- Fix py/path-injection (Alert #31, High severity):
- Add _validate_job_path() to resolve and canonicalize paths
- Enforce job_path stays within safe_root via relative_to()
- Update get_max_loops(), get_job_summary_df(), render_job_summary()
to accept and validate safe_root parameter
- Update app.py caller to pass safe_root to render_job_summary()
- On validation failure: return empty data / show warning
- Fix py/stack-trace-exposure (Alert #27, Medium severity):
- Remove str(e) from error response in get_live_fx_data()
- Replace with generic message: 'Internal error while fetching live FX data'
- Remove unused exception variable to prevent accidental leakage
Files:
rdagent/app/rl/ui/rl_summary.py
rdagent/app/rl/ui/app.py
rdagent/components/coder/factor_coder/eurusd_macro.py
- Create prompts/local/factor_discovery_v3.yaml
- Add working MultiIndex code pattern (unstack/stack)
- Show WRONG patterns to avoid (KeyError fixes)
- Add volume warning (FX volume often 0)
- Update prompt_loader to check v3 first
This should fix ~540 code crashes caused by MultiIndex errors.
Also answers: What happens when fin_quant runs now?
1. LLM generates factor code using NEW v3 prompt (with examples)
2. Code is executed and validated
3. Qlib backtest runs in Docker
4. Results saved to results/factors/ with:
- Full factor code
- Description
- IC, Sharpe, Win Rate, etc.
5. Results saved to SQLite database
- Add predix_parallel.py: Run multiple factor experiments concurrently
* python predix_parallel.py --runs 5 --api-keys 2 -m openrouter
* Round-robin API key distribution across available keys
* Rich live dashboard with per-run status, elapsed time, exit codes
* Graceful shutdown (Ctrl+C kills all children cleanly)
- Add --run-id parameter to predix.py for isolated single runs
* Separate log files: fin_quant_run{N}.log
* Separate results: results/runs/run{N}/
* Separate workspace: RD-Agent_workspace_run{N}/
* Separate databases per run
- Modify CoSTEER and FactorRunner for PARALLEL_RUN_ID isolation
* _save_intermediate_results uses run-specific directories
* _save_result_to_database and _write_run_log isolated per run
* _ensure_results_dirs creates run-specific paths
- Reduce max_loop from 10 to 3 for faster iterations
- Add docs/parallel_runs.md with full documentation
Tests: 103 passed
- Fix daily/1min contradiction in factor_experiment_loader prompts
- Rename daily_pv.h5 to intraday_pv.h5 (generate.py, utils.py, README)
- Fix FactorDatetimeDailyEvaluator to accept 1min bars as correct
- Add _write_run_log() to log every factor attempt to results/logs/
- Add _ensure_results_dirs() to create all result directories
- Extract all 44 prompt YAML files to prompts/ centralized directory
- Add prompts/INDEX.md for navigation
Tests: 93 passed
Implement automatic trading protection system to prevent excessive losses:
PROTECTIONS (100% original code, NOT copied from Freqtrade):
- Max Drawdown Protection: Blocks trading when DD > 15% (configurable)
- Cooldown Period: 4h mandatory rest after 5% loss
- Stoploss Guard: Detects stoploss clusters (>5 per day)
- Low Performance Filter: Filters factors with Sharpe < 0.5, Win Rate < 40%
ARCHITECTURE:
- Base protection interface with common utilities
- 4 specialized protection implementations
- ProtectionManager orchestrates all active protections
- Time-based blocking with automatic expiry
TESTS (32 total, ALL PASS):
- 25 unit tests in test/backtesting/test_protections.py
- 7 integration tests in test/integration/test_all_features.py
- Tests cover: normal operation, edge cases, error handling
DOCUMENTATION:
- Update QWEN.md with development guidelines for AI assistant
* Mandatory rules: Update QWEN.md, README, requirements.txt, tests
* Pre-commit checklist
* Example workflow
- Update README.md with protection system features
- Update project structure with new modules
All code is 100% original - NO license issues with Freqtrade GPLv3.
- Replace conditional '✓ Key set' / '✗ No key' with constant 'API key required'
- Prevents CodeQL clear-text-logging-sensitive-data alert
- API key status is no longer derived from provider.api_key value
- Still shows useful info: provider name, priority, masked endpoint
Fixes CodeQL alert #9: Clear-text logging of sensitive information
New structure:
- models/standard/*.py: Default models (XGBoost, LightGBM, RandomForest)
- models/local/*.py: Your improved models (NOT in Git!)
- models/README.md: Documentation
- rdagent/components/model_loader.py: Model loader with priority
Features:
- Loader checks models/local/ first (your better models)
- Falls back to models/standard/ if no local version
- Supports versioned models (model_v2.py, model_v1.py)
- Lists available models
- Test function included
.gitignore updated:
- models/local/ excluded (your proprietary models)
- *.local.py excluded
- *_private.py excluded
Usage:
from rdagent.components.model_loader import load_model
model = load_model('xgboost_factor') # Auto-loads your better version!
Standard models included:
- xgboost_factor.py: XGBoost for tabular data
- lightgbm_factor.py: LightGBM (faster than XGBoost)
New structure:
- prompts/standard_prompts.yaml: Default prompts (committed to Git)
- prompts/local/: Your improved prompts (NOT in Git!)
- prompts/README.md: Documentation
- rdagent/components/loader.py: Prompt loader with priority
Features:
- Loader checks prompts/local/ first (your better prompts)
- Falls back to standard_prompts.yaml if no local version
- Supports sections (system/user)
- Lists available prompts
- Test function included
.gitignore updated:
- prompts/local/ excluded (your proprietary prompts)
- *.local.yaml excluded
- *_private.yaml excluded
Usage:
from rdagent.components.loader import load_prompt
prompt = load_prompt('factor_discovery') # Auto-loads your better version!
- Mask API endpoint to prevent full URL exposure
- Change '✓' to '✓ Key set' for clearer status
- Add security comment explaining the fix
- Fixes GitHub Security Alert #7 (py/clear-text-logging-sensitive-data)
API keys are no longer logged, only their presence is indicated.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Updated QWEN.md with English-only comment policy
- Translated all German comments in:
* eurusd_regime.py
* eurusd_llm.py
* eurusd_reflection.py
* eurusd_memory.py
* eurusd_macro.py
* eurusd_debate.py
* predix_dashboard.py
- All comments, docstrings, and print statements now in English
- Ensures consistency with commit messages and documentation
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Removed 'Inspiriert von' comments from all source files
- Added comprehensive Acknowledgments section to README.md
- Credits to:
* Microsoft RD-Agent (MIT) - R&D framework foundation
* TradingAgents (Apache 2.0) - Multi-agent patterns
* ai-hedge-fund - Macro analysis and risk management concepts
- Clarified that all code is originally written and implemented independently
- Ensures license compliance (MIT, Apache 2.0 compatible)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Change: Instead of truncating texts, now using intelligent chunking:
1. Content ≤ 20,000 characters: Single embedding (complete)
2. Content > 20,000 characters: Split into 20k chunks
- Each chunk gets its own embedding
- All embeddings are averaged
- No information loss!
Benefits:
- No more text truncation
- Full information preserved
- Stays under 8192 token limit (nomic-embed-text)
- Average embedding represents entire text
Affected files:
- rdagent/components/knowledge_management/vector_base.py
Problem: Knowledge Graph versucht zu lange Texte zu embedden
- nomic-embed-text Limit: 8192 Token
- Fehler: 'the input length exceeds the context length'
- System crasht nach 10 Retries
Lösung:
1. Content für Embeddings auf 15.000 Zeichen kürzen (~4000 Token)
2. Trunk-Größe auf max 4000 begrenzt
3. Hinweis '[truncated for embedding]' bei Kürzung
Betroffene Dateien:
- rdagent/components/knowledge_management/vector_base.py
Jetzt sollte fin_quant ohne Embedding-Fehler durchlaufen.
Add automatic dashboard launch options for trading loop:
1. CLI integration (rdagent/app/cli.py)
- --with-dashboard/-d flag for web dashboard
- --cli-dashboard/-c flag for terminal UI
- --dashboard-port for custom port configuration
- Automatic background process spawning
2. Dashboard auto-start
- Web dashboard launches in background thread
- CLI dashboard opens in separate terminal window
- Graceful startup with 2-second delay
3. Process management
- Dashboard runs as daemon thread
- Automatic cleanup on main process exit
- Error handling for dashboard startup failures
4. Documentation
- Updated help text with examples
- Usage instructions in README
- Dashboard URLs displayed on startup
Usage examples:
rdagent fin_quant -d # Web dashboard
rdagent fin_quant -c # CLI dashboard
rdagent fin_quant -d -c # Both dashboards
rdagent fin_quant -d --port 5001 # Custom port
Neue Module für fortgeschrittenes Trading:
1. Bull vs Bear vs Neutral Debatte (eurusd_debate.py)
- Multi-Perspektiven-Analyse für bessere Entscheidungen
- Bull Agent: Argumentiert für LONG
- Bear Agent: Argumentiert für SHORT
- Neutral Agent: Argumentiert für WAIT
- Research Manager: Bewertet Debatte und trifft finale Entscheidung
- Decision-Logik: LONG wenn Bull > 70% und > Bear + 20
2. EURUSD Macro Agent (eurusd_macro.py)
- Stanley Druckenmiller Stil für Makro-Trading
- Analysiert Zinsdifferential (Fed vs EZB)
- Wirtschaftswachstum (BIP, PMI, NFP)
- Momentum (DXY Trend)
- Sentiment (Risk-On/Off, COT Report)
- Asymmetrische Risk-Reward-Analyse
- Bei hoher Conviction + asymmetrischer Chance: große Position
3. Reflection System (eurusd_reflection.py)
- Lernt aus vergangenen Trades kontinuierlich
- Analysiert was richtig/falsch lief
- Extrahiert Lessons Learned
- Speichert im BM25 Memory für ähnliche Situationen
- Aggregierte Insights für letzte N Trades
4. Korrelations-Adjustierung (in eurusd_risk.py erweitert)
- Berechnet Korrelation mit anderen Forex-Positionen
- GBPUSD: +0.75, USDCHF: -0.70, DXY: -0.85
- Hohe Korrelation → Risk reduzieren (0.7x)
- Negative Korrelation → natürlicher Hedge (1.1x)
Alle Module getestet und funktionsfähig.
* update rdagent cmd
* fix log error message
* use multiProcessing.Process instead of subprocess.Popen
* add traces to gitignore
* add user interactor in RDLoop (finance scenarios)
* add interactor (feedback, hypothesis) for quant scens
* fix the test_end in qlib conf
* add features init config, general instruction to qlib scenarios
* set base features for based exp
* fix bug when combine factors
* move traces folder to git_ignore_folder
* fix bug in features init
* fix quant interact bug
* fix logger warning error
* bug fixes
* modify rdagent logger, now it can set file output
* adjust cli functions and fix logger bug
* fix server port transport problem
* update server_ui in cli
* add web code
* fix CI problem
* black fix
* update web ui README
* update README
* update readme