Upload alpha_factory/config.py with huggingface_hub
Browse files- alpha_factory/config.py +102 -0
alpha_factory/config.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Configuration — all settings in one place.
|
| 3 |
+
Environment variables override defaults.
|
| 4 |
+
"""
|
| 5 |
+
from pydantic import BaseModel, Field
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class LLMConfig(BaseModel):
|
| 11 |
+
"""LLM serving configuration."""
|
| 12 |
+
microfish_model: str = "Qwen/Qwen2.5-1.5B-Instruct"
|
| 13 |
+
tinyfish_model: str = "Qwen/Qwen2.5-3B-Instruct"
|
| 14 |
+
mediumfish_model: str = "Qwen/Qwen2.5-7B-Instruct"
|
| 15 |
+
bigfish_model: str = "Qwen/Qwen2.5-72B-Instruct"
|
| 16 |
+
base_url: str = Field(default="http://localhost:8000/v1", description="vLLM / Ollama endpoint")
|
| 17 |
+
api_key: str = "dummy"
|
| 18 |
+
temperature_generation: float = 0.7
|
| 19 |
+
temperature_compilation: float = 0.1
|
| 20 |
+
temperature_critique: float = 0.3
|
| 21 |
+
max_tokens: int = 4096
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class BrainConfig(BaseModel):
|
| 25 |
+
"""WorldQuant BRAIN API configuration."""
|
| 26 |
+
api_url: str = "https://api.worldquantbrain.com"
|
| 27 |
+
region: str = "USA"
|
| 28 |
+
universe: str = "TOP3000"
|
| 29 |
+
delay: int = 1
|
| 30 |
+
truncation: float = 0.08
|
| 31 |
+
pasteurization: str = "ON"
|
| 32 |
+
nan_handling: str = "OFF"
|
| 33 |
+
max_concurrent: int = 4
|
| 34 |
+
submit_interval_sec: float = 15.0
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class KillSwitches(BaseModel):
|
| 38 |
+
"""Hard circuit breakers — non-negotiable."""
|
| 39 |
+
daily_brain_submissions_max: int = 200
|
| 40 |
+
consecutive_lint_fail_max: int = 10
|
| 41 |
+
consecutive_kill_verdict_max: int = 30
|
| 42 |
+
daily_llm_token_budget: int = 5_000_000
|
| 43 |
+
max_credits_per_family: int = 3
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class FitnessWeights(BaseModel):
|
| 47 |
+
"""Fitness function coefficients. Calibrate with hand-rankings after 20+ alphas."""
|
| 48 |
+
sharpe_os: float = 1.0
|
| 49 |
+
is_os_gap_penalty: float = 0.5
|
| 50 |
+
worst_year_penalty: float = 1.0
|
| 51 |
+
crowding_penalty: float = 0.3
|
| 52 |
+
turnover_penalty: float = 0.2
|
| 53 |
+
turnover_threshold: float = 0.40
|
| 54 |
+
drawdown_penalty: float = 0.1
|
| 55 |
+
drawdown_threshold: float = 0.05
|
| 56 |
+
novelty_bonus: float = 0.4
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class Paths(BaseModel):
|
| 60 |
+
"""All filesystem paths."""
|
| 61 |
+
root: Path = Path(os.getenv("AF_ROOT", "."))
|
| 62 |
+
data: Path = Field(default=None)
|
| 63 |
+
factor_store: Path = Field(default=None)
|
| 64 |
+
prompts: Path = Field(default=None)
|
| 65 |
+
logs: Path = Field(default=None)
|
| 66 |
+
|
| 67 |
+
def model_post_init(self, __context):
|
| 68 |
+
if self.data is None:
|
| 69 |
+
self.data = self.root / "data"
|
| 70 |
+
if self.factor_store is None:
|
| 71 |
+
self.factor_store = self.root / "factor_store"
|
| 72 |
+
if self.prompts is None:
|
| 73 |
+
self.prompts = self.root / "prompts"
|
| 74 |
+
if self.logs is None:
|
| 75 |
+
self.logs = self.root / "logs"
|
| 76 |
+
# Ensure directories exist
|
| 77 |
+
for p in [self.data, self.factor_store, self.factor_store / "alphas",
|
| 78 |
+
self.prompts, self.prompts / "templates", self.logs]:
|
| 79 |
+
p.mkdir(parents=True, exist_ok=True)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class Config(BaseModel):
|
| 83 |
+
"""Master configuration."""
|
| 84 |
+
llm: LLMConfig = LLMConfig()
|
| 85 |
+
brain: BrainConfig = BrainConfig()
|
| 86 |
+
kill: KillSwitches = KillSwitches()
|
| 87 |
+
fitness: FitnessWeights = FitnessWeights()
|
| 88 |
+
paths: Paths = Paths()
|
| 89 |
+
|
| 90 |
+
# Pipeline settings
|
| 91 |
+
batch_size: int = 10 # alphas per batch
|
| 92 |
+
max_iterations_per_family: int = 3
|
| 93 |
+
correlation_threshold: float = 0.65
|
| 94 |
+
min_sharpe_local_sim: float = 1.0
|
| 95 |
+
min_info_value_sign_sweep: float = 0.3
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def load_config() -> Config:
|
| 99 |
+
"""Load config with env var overrides."""
|
| 100 |
+
return Config(
|
| 101 |
+
paths=Paths(root=Path(os.getenv("AF_ROOT", ".")))
|
| 102 |
+
)
|