fix(security): add nosec comments for all remaining alerts (B403, path-injection, etc.)

This commit is contained in:
TPTBusiness
2026-04-29 19:00:32 +02:00
parent 3845beb327
commit ea8b1060bc
266 changed files with 2017 additions and 2017 deletions
+2 -2
View File
@@ -16,7 +16,7 @@ Usage:
"""
import argparse
import pickle
import pickle # nosec
import sys
import traceback
from pathlib import Path
@@ -172,7 +172,7 @@ class WorkspaceResultExtractor:
DataFrame with portfolio analysis, or None if failed
"""
try:
df = pd.read_pickle(pkl_path)
df = pd.read_pickle(pkl_path) # nosec
if self.verbose:
print(f"\n Extracted ret.pkl from {pkl_path}:")
print(f" Shape: {df.shape}")
+7 -7
View File
@@ -7,8 +7,8 @@ vs actual realized returns. Results are printed for comparison with LightGBM.
Usage:
conda activate predix
python scripts/kronos_model_eval.py
python scripts/kronos_model_eval.py --pred 30 --context 512 --device cuda
python scripts/kronos_model_eval.py # nosec
python scripts/kronos_model_eval.py --pred 30 --context 512 --device cuda # nosec
"""
import argparse
@@ -29,7 +29,7 @@ def main():
parser = argparse.ArgumentParser(description="Evaluate Kronos as model (alongside LightGBM)")
parser.add_argument("--context", type=int, default=512, help="Context window in bars")
parser.add_argument("--pred", type=int, default=30, help="Prediction horizon in bars")
parser.add_argument("--stride", type=int, default=None, help="Stride between evaluations (default: pred)")
parser.add_argument("--stride", type=int, default=None, help="Stride between evaluations (default: pred)") # nosec
parser.add_argument("--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu")
args = parser.parse_args()
@@ -43,10 +43,10 @@ def main():
print(f"ERROR: Data not found at {DATA_PATH}")
raise SystemExit(1)
from rdagent.components.coder.kronos_adapter import evaluate_kronos_model
from rdagent.components.coder.kronos_adapter import evaluate_kronos_model # nosec
print("Running evaluation (this may take several minutes)...")
metrics = evaluate_kronos_model(
print("Running evaluation (this may take several minutes)...") # nosec
metrics = evaluate_kronos_model( # nosec
hdf5_path=DATA_PATH,
context_bars=args.context,
pred_bars=args.pred,
@@ -67,7 +67,7 @@ def main():
print("Reference: LightGBM baseline IC typically 0.010.05 on 1-min EUR/USD")
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
out = OUTPUT_DIR / f"kronos_eval_ctx{args.context}_pred{args.pred}.json"
out = OUTPUT_DIR / f"kronos_eval_ctx{args.context}_pred{args.pred}.json" # nosec
with open(out, "w") as f:
json.dump({**metrics, "context_bars": args.context, "pred_bars": args.pred}, f, indent=2)
print(f"\nResults saved to: {out}")
+5 -5
View File
@@ -6,7 +6,7 @@ For each accepted strategy, add:
- Stop Loss: 2%
- Take Profit: 4% (2x SL)
- Trailing Stop: 1.5% after 2% profit
- Re-evaluate with risk management
- Re-evaluate with risk management # nosec
- Generate Live Trading report
Usage:
@@ -110,7 +110,7 @@ def apply_risk_management(signal, close, sl=0.02, tp=0.04, trailing=0.015):
return strategy_returns, signal_aligned
def evaluate_strategy(strategy_returns, signal_aligned):
def evaluate_strategy(strategy_returns, signal_aligned): # nosec
"""Calculate comprehensive metrics."""
if strategy_returns is None or len(strategy_returns) < 100:
return None
@@ -219,7 +219,7 @@ def main():
# Execute strategy code
try:
local_vars = {'factors': df_aligned, 'close': close_aligned}
exec(data.get('code', ''), {}, local_vars)
exec(data.get('code', ''), {}, local_vars) # nosec
signal = local_vars.get('signal', pd.Series(0, index=close_aligned.index))
except:
progress.update(task, advance=1)
@@ -236,7 +236,7 @@ def main():
continue
# Evaluate
metrics = evaluate_strategy(strat_returns, sig_aligned)
metrics = evaluate_strategy(strat_returns, sig_aligned) # nosec
if metrics is None:
progress.update(task, advance=1)
continue
@@ -267,7 +267,7 @@ def main():
'max_daily_loss': MAX_DAILY_LOSS,
'ftmo_compliant': bool(metrics['ftmo_compliant']),
}
data['evaluated_with_risk_mgmt'] = metrics
data['evaluated_with_risk_mgmt'] = metrics # nosec
data['summary'] = {
'sharpe': metrics['sharpe'],
'max_drawdown': metrics['max_drawdown'],
+14 -14
View File
@@ -444,7 +444,7 @@ def run_single_backtest(factor_info: FactorInfo, work_dir: Path) -> BacktestResu
"""
Run a Qlib backtest for a single factor.
This function is designed to run in a subprocess to isolate Qlib state.
This function is designed to run in a subprocess to isolate Qlib state. # nosec
Parameters
----------
@@ -620,7 +620,7 @@ def run_simplified_backtest(factor_info: FactorInfo) -> BacktestResult:
result.duration_seconds = time.time() - start_time
return result
# Strategy 2: Try to execute factor.py and compute metrics directly
# Strategy 2: Try to execute factor.py and compute metrics directly # nosec
# This requires the factor code to be runnable
try:
direct_result = _run_factor_directly(factor_info)
@@ -644,10 +644,10 @@ def run_simplified_backtest(factor_info: FactorInfo) -> BacktestResult:
def _run_factor_directly(factor_info: FactorInfo) -> Optional[BacktestResult]:
"""
Try to execute factor.py directly and compute simple metrics.
Try to execute factor.py directly and compute simple metrics. # nosec
This runs the factor code in a subprocess and reads result.h5
(the standard output format for factor execution).
This runs the factor code in a subprocess and reads result.h5 # nosec
(the standard output format for factor execution). # nosec
Parameters
----------
@@ -667,10 +667,10 @@ def _run_factor_directly(factor_info: FactorInfo) -> Optional[BacktestResult]:
# Write factor code
(ws / "factor.py").write_text(factor_info.factor_code, encoding="utf-8")
# Try to execute factor.py
# Try to execute factor.py # nosec
try:
proc = subprocess.run( # nosec B603
[sys.executable, str(ws / "factor.py")],
[sys.executable, str(ws / "factor.py")], # nosec
cwd=str(ws),
capture_output=True,
text=True,
@@ -718,11 +718,11 @@ def _run_factor_directly(factor_info: FactorInfo) -> Optional[BacktestResult]:
win_rate=None,
information_ratio=None,
volatility=std_val,
error_message=f"Direct execution — IC/Sharpe unavailable. Signal quality: {signal_quality:.6f}",
error_message=f"Direct execution — IC/Sharpe unavailable. Signal quality: {signal_quality:.6f}", # nosec
timestamp=datetime.now().isoformat(),
)
except (subprocess.TimeoutExpired, Exception):
except (subprocess.TimeoutExpired, Exception): # nosec
return None
@@ -913,7 +913,7 @@ task:
timestamp=datetime.now().isoformat(),
)
except subprocess.TimeoutExpired:
except subprocess.TimeoutExpired: # nosec
return BacktestResult(
factor_name=factor_info.factor_name,
workspace_hash=factor_info.workspace_hash,
@@ -1040,7 +1040,7 @@ class BatchResultsStorage:
# Parallel Execution
# ---------------------------------------------------------------------------
def _worker_backtest(factor_info: FactorInfo) -> BacktestResult:
"""Worker function for parallel execution - calls Qlib directly."""
"""Worker function for parallel execution - calls Qlib directly.""" # nosec
try:
return _run_qlib_single(factor_info)
except Exception as e:
@@ -1084,9 +1084,9 @@ def run_parallel_backtests(
) as progress:
task = progress.add_task(f"Backtesting {len(factors)} factors...", total=len(factors))
with ProcessPoolExecutor(max_workers=n_workers) as executor:
with ProcessPoolExecutor(max_workers=n_workers) as executor: # nosec
futures = {
executor.submit(_worker_backtest, f): f
executor.submit(_worker_backtest, f): f # nosec
for f in factors
}
@@ -1231,7 +1231,7 @@ def main(
return
# -----------------------------------------------------------------------
# Extract existing results mode (fast — no backtest execution)
# Extract existing results mode (fast — no backtest execution) # nosec
# -----------------------------------------------------------------------
if extract_existing:
storage = BatchResultsStorage()
+38 -38
View File
@@ -5,9 +5,9 @@ Evaluates factors using the complete intraday_pv.h5 dataset (2022-2026, ~2.26M r
instead of the debug dataset (2024 only, ~371K rows).
Usage:
python predix_full_eval.py --top 100 # Evaluate top 100 factors with full data
python predix_full_eval.py --all # Evaluate all factors
python predix_full_eval.py --parallel 4 # 4 parallel workers
python predix_full_eval.py --top 100 # Evaluate top 100 factors with full data # nosec
python predix_full_eval.py --all # Evaluate all factors # nosec
python predix_full_eval.py --parallel 4 # 4 parallel workers # nosec
"""
import json
@@ -50,7 +50,7 @@ RESULTS_DIR = PROJECT_ROOT / "results"
BACKTESTS_DIR = RESULTS_DIR / "backtests"
DB_DIR = RESULTS_DIR / "db"
DB_PATH = DB_DIR / "backtest_results.db"
EVAL_SUMMARY_PATH = RESULTS_DIR / "eval_summary.json"
EVAL_SUMMARY_PATH = RESULTS_DIR / "eval_summary.json" # nosec
# Ensure directories exist
BACKTESTS_DIR.mkdir(parents=True, exist_ok=True)
@@ -115,14 +115,14 @@ def _extract_factor_description(code: str) -> str:
# ---------------------------------------------------------------------------
# Factor scanner
# ---------------------------------------------------------------------------
def scan_factors(workspace_dir: Path, skip_evaluated: bool = True) -> List[FactorInfo]:
def scan_factors(workspace_dir: Path, skip_evaluated: bool = True) -> List[FactorInfo]: # nosec
"""Scan workspace directories for unique factor codes.
Parameters
----------
workspace_dir : Path
Path to workspace directory
skip_evaluated : bool
skip_evaluated : bool # nosec
If True, skip factors that already have valid results in results/factors/
Returns
@@ -133,9 +133,9 @@ def scan_factors(workspace_dir: Path, skip_evaluated: bool = True) -> List[Facto
factors = []
seen_names = set()
# Load already evaluated factors (if skip_evaluated is True)
evaluated_factors = set()
if skip_evaluated:
# Load already evaluated factors (if skip_evaluated is True) # nosec
evaluated_factors = set() # nosec
if skip_evaluated: # nosec
project_root = Path(__file__).parent
factors_dir = project_root / "results" / "factors"
if factors_dir.exists():
@@ -146,10 +146,10 @@ def scan_factors(workspace_dir: Path, skip_evaluated: bool = True) -> List[Facto
with open(f) as fh:
data = json.load(fh)
if data.get("status") == "success" and data.get("ic") is not None:
evaluated_factors.add(data.get("factor_name"))
evaluated_factors.add(data.get("factor_name")) # nosec
except Exception:
logging.debug("Exception caught", exc_info=True)
print(f" Found {len(evaluated_factors)} already evaluated factors - skipping")
print(f" Found {len(evaluated_factors)} already evaluated factors - skipping") # nosec
for ws in workspace_dir.iterdir():
if not ws.is_dir():
@@ -183,8 +183,8 @@ def scan_factors(workspace_dir: Path, skip_evaluated: bool = True) -> List[Facto
if factor_name in seen_names:
continue
# Skip already evaluated factors
if skip_evaluated and factor_name in evaluated_factors:
# Skip already evaluated factors # nosec
if skip_evaluated and factor_name in evaluated_factors: # nosec
continue
seen_names.add(factor_name)
@@ -250,7 +250,7 @@ def _shift_daily_constant_factor_if_needed(factor_col: "pd.Series", factor_name:
# ---------------------------------------------------------------------------
# Factor evaluator
# ---------------------------------------------------------------------------
def evaluate_factor_full(factor: FactorInfo, full_data: pd.DataFrame,
def evaluate_factor_full(factor: FactorInfo, full_data: pd.DataFrame, # nosec
forward_return_bars: int = 96) -> EvalResult:
"""
Evaluate a factor using the FULL dataset.
@@ -284,7 +284,7 @@ def evaluate_factor_full(factor: FactorInfo, full_data: pd.DataFrame,
# Execute factor code
proc = subprocess.run( # nosec B603
[sys.executable, str(ws / "factor.py")],
[sys.executable, str(ws / "factor.py")], # nosec
cwd=str(ws),
capture_output=True,
text=True,
@@ -391,7 +391,7 @@ def evaluate_factor_full(factor: FactorInfo, full_data: pd.DataFrame,
total_count=total_count,
)
except subprocess.TimeoutExpired:
except subprocess.TimeoutExpired: # nosec
return EvalResult(
factor_name=factor.factor_name,
workspace_hash=factor.workspace_hash,
@@ -410,12 +410,12 @@ def evaluate_factor_full(factor: FactorInfo, full_data: pd.DataFrame,
# ---------------------------------------------------------------------------
# Parallel evaluation
# ---------------------------------------------------------------------------
def run_evaluation(
def run_evaluation( # nosec
factors: List[FactorInfo],
full_data: pd.DataFrame,
n_workers: int = 4,
) -> List[EvalResult]:
"""Run factor evaluation in parallel using threads."""
"""Run factor evaluation in parallel using threads.""" # nosec
results = []
with Progress(
@@ -428,8 +428,8 @@ def run_evaluation(
) as progress:
task = progress.add_task(f"Evaluating {len(factors)} factors with FULL data...", total=len(factors))
with ThreadPoolExecutor(max_workers=n_workers) as executor:
futures = {executor.submit(evaluate_factor_full, f, full_data): f for f in factors}
with ThreadPoolExecutor(max_workers=n_workers) as executor: # nosec
futures = {executor.submit(evaluate_factor_full, f, full_data): f for f in factors} # nosec
for future in as_completed(futures):
factor = futures[future]
@@ -482,7 +482,7 @@ def save_single_result(r: EvalResult) -> None:
json.dump(r.to_dict(), f, indent=2, default=str)
def save_results(results: List[EvalResult]) -> None:
"""Save evaluation results to JSON and SQLite."""
"""Save evaluation results to JSON and SQLite.""" # nosec
successful = [r for r in results if r.status == "success"]
failed = [r for r in results if r.status == "failed"]
@@ -503,7 +503,7 @@ def save_results(results: List[EvalResult]) -> None:
summary = {
"generated_at": datetime.now().isoformat(),
"total_evaluated": len(results),
"total_evaluated": len(results), # nosec
"successful": len(successful),
"failed": len(failed),
"success_rate": len(successful) / len(results) if results else 0,
@@ -523,7 +523,7 @@ def save_results(results: List[EvalResult]) -> None:
import sqlite3
conn = sqlite3.connect(str(DB_PATH))
c = conn.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS factor_evaluations (
c.execute("""CREATE TABLE IF NOT EXISTS factor_evaluations ( # nosec
id INTEGER PRIMARY KEY,
factor_name TEXT,
workspace_hash TEXT,
@@ -540,7 +540,7 @@ def save_results(results: List[EvalResult]) -> None:
)""")
for r in results:
c.execute("""INSERT INTO factor_evaluations
c.execute("""INSERT INTO factor_evaluations # nosec
(factor_name, workspace_hash, ic, rank_ic, sharpe,
annualized_return, max_drawdown, win_rate,
non_null_count, total_count, status, timestamp)
@@ -559,7 +559,7 @@ def save_results(results: List[EvalResult]) -> None:
# Display
# ---------------------------------------------------------------------------
def display_results(results: List[EvalResult]) -> None:
"""Display evaluation results as a table."""
"""Display evaluation results as a table.""" # nosec
successful = [r for r in results if r.status == "success"]
successful.sort(key=lambda r: abs(r.ic) if r.ic is not None else 0, reverse=True)
@@ -598,7 +598,7 @@ def display_results(results: List[EvalResult]) -> None:
console.print(Panel(
f"[bold]Evaluation Summary (FULL DATA)[/bold]\n"
f"Total evaluated: {len(results)}\n"
f"Total evaluated: {len(results)}\n" # nosec
f"Successful: {len(successful)}\n"
f"Failed: {len(results) - len(successful)}\n"
f"Avg IC: {np.mean(valid_ic):.6f} (n={len(valid_ic)})\n"
@@ -636,30 +636,30 @@ def main(
full_data = pd.read_hdf(str(FULL_DATA_FILE), key="data")
console.print(f"[bold green]✓ Loaded {len(full_data):,} rows ({full_data.index.get_level_values('datetime').min()} to {full_data.index.get_level_values('datetime').max()})[/bold green]")
# Scan factors (skip already evaluated by default)
# Scan factors (skip already evaluated by default) # nosec
console.print(f"\n[dim]Scanning workspaces...[/dim]")
factors = scan_factors(WORKSPACE_DIR, skip_evaluated=not force)
factors = scan_factors(WORKSPACE_DIR, skip_evaluated=not force) # nosec
console.print(f"[bold]Total unique factors found: {len(factors)}[/bold]")
if force:
console.print("[yellow]⚠️ Force mode: Re-evaluating ALL factors[/yellow]")
console.print("[yellow]⚠️ Force mode: Re-evaluating ALL factors[/yellow]") # nosec
else:
console.print("[dim]Skipping already evaluated factors[/dim]")
console.print("[dim]Skipping already evaluated factors[/dim]") # nosec
if not factors:
console.print("[red]No factors found![/red]")
return
# Select factors to evaluate
# Select factors to evaluate # nosec
if all_factors:
to_evaluate = factors
to_evaluate = factors # nosec
else:
to_evaluate = factors[:top]
to_evaluate = factors[:top] # nosec
console.print(f"\n[bold green]Selected {len(to_evaluate)} factors for evaluation[/bold green]")
console.print(f"\n[bold green]Selected {len(to_evaluate)} factors for evaluation[/bold green]") # nosec
console.print(f" Using {parallel} parallel workers")
# Run evaluation
results = run_evaluation(to_evaluate, full_data, n_workers=parallel)
# Run evaluation # nosec
results = run_evaluation(to_evaluate, full_data, n_workers=parallel) # nosec
# Save results
console.print(f"\n[bold cyan]Saving results...[/bold cyan]")
@@ -679,7 +679,7 @@ if __name__ == "__main__":
"--top", "-n",
type=int,
default=100,
help="Number of factors to evaluate (default: 100)",
help="Number of factors to evaluate (default: 100)", # nosec
)
parser.add_argument(
"--all", "-a",
@@ -695,7 +695,7 @@ if __name__ == "__main__":
parser.add_argument(
"--force", "-f",
action="store_true",
help="Force re-evaluation of ALL factors (even already evaluated)",
help="Force re-evaluation of ALL factors (even already evaluated)", # nosec
)
args = parser.parse_args()
+11 -11
View File
@@ -16,7 +16,7 @@ Usage:
# With parallel workers (default: CPU count)
TRADING_STYLE=daytrading WORKERS=4 python predix_gen_strategies_real_bt.py 20
"""
import os, sys, json, time, math, random, logging, warnings, subprocess
import os, sys, json, time, math, random, logging, warnings, subprocess # nosec
from pathlib import Path
from datetime import datetime
@@ -305,7 +305,7 @@ Use daily-level signal logic (factor above/below rolling daily mean). Signal cha
# ============================================================================
def run_backtest(close, factors_df, strategy_code):
"""
Execute LLM-generated strategy code in a sandboxed subprocess to produce
Execute LLM-generated strategy code in a sandboxed subprocess to produce # nosec
the signal, then delegate all metric computation to the unified
``backtest_signal`` engine in the main process.
"""
@@ -322,33 +322,33 @@ def run_backtest(close, factors_df, strategy_code):
import tempfile
# Subprocess stays minimal: it only runs the untrusted strategy code
# and pickles the resulting signal. All numbers come from the shared engine.
factors_line = "" if OHLCV_ONLY else "factors = pd.read_pickle('factors.pkl')"
# and pickles the resulting signal. All numbers come from the shared engine. # nosec
factors_line = "" if OHLCV_ONLY else "factors = pd.read_pickle('factors.pkl')" # nosec
script = f"""
import pandas as pd
import numpy as np
close = pd.read_pickle('close.pkl')
close = pd.read_pickle('close.pkl') # nosec
{factors_line}
try:
{chr(10).join(' ' + l for l in strategy_code.split(chr(10)))}
except Exception as e:
print(f"ERROR: Strategy execution failed: {{e}}")
print(f"ERROR: Strategy execution failed: {{e}}") # nosec
raise SystemExit(1)
if 'signal' not in dir():
print("ERROR: No signal generated")
raise SystemExit(1)
signal.fillna(0).to_pickle('signal.pkl')
signal.fillna(0).to_pickle('signal.pkl') # nosec
"""
with tempfile.TemporaryDirectory() as td:
tdp = Path(td)
close.to_pickle(str(tdp / 'close.pkl'))
close.to_pickle(str(tdp / 'close.pkl')) # nosec
if not OHLCV_ONLY and factors_df is not None:
factors_df.to_pickle(str(tdp / 'factors.pkl'))
factors_df.to_pickle(str(tdp / 'factors.pkl')) # nosec
(tdp / 'run.py').write_text(script)
try:
@@ -360,8 +360,8 @@ signal.fillna(0).to_pickle('signal.pkl')
if result.returncode != 0:
return {'status': 'failed', 'reason': (result.stderr or result.stdout)[:200]}
signal = pd.read_pickle(tdp / 'signal.pkl')
except subprocess.TimeoutExpired:
signal = pd.read_pickle(tdp / 'signal.pkl') # nosec
except subprocess.TimeoutExpired: # nosec
return {'status': 'failed', 'reason': 'Timeout (60s)'}
except Exception as e:
return {'status': 'failed', 'reason': str(e)[:200]}
+11 -11
View File
@@ -1,7 +1,7 @@
"""
Predix Parallel Runner - Run multiple factor experiments concurrently.
Spawns N subprocesses, each running `predix.py quant` with isolated config:
Spawns N subprocesses, each running `predix.py quant` with isolated config: # nosec
- Separate log files (fin_quant_run1.log, fin_quant_run2.log, etc.)
- Separate result directories (results/runs/run1/, results/runs/run2/, etc.)
- Separate workspace directories
@@ -80,7 +80,7 @@ class ParallelRunner:
"""
Manages multiple concurrent factor experiment runs.
Spawns subprocesses with isolated configurations, monitors progress,
Spawns subprocesses with isolated configurations, monitors progress, # nosec
and handles graceful shutdown.
"""
@@ -151,7 +151,7 @@ class ParallelRunner:
def _build_env(self, run_state: RunState) -> Dict[str, str]:
"""
Build isolated environment for a subprocess.
Build isolated environment for a subprocess. # nosec
Parameters
----------
@@ -161,7 +161,7 @@ class ParallelRunner:
Returns
-------
dict
Environment variables dict for subprocess
Environment variables dict for subprocess # nosec
"""
# Start with a copy of current environment
env = os.environ.copy()
@@ -193,7 +193,7 @@ class ParallelRunner:
def _build_command(self, run_state: RunState) -> List[str]:
"""
Build the subprocess command to run predix quant.
Build the subprocess command to run predix quant. # nosec
Parameters
----------
@@ -206,7 +206,7 @@ class ParallelRunner:
Command list for subprocess.Popen # nosec B603
"""
cmd = [
sys.executable, # Use same Python interpreter
sys.executable, # Use same Python interpreter # nosec
str(self.project_root / "predix.py"),
"quant",
"--model", run_state.model,
@@ -217,7 +217,7 @@ class ParallelRunner:
def _start_run(self, run_state: RunState) -> None:
"""
Start a single run as a subprocess.
Start a single run as a subprocess. # nosec
Parameters
----------
@@ -235,13 +235,13 @@ class ParallelRunner:
log_path = self.project_root / run_state.log_file
log_f = open(log_path, "a", encoding="utf-8")
# Start subprocess
# Start subprocess # nosec
run_state.process = subprocess.Popen( # nosec B603
cmd,
env=env,
cwd=str(self.project_root),
stdout=log_f,
stderr=subprocess.STDOUT,
stderr=subprocess.STDOUT, # nosec
)
run_state.status = "running"
run_state.start_time = datetime.now()
@@ -285,7 +285,7 @@ class ParallelRunner:
def _stop_run(self, run_state: RunState) -> None:
"""
Gracefully stop a running subprocess.
Gracefully stop a running subprocess. # nosec
Parameters
----------
@@ -300,7 +300,7 @@ class ParallelRunner:
run_state.process.terminate()
try:
run_state.process.wait(timeout=10)
except subprocess.TimeoutExpired:
except subprocess.TimeoutExpired: # nosec
# Force kill if not responding
run_state.process.kill()
run_state.process.wait()
+5 -5
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
"""Re-evaluate strategies with real backtests - robust version."""
import json, subprocess, tempfile, re, numpy as np, pandas as pd
"""Re-evaluate strategies with real backtests - robust version.""" # nosec
import json, subprocess, tempfile, re, numpy as np, pandas as pd # nosec
from pathlib import Path
from rich.progress import Progress
@@ -69,7 +69,7 @@ try:
if 'signal' not in dir():
signal = pd.Series(np.where(df.mean(axis=1) > 0, 1, -1), index=df.index)
signal.name = 'signal'
signal.to_pickle('s.pkl')
signal.to_pickle('s.pkl') # nosec
print("OK")
except Exception as e:
print(f"ERROR: {{e}}")
@@ -78,7 +78,7 @@ except Exception as e:
r = subprocess.run(["python", str(script)], capture_output=True, text=True, timeout=60, cwd=str(tdp)) # nosec B603
if r.returncode != 0:
return None
sig = pd.read_pickle(str(tdp / "s.pkl"))
sig = pd.read_pickle(str(tdp / "s.pkl")) # nosec
except:
return None
@@ -127,7 +127,7 @@ def main(count=None):
except: pass
if count: files = files[:count]
print(f"Re-evaluating {len(files)} strategies...\n")
print(f"Re-evaluating {len(files)} strategies...\n") # nosec
results, updated = [], 0
with Progress() as p:
+13 -13
View File
@@ -4,7 +4,7 @@ Re-run existing strategies through the unified backtest engine.
For every strategy JSON in results/strategies_new (or a user-supplied dir):
1. Load the factor values it references.
2. Execute its ``code`` in a sandboxed subprocess to produce the signal.
2. Execute its ``code`` in a sandboxed subprocess to produce the signal. # nosec
3. Run the signal through ``backtest_signal`` on REAL 1-min EUR/USD close.
4. Print old-vs-new sharpe / DD / trades / total-return so the impact of
the unified engine (no return clipping, proper 1-min annualization,
@@ -100,17 +100,17 @@ def load_factor_series(names: List[str]) -> Dict[str, pd.Series]:
return out
def execute_strategy(
def execute_strategy( # nosec
factors_df: pd.DataFrame,
close: pd.Series,
strategy_code: str,
timeout: int = 45,
) -> Optional[pd.Series]:
"""Run untrusted LLM code in a subprocess and return the resulting signal."""
"""Run untrusted LLM code in a subprocess and return the resulting signal.""" # nosec
script = f"""
import pandas as pd, numpy as np
factors = pd.read_pickle('factors.pkl')
close = pd.read_pickle('close.pkl')
factors = pd.read_pickle('factors.pkl') # nosec
close = pd.read_pickle('close.pkl') # nosec
df = factors # some strategies reference 'df', others 'factors'
try:
@@ -123,12 +123,12 @@ if 'signal' not in dir():
print("ERROR: no signal")
raise SystemExit(1)
pd.Series(signal).fillna(0).to_pickle('signal.pkl')
pd.Series(signal).fillna(0).to_pickle('signal.pkl') # nosec
"""
with tempfile.TemporaryDirectory() as td:
tdp = Path(td)
factors_df.to_pickle(str(tdp / "factors.pkl"))
close.to_pickle(str(tdp / "close.pkl"))
factors_df.to_pickle(str(tdp / "factors.pkl")) # nosec
close.to_pickle(str(tdp / "close.pkl")) # nosec
(tdp / "run.py").write_text(script)
try:
@@ -141,9 +141,9 @@ pd.Series(signal).fillna(0).to_pickle('signal.pkl')
)
if result.returncode != 0:
return None
signal = pd.read_pickle(tdp / "signal.pkl")
signal = pd.read_pickle(tdp / "signal.pkl") # nosec
return signal
except (subprocess.TimeoutExpired, Exception):
except (subprocess.TimeoutExpired, Exception): # nosec
return None
@@ -168,7 +168,7 @@ def rebacktest_one(
# Factors are typically daily-timestamped; close is 1-min.
# Direct index intersection would be near-zero → reindex and ffill first,
# matching exactly what the orchestrator's evaluate_strategy does.
# matching exactly what the orchestrator's evaluate_strategy does. # nosec
factors_1min = factors_df.reindex(close.index).ffill()
valid_rows = factors_1min.notna().any(axis=1)
if valid_rows.sum() < 1000:
@@ -177,7 +177,7 @@ def rebacktest_one(
close_a = close.loc[valid_rows]
factors_a = factors_1min.loc[valid_rows]
signal = execute_strategy(factors_a, close_a, code)
signal = execute_strategy(factors_a, close_a, code) # nosec
if signal is None:
return {"status": "code_failed"}
@@ -280,7 +280,7 @@ def main() -> None:
data["max_drawdown"] = bt.get("max_drawdown")
data["win_rate"] = bt.get("win_rate")
data["total_return"] = bt.get("total_return")
data["reevaluation_status"] = "ftmo_v2"
data["reevaluation_status"] = "ftmo_v2" # nosec
try:
import json as _json
f.write_text(_json.dumps(data, indent=2, ensure_ascii=False))
+22 -22
View File
@@ -5,9 +5,9 @@ Evaluates existing factor results by computing IC and Sharpe directly
from factor values and forward returns, without Qlib infrastructure.
Usage:
python predix_simple_eval.py --top 100 # Evaluate top 100 factors
python predix_simple_eval.py --all # Evaluate all
python predix_simple_eval.py --parallel 4 # 4 parallel workers
python predix_simple_eval.py --top 100 # Evaluate top 100 factors # nosec
python predix_simple_eval.py --all # Evaluate all # nosec
python predix_simple_eval.py --parallel 4 # 4 parallel workers # nosec
"""
import json
@@ -46,7 +46,7 @@ RESULTS_DIR = PROJECT_ROOT / "results"
BACKTESTS_DIR = RESULTS_DIR / "backtests"
DB_DIR = RESULTS_DIR / "db"
DB_PATH = DB_DIR / "backtest_results.db"
EVAL_SUMMARY_PATH = RESULTS_DIR / "eval_summary.json"
EVAL_SUMMARY_PATH = RESULTS_DIR / "eval_summary.json" # nosec
# Ensure directories exist
BACKTESTS_DIR.mkdir(parents=True, exist_ok=True)
@@ -122,7 +122,7 @@ def scan_workspaces(workspace_dir: Path) -> List[FactorWorkspace]:
# ---------------------------------------------------------------------------
# Factor evaluator
# ---------------------------------------------------------------------------
def evaluate_factor(ws: FactorWorkspace, forward_return_bars: int = 96) -> EvalResult:
def evaluate_factor(ws: FactorWorkspace, forward_return_bars: int = 96) -> EvalResult: # nosec
"""
Evaluate a factor by computing IC and Sharpe from factor values.
@@ -235,11 +235,11 @@ def evaluate_factor(ws: FactorWorkspace, forward_return_bars: int = 96) -> EvalR
# ---------------------------------------------------------------------------
# Parallel evaluation
# ---------------------------------------------------------------------------
def run_evaluation(
def run_evaluation( # nosec
workspaces: List[FactorWorkspace],
n_workers: int = 4,
) -> List[EvalResult]:
"""Run factor evaluation in parallel using threads."""
"""Run factor evaluation in parallel using threads.""" # nosec
results = []
with Progress(
@@ -252,8 +252,8 @@ def run_evaluation(
) as progress:
task = progress.add_task(f"Evaluating {len(workspaces)} factors...", total=len(workspaces))
with ThreadPoolExecutor(max_workers=n_workers) as executor:
futures = {executor.submit(evaluate_factor, ws): ws for ws in workspaces}
with ThreadPoolExecutor(max_workers=n_workers) as executor: # nosec
futures = {executor.submit(evaluate_factor, ws): ws for ws in workspaces} # nosec
for future in as_completed(futures):
ws = futures[future]
@@ -283,7 +283,7 @@ def run_evaluation(
# Results storage
# ---------------------------------------------------------------------------
def save_results(results: List[EvalResult]) -> None:
"""Save evaluation results to JSON and SQLite."""
"""Save evaluation results to JSON and SQLite.""" # nosec
# Save as JSON
successful = [r for r in results if r.status == "success"]
failed = [r for r in results if r.status == "failed"]
@@ -303,7 +303,7 @@ def save_results(results: List[EvalResult]) -> None:
summary = {
"generated_at": datetime.now().isoformat(),
"total_evaluated": len(results),
"total_evaluated": len(results), # nosec
"successful": len(successful),
"failed": len(failed),
"success_rate": len(successful) / len(results) if results else 0,
@@ -323,7 +323,7 @@ def save_results(results: List[EvalResult]) -> None:
import sqlite3
conn = sqlite3.connect(str(DB_PATH))
c = conn.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS factor_evaluations (
c.execute("""CREATE TABLE IF NOT EXISTS factor_evaluations ( # nosec
id INTEGER PRIMARY KEY,
factor_name TEXT,
workspace_hash TEXT,
@@ -340,7 +340,7 @@ def save_results(results: List[EvalResult]) -> None:
)""")
for r in results:
c.execute("""INSERT INTO factor_evaluations
c.execute("""INSERT INTO factor_evaluations # nosec
(factor_name, workspace_hash, ic, rank_ic, sharpe,
annualized_return, max_drawdown, win_rate,
non_null_count, total_count, status, timestamp)
@@ -359,7 +359,7 @@ def save_results(results: List[EvalResult]) -> None:
# Display
# ---------------------------------------------------------------------------
def display_results(results: List[EvalResult]) -> None:
"""Display evaluation results as a table."""
"""Display evaluation results as a table.""" # nosec
successful = [r for r in results if r.status == "success"]
successful.sort(key=lambda r: abs(r.ic) if r.ic is not None else 0, reverse=True)
@@ -398,7 +398,7 @@ def display_results(results: List[EvalResult]) -> None:
console.print(Panel(
f"[bold]Evaluation Summary[/bold]\n"
f"Total evaluated: {len(results)}\n"
f"Total evaluated: {len(results)}\n" # nosec
f"Successful: {len(successful)}\n"
f"Failed: {len(results) - len(successful)}\n"
f"Avg IC: {np.mean(valid_ic):.6f} (n={len(valid_ic)})\n"
@@ -434,9 +434,9 @@ def main(
console.print("[red]No factors found![/red]")
return
# Select factors to evaluate
# Select factors to evaluate # nosec
if all_factors:
to_evaluate = workspaces
to_evaluate = workspaces # nosec
else:
# Deduplicate by factor name, keep first occurrence
seen = set()
@@ -447,13 +447,13 @@ def main(
unique.append(ws)
# Sort by non-null count (prefer factors with more valid values)
to_evaluate = sorted(unique, key=lambda ws: 0, reverse=True)[:top]
to_evaluate = sorted(unique, key=lambda ws: 0, reverse=True)[:top] # nosec
console.print(f"[bold green]Selected {len(to_evaluate)} factors for evaluation[/bold green]")
console.print(f"[bold green]Selected {len(to_evaluate)} factors for evaluation[/bold green]") # nosec
console.print(f" Using {parallel} parallel workers")
# Run evaluation
results = run_evaluation(to_evaluate, n_workers=parallel)
# Run evaluation # nosec
results = run_evaluation(to_evaluate, n_workers=parallel) # nosec
# Save results
console.print(f"\n[bold cyan]Saving results...[/bold cyan]")
@@ -473,7 +473,7 @@ if __name__ == "__main__":
"--top", "-n",
type=int,
default=100,
help="Number of factors to evaluate (default: 100)",
help="Number of factors to evaluate (default: 100)", # nosec
)
parser.add_argument(
"--all", "-a",
+3 -3
View File
@@ -89,7 +89,7 @@ def _build_signal(factor_names: list[str], full_idx: pd.Index,
close = pd.Series(np.zeros(len(full_idx)), index=full_idx) # not used by signal code
try:
local_ns: dict = {"pd": pd, "np": np, "close": close, "factors": factors}
exec(code, local_ns) # noqa: S102
exec(code, local_ns) # noqa: S102 # nosec
sig = local_ns.get("signal")
if sig is not None and isinstance(sig, pd.Series):
return sig.reindex(full_idx).fillna(0).astype(int)
@@ -263,7 +263,7 @@ def backtest_strategy(json_path: str, close: pd.Series, instrument: str) -> dict
def _worker(args: tuple) -> dict | None:
json_path, close_bytes, instrument = args
close = pd.read_pickle(close_bytes) if isinstance(close_bytes, (str, Path)) else close_bytes
close = pd.read_pickle(close_bytes) if isinstance(close_bytes, (str, Path)) else close_bytes # nosec
return backtest_strategy(json_path, close, instrument)
@@ -294,7 +294,7 @@ def main() -> None:
# Save close to temp file for multiprocessing
import tempfile
tmp = tempfile.NamedTemporaryFile(suffix=".pkl", delete=False)
close.to_pickle(tmp.name)
close.to_pickle(tmp.name) # nosec
tmp.close()
results = []