Upload alpha_factory/run.py
Browse files- alpha_factory/run.py +75 -86
alpha_factory/run.py
CHANGED
|
@@ -1,135 +1,124 @@
|
|
| 1 |
"""
|
| 2 |
-
Alpha Factory β Entry Point
|
| 3 |
-
Run: python -m alpha_factory.run [--dry-run] [--
|
|
|
|
| 4 |
"""
|
| 5 |
import os
|
| 6 |
import asyncio
|
| 7 |
import argparse
|
| 8 |
|
|
|
|
| 9 |
try:
|
| 10 |
from dotenv import load_dotenv
|
| 11 |
-
load_dotenv()
|
| 12 |
except ImportError:
|
| 13 |
-
pass
|
| 14 |
|
| 15 |
from rich.console import Console
|
| 16 |
from .config import load_config
|
| 17 |
-
from .infra import ModelManager, LLMClient
|
| 18 |
from .orchestration import AlphaPipeline
|
| 19 |
|
| 20 |
console = Console()
|
| 21 |
|
| 22 |
|
| 23 |
async def setup_models(interactive: bool = False, hf_token: str = None) -> ModelManager:
|
|
|
|
| 24 |
manager = ModelManager(hf_token=hf_token)
|
| 25 |
-
|
|
|
|
| 26 |
await manager.discover_all()
|
| 27 |
-
manager.auto_assign_defaults()
|
| 28 |
-
manager.print_status()
|
| 29 |
-
return manager
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
from .deterministic.proven_templates import generate_batch_from_proven_templates
|
| 35 |
-
from .deterministic.lint import lint
|
| 36 |
-
from .infra import FactorStore
|
| 37 |
-
from pathlib import Path
|
| 38 |
-
|
| 39 |
-
console.print(f"\n[bold green]--- Proven Template Mode (no LLM) ---[/]")
|
| 40 |
-
console.print(f"Generating {batch_size} alphas from Alpha 15/6 structures\n")
|
| 41 |
-
|
| 42 |
-
store = FactorStore(Path("factor_store/alphas.duckdb"))
|
| 43 |
-
existing_hashes = store.get_expression_hashes()
|
| 44 |
-
|
| 45 |
-
batch = generate_batch_from_proven_templates(count=batch_size)
|
| 46 |
-
passed = 0
|
| 47 |
-
stored = 0
|
| 48 |
-
|
| 49 |
-
for i, alpha in enumerate(batch, 1):
|
| 50 |
-
expr = alpha["expression"]
|
| 51 |
-
field = alpha["field_id"]
|
| 52 |
-
template = alpha["template"]
|
| 53 |
-
ac = alpha["field_ac"]
|
| 54 |
-
group = alpha["group_key"]
|
| 55 |
-
|
| 56 |
-
result = lint(expr)
|
| 57 |
-
status = "[green]PASS[/]" if result.passed else "[red]FAIL[/]"
|
| 58 |
-
console.print(f" {i}. {status} [{template}] field={field} (AC={ac}) group={group}")
|
| 59 |
-
|
| 60 |
-
if result.passed:
|
| 61 |
-
passed += 1
|
| 62 |
-
# Store
|
| 63 |
-
from .deterministic.lint import quick_dedup_hash
|
| 64 |
-
alpha_id = quick_dedup_hash(expr, alpha["neutralization"], alpha["decay"])
|
| 65 |
-
if alpha_id not in existing_hashes:
|
| 66 |
-
store.insert_alpha(
|
| 67 |
-
alpha_id=alpha_id,
|
| 68 |
-
expression=expr,
|
| 69 |
-
neutralization=alpha["neutralization"],
|
| 70 |
-
decay=alpha["decay"],
|
| 71 |
-
fields_used=[alpha["field_id"]],
|
| 72 |
-
operators_used=["ts_decay_linear", "group_neutralize", "rank", "zscore", "ts_rank"],
|
| 73 |
-
archetype=alpha["archetype"],
|
| 74 |
-
theme=alpha["theme"],
|
| 75 |
-
anomaly_tag="value",
|
| 76 |
-
academic_anchor=None,
|
| 77 |
-
)
|
| 78 |
-
existing_hashes.add(alpha_id)
|
| 79 |
-
stored += 1
|
| 80 |
-
console.print(f" {expr[:90]}...")
|
| 81 |
-
else:
|
| 82 |
-
console.print(f" [yellow]DEDUP: already exists[/]")
|
| 83 |
-
else:
|
| 84 |
-
console.print(f" [red]Errors: {result.errors}[/]")
|
| 85 |
-
|
| 86 |
-
console.print(f"\n[bold]Results: {passed}/{len(batch)} passed lint, {stored} stored[/]")
|
| 87 |
-
console.print("[dim]Copy expressions from UI or DuckDB. Paste into BRAIN with settings: USA/TOP3000/D1/Decay=5[/]")
|
| 88 |
-
store.close()
|
| 89 |
|
| 90 |
|
| 91 |
def main():
|
| 92 |
-
parser = argparse.ArgumentParser(description="Alpha Factory")
|
| 93 |
-
parser.add_argument("--dry-run", action="store_true", help="
|
| 94 |
-
parser.add_argument("--
|
| 95 |
-
parser.add_argument("--
|
| 96 |
-
parser.add_argument("--
|
| 97 |
-
parser.add_argument("--
|
| 98 |
-
parser.add_argument("--
|
|
|
|
|
|
|
| 99 |
args = parser.parse_args()
|
| 100 |
|
| 101 |
config = load_config()
|
| 102 |
config.batch_size = args.batch_size
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
hf_token = args.hf_token or os.getenv("HF_TOKEN")
|
| 104 |
|
|
|
|
|
|
|
|
|
|
| 105 |
console.print(f"""
|
| 106 |
-
[bold green]
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
-
Mode: {
|
|
|
|
| 109 |
Batch size: {args.batch_size}
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
""")
|
| 112 |
|
| 113 |
-
#
|
| 114 |
-
if args.proven:
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
config.llm.base_url = f"{args.ollama_url}/v1"
|
| 121 |
|
|
|
|
| 122 |
pipeline = AlphaPipeline(config)
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
|
| 125 |
try:
|
| 126 |
result = asyncio.run(pipeline.run_batch(args.batch_size))
|
| 127 |
console.print(f"\n[bold]Final: {result}[/]")
|
| 128 |
except KeyboardInterrupt:
|
| 129 |
-
console.print("\n[yellow]Interrupted[/]")
|
| 130 |
finally:
|
| 131 |
pipeline.close()
|
| 132 |
|
| 133 |
|
| 134 |
if __name__ == "__main__":
|
| 135 |
-
main()
|
|
|
|
| 1 |
"""
|
| 2 |
+
Alpha Factory β Entry Point v2
|
| 3 |
+
Run: python -m alpha_factory.run [--dry-run] [--batch-size N] [--interactive]
|
| 4 |
+
[--proven] [--enable-brain]
|
| 5 |
"""
|
| 6 |
import os
|
| 7 |
import asyncio
|
| 8 |
import argparse
|
| 9 |
|
| 10 |
+
# Load .env file FIRST before anything else reads env vars
|
| 11 |
try:
|
| 12 |
from dotenv import load_dotenv
|
| 13 |
+
load_dotenv() # Reads .env from current directory
|
| 14 |
except ImportError:
|
| 15 |
+
pass # python-dotenv not installed; rely on system env vars
|
| 16 |
|
| 17 |
from rich.console import Console
|
| 18 |
from .config import load_config
|
| 19 |
+
from .infra import ModelManager, interactive_model_select, LLMClient
|
| 20 |
from .orchestration import AlphaPipeline
|
| 21 |
|
| 22 |
console = Console()
|
| 23 |
|
| 24 |
|
| 25 |
async def setup_models(interactive: bool = False, hf_token: str = None) -> ModelManager:
|
| 26 |
+
"""Discover models and optionally let user pick interactively."""
|
| 27 |
manager = ModelManager(hf_token=hf_token)
|
| 28 |
+
|
| 29 |
+
console.print("\n[bold]π Discovering available models...[/]")
|
| 30 |
await manager.discover_all()
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
+
if interactive:
|
| 33 |
+
selections = interactive_model_select(manager)
|
| 34 |
+
for tier, model in selections.items():
|
| 35 |
+
manager.select_model(tier, model)
|
| 36 |
+
else:
|
| 37 |
+
manager.auto_assign_defaults()
|
| 38 |
|
| 39 |
+
manager.print_status()
|
| 40 |
+
return manager
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
|
| 43 |
def main():
|
| 44 |
+
parser = argparse.ArgumentParser(description="Alpha Factory β LLM-Driven Alpha Generation Pipeline")
|
| 45 |
+
parser.add_argument("--dry-run", action="store_true", help="Run without BRAIN submissions")
|
| 46 |
+
parser.add_argument("--batch-size", type=int, default=10, help="Number of candidates per batch")
|
| 47 |
+
parser.add_argument("--interactive", action="store_true", help="Interactively select models")
|
| 48 |
+
parser.add_argument("--hf-token", type=str, default=None, help="HuggingFace API token (or set HF_TOKEN env)")
|
| 49 |
+
parser.add_argument("--ollama-url", type=str, default="http://localhost:11434", help="Ollama server URL")
|
| 50 |
+
parser.add_argument("--proven", action="store_true", help="Use proven templates (no LLM, deterministic generation)")
|
| 51 |
+
parser.add_argument("--enable-brain", action="store_true", help="Enable live BRAIN submission (requires BRAIN_SESSION_TOKEN)")
|
| 52 |
+
parser.add_argument("--local-sim", action="store_true", help="Enable local BRAIN simulation (requires yfinance)")
|
| 53 |
args = parser.parse_args()
|
| 54 |
|
| 55 |
config = load_config()
|
| 56 |
config.batch_size = args.batch_size
|
| 57 |
+
config.use_proven_templates = args.proven
|
| 58 |
+
config.enable_brain_client = args.enable_brain
|
| 59 |
+
config.enable_local_sim = args.local_sim
|
| 60 |
+
|
| 61 |
+
if args.dry_run:
|
| 62 |
+
config.enable_brain_client = False
|
| 63 |
+
|
| 64 |
+
# Resolve HF token: CLI arg > env var (loaded from .env)
|
| 65 |
hf_token = args.hf_token or os.getenv("HF_TOKEN")
|
| 66 |
|
| 67 |
+
mode_str = "PROVEN TEMPLATES" if args.proven else "LLM GENERATION"
|
| 68 |
+
brain_str = "LIVE (BRAIN submissions)" if config.enable_brain_client else "DRY RUN"
|
| 69 |
+
|
| 70 |
console.print(f"""
|
| 71 |
+
[bold green]ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ[/]
|
| 72 |
+
[bold green] ALPHA FACTORY v0.2.0[/]
|
| 73 |
+
[bold green] Open-Source LLM-Driven Pipeline for WorldQuant BRAIN[/]
|
| 74 |
+
[bold green]ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ[/]
|
| 75 |
|
| 76 |
+
Mode: {mode_str}
|
| 77 |
+
Brain: {brain_str}
|
| 78 |
Batch size: {args.batch_size}
|
| 79 |
+
Ollama: {args.ollama_url}
|
| 80 |
+
HF Token: {"β Set" if hf_token else "β Not set (cloud models unavailable)"}
|
| 81 |
+
|
| 82 |
+
[yellow]NOTE: This is v0.2.0 with real personas wired, but BRAIN integration
|
| 83 |
+
requires a valid BRAIN_SESSION_TOKEN. See .env.example for setup.[/]
|
| 84 |
""")
|
| 85 |
|
| 86 |
+
# Discover and select models (only needed for LLM mode)
|
| 87 |
+
if not args.proven:
|
| 88 |
+
manager = asyncio.run(setup_models(
|
| 89 |
+
interactive=args.interactive,
|
| 90 |
+
hf_token=hf_token,
|
| 91 |
+
))
|
| 92 |
+
else:
|
| 93 |
+
manager = None
|
| 94 |
+
console.print(" [green]Proven template mode β no LLM model discovery needed[/]")
|
| 95 |
+
|
| 96 |
+
# Update LLM config with Ollama URL
|
| 97 |
config.llm.base_url = f"{args.ollama_url}/v1"
|
| 98 |
|
| 99 |
+
# Create pipeline
|
| 100 |
pipeline = AlphaPipeline(config)
|
| 101 |
+
if manager:
|
| 102 |
+
pipeline.llm = LLMClient(config.llm, model_manager=manager)
|
| 103 |
+
|
| 104 |
+
# Initialize BRAIN client if enabled
|
| 105 |
+
if config.enable_brain_client:
|
| 106 |
+
try:
|
| 107 |
+
import aiohttp
|
| 108 |
+
session = aiohttp.ClientSession()
|
| 109 |
+
asyncio.run(pipeline.init_brain_client(session))
|
| 110 |
+
except ImportError:
|
| 111 |
+
console.print("[red]aiohttp required for BRAIN client. pip install aiohttp[/]")
|
| 112 |
+
config.enable_brain_client = False
|
| 113 |
|
| 114 |
try:
|
| 115 |
result = asyncio.run(pipeline.run_batch(args.batch_size))
|
| 116 |
console.print(f"\n[bold]Final: {result}[/]")
|
| 117 |
except KeyboardInterrupt:
|
| 118 |
+
console.print("\n[yellow]Interrupted by user[/]")
|
| 119 |
finally:
|
| 120 |
pipeline.close()
|
| 121 |
|
| 122 |
|
| 123 |
if __name__ == "__main__":
|
| 124 |
+
main()
|