stocker-env / CLAUDE.md
Hydr473's picture
Add scripts for rendering charts and serving vLLM; enhance task validation and introduce council tests
70a0c37
|
Raw
History Blame
4.44 kB

CLAUDE.md

Project Overview

Stocker β€” multi-agent council RL environment for stock trading on OpenEnv. Seven specialist LLM analysts vote each step; a moderator LLM merges votes into a (side, quantity) trade. The moderator is GRPO-trained via TRL on top of google/gemma-4-E4B-it.

Stack

  • Language: Python 3.10+ (Docker image runs 3.13)
  • Framework: FastAPI + Uvicorn
  • Models: Pydantic v2 + pydantic-settings
  • OpenEnv: openenv-core>=0.2.0
  • Package manager: uv (deps grouped into optional extras: data, eval, serve, train)
  • Tests: pytest + FastAPI TestClient (MockLLMClient for council tests β€” no GPU/API needed)
  • Serving: vLLM (OpenAI-compatible at :8000) β€” see scripts/serve_vllm.sh
  • Training: TRL GRPOTrainer + PEFT LoRA β€” see training/train_grpo.py

Layout

.
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ api/                # HTTP routers (health, meta, env, state, frontend)
β”‚   β”œβ”€β”€ council/            # 7 specialists + moderator + asyncio runner
β”‚   β”‚   β”œβ”€β”€ llm.py          # OpenAILLMClient, MockLLMClient, parse_json_object
β”‚   β”‚   β”œβ”€β”€ specialists.py  # ChartPattern / Seasonal / Indicator / News / Forum / Peer / Geo
β”‚   β”‚   β”œβ”€β”€ moderator.py    # merges votes β†’ TradeAction (extra_body for LoRA)
β”‚   β”‚   └── runner.py       # Council.run / run_async + .cache/council/* on-disk cache
β”‚   β”œβ”€β”€ core/               # environment.py, graders.py, tasks.py
β”‚   β”œβ”€β”€ data/loader.py      # parquet lookups + chart_path
β”‚   β”œβ”€β”€ config.py
β”‚   β”œβ”€β”€ main.py
β”‚   └── models.py           # Pydantic schemas (the public OpenEnv contract)
β”œβ”€β”€ data/                   # bundled by scripts/build_dataset.py
β”‚   β”œβ”€β”€ *.parquet
β”‚   β”œβ”€β”€ charts/             # 768x768 candlestick PNGs
β”‚   └── sources/            # curated news / forums / macro JSON
β”œβ”€β”€ server/app.py           # OpenEnv entry point (`server.app:main`)
β”œβ”€β”€ inference.py            # council-driven OpenEnv inference loop (root)
β”œβ”€β”€ client.py
β”œβ”€β”€ scripts/                # build_dataset, render_charts, serve_vllm, validate_tasks
β”œβ”€β”€ training/               # eval_rollout, train_grpo, runs/
β”œβ”€β”€ tests/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ openenv.yaml
└── pyproject.toml

Conventions

  • All Pydantic schemas live in app/models.py. Don't move them. Names: MarketObservation, TradeAction, SpecialistVote, CouncilDecision, RewardResult, StepResult, ResetResult, EnvironmentState.
  • StockerEnv exposes reset() / step() / state() / load_snapshot().
  • The OpenEnv contract is single-agent. Multi-agent council lives in app/council/ and inference.py β€” never inside step().
  • inference.py MUST keep the [START] / [STEP] / [END] log format and also emit [COUNCIL] per step β€” graders parse all four.
  • Reward is clipped to [-1.0, 1.0] at the env boundary (app/core/graders.py).
  • Specialists return JSON {"signal": float, "confidence": float, "rationale": str} β€” the parser in app/council/llm.py tolerates fenced code blocks and trailing prose.
  • The moderator response goes with extra_body={"lora_request": {"name": ...}} when a LoRA is configured, otherwise plain base.
  • Cache layout: .cache/council/<role>/base/<ticker>__<date>.json for specialists, .cache/council/moderator/<lora>/<ticker>__<date>__<hash>.json for the moderator (votes hash differentiates).
  • Tests use MockLLMClient β€” never HF_TOKEN in CI. The mock routes by system-prompt keyword, so changing role keywords requires updating MockLLMClient.SIGNAL_BIAS.

Don't

  • Don't introduce a frontend build step β€” the HTML lives inline in app/api/frontend.py.
  • Don't bake live API calls into specialists. Council inputs come from the bundled parquet dataset (app/data/loader.py). Live sources are the data builder's job.
  • Don't pull large model weights into the Docker image; serve via vLLM externally.
  • Don't break the per-step [COUNCIL] log line format β€” the writeup + trainer's reward replay both depend on it.
  • Don't make specialists rely on the moderator's LoRA. Specialists must remain frozen so their cached votes are reusable across GRPO steps.