{"owner":"ValueCell-ai","repo":"valuecell","hasSkills":true,"totalSkillsCount":5,"totalTokensCount":7591,"categories":["root-instruction","anthropic-skill","subagent-persona"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md","python/configs/agents/super_agent.yaml","python/configs/agents/research_agent.yaml","python/configs/agents/news_agent.yaml","python/valuecell/agents/common/trading/README.md"],"skills":{"AGENTS.md":"# Guidelines\n\n## Python Programming\n\n### Python Environment\n\n* Package manager: uv\n* Virtual environment: `./python/.venv`\n* Testing command: `uv run pytest`\n\n### Imports\n\n* Avoid inline imports unless required to break a circular dependency.\n* If you import more than three names from a single module, prefer qualified imports:\n  * Prefer: `import pathlib; pathlib.Path, pathlib.PurePath`\n  * Avoid: `from pathlib import Path, PurePath, PurePosixPath, ...`\n* Postpone changes to `__init__` and `__all__` until APIs stabilize.\n* Use TYPE_CHECKING for imports only needed for type hints.\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypkg.schemas import AgentConfig\n```\n\n### Runtime Checks\n\n* Avoid excessive use of `getattr`, `hasattr`, and runtime type checks.\n* If an object is a pydantic `BaseModel`, prefer using its validated attributes and type annotations instead of probing attributes at runtime.\n* Rely on pydantic validation, model validators, and type hints; prefer `TypedDict` or `Protocol` for structural typing when appropriate.\n* When runtime checks are necessary, make them explicit, minimal, and well-documented so the reason for the guard is clear.\n\n### Async-First Design\n\n* Prefer asynchronous APIs for I/O-bound work.\n* Use asyncio or anyio; for HTTP, prefer httpx (async client).\n* Ensure clear async boundaries: public APIs and I/O paths should be async.\n* Provide minimal sync adapters only when needed, and document them.\n\n```python\nimport asyncio\nfrom loguru import logger\nimport httpx\n\nasync def fetch_agent_state(url: str, timeout_s: float) -> dict:\n    \"\"\"Fetch agent state from a remote endpoint.\"\"\"\n    async with httpx.AsyncClient(timeout=timeout_s) as client:\n        resp = await client.get(url)\n        resp.raise_for_status()\n        data = resp.json()\n        logger.info(\"Fetched state from {url}\", url=url)\n        return data\n\ndef fetch_agent_state_sync(url: str, timeout_s: float) -> dict:\n    \"\"\"Synchronous adapter. Prefer the async variant.\"\"\"\n    return asyncio.run(fetch_agent_state(url, timeout_s))\n```\n\n### Logging\n\n* Use loguru; placeholders must be {} rather than %.\n* Log key events at info; avoid excessive logging.\n* Do not log sensitive data.\n* Use `logger.exception` sparingly: only for truly unexpected errors that require stack traces for debugging. For expected or recoverable errors, prefer `logger.warning` or `logger.error` with explicit context.\n* Prefer `logger.warning` for recoverable issues, degraded states, or when an operation can continue despite an error.\n\n```python\nfrom loguru import logger\n\ndef process_items(items: list[str]) -> int:\n    \"\"\"Process items and return count.\"\"\"\n    count = len(items)\n    logger.info(\"Processing {count} items\", count=count)\n    # ...\n    logger.info(\"Processed {count} items\", count=count)\n    return count\n\n# Good: expected error, use warning with context\nasync def send_notification(msg: str) -> None:\n    \"\"\"Send notification; log warning if it fails (non-critical).\"\"\"\n    try:\n        await notify_service(msg)\n    except NetworkError as exc:\n        logger.warning(\"Notification failed, continuing: {err}\", err=str(exc))\n\n# Good: unexpected error requiring investigation, use exception\nasync def critical_operation() -> None:\n    \"\"\"Perform critical operation that should never fail.\"\"\"\n    try:\n        await process_critical_data()\n    except Exception:\n        logger.exception(\"Critical operation failed unexpectedly\")\n        raise\n```\n\n### Type Hints and Comments\n\n* Add type hints across public and internal APIs.\n* Comments and docstrings should be in English and explain why, not only what.\n* Use Protocols and TypedDict or pydantic models where appropriate.\n* Avoid excessive literal dict access (for example, using `obj['key']` everywhere); prefer typed structures such as `dataclass`, pydantic models, or `TypedDict` for clearer contracts and better type safety.\n\n### Error Handling\n\n* Keep try-except depth to at most two levels.\n* Catch specific exceptions. Re-raise with context if needed.\n* Prefer explicit None checks and guard clauses over broad exception use.\n\n```python\nimport json\nfrom loguru import logger\n\ndef parse_payload(raw: str) -> dict:\n    \"\"\"Parse payload; return empty dict on known format errors.\"\"\"\n    try:\n        data = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        logger.info(\"Invalid JSON: {err}\", err=str(exc))\n        return {}\n    return data\n```\n\n### Structure and Size\n\n* Avoid nested functions; extract helpers at module level.\n* Keep functions under 200 lines. Split into well-named helpers.\n* Avoid functions with more than 10 parameters; prefer wrapping parameters in a struct or object.\n* Separate concerns: I/O, parsing, business logic, and orchestration.\n\n### Strings and Literals\n\n* Avoid long string literals; wrap lines under 100 characters.\n* Avoid magic numbers and ad-hoc string literals. Centralize constants.\n\n```python\n# constants.py\nDEFAULT_TIMEOUT_S: float = 10.0\nMAX_RETRIES: int = 3\n```\n\n### Boolean Logic\n\n* Be careful with or where 0, empty, or False may be meaningful.\n* Prefer explicit checks:\n\n```python\n# Prefer\nvalue = user_value if user_value is not None else default\n\n# Avoid\nvalue = user_value or default\n```\n\n### Module and Package Layout\n\n* Group agent core, adapters, and utilities into separate modules.\n* Keep public surface small. Delay re-exports in __init__ until stable.\n* If circular dependencies appear, refactor shared contracts to a thin shared module (e.g., interfaces.py or contracts.py).\n","python/configs/agents/super_agent.yaml":"# ============================================\n# Super Agent Configuration\n# ============================================\n# The Super Agent acts as the orchestration layer that:\n# - Triages user intent before planning\n# - Decides whether to answer directly or handoff to Planner\n# - Provides initial query enrichment and context gathering\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file \n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"Super Agent\"\nenabled: true\n\n# TODO support agent level model config\n\n# Model Configuration\n# Super Agent typically needs a capable reasoning model\n#models:\n#  # Primary model for triage, reasoning, and query enrichment\n#  primary:\n#    model_id: \"anthropic/claude-haiku-4.5\"\n#    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n#\n#    # Provider-specific model mappings for fallback\n#    # Used when primary provider fails and fallback is attempted\n#    provider_models:\n#      siliconflow: \"deepseek-ai/DeepSeek-V3.1-Terminus\"  # Similar capability to Claude Haiku\n#      google: \"gemini-2.5-flash\"  # Fast and efficient like Claude Haiku\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  PLANNER_MODEL_ID: \"models.primary.model_id\"\n  SUPER_AGENT_MODEL_ID: \"models.primary.model_id\"  # Alias for clarity\n  SUPER_AGENT_PROVIDER: \"models.primary.provider\"\n  SUPER_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  SUPER_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n# Super Agent Capabilities\ncapabilities:\n  # Enable web search for context enrichment\n  web_search: true\n  \n  # Enable crawling capabilities\n  web_crawl: true\n  \n  # Session management\n  session_management:\n    enabled: true\n    max_history_runs: 5\n    enable_summaries: true\n\n# Advanced Settings\nadvanced:\n  # Debug mode (can be overridden by AGENT_DEBUG_MODE env var)\n  debug_mode: false\n\n  # Output format\n  markdown: false\n  \n  # Context settings\n  add_datetime_to_context: true\n  add_history_to_context: true\n  read_chat_history: true\n\n","python/configs/agents/research_agent.yaml":"# ============================================\n# Research Agent Configuration\n# ============================================\nname: \"Research Agent\"\nenabled: true\n\n# Model Configuration\n# Priority: Environment Variables > .env > YAML\nmodels:\n  # Primary model for reasoning and generation\n  primary:\n    model_id: \"google/gemini-2.5-flash\"\n    provider: \"openrouter\"\n    # Provider-specific model mappings for fallback\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"\n      google: \"gemini-2.5-flash\"\n    parameters:\n      # temperature: 0.7\n      # max_tokens: 8192\n  \n  # Embedding model for knowledge base\n  # Note: If not specified, will auto-select from available providers\n  embedding:\n    model_id: \"Qwen/Qwen3-Embedding-4B\"  # Optional, uses provider default\n    provider: \"siliconflow\"  # Must explicitly specify provider\n    # Provider-specific embedding model mappings for fallback\n    provider_models:\n      google: \"gemini-embedding-001\"\n    parameters:\n      dimensions: ${EMBEDDER_DIMENSION:2560}\n      # encoding_format: \"float\"\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\nenv_overrides:\n  # Primary model overrides\n  RESEARCH_AGENT_MODEL_ID: \"models.primary.model_id\"\n  RESEARCH_AGENT_PROVIDER: \"models.primary.provider\"\n  RESEARCH_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  RESEARCH_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n  \n  # Embedding model overrides (backward compatible with existing env vars)\n  EMBEDDER_MODEL_ID: \"models.embedding.model_id\"\n  EMBEDDER_MODEL_PROVIDER: \"models.embedding.provider\"\n  EMBEDDER_DIMENSION: \"models.embedding.parameters.dimensions\"\n\n","python/configs/agents/news_agent.yaml":"# ============================================\n# News Agent Configuration\n# ============================================\n# The News Agent specializes in gathering, analyzing, and presenting news information.\n# It provides real-time news search, categorized news retrieval, and comprehensive analysis.\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file\n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"News Agent\"\nenabled: true\n\n# Model Configuration\n# News Agent needs a capable model for news analysis and summarization\nmodels:\n  # Primary model for news analysis, summarization, and query processing\n  primary:\n    model_id: \"qwen/qwen3-max\"\n    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n\n    # Provider-specific model mappings for fallback\n    # Used when primary provider fails and fallback is attempted\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"  # Strong reasoning for news analysis\n      google: \"gemini-2.5-flash\"  # Fast and efficient for news processing\n\n    parameters:\n      # temperature: 0.3  # Lower temperature for more factual news reporting\n      # max_tokens: 4096  # Sufficient for comprehensive news analysis\n\n  # Web search model for real-time information gathering\n  # Uses specialized models optimized for web search and real-time data\n  search:\n    model_id: \"perplexity/sonar\"\n    provider: \"openrouter\"\n\n    # Provider-specific search model mappings\n    provider_models:\n      google: \"gemini-2.5-flash\"  # With search grounding enabled\n\n    parameters:\n      # max_tokens: 2048  # Optimized for search result processing\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  NEWS_AGENT_MODEL_ID: \"models.primary.model_id\"\n  NEWS_AGENT_PROVIDER: \"models.primary.provider\"\n  NEWS_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  NEWS_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n  # Search model overrides\n  NEWS_SEARCH_MODEL_ID: \"models.search.model_id\"\n  NEWS_SEARCH_PROVIDER: \"models.search.provider\"\n\n  # Web search provider configuration\n  WEB_SEARCH_PROVIDER: \"capabilities.web_search.provider\"\n\n# News Agent Capabilities\ncapabilities:\n  # Web search configuration\n  web_search:\n    enabled: true\n    provider: \"perplexity\"  # Default: perplexity, alternative: google\n    max_results: 10\n\n  # Breaking news monitoring\n  breaking_news:\n    enabled: true  # Enable breaking news monitoring\n    refresh_interval: 300  # seconds\n\n  # Financial news specialization\n  financial_news:\n    enabled: true\n    supported_markets: [\"US\", \"Global\"]\n    include_sectors: true\n    include_individual_stocks: true\n\n\n\n  # Multi-language support\n  languages:\n    enabled: true\n    supported: [\"en\", \"zh\", \"ja\", \"ko\", \"es\", \"fr\", \"de\"]\n    default: \"en\"\n\n  # News analysis features\n  analysis:\n    sentiment_analysis: true\n    topic_extraction: true\n    entity_recognition: true\n    summarization: true\n    fact_checking: false  # Requires additional verification tools\n\n# Tool Configuration\ntools:\n  web_search:\n    enabled: true\n\n  get_breaking_news:\n    enabled: true\n\n  get_financial_news:\n    enabled: true","python/valuecell/agents/common/trading/README.md":"# Trading Agent Framework\n\nThis document describes the common trading agent framework: a flexible, composable architecture for building LLM-driven trading strategies with clean separation of concerns and extensible components.\n\n## Architecture Overview\n\nThe framework provides a base class (`BaseStrategyAgent`) that handles lifecycle management, streaming, and persistence, while allowing users to customize decision logic and feature computation through well-defined extension points.\n\n**Key Principles:**\n\n- **Separation of Concerns**: Data fetching, feature computation, decision making, execution, and history tracking are independent modules\n- **Extensibility**: Override specific components without rewriting the entire pipeline\n- **Type Safety**: Pydantic models ensure data contracts across boundaries\n- **Async-First**: Built on asyncio for efficient I/O and concurrent operations\n- **Auditable**: Each decision cycle has a unique `compose_id` for tracing\n\n## Module Layout\n\n```text\ncommon/trading/\n├── base_agent.py          # BaseStrategyAgent abstract class\n├── models.py              # Pydantic DTOs and enums\n├── constants.py           # Default configuration values\n├── utils.py               # Shared utilities\n├── _internal/             # Internal runtime implementation\n│   ├── coordinator.py     # DefaultDecisionCoordinator\n│   ├── runtime.py         # StrategyRuntime factory\n│   └── stream_controller.py  # Persistence and streaming\n├── data/                  # Market data sources\n│   ├── interfaces.py      # BaseMarketDataSource\n│   └── market.py          # SimpleMarketDataSource (CCXT)\n├── features/              # Feature computation\n│   ├── interfaces.py      # BaseFeaturesPipeline, CandleBasedFeatureComputer\n│   ├── pipeline.py        # DefaultFeaturesPipeline\n│   ├── candle.py          # SimpleCandleFeatureComputer\n│   └── market_snapshot.py # MarketSnapshotFeatureComputer\n├── decision/              # Decision composers\n│   ├── interfaces.py      # BaseComposer\n│   └── prompt_based/\n│       ├── composer.py    # LlmComposer\n│       └── system_prompt.py\n├── execution/             # Trade execution\n│   ├── interfaces.py      # BaseExecutionGateway\n│   ├── factory.py         # Gateway factory\n│   ├── paper_trading.py   # PaperExecutionGateway\n│   └── ccxt_trading.py    # CCXTExecutionGateway (live)\n├── portfolio/             # Portfolio management\n│   ├── interfaces.py      # BasePortfolioService\n│   └── in_memory.py       # InMemoryPortfolioService\n└── trading_history/       # History and digest\n    ├── interfaces.py      # BaseHistoryRecorder, BaseDigestBuilder\n    ├── recorder.py        # InMemoryHistoryRecorder\n    └── digest.py          # RollingDigestBuilder\n```\n\n## Data Flow (Decision Cycle)\n\nEach decision cycle follows this pipeline:\n\n1. **Portfolio State**: Coordinator fetches current `PortfolioView` (positions, cash, constraints)\n2. **Data Collection**: Pipeline pulls market data (candles, tickers, funding rates, etc.)\n3. **Feature Computation**: Pipeline computes `FeatureVector[]` from raw data\n4. **Context Assembly**: Coordinator builds `ComposeContext` with features, portfolio, digest, and constraints\n5. **Decision**: Composer (LLM + guardrails) produces normalized `TradeInstruction[]`\n6. **Execution**: Gateway executes instructions and returns `TxResult[]`\n7. **Portfolio Update**: Service applies trades to update positions and metrics\n8. **History**: Recorder checkpoints features, instructions, trades, and summary\n9. **Digest**: Builder updates `TradeDigest` for next cycle's context\n\n```text\n                                        ┌─────────────┐\n                                        │  Portfolio  │\n                                        │    View     │\n                                        └──────┬──────┘\n                                               │\n                                               ▼\n┌─────────────┐    ┌──────────────┐    ┌─────────────┐\n│   Market    │───▶│   Features   │───▶│   Context   │\n│    Data     │    │   Pipeline   │    │  Assembly   │\n└─────────────┘    └──────────────┘    └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Composer   │\n                                       │             │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Execution  │\n                                       │   Gateway   │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n       ┌──────────────────────────────────────┴────────────────┐\n       │                                                       │\n       ▼                                                       ▼\n┌─────────────┐                                         ┌─────────────┐\n│   History   │                                         │  Portfolio  │\n│   Recorder  │                                         │   Update    │\n└──────┬──────┘                                         └─────────────┘\n       │\n       ▼\n┌─────────────┐\n│   Digest    │\n│   Builder   │\n└─────────────┘\n```\n\n## Core Data Models\n\n### Configuration\n\nUserRequest\n\n- `llm_model_config: LLMModelConfig` — AI model settings\n- `exchange_config: ExchangeConfig` — Trading mode, exchange, credentials\n- `trading_config: TradingConfig` — Strategy parameters\n\nTradingConfig\n\n- `strategy_name?: str` — Display name\n- `initial_capital: float` — Starting total cash in USD\n- `initial_free_cash: float` — Starting free cash in USD (same as initial_capital if there's no initial positions)\n- `max_leverage: float` — Maximum leverage allowed\n- `max_positions: int` — Concurrent position limit\n- `symbols: List[str]` — Instruments to trade (e.g., `[\"BTC-USDT\", \"ETH-USDT\"]`)\n- `decide_interval: int` — Seconds between cycles\n- `custom_prompt?: str` — Custom strategy prompt\n- `prompt_text?: str` — Additional prompt text\n\n### Market Data\n\nCandle\n\n- `ts: int` — Timestamp (milliseconds)\n- `instrument: InstrumentRef` — Symbol reference\n- `open, high, low, close, volume: float` — OHLCV data\n- `interval: str` — Timeframe (e.g., \"1m\", \"1h\")\n\nFeatureVector\n\n- `ts: int` — Feature timestamp\n- `instrument: InstrumentRef` — Associated symbol\n- `values: Dict[str, float]` — Feature key-value pairs\n- `meta?: Dict[str, Any]` — Optional metadata (interval, group_by_key, etc.)\n\n### Portfolio\n\nPositionSnapshot\n\n- `instrument: InstrumentRef`\n- `quantity: float` — Signed quantity (+long, -short)\n- `avg_price?: float` — Average entry price\n- `mark_price?: float` — Current market price\n- `unrealized_pnl?: float` — Unrealized profit/loss\n- `leverage?: float` — Applied leverage\n- `entry_ts?: int` — Entry timestamp\n\nPortfolioView\n\n- `strategy_id: str`\n- `ts: int` — Snapshot timestamp\n- `account_balance: float` — Cash balance\n- `positions: Dict[str, PositionSnapshot]` — Active positions by symbol\n- `total_value?: float` — Portfolio equity\n- `total_unrealized_pnl?: float` — Sum of position unrealized PnL\n- `buying_power?: float` — Available buying power\n- `constraints?: Constraints` — Position and leverage limits\n\n### Decision\n\nComposeContext\n\n- `ts: int` — Cycle timestamp\n- `compose_id: str` — Unique cycle identifier\n- `strategy_id: str`\n- `features: List[FeatureVector]` — Computed features\n- `portfolio: PortfolioView` — Current portfolio state\n- `digest: TradeDigest` — Historical performance summary\n\nTradeInstruction\n\n- `instruction_id: str` — Unique instruction ID\n- `compose_id: str` — Parent cycle ID\n- `instrument: InstrumentRef`\n- `side: TradeSide` — BUY or SELL\n- `quantity: float` — Order quantity\n- `leverage?: float` — Applied leverage\n- `max_slippage_bps?: int` — Maximum slippage (basis points)\n- `meta?: Dict` — Optional metadata\n\n### Execution\n\nTxResult\n\n- `instruction_id: str`\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `status: TxStatus` — FILLED, PARTIAL, REJECTED, ERROR\n- `requested_qty: float`\n- `filled_qty: float`\n- `avg_exec_price?: float`\n- `fee_cost?: float`\n- `leverage?: float`\n\n### History\n\nTradeHistoryEntry\n\n- `trade_id: str`\n- `compose_id: str` — Originating cycle\n- `instruction_id: str` — Originating instruction\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `type: TradeType` — LONG or SHORT\n- `quantity: float`\n- `entry_price?, exit_price?: float`\n- `entry_ts?, exit_ts?: int`\n- `realized_pnl?: float` — Profit/loss on close\n- `holding_ms?: int` — Position duration\n\nTradeDigest\n\n- `ts: int`\n- `by_instrument: Dict[str, TradeDigestEntry]`\n- `sharpe_ratio?: float` — Portfolio Sharpe ratio\n\n**TradeDigestEntry** (per-symbol stats)\n\n- `trade_count: int`\n- `realized_pnl: float`\n- `win_rate?: float`\n- `avg_holding_ms?: int`\n- `last_trade_ts?: int`\n\n---\n\n## Integration Guide\n\n### Quick Start: Using the Default Agent\n\nThe simplest way to create a trading agent is to use `prompt_strategy_agent`, which provides default implementations for all components:\n\n```python\n# python/valuecell/agents/prompt_strategy_agent/__main__.py\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import StrategyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(StrategyAgent)\n    asyncio.run(agent.serve())\n```\n\n**StrategyAgent** (in `core.py`) extends `BaseStrategyAgent` and uses:\n\n- `DefaultFeaturesPipeline`: Fetches candles and computes technical indicators\n- `LlmComposer`: LLM-based decision making with guardrails\n\nTo run:\n\n```bash\ncd python/valuecell/agents/prompt_strategy_agent\npython -m valuecell.agents.prompt_strategy_agent\n```\n\n### Custom Agent: Override Specific Components\n\nCreate a custom agent by subclassing `BaseStrategyAgent` and overriding extension points:\n\n#### Example 1: Custom Feature Pipeline\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.features import BaseFeaturesPipeline\nfrom valuecell.agents.common.trading.models import (\n    FeaturesPipelineResult,\n    FeatureVector,\n    UserRequest,\n)\n\nclass MyFeaturesPipeline(BaseFeaturesPipeline):\n    \"\"\"Custom pipeline with specialized indicators.\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n        self.symbols = request.trading_config.symbols\n        # Initialize custom data sources, indicators, etc.\n    \n    async def build(self) -> FeaturesPipelineResult:\n        features = []\n        # Fetch data and compute custom features\n        # ... your logic here ...\n        return FeaturesPipelineResult(features=features)\n\n\nclass MyCustomAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom feature computation.\"\"\"\n    \n    async def _build_features_pipeline(\n        self, request: UserRequest\n    ) -> BaseFeaturesPipeline | None:\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Use default LLM composer\n        return None\n```\n\n#### Example 2: Custom Decision Composer\n\n```python\nfrom valuecell.agents.common.trading.decision import BaseComposer\nfrom valuecell.agents.common.trading.models import (\n    ComposeContext,\n    ComposeResult,\n    TradeInstruction,\n)\n\nclass RuleBasedComposer(BaseComposer):\n    \"\"\"Simple rule-based decision maker (no LLM).\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n    \n    async def compose(self, context: ComposeContext) -> ComposeResult:\n        instructions = []\n        # Implement your trading rules\n        # Example: Buy when RSI < 30, sell when RSI > 70\n        for fv in context.features:\n            rsi = fv.values.get(\"rsi\")\n            if rsi and rsi < 30:\n                # Create buy instruction\n                pass\n            elif rsi and rsi > 70:\n                # Create sell instruction\n                pass\n        \n        return ComposeResult(\n            instructions=instructions,\n            rationale=\"Rule-based signals\"\n        )\n\n\nclass RuleBasedAgent(BaseStrategyAgent):\n    \"\"\"Agent using rule-based decisions.\"\"\"\n    \n    async def _build_features_pipeline(self, request: UserRequest):\n        # Use default pipeline\n        return None\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        return RuleBasedComposer(request)\n```\n\n#### Example 3: Lifecycle Hooks\n\n```python\nclass MonitoredAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom monitoring and logging.\"\"\"\n    \n    async def _on_start(self, runtime, request):\n        \"\"\"Called once after runtime creation.\"\"\"\n        self.cycle_count = 0\n        print(f\"Strategy {runtime.strategy_id} starting...\")\n    \n    async def _on_cycle_result(self, result, runtime, request):\n        \"\"\"Called after each cycle completes.\"\"\"\n        self.cycle_count += 1\n        print(f\"Cycle {self.cycle_count}: \"\n              f\"{len(result.trades)} trades, \"\n              f\"PnL: {result.strategy_summary.realized_pnl}\")\n        \n        # Send metrics to external monitoring\n        # ... custom logic ...\n    \n    async def _on_stop(self, runtime, request, reason):\n        \"\"\"Called before finalization.\"\"\"\n        print(f\"Strategy stopping: {reason}\")\n        print(f\"Total cycles: {self.cycle_count}\")\n    \n    async def _build_features_pipeline(self, request):\n        return None  # Use defaults\n    \n    async def _create_decision_composer(self, request):\n        return None  # Use defaults\n```\n\n### Creating a Complete Custom Agent Module\n\n**Directory Structure:**\n\n```text\npython/valuecell/agents/my_agent/\n├── __init__.py\n├── __main__.py          # Entry point\n├── core.py              # Agent implementation\n├── features.py          # Custom features (optional)\n├── composer.py          # Custom composer (optional)\n└── templates/\n    └── strategy.txt     # Strategy prompt template\n```\n\n**`__main__.py`:**\n\n```python\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import MyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(MyAgent)\n    asyncio.run(agent.serve())\n```\n\n**`core.py`:**\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.models import UserRequest\nfrom .features import MyFeaturesPipeline  # if custom\nfrom .composer import MyComposer  # if custom\n\nclass MyAgent(BaseStrategyAgent):\n    async def _build_features_pipeline(self, request: UserRequest):\n        # Return custom pipeline or None for default\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Return custom composer or None for default\n        return MyComposer(request)\n```\n\n**Run your agent:**\n\n```bash\ncd python/valuecell/agents/my_agent\npython -m valuecell.agents.my_agent\n```\n\n### Live Trading Setup\n\nFor live trading with real exchanges:\n\n**Set trading mode to LIVE:**\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"live\",\n    \"exchange_id\": \"binance\",\n    \"api_key\": \"YOUR_API_KEY\",\n    \"secret_key\": \"YOUR_SECRET_KEY\",\n    \"testnet\": true  // Use testnet first!\n  }\n}\n```\n\n**The runtime automatically:**\n\n- Fetches real account balance\n- Sets `initial_capital` to account total cash\n- Sets `initial_free_cash` to available cash\n- Uses `CCXTExecutionGateway` for order submission\n\n**Always test on testnet first** before using real funds\n\n### Testing Strategies\n\n#### Paper Trading (Default)\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"virtual\",\n    \"fee_bps\": 10.0  // 0.1% simulated fees\n  }\n}\n```\n\nPaper trading uses `PaperExecutionGateway` which:\n\n- Simulates order fills at market price ± slippage\n- Applies configurable fees\n- No real exchange connection needed\n\n#### Backtesting\n\nCreate a custom `BaseMarketDataSource` that replays historical data:\n\n```python\nfrom valuecell.agents.common.trading.data import BaseMarketDataSource\nfrom valuecell.agents.common.trading.models import Candle\n\nclass BacktestDataSource(BaseMarketDataSource):\n    def __init__(self, historical_data):\n        self.data = historical_data\n        self.current_index = 0\n    \n    async def get_recent_candles(self, symbols, interval, lookback):\n        # Return historical candles for current timestamp\n        candles = self.data[self.current_index]\n        self.current_index += 1\n        return candles\n    \n    async def get_market_snapshot(self, symbols):\n        # Return snapshot from historical data\n        return {}\n```\n\nThen use it in your custom pipeline.\n\n### Extension Points Summary\n\n| Component | Method | Purpose |\n|-----------|--------|---------|\n| **Features** | `_build_features_pipeline()` | Define how market data is fetched and processed |\n| **Decision** | `_create_decision_composer()` | Customize trading logic (LLM, rules, ML) |\n| **Lifecycle** | `_on_start()` | Initialize resources after runtime creation |\n| **Lifecycle** | `_on_cycle_result()` | Monitor/log each cycle result |\n| **Lifecycle** | `_on_stop()` | Cleanup before finalization |\n\n### Best Practices\n\n1. **Start with defaults**: Use `prompt_strategy_agent` as a template\n2. **Override incrementally**: Only customize what you need\n3. **Type safety**: Use Pydantic models for all data contracts\n4. **Async operations**: Mark I/O operations as `async`\n5. **Error handling**: Hooks swallow exceptions to prevent crashes\n6. **Testnet first**: Always test live trading on testnet\n7. **Monitor carefully**: Use lifecycle hooks for observability\n\n### Common Patterns\n\n#### Adding Custom Indicators\n\n```python\nclass CustomFeaturesPipeline(BaseFeaturesPipeline):\n    async def build(self):\n        # Fetch candles\n        candles = await self.market_data.get_recent_candles(...)\n        \n        # Compute standard indicators\n        rsi = compute_rsi(candles)\n        macd = compute_macd(candles)\n        \n        # Add custom indicators\n        my_signal = compute_custom_indicator(candles)\n        \n        features = []\n        for symbol in symbols:\n            features.append(FeatureVector(\n                ts=timestamp,\n                instrument=InstrumentRef(symbol=symbol),\n                values={\n                    \"rsi\": rsi[symbol],\n                    \"macd\": macd[symbol],\n                    \"custom_signal\": my_signal[symbol],\n                }\n            ))\n        \n        return FeaturesPipelineResult(features=features)\n```\n\n#### Combining LLM with Rules\n\n```python\nclass HybridComposer(BaseComposer):\n    def __init__(self, request):\n        self.llm_composer = LlmComposer(request)\n        self.request = request\n    \n    async def compose(self, context):\n        # Get LLM suggestions\n        llm_result = await self.llm_composer.compose(context)\n        \n        # Apply additional rule filters\n        filtered_instructions = []\n        for inst in llm_result.instructions:\n            if self._passes_risk_check(inst, context):\n                filtered_instructions.append(inst)\n        \n        return ComposeResult(\n            instructions=filtered_instructions,\n            rationale=f\"LLM + risk filters: {llm_result.rationale}\"\n        )\n    \n    def _passes_risk_check(self, inst, context):\n        # Custom risk rules\n        return True\n```\n\n### Debugging\n\nEnable detailed logging:\n\n```python\nimport logging\nfrom loguru import logger\n\nlogger.add(\"strategy_{time}.log\", level=\"DEBUG\")\n```\n\nThe framework logs:\n\n- Cycle start/end with compose_id\n- Instruction count and details\n- Execution results and fills\n- Portfolio updates\n- Error traces with context\n\n---\n\n## Advanced Topics\n\n### Custom Execution Gateway\n\nImplement `BaseExecutionGateway` to integrate custom execution logic:\n\n```python\nfrom valuecell.agents.common.trading.execution import BaseExecutionGateway\nfrom valuecell.agents.common.trading.models import (\n    TradeInstruction,\n    TxResult,\n    TxStatus,\n)\n\nclass MyExecutionGateway(BaseExecutionGateway):\n    async def execute(self, instructions, market_features):\n        results = []\n        for inst in instructions:\n            # Your execution logic\n            result = TxResult(\n                instruction_id=inst.instruction_id,\n                instrument=inst.instrument,\n                side=inst.side,\n                status=TxStatus.FILLED,\n                requested_qty=inst.quantity,\n                filled_qty=inst.quantity,\n                avg_exec_price=100.0,  # from your system\n            )\n            results.append(result)\n        return results\n```\n\n### Custom Portfolio Service\n\nOverride portfolio management for complex accounting:\n\n```python\nfrom valuecell.agents.common.trading.portfolio import BasePortfolioService\n\nclass CustomPortfolioService(BasePortfolioService):\n    def get_view(self):\n        # Return custom PortfolioView\n        pass\n    \n    def apply_trades(self, trades, market_features):\n        # Update internal state\n        pass\n```\n\n### Persistence Integration\n\nUse `StreamController` to persist strategy state to your database. The framework already handles:\n\n- Initial portfolio snapshot\n- Cycle results (compose cycles, instructions, execution details)\n- Final cleanup and status updates\n\nSee `_internal/stream_controller.py` for persistence logic.\n"},"files":{"AGENTS.md":"# Guidelines\n\n## Python Programming\n\n### Python Environment\n\n* Package manager: uv\n* Virtual environment: `./python/.venv`\n* Testing command: `uv run pytest`\n\n### Imports\n\n* Avoid inline imports unless required to break a circular dependency.\n* If you import more than three names from a single module, prefer qualified imports:\n  * Prefer: `import pathlib; pathlib.Path, pathlib.PurePath`\n  * Avoid: `from pathlib import Path, PurePath, PurePosixPath, ...`\n* Postpone changes to `__init__` and `__all__` until APIs stabilize.\n* Use TYPE_CHECKING for imports only needed for type hints.\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypkg.schemas import AgentConfig\n```\n\n### Runtime Checks\n\n* Avoid excessive use of `getattr`, `hasattr`, and runtime type checks.\n* If an object is a pydantic `BaseModel`, prefer using its validated attributes and type annotations instead of probing attributes at runtime.\n* Rely on pydantic validation, model validators, and type hints; prefer `TypedDict` or `Protocol` for structural typing when appropriate.\n* When runtime checks are necessary, make them explicit, minimal, and well-documented so the reason for the guard is clear.\n\n### Async-First Design\n\n* Prefer asynchronous APIs for I/O-bound work.\n* Use asyncio or anyio; for HTTP, prefer httpx (async client).\n* Ensure clear async boundaries: public APIs and I/O paths should be async.\n* Provide minimal sync adapters only when needed, and document them.\n\n```python\nimport asyncio\nfrom loguru import logger\nimport httpx\n\nasync def fetch_agent_state(url: str, timeout_s: float) -> dict:\n    \"\"\"Fetch agent state from a remote endpoint.\"\"\"\n    async with httpx.AsyncClient(timeout=timeout_s) as client:\n        resp = await client.get(url)\n        resp.raise_for_status()\n        data = resp.json()\n        logger.info(\"Fetched state from {url}\", url=url)\n        return data\n\ndef fetch_agent_state_sync(url: str, timeout_s: float) -> dict:\n    \"\"\"Synchronous adapter. Prefer the async variant.\"\"\"\n    return asyncio.run(fetch_agent_state(url, timeout_s))\n```\n\n### Logging\n\n* Use loguru; placeholders must be {} rather than %.\n* Log key events at info; avoid excessive logging.\n* Do not log sensitive data.\n* Use `logger.exception` sparingly: only for truly unexpected errors that require stack traces for debugging. For expected or recoverable errors, prefer `logger.warning` or `logger.error` with explicit context.\n* Prefer `logger.warning` for recoverable issues, degraded states, or when an operation can continue despite an error.\n\n```python\nfrom loguru import logger\n\ndef process_items(items: list[str]) -> int:\n    \"\"\"Process items and return count.\"\"\"\n    count = len(items)\n    logger.info(\"Processing {count} items\", count=count)\n    # ...\n    logger.info(\"Processed {count} items\", count=count)\n    return count\n\n# Good: expected error, use warning with context\nasync def send_notification(msg: str) -> None:\n    \"\"\"Send notification; log warning if it fails (non-critical).\"\"\"\n    try:\n        await notify_service(msg)\n    except NetworkError as exc:\n        logger.warning(\"Notification failed, continuing: {err}\", err=str(exc))\n\n# Good: unexpected error requiring investigation, use exception\nasync def critical_operation() -> None:\n    \"\"\"Perform critical operation that should never fail.\"\"\"\n    try:\n        await process_critical_data()\n    except Exception:\n        logger.exception(\"Critical operation failed unexpectedly\")\n        raise\n```\n\n### Type Hints and Comments\n\n* Add type hints across public and internal APIs.\n* Comments and docstrings should be in English and explain why, not only what.\n* Use Protocols and TypedDict or pydantic models where appropriate.\n* Avoid excessive literal dict access (for example, using `obj['key']` everywhere); prefer typed structures such as `dataclass`, pydantic models, or `TypedDict` for clearer contracts and better type safety.\n\n### Error Handling\n\n* Keep try-except depth to at most two levels.\n* Catch specific exceptions. Re-raise with context if needed.\n* Prefer explicit None checks and guard clauses over broad exception use.\n\n```python\nimport json\nfrom loguru import logger\n\ndef parse_payload(raw: str) -> dict:\n    \"\"\"Parse payload; return empty dict on known format errors.\"\"\"\n    try:\n        data = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        logger.info(\"Invalid JSON: {err}\", err=str(exc))\n        return {}\n    return data\n```\n\n### Structure and Size\n\n* Avoid nested functions; extract helpers at module level.\n* Keep functions under 200 lines. Split into well-named helpers.\n* Avoid functions with more than 10 parameters; prefer wrapping parameters in a struct or object.\n* Separate concerns: I/O, parsing, business logic, and orchestration.\n\n### Strings and Literals\n\n* Avoid long string literals; wrap lines under 100 characters.\n* Avoid magic numbers and ad-hoc string literals. Centralize constants.\n\n```python\n# constants.py\nDEFAULT_TIMEOUT_S: float = 10.0\nMAX_RETRIES: int = 3\n```\n\n### Boolean Logic\n\n* Be careful with or where 0, empty, or False may be meaningful.\n* Prefer explicit checks:\n\n```python\n# Prefer\nvalue = user_value if user_value is not None else default\n\n# Avoid\nvalue = user_value or default\n```\n\n### Module and Package Layout\n\n* Group agent core, adapters, and utilities into separate modules.\n* Keep public surface small. Delay re-exports in __init__ until stable.\n* If circular dependencies appear, refactor shared contracts to a thin shared module (e.g., interfaces.py or contracts.py).\n","python/configs/agents/super_agent.yaml":"# ============================================\n# Super Agent Configuration\n# ============================================\n# The Super Agent acts as the orchestration layer that:\n# - Triages user intent before planning\n# - Decides whether to answer directly or handoff to Planner\n# - Provides initial query enrichment and context gathering\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file \n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"Super Agent\"\nenabled: true\n\n# TODO support agent level model config\n\n# Model Configuration\n# Super Agent typically needs a capable reasoning model\n#models:\n#  # Primary model for triage, reasoning, and query enrichment\n#  primary:\n#    model_id: \"anthropic/claude-haiku-4.5\"\n#    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n#\n#    # Provider-specific model mappings for fallback\n#    # Used when primary provider fails and fallback is attempted\n#    provider_models:\n#      siliconflow: \"deepseek-ai/DeepSeek-V3.1-Terminus\"  # Similar capability to Claude Haiku\n#      google: \"gemini-2.5-flash\"  # Fast and efficient like Claude Haiku\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  PLANNER_MODEL_ID: \"models.primary.model_id\"\n  SUPER_AGENT_MODEL_ID: \"models.primary.model_id\"  # Alias for clarity\n  SUPER_AGENT_PROVIDER: \"models.primary.provider\"\n  SUPER_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  SUPER_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n# Super Agent Capabilities\ncapabilities:\n  # Enable web search for context enrichment\n  web_search: true\n  \n  # Enable crawling capabilities\n  web_crawl: true\n  \n  # Session management\n  session_management:\n    enabled: true\n    max_history_runs: 5\n    enable_summaries: true\n\n# Advanced Settings\nadvanced:\n  # Debug mode (can be overridden by AGENT_DEBUG_MODE env var)\n  debug_mode: false\n\n  # Output format\n  markdown: false\n  \n  # Context settings\n  add_datetime_to_context: true\n  add_history_to_context: true\n  read_chat_history: true\n\n","python/configs/agents/research_agent.yaml":"# ============================================\n# Research Agent Configuration\n# ============================================\nname: \"Research Agent\"\nenabled: true\n\n# Model Configuration\n# Priority: Environment Variables > .env > YAML\nmodels:\n  # Primary model for reasoning and generation\n  primary:\n    model_id: \"google/gemini-2.5-flash\"\n    provider: \"openrouter\"\n    # Provider-specific model mappings for fallback\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"\n      google: \"gemini-2.5-flash\"\n    parameters:\n      # temperature: 0.7\n      # max_tokens: 8192\n  \n  # Embedding model for knowledge base\n  # Note: If not specified, will auto-select from available providers\n  embedding:\n    model_id: \"Qwen/Qwen3-Embedding-4B\"  # Optional, uses provider default\n    provider: \"siliconflow\"  # Must explicitly specify provider\n    # Provider-specific embedding model mappings for fallback\n    provider_models:\n      google: \"gemini-embedding-001\"\n    parameters:\n      dimensions: ${EMBEDDER_DIMENSION:2560}\n      # encoding_format: \"float\"\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\nenv_overrides:\n  # Primary model overrides\n  RESEARCH_AGENT_MODEL_ID: \"models.primary.model_id\"\n  RESEARCH_AGENT_PROVIDER: \"models.primary.provider\"\n  RESEARCH_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  RESEARCH_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n  \n  # Embedding model overrides (backward compatible with existing env vars)\n  EMBEDDER_MODEL_ID: \"models.embedding.model_id\"\n  EMBEDDER_MODEL_PROVIDER: \"models.embedding.provider\"\n  EMBEDDER_DIMENSION: \"models.embedding.parameters.dimensions\"\n\n","python/configs/agents/news_agent.yaml":"# ============================================\n# News Agent Configuration\n# ============================================\n# The News Agent specializes in gathering, analyzing, and presenting news information.\n# It provides real-time news search, categorized news retrieval, and comprehensive analysis.\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file\n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"News Agent\"\nenabled: true\n\n# Model Configuration\n# News Agent needs a capable model for news analysis and summarization\nmodels:\n  # Primary model for news analysis, summarization, and query processing\n  primary:\n    model_id: \"qwen/qwen3-max\"\n    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n\n    # Provider-specific model mappings for fallback\n    # Used when primary provider fails and fallback is attempted\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"  # Strong reasoning for news analysis\n      google: \"gemini-2.5-flash\"  # Fast and efficient for news processing\n\n    parameters:\n      # temperature: 0.3  # Lower temperature for more factual news reporting\n      # max_tokens: 4096  # Sufficient for comprehensive news analysis\n\n  # Web search model for real-time information gathering\n  # Uses specialized models optimized for web search and real-time data\n  search:\n    model_id: \"perplexity/sonar\"\n    provider: \"openrouter\"\n\n    # Provider-specific search model mappings\n    provider_models:\n      google: \"gemini-2.5-flash\"  # With search grounding enabled\n\n    parameters:\n      # max_tokens: 2048  # Optimized for search result processing\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  NEWS_AGENT_MODEL_ID: \"models.primary.model_id\"\n  NEWS_AGENT_PROVIDER: \"models.primary.provider\"\n  NEWS_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  NEWS_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n  # Search model overrides\n  NEWS_SEARCH_MODEL_ID: \"models.search.model_id\"\n  NEWS_SEARCH_PROVIDER: \"models.search.provider\"\n\n  # Web search provider configuration\n  WEB_SEARCH_PROVIDER: \"capabilities.web_search.provider\"\n\n# News Agent Capabilities\ncapabilities:\n  # Web search configuration\n  web_search:\n    enabled: true\n    provider: \"perplexity\"  # Default: perplexity, alternative: google\n    max_results: 10\n\n  # Breaking news monitoring\n  breaking_news:\n    enabled: true  # Enable breaking news monitoring\n    refresh_interval: 300  # seconds\n\n  # Financial news specialization\n  financial_news:\n    enabled: true\n    supported_markets: [\"US\", \"Global\"]\n    include_sectors: true\n    include_individual_stocks: true\n\n\n\n  # Multi-language support\n  languages:\n    enabled: true\n    supported: [\"en\", \"zh\", \"ja\", \"ko\", \"es\", \"fr\", \"de\"]\n    default: \"en\"\n\n  # News analysis features\n  analysis:\n    sentiment_analysis: true\n    topic_extraction: true\n    entity_recognition: true\n    summarization: true\n    fact_checking: false  # Requires additional verification tools\n\n# Tool Configuration\ntools:\n  web_search:\n    enabled: true\n\n  get_breaking_news:\n    enabled: true\n\n  get_financial_news:\n    enabled: true","python/valuecell/agents/common/trading/README.md":"# Trading Agent Framework\n\nThis document describes the common trading agent framework: a flexible, composable architecture for building LLM-driven trading strategies with clean separation of concerns and extensible components.\n\n## Architecture Overview\n\nThe framework provides a base class (`BaseStrategyAgent`) that handles lifecycle management, streaming, and persistence, while allowing users to customize decision logic and feature computation through well-defined extension points.\n\n**Key Principles:**\n\n- **Separation of Concerns**: Data fetching, feature computation, decision making, execution, and history tracking are independent modules\n- **Extensibility**: Override specific components without rewriting the entire pipeline\n- **Type Safety**: Pydantic models ensure data contracts across boundaries\n- **Async-First**: Built on asyncio for efficient I/O and concurrent operations\n- **Auditable**: Each decision cycle has a unique `compose_id` for tracing\n\n## Module Layout\n\n```text\ncommon/trading/\n├── base_agent.py          # BaseStrategyAgent abstract class\n├── models.py              # Pydantic DTOs and enums\n├── constants.py           # Default configuration values\n├── utils.py               # Shared utilities\n├── _internal/             # Internal runtime implementation\n│   ├── coordinator.py     # DefaultDecisionCoordinator\n│   ├── runtime.py         # StrategyRuntime factory\n│   └── stream_controller.py  # Persistence and streaming\n├── data/                  # Market data sources\n│   ├── interfaces.py      # BaseMarketDataSource\n│   └── market.py          # SimpleMarketDataSource (CCXT)\n├── features/              # Feature computation\n│   ├── interfaces.py      # BaseFeaturesPipeline, CandleBasedFeatureComputer\n│   ├── pipeline.py        # DefaultFeaturesPipeline\n│   ├── candle.py          # SimpleCandleFeatureComputer\n│   └── market_snapshot.py # MarketSnapshotFeatureComputer\n├── decision/              # Decision composers\n│   ├── interfaces.py      # BaseComposer\n│   └── prompt_based/\n│       ├── composer.py    # LlmComposer\n│       └── system_prompt.py\n├── execution/             # Trade execution\n│   ├── interfaces.py      # BaseExecutionGateway\n│   ├── factory.py         # Gateway factory\n│   ├── paper_trading.py   # PaperExecutionGateway\n│   └── ccxt_trading.py    # CCXTExecutionGateway (live)\n├── portfolio/             # Portfolio management\n│   ├── interfaces.py      # BasePortfolioService\n│   └── in_memory.py       # InMemoryPortfolioService\n└── trading_history/       # History and digest\n    ├── interfaces.py      # BaseHistoryRecorder, BaseDigestBuilder\n    ├── recorder.py        # InMemoryHistoryRecorder\n    └── digest.py          # RollingDigestBuilder\n```\n\n## Data Flow (Decision Cycle)\n\nEach decision cycle follows this pipeline:\n\n1. **Portfolio State**: Coordinator fetches current `PortfolioView` (positions, cash, constraints)\n2. **Data Collection**: Pipeline pulls market data (candles, tickers, funding rates, etc.)\n3. **Feature Computation**: Pipeline computes `FeatureVector[]` from raw data\n4. **Context Assembly**: Coordinator builds `ComposeContext` with features, portfolio, digest, and constraints\n5. **Decision**: Composer (LLM + guardrails) produces normalized `TradeInstruction[]`\n6. **Execution**: Gateway executes instructions and returns `TxResult[]`\n7. **Portfolio Update**: Service applies trades to update positions and metrics\n8. **History**: Recorder checkpoints features, instructions, trades, and summary\n9. **Digest**: Builder updates `TradeDigest` for next cycle's context\n\n```text\n                                        ┌─────────────┐\n                                        │  Portfolio  │\n                                        │    View     │\n                                        └──────┬──────┘\n                                               │\n                                               ▼\n┌─────────────┐    ┌──────────────┐    ┌─────────────┐\n│   Market    │───▶│   Features   │───▶│   Context   │\n│    Data     │    │   Pipeline   │    │  Assembly   │\n└─────────────┘    └──────────────┘    └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Composer   │\n                                       │             │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Execution  │\n                                       │   Gateway   │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n       ┌──────────────────────────────────────┴────────────────┐\n       │                                                       │\n       ▼                                                       ▼\n┌─────────────┐                                         ┌─────────────┐\n│   History   │                                         │  Portfolio  │\n│   Recorder  │                                         │   Update    │\n└──────┬──────┘                                         └─────────────┘\n       │\n       ▼\n┌─────────────┐\n│   Digest    │\n│   Builder   │\n└─────────────┘\n```\n\n## Core Data Models\n\n### Configuration\n\nUserRequest\n\n- `llm_model_config: LLMModelConfig` — AI model settings\n- `exchange_config: ExchangeConfig` — Trading mode, exchange, credentials\n- `trading_config: TradingConfig` — Strategy parameters\n\nTradingConfig\n\n- `strategy_name?: str` — Display name\n- `initial_capital: float` — Starting total cash in USD\n- `initial_free_cash: float` — Starting free cash in USD (same as initial_capital if there's no initial positions)\n- `max_leverage: float` — Maximum leverage allowed\n- `max_positions: int` — Concurrent position limit\n- `symbols: List[str]` — Instruments to trade (e.g., `[\"BTC-USDT\", \"ETH-USDT\"]`)\n- `decide_interval: int` — Seconds between cycles\n- `custom_prompt?: str` — Custom strategy prompt\n- `prompt_text?: str` — Additional prompt text\n\n### Market Data\n\nCandle\n\n- `ts: int` — Timestamp (milliseconds)\n- `instrument: InstrumentRef` — Symbol reference\n- `open, high, low, close, volume: float` — OHLCV data\n- `interval: str` — Timeframe (e.g., \"1m\", \"1h\")\n\nFeatureVector\n\n- `ts: int` — Feature timestamp\n- `instrument: InstrumentRef` — Associated symbol\n- `values: Dict[str, float]` — Feature key-value pairs\n- `meta?: Dict[str, Any]` — Optional metadata (interval, group_by_key, etc.)\n\n### Portfolio\n\nPositionSnapshot\n\n- `instrument: InstrumentRef`\n- `quantity: float` — Signed quantity (+long, -short)\n- `avg_price?: float` — Average entry price\n- `mark_price?: float` — Current market price\n- `unrealized_pnl?: float` — Unrealized profit/loss\n- `leverage?: float` — Applied leverage\n- `entry_ts?: int` — Entry timestamp\n\nPortfolioView\n\n- `strategy_id: str`\n- `ts: int` — Snapshot timestamp\n- `account_balance: float` — Cash balance\n- `positions: Dict[str, PositionSnapshot]` — Active positions by symbol\n- `total_value?: float` — Portfolio equity\n- `total_unrealized_pnl?: float` — Sum of position unrealized PnL\n- `buying_power?: float` — Available buying power\n- `constraints?: Constraints` — Position and leverage limits\n\n### Decision\n\nComposeContext\n\n- `ts: int` — Cycle timestamp\n- `compose_id: str` — Unique cycle identifier\n- `strategy_id: str`\n- `features: List[FeatureVector]` — Computed features\n- `portfolio: PortfolioView` — Current portfolio state\n- `digest: TradeDigest` — Historical performance summary\n\nTradeInstruction\n\n- `instruction_id: str` — Unique instruction ID\n- `compose_id: str` — Parent cycle ID\n- `instrument: InstrumentRef`\n- `side: TradeSide` — BUY or SELL\n- `quantity: float` — Order quantity\n- `leverage?: float` — Applied leverage\n- `max_slippage_bps?: int` — Maximum slippage (basis points)\n- `meta?: Dict` — Optional metadata\n\n### Execution\n\nTxResult\n\n- `instruction_id: str`\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `status: TxStatus` — FILLED, PARTIAL, REJECTED, ERROR\n- `requested_qty: float`\n- `filled_qty: float`\n- `avg_exec_price?: float`\n- `fee_cost?: float`\n- `leverage?: float`\n\n### History\n\nTradeHistoryEntry\n\n- `trade_id: str`\n- `compose_id: str` — Originating cycle\n- `instruction_id: str` — Originating instruction\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `type: TradeType` — LONG or SHORT\n- `quantity: float`\n- `entry_price?, exit_price?: float`\n- `entry_ts?, exit_ts?: int`\n- `realized_pnl?: float` — Profit/loss on close\n- `holding_ms?: int` — Position duration\n\nTradeDigest\n\n- `ts: int`\n- `by_instrument: Dict[str, TradeDigestEntry]`\n- `sharpe_ratio?: float` — Portfolio Sharpe ratio\n\n**TradeDigestEntry** (per-symbol stats)\n\n- `trade_count: int`\n- `realized_pnl: float`\n- `win_rate?: float`\n- `avg_holding_ms?: int`\n- `last_trade_ts?: int`\n\n---\n\n## Integration Guide\n\n### Quick Start: Using the Default Agent\n\nThe simplest way to create a trading agent is to use `prompt_strategy_agent`, which provides default implementations for all components:\n\n```python\n# python/valuecell/agents/prompt_strategy_agent/__main__.py\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import StrategyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(StrategyAgent)\n    asyncio.run(agent.serve())\n```\n\n**StrategyAgent** (in `core.py`) extends `BaseStrategyAgent` and uses:\n\n- `DefaultFeaturesPipeline`: Fetches candles and computes technical indicators\n- `LlmComposer`: LLM-based decision making with guardrails\n\nTo run:\n\n```bash\ncd python/valuecell/agents/prompt_strategy_agent\npython -m valuecell.agents.prompt_strategy_agent\n```\n\n### Custom Agent: Override Specific Components\n\nCreate a custom agent by subclassing `BaseStrategyAgent` and overriding extension points:\n\n#### Example 1: Custom Feature Pipeline\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.features import BaseFeaturesPipeline\nfrom valuecell.agents.common.trading.models import (\n    FeaturesPipelineResult,\n    FeatureVector,\n    UserRequest,\n)\n\nclass MyFeaturesPipeline(BaseFeaturesPipeline):\n    \"\"\"Custom pipeline with specialized indicators.\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n        self.symbols = request.trading_config.symbols\n        # Initialize custom data sources, indicators, etc.\n    \n    async def build(self) -> FeaturesPipelineResult:\n        features = []\n        # Fetch data and compute custom features\n        # ... your logic here ...\n        return FeaturesPipelineResult(features=features)\n\n\nclass MyCustomAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom feature computation.\"\"\"\n    \n    async def _build_features_pipeline(\n        self, request: UserRequest\n    ) -> BaseFeaturesPipeline | None:\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Use default LLM composer\n        return None\n```\n\n#### Example 2: Custom Decision Composer\n\n```python\nfrom valuecell.agents.common.trading.decision import BaseComposer\nfrom valuecell.agents.common.trading.models import (\n    ComposeContext,\n    ComposeResult,\n    TradeInstruction,\n)\n\nclass RuleBasedComposer(BaseComposer):\n    \"\"\"Simple rule-based decision maker (no LLM).\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n    \n    async def compose(self, context: ComposeContext) -> ComposeResult:\n        instructions = []\n        # Implement your trading rules\n        # Example: Buy when RSI < 30, sell when RSI > 70\n        for fv in context.features:\n            rsi = fv.values.get(\"rsi\")\n            if rsi and rsi < 30:\n                # Create buy instruction\n                pass\n            elif rsi and rsi > 70:\n                # Create sell instruction\n                pass\n        \n        return ComposeResult(\n            instructions=instructions,\n            rationale=\"Rule-based signals\"\n        )\n\n\nclass RuleBasedAgent(BaseStrategyAgent):\n    \"\"\"Agent using rule-based decisions.\"\"\"\n    \n    async def _build_features_pipeline(self, request: UserRequest):\n        # Use default pipeline\n        return None\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        return RuleBasedComposer(request)\n```\n\n#### Example 3: Lifecycle Hooks\n\n```python\nclass MonitoredAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom monitoring and logging.\"\"\"\n    \n    async def _on_start(self, runtime, request):\n        \"\"\"Called once after runtime creation.\"\"\"\n        self.cycle_count = 0\n        print(f\"Strategy {runtime.strategy_id} starting...\")\n    \n    async def _on_cycle_result(self, result, runtime, request):\n        \"\"\"Called after each cycle completes.\"\"\"\n        self.cycle_count += 1\n        print(f\"Cycle {self.cycle_count}: \"\n              f\"{len(result.trades)} trades, \"\n              f\"PnL: {result.strategy_summary.realized_pnl}\")\n        \n        # Send metrics to external monitoring\n        # ... custom logic ...\n    \n    async def _on_stop(self, runtime, request, reason):\n        \"\"\"Called before finalization.\"\"\"\n        print(f\"Strategy stopping: {reason}\")\n        print(f\"Total cycles: {self.cycle_count}\")\n    \n    async def _build_features_pipeline(self, request):\n        return None  # Use defaults\n    \n    async def _create_decision_composer(self, request):\n        return None  # Use defaults\n```\n\n### Creating a Complete Custom Agent Module\n\n**Directory Structure:**\n\n```text\npython/valuecell/agents/my_agent/\n├── __init__.py\n├── __main__.py          # Entry point\n├── core.py              # Agent implementation\n├── features.py          # Custom features (optional)\n├── composer.py          # Custom composer (optional)\n└── templates/\n    └── strategy.txt     # Strategy prompt template\n```\n\n**`__main__.py`:**\n\n```python\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import MyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(MyAgent)\n    asyncio.run(agent.serve())\n```\n\n**`core.py`:**\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.models import UserRequest\nfrom .features import MyFeaturesPipeline  # if custom\nfrom .composer import MyComposer  # if custom\n\nclass MyAgent(BaseStrategyAgent):\n    async def _build_features_pipeline(self, request: UserRequest):\n        # Return custom pipeline or None for default\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Return custom composer or None for default\n        return MyComposer(request)\n```\n\n**Run your agent:**\n\n```bash\ncd python/valuecell/agents/my_agent\npython -m valuecell.agents.my_agent\n```\n\n### Live Trading Setup\n\nFor live trading with real exchanges:\n\n**Set trading mode to LIVE:**\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"live\",\n    \"exchange_id\": \"binance\",\n    \"api_key\": \"YOUR_API_KEY\",\n    \"secret_key\": \"YOUR_SECRET_KEY\",\n    \"testnet\": true  // Use testnet first!\n  }\n}\n```\n\n**The runtime automatically:**\n\n- Fetches real account balance\n- Sets `initial_capital` to account total cash\n- Sets `initial_free_cash` to available cash\n- Uses `CCXTExecutionGateway` for order submission\n\n**Always test on testnet first** before using real funds\n\n### Testing Strategies\n\n#### Paper Trading (Default)\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"virtual\",\n    \"fee_bps\": 10.0  // 0.1% simulated fees\n  }\n}\n```\n\nPaper trading uses `PaperExecutionGateway` which:\n\n- Simulates order fills at market price ± slippage\n- Applies configurable fees\n- No real exchange connection needed\n\n#### Backtesting\n\nCreate a custom `BaseMarketDataSource` that replays historical data:\n\n```python\nfrom valuecell.agents.common.trading.data import BaseMarketDataSource\nfrom valuecell.agents.common.trading.models import Candle\n\nclass BacktestDataSource(BaseMarketDataSource):\n    def __init__(self, historical_data):\n        self.data = historical_data\n        self.current_index = 0\n    \n    async def get_recent_candles(self, symbols, interval, lookback):\n        # Return historical candles for current timestamp\n        candles = self.data[self.current_index]\n        self.current_index += 1\n        return candles\n    \n    async def get_market_snapshot(self, symbols):\n        # Return snapshot from historical data\n        return {}\n```\n\nThen use it in your custom pipeline.\n\n### Extension Points Summary\n\n| Component | Method | Purpose |\n|-----------|--------|---------|\n| **Features** | `_build_features_pipeline()` | Define how market data is fetched and processed |\n| **Decision** | `_create_decision_composer()` | Customize trading logic (LLM, rules, ML) |\n| **Lifecycle** | `_on_start()` | Initialize resources after runtime creation |\n| **Lifecycle** | `_on_cycle_result()` | Monitor/log each cycle result |\n| **Lifecycle** | `_on_stop()` | Cleanup before finalization |\n\n### Best Practices\n\n1. **Start with defaults**: Use `prompt_strategy_agent` as a template\n2. **Override incrementally**: Only customize what you need\n3. **Type safety**: Use Pydantic models for all data contracts\n4. **Async operations**: Mark I/O operations as `async`\n5. **Error handling**: Hooks swallow exceptions to prevent crashes\n6. **Testnet first**: Always test live trading on testnet\n7. **Monitor carefully**: Use lifecycle hooks for observability\n\n### Common Patterns\n\n#### Adding Custom Indicators\n\n```python\nclass CustomFeaturesPipeline(BaseFeaturesPipeline):\n    async def build(self):\n        # Fetch candles\n        candles = await self.market_data.get_recent_candles(...)\n        \n        # Compute standard indicators\n        rsi = compute_rsi(candles)\n        macd = compute_macd(candles)\n        \n        # Add custom indicators\n        my_signal = compute_custom_indicator(candles)\n        \n        features = []\n        for symbol in symbols:\n            features.append(FeatureVector(\n                ts=timestamp,\n                instrument=InstrumentRef(symbol=symbol),\n                values={\n                    \"rsi\": rsi[symbol],\n                    \"macd\": macd[symbol],\n                    \"custom_signal\": my_signal[symbol],\n                }\n            ))\n        \n        return FeaturesPipelineResult(features=features)\n```\n\n#### Combining LLM with Rules\n\n```python\nclass HybridComposer(BaseComposer):\n    def __init__(self, request):\n        self.llm_composer = LlmComposer(request)\n        self.request = request\n    \n    async def compose(self, context):\n        # Get LLM suggestions\n        llm_result = await self.llm_composer.compose(context)\n        \n        # Apply additional rule filters\n        filtered_instructions = []\n        for inst in llm_result.instructions:\n            if self._passes_risk_check(inst, context):\n                filtered_instructions.append(inst)\n        \n        return ComposeResult(\n            instructions=filtered_instructions,\n            rationale=f\"LLM + risk filters: {llm_result.rationale}\"\n        )\n    \n    def _passes_risk_check(self, inst, context):\n        # Custom risk rules\n        return True\n```\n\n### Debugging\n\nEnable detailed logging:\n\n```python\nimport logging\nfrom loguru import logger\n\nlogger.add(\"strategy_{time}.log\", level=\"DEBUG\")\n```\n\nThe framework logs:\n\n- Cycle start/end with compose_id\n- Instruction count and details\n- Execution results and fills\n- Portfolio updates\n- Error traces with context\n\n---\n\n## Advanced Topics\n\n### Custom Execution Gateway\n\nImplement `BaseExecutionGateway` to integrate custom execution logic:\n\n```python\nfrom valuecell.agents.common.trading.execution import BaseExecutionGateway\nfrom valuecell.agents.common.trading.models import (\n    TradeInstruction,\n    TxResult,\n    TxStatus,\n)\n\nclass MyExecutionGateway(BaseExecutionGateway):\n    async def execute(self, instructions, market_features):\n        results = []\n        for inst in instructions:\n            # Your execution logic\n            result = TxResult(\n                instruction_id=inst.instruction_id,\n                instrument=inst.instrument,\n                side=inst.side,\n                status=TxStatus.FILLED,\n                requested_qty=inst.quantity,\n                filled_qty=inst.quantity,\n                avg_exec_price=100.0,  # from your system\n            )\n            results.append(result)\n        return results\n```\n\n### Custom Portfolio Service\n\nOverride portfolio management for complex accounting:\n\n```python\nfrom valuecell.agents.common.trading.portfolio import BasePortfolioService\n\nclass CustomPortfolioService(BasePortfolioService):\n    def get_view(self):\n        # Return custom PortfolioView\n        pass\n    \n    def apply_trades(self, trades, market_features):\n        # Update internal state\n        pass\n```\n\n### Persistence Integration\n\nUse `StreamController` to persist strategy state to your database. The framework already handles:\n\n- Initial portfolio snapshot\n- Cycle results (compose cycles, instructions, execution details)\n- Final cleanup and status updates\n\nSee `_internal/stream_controller.py` for persistence logic.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/ValueCell-ai/valuecell/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Guidelines\n\n## Python Programming\n\n### Python Environment\n\n* Package manager: uv\n* Virtual environment: `./python/.venv`\n* Testing command: `uv run pytest`\n\n### Imports\n\n* Avoid inline imports unless required to break a circular dependency.\n* If you import more than three names from a single module, prefer qualified imports:\n  * Prefer: `import pathlib; pathlib.Path, pathlib.PurePath`\n  * Avoid: `from pathlib import Path, PurePath, PurePosixPath, ...`\n* Postpone changes to `__init__` and `__all__` until APIs stabilize.\n* Use TYPE_CHECKING for imports only needed for type hints.\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypkg.schemas import AgentConfig\n```\n\n### Runtime Checks\n\n* Avoid excessive use of `getattr`, `hasattr`, and runtime type checks.\n* If an object is a pydantic `BaseModel`, prefer using its validated attributes and type annotations instead of probing attributes at runtime.\n* Rely on pydantic validation, model validators, and type hints; prefer `TypedDict` or `Protocol` for structural typing when appropriate.\n* When runtime checks are necessary, make them explicit, minimal, and well-documented so the reason for the guard is clear.\n\n### Async-First Design\n\n* Prefer asynchronous APIs for I/O-bound work.\n* Use asyncio or anyio; for HTTP, prefer httpx (async client).\n* Ensure clear async boundaries: public APIs and I/O paths should be async.\n* Provide minimal sync adapters only when needed, and document them.\n\n```python\nimport asyncio\nfrom loguru import logger\nimport httpx\n\nasync def fetch_agent_state(url: str, timeout_s: float) -> dict:\n    \"\"\"Fetch agent state from a remote endpoint.\"\"\"\n    async with httpx.AsyncClient(timeout=timeout_s) as client:\n        resp = await client.get(url)\n        resp.raise_for_status()\n        data = resp.json()\n        logger.info(\"Fetched state from {url}\", url=url)\n        return data\n\ndef fetch_agent_state_sync(url: str, timeout_s: float) -> dict:\n    \"\"\"Synchronous adapter. Prefer the async variant.\"\"\"\n    return asyncio.run(fetch_agent_state(url, timeout_s))\n```\n\n### Logging\n\n* Use loguru; placeholders must be {} rather than %.\n* Log key events at info; avoid excessive logging.\n* Do not log sensitive data.\n* Use `logger.exception` sparingly: only for truly unexpected errors that require stack traces for debugging. For expected or recoverable errors, prefer `logger.warning` or `logger.error` with explicit context.\n* Prefer `logger.warning` for recoverable issues, degraded states, or when an operation can continue despite an error.\n\n```python\nfrom loguru import logger\n\ndef process_items(items: list[str]) -> int:\n    \"\"\"Process items and return count.\"\"\"\n    count = len(items)\n    logger.info(\"Processing {count} items\", count=count)\n    # ...\n    logger.info(\"Processed {count} items\", count=count)\n    return count\n\n# Good: expected error, use warning with context\nasync def send_notification(msg: str) -> None:\n    \"\"\"Send notification; log warning if it fails (non-critical).\"\"\"\n    try:\n        await notify_service(msg)\n    except NetworkError as exc:\n        logger.warning(\"Notification failed, continuing: {err}\", err=str(exc))\n\n# Good: unexpected error requiring investigation, use exception\nasync def critical_operation() -> None:\n    \"\"\"Perform critical operation that should never fail.\"\"\"\n    try:\n        await process_critical_data()\n    except Exception:\n        logger.exception(\"Critical operation failed unexpectedly\")\n        raise\n```\n\n### Type Hints and Comments\n\n* Add type hints across public and internal APIs.\n* Comments and docstrings should be in English and explain why, not only what.\n* Use Protocols and TypedDict or pydantic models where appropriate.\n* Avoid excessive literal dict access (for example, using `obj['key']` everywhere); prefer typed structures such as `dataclass`, pydantic models, or `TypedDict` for clearer contracts and better type safety.\n\n### Error Handling\n\n* Keep try-except depth to at most two levels.\n* Catch specific exceptions. Re-raise with context if needed.\n* Prefer explicit None checks and guard clauses over broad exception use.\n\n```python\nimport json\nfrom loguru import logger\n\ndef parse_payload(raw: str) -> dict:\n    \"\"\"Parse payload; return empty dict on known format errors.\"\"\"\n    try:\n        data = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        logger.info(\"Invalid JSON: {err}\", err=str(exc))\n        return {}\n    return data\n```\n\n### Structure and Size\n\n* Avoid nested functions; extract helpers at module level.\n* Keep functions under 200 lines. Split into well-named helpers.\n* Avoid functions with more than 10 parameters; prefer wrapping parameters in a struct or object.\n* Separate concerns: I/O, parsing, business logic, and orchestration.\n\n### Strings and Literals\n\n* Avoid long string literals; wrap lines under 100 characters.\n* Avoid magic numbers and ad-hoc string literals. Centralize constants.\n\n```python\n# constants.py\nDEFAULT_TIMEOUT_S: float = 10.0\nMAX_RETRIES: int = 3\n```\n\n### Boolean Logic\n\n* Be careful with or where 0, empty, or False may be meaningful.\n* Prefer explicit checks:\n\n```python\n# Prefer\nvalue = user_value if user_value is not None else default\n\n# Avoid\nvalue = user_value or default\n```\n\n### Module and Package Layout\n\n* Group agent core, adapters, and utilities into separate modules.\n* Keep public surface small. Delay re-exports in __init__ until stable.\n* If circular dependencies appear, refactor shared contracts to a thin shared module (e.g., interfaces.py or contracts.py).\n","isInternal":false,"tokens":1224,"sizeBytes":5537},{"name":"news_agent.yaml","path":"python/configs/agents/news_agent.yaml","rawUrl":"https://raw.githubusercontent.com/ValueCell-ai/valuecell/HEAD/python/configs/agents/news_agent.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# ============================================\n# News Agent Configuration\n# ============================================\n# The News Agent specializes in gathering, analyzing, and presenting news information.\n# It provides real-time news search, categorized news retrieval, and comprehensive analysis.\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file\n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"News Agent\"\nenabled: true\n\n# Model Configuration\n# News Agent needs a capable model for news analysis and summarization\nmodels:\n  # Primary model for news analysis, summarization, and query processing\n  primary:\n    model_id: \"qwen/qwen3-max\"\n    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n\n    # Provider-specific model mappings for fallback\n    # Used when primary provider fails and fallback is attempted\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"  # Strong reasoning for news analysis\n      google: \"gemini-2.5-flash\"  # Fast and efficient for news processing\n\n    parameters:\n      # temperature: 0.3  # Lower temperature for more factual news reporting\n      # max_tokens: 4096  # Sufficient for comprehensive news analysis\n\n  # Web search model for real-time information gathering\n  # Uses specialized models optimized for web search and real-time data\n  search:\n    model_id: \"perplexity/sonar\"\n    provider: \"openrouter\"\n\n    # Provider-specific search model mappings\n    provider_models:\n      google: \"gemini-2.5-flash\"  # With search grounding enabled\n\n    parameters:\n      # max_tokens: 2048  # Optimized for search result processing\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  NEWS_AGENT_MODEL_ID: \"models.primary.model_id\"\n  NEWS_AGENT_PROVIDER: \"models.primary.provider\"\n  NEWS_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  NEWS_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n  # Search model overrides\n  NEWS_SEARCH_MODEL_ID: \"models.search.model_id\"\n  NEWS_SEARCH_PROVIDER: \"models.search.provider\"\n\n  # Web search provider configuration\n  WEB_SEARCH_PROVIDER: \"capabilities.web_search.provider\"\n\n# News Agent Capabilities\ncapabilities:\n  # Web search configuration\n  web_search:\n    enabled: true\n    provider: \"perplexity\"  # Default: perplexity, alternative: google\n    max_results: 10\n\n  # Breaking news monitoring\n  breaking_news:\n    enabled: true  # Enable breaking news monitoring\n    refresh_interval: 300  # seconds\n\n  # Financial news specialization\n  financial_news:\n    enabled: true\n    supported_markets: [\"US\", \"Global\"]\n    include_sectors: true\n    include_individual_stocks: true\n\n\n\n  # Multi-language support\n  languages:\n    enabled: true\n    supported: [\"en\", \"zh\", \"ja\", \"ko\", \"es\", \"fr\", \"de\"]\n    default: \"en\"\n\n  # News analysis features\n  analysis:\n    sentiment_analysis: true\n    topic_extraction: true\n    entity_recognition: true\n    summarization: true\n    fact_checking: false  # Requires additional verification tools\n\n# Tool Configuration\ntools:\n  web_search:\n    enabled: true\n\n  get_breaking_news:\n    enabled: true\n\n  get_financial_news:\n    enabled: true","isInternal":false,"tokens":753,"sizeBytes":3399},{"name":"research_agent.yaml","path":"python/configs/agents/research_agent.yaml","rawUrl":"https://raw.githubusercontent.com/ValueCell-ai/valuecell/HEAD/python/configs/agents/research_agent.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# ============================================\n# Research Agent Configuration\n# ============================================\nname: \"Research Agent\"\nenabled: true\n\n# Model Configuration\n# Priority: Environment Variables > .env > YAML\nmodels:\n  # Primary model for reasoning and generation\n  primary:\n    model_id: \"google/gemini-2.5-flash\"\n    provider: \"openrouter\"\n    # Provider-specific model mappings for fallback\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"\n      google: \"gemini-2.5-flash\"\n    parameters:\n      # temperature: 0.7\n      # max_tokens: 8192\n  \n  # Embedding model for knowledge base\n  # Note: If not specified, will auto-select from available providers\n  embedding:\n    model_id: \"Qwen/Qwen3-Embedding-4B\"  # Optional, uses provider default\n    provider: \"siliconflow\"  # Must explicitly specify provider\n    # Provider-specific embedding model mappings for fallback\n    provider_models:\n      google: \"gemini-embedding-001\"\n    parameters:\n      dimensions: ${EMBEDDER_DIMENSION:2560}\n      # encoding_format: \"float\"\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\nenv_overrides:\n  # Primary model overrides\n  RESEARCH_AGENT_MODEL_ID: \"models.primary.model_id\"\n  RESEARCH_AGENT_PROVIDER: \"models.primary.provider\"\n  RESEARCH_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  RESEARCH_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n  \n  # Embedding model overrides (backward compatible with existing env vars)\n  EMBEDDER_MODEL_ID: \"models.embedding.model_id\"\n  EMBEDDER_MODEL_PROVIDER: \"models.embedding.provider\"\n  EMBEDDER_DIMENSION: \"models.embedding.parameters.dimensions\"\n\n","isInternal":false,"tokens":386,"sizeBytes":1677},{"name":"super_agent.yaml","path":"python/configs/agents/super_agent.yaml","rawUrl":"https://raw.githubusercontent.com/ValueCell-ai/valuecell/HEAD/python/configs/agents/super_agent.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# ============================================\n# Super Agent Configuration\n# ============================================\n# The Super Agent acts as the orchestration layer that:\n# - Triages user intent before planning\n# - Decides whether to answer directly or handoff to Planner\n# - Provides initial query enrichment and context gathering\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file \n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"Super Agent\"\nenabled: true\n\n# TODO support agent level model config\n\n# Model Configuration\n# Super Agent typically needs a capable reasoning model\n#models:\n#  # Primary model for triage, reasoning, and query enrichment\n#  primary:\n#    model_id: \"anthropic/claude-haiku-4.5\"\n#    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n#\n#    # Provider-specific model mappings for fallback\n#    # Used when primary provider fails and fallback is attempted\n#    provider_models:\n#      siliconflow: \"deepseek-ai/DeepSeek-V3.1-Terminus\"  # Similar capability to Claude Haiku\n#      google: \"gemini-2.5-flash\"  # Fast and efficient like Claude Haiku\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  PLANNER_MODEL_ID: \"models.primary.model_id\"\n  SUPER_AGENT_MODEL_ID: \"models.primary.model_id\"  # Alias for clarity\n  SUPER_AGENT_PROVIDER: \"models.primary.provider\"\n  SUPER_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  SUPER_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n# Super Agent Capabilities\ncapabilities:\n  # Enable web search for context enrichment\n  web_search: true\n  \n  # Enable crawling capabilities\n  web_crawl: true\n  \n  # Session management\n  session_management:\n    enabled: true\n    max_history_runs: 5\n    enable_summaries: true\n\n# Advanced Settings\nadvanced:\n  # Debug mode (can be overridden by AGENT_DEBUG_MODE env var)\n  debug_mode: false\n\n  # Output format\n  markdown: false\n  \n  # Context settings\n  add_datetime_to_context: true\n  add_history_to_context: true\n  read_chat_history: true\n\n","isInternal":false,"tokens":506,"sizeBytes":2284},{"name":"README.md","path":"python/valuecell/agents/common/trading/README.md","rawUrl":"https://raw.githubusercontent.com/ValueCell-ai/valuecell/HEAD/python/valuecell/agents/common/trading/README.md","title":"Subagent: readme","category":"subagent-persona","format":"markdown","content":"# Trading Agent Framework\n\nThis document describes the common trading agent framework: a flexible, composable architecture for building LLM-driven trading strategies with clean separation of concerns and extensible components.\n\n## Architecture Overview\n\nThe framework provides a base class (`BaseStrategyAgent`) that handles lifecycle management, streaming, and persistence, while allowing users to customize decision logic and feature computation through well-defined extension points.\n\n**Key Principles:**\n\n- **Separation of Concerns**: Data fetching, feature computation, decision making, execution, and history tracking are independent modules\n- **Extensibility**: Override specific components without rewriting the entire pipeline\n- **Type Safety**: Pydantic models ensure data contracts across boundaries\n- **Async-First**: Built on asyncio for efficient I/O and concurrent operations\n- **Auditable**: Each decision cycle has a unique `compose_id` for tracing\n\n## Module Layout\n\n```text\ncommon/trading/\n├── base_agent.py          # BaseStrategyAgent abstract class\n├── models.py              # Pydantic DTOs and enums\n├── constants.py           # Default configuration values\n├── utils.py               # Shared utilities\n├── _internal/             # Internal runtime implementation\n│   ├── coordinator.py     # DefaultDecisionCoordinator\n│   ├── runtime.py         # StrategyRuntime factory\n│   └── stream_controller.py  # Persistence and streaming\n├── data/                  # Market data sources\n│   ├── interfaces.py      # BaseMarketDataSource\n│   └── market.py          # SimpleMarketDataSource (CCXT)\n├── features/              # Feature computation\n│   ├── interfaces.py      # BaseFeaturesPipeline, CandleBasedFeatureComputer\n│   ├── pipeline.py        # DefaultFeaturesPipeline\n│   ├── candle.py          # SimpleCandleFeatureComputer\n│   └── market_snapshot.py # MarketSnapshotFeatureComputer\n├── decision/              # Decision composers\n│   ├── interfaces.py      # BaseComposer\n│   └── prompt_based/\n│       ├── composer.py    # LlmComposer\n│       └── system_prompt.py\n├── execution/             # Trade execution\n│   ├── interfaces.py      # BaseExecutionGateway\n│   ├── factory.py         # Gateway factory\n│   ├── paper_trading.py   # PaperExecutionGateway\n│   └── ccxt_trading.py    # CCXTExecutionGateway (live)\n├── portfolio/             # Portfolio management\n│   ├── interfaces.py      # BasePortfolioService\n│   └── in_memory.py       # InMemoryPortfolioService\n└── trading_history/       # History and digest\n    ├── interfaces.py      # BaseHistoryRecorder, BaseDigestBuilder\n    ├── recorder.py        # InMemoryHistoryRecorder\n    └── digest.py          # RollingDigestBuilder\n```\n\n## Data Flow (Decision Cycle)\n\nEach decision cycle follows this pipeline:\n\n1. **Portfolio State**: Coordinator fetches current `PortfolioView` (positions, cash, constraints)\n2. **Data Collection**: Pipeline pulls market data (candles, tickers, funding rates, etc.)\n3. **Feature Computation**: Pipeline computes `FeatureVector[]` from raw data\n4. **Context Assembly**: Coordinator builds `ComposeContext` with features, portfolio, digest, and constraints\n5. **Decision**: Composer (LLM + guardrails) produces normalized `TradeInstruction[]`\n6. **Execution**: Gateway executes instructions and returns `TxResult[]`\n7. **Portfolio Update**: Service applies trades to update positions and metrics\n8. **History**: Recorder checkpoints features, instructions, trades, and summary\n9. **Digest**: Builder updates `TradeDigest` for next cycle's context\n\n```text\n                                        ┌─────────────┐\n                                        │  Portfolio  │\n                                        │    View     │\n                                        └──────┬──────┘\n                                               │\n                                               ▼\n┌─────────────┐    ┌──────────────┐    ┌─────────────┐\n│   Market    │───▶│   Features   │───▶│   Context   │\n│    Data     │    │   Pipeline   │    │  Assembly   │\n└─────────────┘    └──────────────┘    └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Composer   │\n                                       │             │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Execution  │\n                                       │   Gateway   │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n       ┌──────────────────────────────────────┴────────────────┐\n       │                                                       │\n       ▼                                                       ▼\n┌─────────────┐                                         ┌─────────────┐\n│   History   │                                         │  Portfolio  │\n│   Recorder  │                                         │   Update    │\n└──────┬──────┘                                         └─────────────┘\n       │\n       ▼\n┌─────────────┐\n│   Digest    │\n│   Builder   │\n└─────────────┘\n```\n\n## Core Data Models\n\n### Configuration\n\nUserRequest\n\n- `llm_model_config: LLMModelConfig` — AI model settings\n- `exchange_config: ExchangeConfig` — Trading mode, exchange, credentials\n- `trading_config: TradingConfig` — Strategy parameters\n\nTradingConfig\n\n- `strategy_name?: str` — Display name\n- `initial_capital: float` — Starting total cash in USD\n- `initial_free_cash: float` — Starting free cash in USD (same as initial_capital if there's no initial positions)\n- `max_leverage: float` — Maximum leverage allowed\n- `max_positions: int` — Concurrent position limit\n- `symbols: List[str]` — Instruments to trade (e.g., `[\"BTC-USDT\", \"ETH-USDT\"]`)\n- `decide_interval: int` — Seconds between cycles\n- `custom_prompt?: str` — Custom strategy prompt\n- `prompt_text?: str` — Additional prompt text\n\n### Market Data\n\nCandle\n\n- `ts: int` — Timestamp (milliseconds)\n- `instrument: InstrumentRef` — Symbol reference\n- `open, high, low, close, volume: float` — OHLCV data\n- `interval: str` — Timeframe (e.g., \"1m\", \"1h\")\n\nFeatureVector\n\n- `ts: int` — Feature timestamp\n- `instrument: InstrumentRef` — Associated symbol\n- `values: Dict[str, float]` — Feature key-value pairs\n- `meta?: Dict[str, Any]` — Optional metadata (interval, group_by_key, etc.)\n\n### Portfolio\n\nPositionSnapshot\n\n- `instrument: InstrumentRef`\n- `quantity: float` — Signed quantity (+long, -short)\n- `avg_price?: float` — Average entry price\n- `mark_price?: float` — Current market price\n- `unrealized_pnl?: float` — Unrealized profit/loss\n- `leverage?: float` — Applied leverage\n- `entry_ts?: int` — Entry timestamp\n\nPortfolioView\n\n- `strategy_id: str`\n- `ts: int` — Snapshot timestamp\n- `account_balance: float` — Cash balance\n- `positions: Dict[str, PositionSnapshot]` — Active positions by symbol\n- `total_value?: float` — Portfolio equity\n- `total_unrealized_pnl?: float` — Sum of position unrealized PnL\n- `buying_power?: float` — Available buying power\n- `constraints?: Constraints` — Position and leverage limits\n\n### Decision\n\nComposeContext\n\n- `ts: int` — Cycle timestamp\n- `compose_id: str` — Unique cycle identifier\n- `strategy_id: str`\n- `features: List[FeatureVector]` — Computed features\n- `portfolio: PortfolioView` — Current portfolio state\n- `digest: TradeDigest` — Historical performance summary\n\nTradeInstruction\n\n- `instruction_id: str` — Unique instruction ID\n- `compose_id: str` — Parent cycle ID\n- `instrument: InstrumentRef`\n- `side: TradeSide` — BUY or SELL\n- `quantity: float` — Order quantity\n- `leverage?: float` — Applied leverage\n- `max_slippage_bps?: int` — Maximum slippage (basis points)\n- `meta?: Dict` — Optional metadata\n\n### Execution\n\nTxResult\n\n- `instruction_id: str`\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `status: TxStatus` — FILLED, PARTIAL, REJECTED, ERROR\n- `requested_qty: float`\n- `filled_qty: float`\n- `avg_exec_price?: float`\n- `fee_cost?: float`\n- `leverage?: float`\n\n### History\n\nTradeHistoryEntry\n\n- `trade_id: str`\n- `compose_id: str` — Originating cycle\n- `instruction_id: str` — Originating instruction\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `type: TradeType` — LONG or SHORT\n- `quantity: float`\n- `entry_price?, exit_price?: float`\n- `entry_ts?, exit_ts?: int`\n- `realized_pnl?: float` — Profit/loss on close\n- `holding_ms?: int` — Position duration\n\nTradeDigest\n\n- `ts: int`\n- `by_instrument: Dict[str, TradeDigestEntry]`\n- `sharpe_ratio?: float` — Portfolio Sharpe ratio\n\n**TradeDigestEntry** (per-symbol stats)\n\n- `trade_count: int`\n- `realized_pnl: float`\n- `win_rate?: float`\n- `avg_holding_ms?: int`\n- `last_trade_ts?: int`\n\n---\n\n## Integration Guide\n\n### Quick Start: Using the Default Agent\n\nThe simplest way to create a trading agent is to use `prompt_strategy_agent`, which provides default implementations for all components:\n\n```python\n# python/valuecell/agents/prompt_strategy_agent/__main__.py\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import StrategyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(StrategyAgent)\n    asyncio.run(agent.serve())\n```\n\n**StrategyAgent** (in `core.py`) extends `BaseStrategyAgent` and uses:\n\n- `DefaultFeaturesPipeline`: Fetches candles and computes technical indicators\n- `LlmComposer`: LLM-based decision making with guardrails\n\nTo run:\n\n```bash\ncd python/valuecell/agents/prompt_strategy_agent\npython -m valuecell.agents.prompt_strategy_agent\n```\n\n### Custom Agent: Override Specific Components\n\nCreate a custom agent by subclassing `BaseStrategyAgent` and overriding extension points:\n\n#### Example 1: Custom Feature Pipeline\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.features import BaseFeaturesPipeline\nfrom valuecell.agents.common.trading.models import (\n    FeaturesPipelineResult,\n    FeatureVector,\n    UserRequest,\n)\n\nclass MyFeaturesPipeline(BaseFeaturesPipeline):\n    \"\"\"Custom pipeline with specialized indicators.\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n        self.symbols = request.trading_config.symbols\n        # Initialize custom data sources, indicators, etc.\n    \n    async def build(self) -> FeaturesPipelineResult:\n        features = []\n        # Fetch data and compute custom features\n        # ... your logic here ...\n        return FeaturesPipelineResult(features=features)\n\n\nclass MyCustomAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom feature computation.\"\"\"\n    \n    async def _build_features_pipeline(\n        self, request: UserRequest\n    ) -> BaseFeaturesPipeline | None:\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Use default LLM composer\n        return None\n```\n\n#### Example 2: Custom Decision Composer\n\n```python\nfrom valuecell.agents.common.trading.decision import BaseComposer\nfrom valuecell.agents.common.trading.models import (\n    ComposeContext,\n    ComposeResult,\n    TradeInstruction,\n)\n\nclass RuleBasedComposer(BaseComposer):\n    \"\"\"Simple rule-based decision maker (no LLM).\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n    \n    async def compose(self, context: ComposeContext) -> ComposeResult:\n        instructions = []\n        # Implement your trading rules\n        # Example: Buy when RSI < 30, sell when RSI > 70\n        for fv in context.features:\n            rsi = fv.values.get(\"rsi\")\n            if rsi and rsi < 30:\n                # Create buy instruction\n                pass\n            elif rsi and rsi > 70:\n                # Create sell instruction\n                pass\n        \n        return ComposeResult(\n            instructions=instructions,\n            rationale=\"Rule-based signals\"\n        )\n\n\nclass RuleBasedAgent(BaseStrategyAgent):\n    \"\"\"Agent using rule-based decisions.\"\"\"\n    \n    async def _build_features_pipeline(self, request: UserRequest):\n        # Use default pipeline\n        return None\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        return RuleBasedComposer(request)\n```\n\n#### Example 3: Lifecycle Hooks\n\n```python\nclass MonitoredAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom monitoring and logging.\"\"\"\n    \n    async def _on_start(self, runtime, request):\n        \"\"\"Called once after runtime creation.\"\"\"\n        self.cycle_count = 0\n        print(f\"Strategy {runtime.strategy_id} starting...\")\n    \n    async def _on_cycle_result(self, result, runtime, request):\n        \"\"\"Called after each cycle completes.\"\"\"\n        self.cycle_count += 1\n        print(f\"Cycle {self.cycle_count}: \"\n              f\"{len(result.trades)} trades, \"\n              f\"PnL: {result.strategy_summary.realized_pnl}\")\n        \n        # Send metrics to external monitoring\n        # ... custom logic ...\n    \n    async def _on_stop(self, runtime, request, reason):\n        \"\"\"Called before finalization.\"\"\"\n        print(f\"Strategy stopping: {reason}\")\n        print(f\"Total cycles: {self.cycle_count}\")\n    \n    async def _build_features_pipeline(self, request):\n        return None  # Use defaults\n    \n    async def _create_decision_composer(self, request):\n        return None  # Use defaults\n```\n\n### Creating a Complete Custom Agent Module\n\n**Directory Structure:**\n\n```text\npython/valuecell/agents/my_agent/\n├── __init__.py\n├── __main__.py          # Entry point\n├── core.py              # Agent implementation\n├── features.py          # Custom features (optional)\n├── composer.py          # Custom composer (optional)\n└── templates/\n    └── strategy.txt     # Strategy prompt template\n```\n\n**`__main__.py`:**\n\n```python\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import MyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(MyAgent)\n    asyncio.run(agent.serve())\n```\n\n**`core.py`:**\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.models import UserRequest\nfrom .features import MyFeaturesPipeline  # if custom\nfrom .composer import MyComposer  # if custom\n\nclass MyAgent(BaseStrategyAgent):\n    async def _build_features_pipeline(self, request: UserRequest):\n        # Return custom pipeline or None for default\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Return custom composer or None for default\n        return MyComposer(request)\n```\n\n**Run your agent:**\n\n```bash\ncd python/valuecell/agents/my_agent\npython -m valuecell.agents.my_agent\n```\n\n### Live Trading Setup\n\nFor live trading with real exchanges:\n\n**Set trading mode to LIVE:**\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"live\",\n    \"exchange_id\": \"binance\",\n    \"api_key\": \"YOUR_API_KEY\",\n    \"secret_key\": \"YOUR_SECRET_KEY\",\n    \"testnet\": true  // Use testnet first!\n  }\n}\n```\n\n**The runtime automatically:**\n\n- Fetches real account balance\n- Sets `initial_capital` to account total cash\n- Sets `initial_free_cash` to available cash\n- Uses `CCXTExecutionGateway` for order submission\n\n**Always test on testnet first** before using real funds\n\n### Testing Strategies\n\n#### Paper Trading (Default)\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"virtual\",\n    \"fee_bps\": 10.0  // 0.1% simulated fees\n  }\n}\n```\n\nPaper trading uses `PaperExecutionGateway` which:\n\n- Simulates order fills at market price ± slippage\n- Applies configurable fees\n- No real exchange connection needed\n\n#### Backtesting\n\nCreate a custom `BaseMarketDataSource` that replays historical data:\n\n```python\nfrom valuecell.agents.common.trading.data import BaseMarketDataSource\nfrom valuecell.agents.common.trading.models import Candle\n\nclass BacktestDataSource(BaseMarketDataSource):\n    def __init__(self, historical_data):\n        self.data = historical_data\n        self.current_index = 0\n    \n    async def get_recent_candles(self, symbols, interval, lookback):\n        # Return historical candles for current timestamp\n        candles = self.data[self.current_index]\n        self.current_index += 1\n        return candles\n    \n    async def get_market_snapshot(self, symbols):\n        # Return snapshot from historical data\n        return {}\n```\n\nThen use it in your custom pipeline.\n\n### Extension Points Summary\n\n| Component | Method | Purpose |\n|-----------|--------|---------|\n| **Features** | `_build_features_pipeline()` | Define how market data is fetched and processed |\n| **Decision** | `_create_decision_composer()` | Customize trading logic (LLM, rules, ML) |\n| **Lifecycle** | `_on_start()` | Initialize resources after runtime creation |\n| **Lifecycle** | `_on_cycle_result()` | Monitor/log each cycle result |\n| **Lifecycle** | `_on_stop()` | Cleanup before finalization |\n\n### Best Practices\n\n1. **Start with defaults**: Use `prompt_strategy_agent` as a template\n2. **Override incrementally**: Only customize what you need\n3. **Type safety**: Use Pydantic models for all data contracts\n4. **Async operations**: Mark I/O operations as `async`\n5. **Error handling**: Hooks swallow exceptions to prevent crashes\n6. **Testnet first**: Always test live trading on testnet\n7. **Monitor carefully**: Use lifecycle hooks for observability\n\n### Common Patterns\n\n#### Adding Custom Indicators\n\n```python\nclass CustomFeaturesPipeline(BaseFeaturesPipeline):\n    async def build(self):\n        # Fetch candles\n        candles = await self.market_data.get_recent_candles(...)\n        \n        # Compute standard indicators\n        rsi = compute_rsi(candles)\n        macd = compute_macd(candles)\n        \n        # Add custom indicators\n        my_signal = compute_custom_indicator(candles)\n        \n        features = []\n        for symbol in symbols:\n            features.append(FeatureVector(\n                ts=timestamp,\n                instrument=InstrumentRef(symbol=symbol),\n                values={\n                    \"rsi\": rsi[symbol],\n                    \"macd\": macd[symbol],\n                    \"custom_signal\": my_signal[symbol],\n                }\n            ))\n        \n        return FeaturesPipelineResult(features=features)\n```\n\n#### Combining LLM with Rules\n\n```python\nclass HybridComposer(BaseComposer):\n    def __init__(self, request):\n        self.llm_composer = LlmComposer(request)\n        self.request = request\n    \n    async def compose(self, context):\n        # Get LLM suggestions\n        llm_result = await self.llm_composer.compose(context)\n        \n        # Apply additional rule filters\n        filtered_instructions = []\n        for inst in llm_result.instructions:\n            if self._passes_risk_check(inst, context):\n                filtered_instructions.append(inst)\n        \n        return ComposeResult(\n            instructions=filtered_instructions,\n            rationale=f\"LLM + risk filters: {llm_result.rationale}\"\n        )\n    \n    def _passes_risk_check(self, inst, context):\n        # Custom risk rules\n        return True\n```\n\n### Debugging\n\nEnable detailed logging:\n\n```python\nimport logging\nfrom loguru import logger\n\nlogger.add(\"strategy_{time}.log\", level=\"DEBUG\")\n```\n\nThe framework logs:\n\n- Cycle start/end with compose_id\n- Instruction count and details\n- Execution results and fills\n- Portfolio updates\n- Error traces with context\n\n---\n\n## Advanced Topics\n\n### Custom Execution Gateway\n\nImplement `BaseExecutionGateway` to integrate custom execution logic:\n\n```python\nfrom valuecell.agents.common.trading.execution import BaseExecutionGateway\nfrom valuecell.agents.common.trading.models import (\n    TradeInstruction,\n    TxResult,\n    TxStatus,\n)\n\nclass MyExecutionGateway(BaseExecutionGateway):\n    async def execute(self, instructions, market_features):\n        results = []\n        for inst in instructions:\n            # Your execution logic\n            result = TxResult(\n                instruction_id=inst.instruction_id,\n                instrument=inst.instrument,\n                side=inst.side,\n                status=TxStatus.FILLED,\n                requested_qty=inst.quantity,\n                filled_qty=inst.quantity,\n                avg_exec_price=100.0,  # from your system\n            )\n            results.append(result)\n        return results\n```\n\n### Custom Portfolio Service\n\nOverride portfolio management for complex accounting:\n\n```python\nfrom valuecell.agents.common.trading.portfolio import BasePortfolioService\n\nclass CustomPortfolioService(BasePortfolioService):\n    def get_view(self):\n        # Return custom PortfolioView\n        pass\n    \n    def apply_trades(self, trades, market_features):\n        # Update internal state\n        pass\n```\n\n### Persistence Integration\n\nUse `StreamController` to persist strategy state to your database. The framework already handles:\n\n- Initial portfolio snapshot\n- Cycle results (compose cycles, instructions, execution details)\n- Final cleanup and status updates\n\nSee `_internal/stream_controller.py` for persistence logic.\n","isInternal":false,"tokens":4722,"sizeBytes":22505}],"systemPromptSnippet":"<yakaai_skills repo=\"ValueCell-ai/valuecell\">\n<!-- File: AGENTS.md (Tokens: ~1224 | Category: root-instruction) -->\n# Guidelines\n\n## Python Programming\n\n### Python Environment\n\n* Package manager: uv\n* Virtual environment: `./python/.venv`\n* Testing command: `uv run pytest`\n\n### Imports\n\n* Avoid inline imports unless required to break a circular dependency.\n* If you import more than three names from a single module, prefer qualified imports:\n  * Prefer: `import pathlib; pathlib.Path, pathlib.PurePath`\n  * Avoid: `from pathlib import Path, PurePath, PurePosixPath, ...`\n* Postpone changes to `__init__` and `__all__` until APIs stabilize.\n* Use TYPE_CHECKING for imports only needed for type hints.\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mypkg.schemas import AgentConfig\n```\n\n### Runtime Checks\n\n* Avoid excessive use of `getattr`, `hasattr`, and runtime type checks.\n* If an object is a pydantic `BaseModel`, prefer using its validated attributes and type annotations instead of probing attributes at runtime.\n* Rely on pydantic validation, model validators, and type hints; prefer `TypedDict` or `Protocol` for structural typing when appropriate.\n* When runtime checks are necessary, make them explicit, minimal, and well-documented so the reason for the guard is clear.\n\n### Async-First Design\n\n* Prefer asynchronous APIs for I/O-bound work.\n* Use asyncio or anyio; for HTTP, prefer httpx (async client).\n* Ensure clear async boundaries: public APIs and I/O paths should be async.\n* Provide minimal sync adapters only when needed, and document them.\n\n```python\nimport asyncio\nfrom loguru import logger\nimport httpx\n\nasync def fetch_agent_state(url: str, timeout_s: float) -> dict:\n    \"\"\"Fetch agent state from a remote endpoint.\"\"\"\n    async with httpx.AsyncClient(timeout=timeout_s) as client:\n        resp = await client.get(url)\n        resp.raise_for_status()\n        data = resp.json()\n        logger.info(\"Fetched state from {url}\", url=url)\n        return data\n\ndef fetch_agent_state_sync(url: str, timeout_s: float) -> dict:\n    \"\"\"Synchronous adapter. Prefer the async variant.\"\"\"\n    return asyncio.run(fetch_agent_state(url, timeout_s))\n```\n\n### Logging\n\n* Use loguru; placeholders must be {} rather than %.\n* Log key events at info; avoid excessive logging.\n* Do not log sensitive data.\n* Use `logger.exception` sparingly: only for truly unexpected errors that require stack traces for debugging. For expected or recoverable errors, prefer `logger.warning` or `logger.error` with explicit context.\n* Prefer `logger.warning` for recoverable issues, degraded states, or when an operation can continue despite an error.\n\n```python\nfrom loguru import logger\n\ndef process_items(items: list[str]) -> int:\n    \"\"\"Process items and return count.\"\"\"\n    count = len(items)\n    logger.info(\"Processing {count} items\", count=count)\n    # ...\n    logger.info(\"Processed {count} items\", count=count)\n    return count\n\n# Good: expected error, use warning with context\nasync def send_notification(msg: str) -> None:\n    \"\"\"Send notification; log warning if it fails (non-critical).\"\"\"\n    try:\n        await notify_service(msg)\n    except NetworkError as exc:\n        logger.warning(\"Notification failed, continuing: {err}\", err=str(exc))\n\n# Good: unexpected error requiring investigation, use exception\nasync def critical_operation() -> None:\n    \"\"\"Perform critical operation that should never fail.\"\"\"\n    try:\n        await process_critical_data()\n    except Exception:\n        logger.exception(\"Critical operation failed unexpectedly\")\n        raise\n```\n\n### Type Hints and Comments\n\n* Add type hints across public and internal APIs.\n* Comments and docstrings should be in English and explain why, not only what.\n* Use Protocols and TypedDict or pydantic models where appropriate.\n* Avoid excessive literal dict access (for example, using `obj['key']` everywhere); prefer typed structures such as `dataclass`, pydantic models, or `TypedDict` for clearer contracts and better type safety.\n\n### Error Handling\n\n* Keep try-except depth to at most two levels.\n* Catch specific exceptions. Re-raise with context if needed.\n* Prefer explicit None checks and guard clauses over broad exception use.\n\n```python\nimport json\nfrom loguru import logger\n\ndef parse_payload(raw: str) -> dict:\n    \"\"\"Parse payload; return empty dict on known format errors.\"\"\"\n    try:\n        data = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        logger.info(\"Invalid JSON: {err}\", err=str(exc))\n        return {}\n    return data\n```\n\n### Structure and Size\n\n* Avoid nested functions; extract helpers at module level.\n* Keep functions under 200 lines. Split into well-named helpers.\n* Avoid functions with more than 10 parameters; prefer wrapping parameters in a struct or object.\n* Separate concerns: I/O, parsing, business logic, and orchestration.\n\n### Strings and Literals\n\n* Avoid long string literals; wrap lines under 100 characters.\n* Avoid magic numbers and ad-hoc string literals. Centralize constants.\n\n```python\n# constants.py\nDEFAULT_TIMEOUT_S: float = 10.0\nMAX_RETRIES: int = 3\n```\n\n### Boolean Logic\n\n* Be careful with or where 0, empty, or False may be meaningful.\n* Prefer explicit checks:\n\n```python\n# Prefer\nvalue = user_value if user_value is not None else default\n\n# Avoid\nvalue = user_value or default\n```\n\n### Module and Package Layout\n\n* Group agent core, adapters, and utilities into separate modules.\n* Keep public surface small. Delay re-exports in __init__ until stable.\n* If circular dependencies appear, refactor shared contracts to a thin shared module (e.g., interfaces.py or contracts.py).\n\n<!-- File: python/configs/agents/news_agent.yaml (Tokens: ~753 | Category: anthropic-skill) -->\n# ============================================\n# News Agent Configuration\n# ============================================\n# The News Agent specializes in gathering, analyzing, and presenting news information.\n# It provides real-time news search, categorized news retrieval, and comprehensive analysis.\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file\n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"News Agent\"\nenabled: true\n\n# Model Configuration\n# News Agent needs a capable model for news analysis and summarization\nmodels:\n  # Primary model for news analysis, summarization, and query processing\n  primary:\n    model_id: \"qwen/qwen3-max\"\n    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n\n    # Provider-specific model mappings for fallback\n    # Used when primary provider fails and fallback is attempted\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"  # Strong reasoning for news analysis\n      google: \"gemini-2.5-flash\"  # Fast and efficient for news processing\n\n    parameters:\n      # temperature: 0.3  # Lower temperature for more factual news reporting\n      # max_tokens: 4096  # Sufficient for comprehensive news analysis\n\n  # Web search model for real-time information gathering\n  # Uses specialized models optimized for web search and real-time data\n  search:\n    model_id: \"perplexity/sonar\"\n    provider: \"openrouter\"\n\n    # Provider-specific search model mappings\n    provider_models:\n      google: \"gemini-2.5-flash\"  # With search grounding enabled\n\n    parameters:\n      # max_tokens: 2048  # Optimized for search result processing\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  NEWS_AGENT_MODEL_ID: \"models.primary.model_id\"\n  NEWS_AGENT_PROVIDER: \"models.primary.provider\"\n  NEWS_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  NEWS_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n  # Search model overrides\n  NEWS_SEARCH_MODEL_ID: \"models.search.model_id\"\n  NEWS_SEARCH_PROVIDER: \"models.search.provider\"\n\n  # Web search provider configuration\n  WEB_SEARCH_PROVIDER: \"capabilities.web_search.provider\"\n\n# News Agent Capabilities\ncapabilities:\n  # Web search configuration\n  web_search:\n    enabled: true\n    provider: \"perplexity\"  # Default: perplexity, alternative: google\n    max_results: 10\n\n  # Breaking news monitoring\n  breaking_news:\n    enabled: true  # Enable breaking news monitoring\n    refresh_interval: 300  # seconds\n\n  # Financial news specialization\n  financial_news:\n    enabled: true\n    supported_markets: [\"US\", \"Global\"]\n    include_sectors: true\n    include_individual_stocks: true\n\n\n\n  # Multi-language support\n  languages:\n    enabled: true\n    supported: [\"en\", \"zh\", \"ja\", \"ko\", \"es\", \"fr\", \"de\"]\n    default: \"en\"\n\n  # News analysis features\n  analysis:\n    sentiment_analysis: true\n    topic_extraction: true\n    entity_recognition: true\n    summarization: true\n    fact_checking: false  # Requires additional verification tools\n\n# Tool Configuration\ntools:\n  web_search:\n    enabled: true\n\n  get_breaking_news:\n    enabled: true\n\n  get_financial_news:\n    enabled: true\n\n<!-- File: python/configs/agents/research_agent.yaml (Tokens: ~386 | Category: anthropic-skill) -->\n# ============================================\n# Research Agent Configuration\n# ============================================\nname: \"Research Agent\"\nenabled: true\n\n# Model Configuration\n# Priority: Environment Variables > .env > YAML\nmodels:\n  # Primary model for reasoning and generation\n  primary:\n    model_id: \"google/gemini-2.5-flash\"\n    provider: \"openrouter\"\n    # Provider-specific model mappings for fallback\n    provider_models:\n      siliconflow: \"Qwen/Qwen3-235B-A22B-Thinking-2507\"\n      google: \"gemini-2.5-flash\"\n    parameters:\n      # temperature: 0.7\n      # max_tokens: 8192\n  \n  # Embedding model for knowledge base\n  # Note: If not specified, will auto-select from available providers\n  embedding:\n    model_id: \"Qwen/Qwen3-Embedding-4B\"  # Optional, uses provider default\n    provider: \"siliconflow\"  # Must explicitly specify provider\n    # Provider-specific embedding model mappings for fallback\n    provider_models:\n      google: \"gemini-embedding-001\"\n    parameters:\n      dimensions: ${EMBEDDER_DIMENSION:2560}\n      # encoding_format: \"float\"\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\nenv_overrides:\n  # Primary model overrides\n  RESEARCH_AGENT_MODEL_ID: \"models.primary.model_id\"\n  RESEARCH_AGENT_PROVIDER: \"models.primary.provider\"\n  RESEARCH_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  RESEARCH_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n  \n  # Embedding model overrides (backward compatible with existing env vars)\n  EMBEDDER_MODEL_ID: \"models.embedding.model_id\"\n  EMBEDDER_MODEL_PROVIDER: \"models.embedding.provider\"\n  EMBEDDER_DIMENSION: \"models.embedding.parameters.dimensions\"\n\n<!-- File: python/configs/agents/super_agent.yaml (Tokens: ~506 | Category: anthropic-skill) -->\n# ============================================\n# Super Agent Configuration\n# ============================================\n# The Super Agent acts as the orchestration layer that:\n# - Triages user intent before planning\n# - Decides whether to answer directly or handoff to Planner\n# - Provides initial query enrichment and context gathering\n# ============================================\n# Configuration Priority (highest to lowest):\n# 1. Environment Variables (highest priority)\n# 2. .env file \n# 3. YAML files (lowest priority, system defaults)\n# ============================================\n\nname: \"Super Agent\"\nenabled: true\n\n# TODO support agent level model config\n\n# Model Configuration\n# Super Agent typically needs a capable reasoning model\n#models:\n#  # Primary model for triage, reasoning, and query enrichment\n#  primary:\n#    model_id: \"anthropic/claude-haiku-4.5\"\n#    provider: \"openrouter\"  # Must explicitly specify provider (not null)\n#\n#    # Provider-specific model mappings for fallback\n#    # Used when primary provider fails and fallback is attempted\n#    provider_models:\n#      siliconflow: \"deepseek-ai/DeepSeek-V3.1-Terminus\"  # Similar capability to Claude Haiku\n#      google: \"gemini-2.5-flash\"  # Fast and efficient like Claude Haiku\n\n# Environment Variable Overrides\n# Format: ENV_VAR_NAME -> config.path\n# These allow runtime configuration through environment variables\nenv_overrides:\n  # Primary model overrides\n  PLANNER_MODEL_ID: \"models.primary.model_id\"\n  SUPER_AGENT_MODEL_ID: \"models.primary.model_id\"  # Alias for clarity\n  SUPER_AGENT_PROVIDER: \"models.primary.provider\"\n  SUPER_AGENT_TEMPERATURE: \"models.primary.parameters.temperature\"\n  SUPER_AGENT_MAX_TOKENS: \"models.primary.parameters.max_tokens\"\n\n# Super Agent Capabilities\ncapabilities:\n  # Enable web search for context enrichment\n  web_search: true\n  \n  # Enable crawling capabilities\n  web_crawl: true\n  \n  # Session management\n  session_management:\n    enabled: true\n    max_history_runs: 5\n    enable_summaries: true\n\n# Advanced Settings\nadvanced:\n  # Debug mode (can be overridden by AGENT_DEBUG_MODE env var)\n  debug_mode: false\n\n  # Output format\n  markdown: false\n  \n  # Context settings\n  add_datetime_to_context: true\n  add_history_to_context: true\n  read_chat_history: true\n\n<!-- File: python/valuecell/agents/common/trading/README.md (Tokens: ~4722 | Category: subagent-persona) -->\n# Trading Agent Framework\n\nThis document describes the common trading agent framework: a flexible, composable architecture for building LLM-driven trading strategies with clean separation of concerns and extensible components.\n\n## Architecture Overview\n\nThe framework provides a base class (`BaseStrategyAgent`) that handles lifecycle management, streaming, and persistence, while allowing users to customize decision logic and feature computation through well-defined extension points.\n\n**Key Principles:**\n\n- **Separation of Concerns**: Data fetching, feature computation, decision making, execution, and history tracking are independent modules\n- **Extensibility**: Override specific components without rewriting the entire pipeline\n- **Type Safety**: Pydantic models ensure data contracts across boundaries\n- **Async-First**: Built on asyncio for efficient I/O and concurrent operations\n- **Auditable**: Each decision cycle has a unique `compose_id` for tracing\n\n## Module Layout\n\n```text\ncommon/trading/\n├── base_agent.py          # BaseStrategyAgent abstract class\n├── models.py              # Pydantic DTOs and enums\n├── constants.py           # Default configuration values\n├── utils.py               # Shared utilities\n├── _internal/             # Internal runtime implementation\n│   ├── coordinator.py     # DefaultDecisionCoordinator\n│   ├── runtime.py         # StrategyRuntime factory\n│   └── stream_controller.py  # Persistence and streaming\n├── data/                  # Market data sources\n│   ├── interfaces.py      # BaseMarketDataSource\n│   └── market.py          # SimpleMarketDataSource (CCXT)\n├── features/              # Feature computation\n│   ├── interfaces.py      # BaseFeaturesPipeline, CandleBasedFeatureComputer\n│   ├── pipeline.py        # DefaultFeaturesPipeline\n│   ├── candle.py          # SimpleCandleFeatureComputer\n│   └── market_snapshot.py # MarketSnapshotFeatureComputer\n├── decision/              # Decision composers\n│   ├── interfaces.py      # BaseComposer\n│   └── prompt_based/\n│       ├── composer.py    # LlmComposer\n│       └── system_prompt.py\n├── execution/             # Trade execution\n│   ├── interfaces.py      # BaseExecutionGateway\n│   ├── factory.py         # Gateway factory\n│   ├── paper_trading.py   # PaperExecutionGateway\n│   └── ccxt_trading.py    # CCXTExecutionGateway (live)\n├── portfolio/             # Portfolio management\n│   ├── interfaces.py      # BasePortfolioService\n│   └── in_memory.py       # InMemoryPortfolioService\n└── trading_history/       # History and digest\n    ├── interfaces.py      # BaseHistoryRecorder, BaseDigestBuilder\n    ├── recorder.py        # InMemoryHistoryRecorder\n    └── digest.py          # RollingDigestBuilder\n```\n\n## Data Flow (Decision Cycle)\n\nEach decision cycle follows this pipeline:\n\n1. **Portfolio State**: Coordinator fetches current `PortfolioView` (positions, cash, constraints)\n2. **Data Collection**: Pipeline pulls market data (candles, tickers, funding rates, etc.)\n3. **Feature Computation**: Pipeline computes `FeatureVector[]` from raw data\n4. **Context Assembly**: Coordinator builds `ComposeContext` with features, portfolio, digest, and constraints\n5. **Decision**: Composer (LLM + guardrails) produces normalized `TradeInstruction[]`\n6. **Execution**: Gateway executes instructions and returns `TxResult[]`\n7. **Portfolio Update**: Service applies trades to update positions and metrics\n8. **History**: Recorder checkpoints features, instructions, trades, and summary\n9. **Digest**: Builder updates `TradeDigest` for next cycle's context\n\n```text\n                                        ┌─────────────┐\n                                        │  Portfolio  │\n                                        │    View     │\n                                        └──────┬──────┘\n                                               │\n                                               ▼\n┌─────────────┐    ┌──────────────┐    ┌─────────────┐\n│   Market    │───▶│   Features   │───▶│   Context   │\n│    Data     │    │   Pipeline   │    │  Assembly   │\n└─────────────┘    └──────────────┘    └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Composer   │\n                                       │             │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n                                       ┌─────────────┐\n                                       │  Execution  │\n                                       │   Gateway   │\n                                       └──────┬──────┘\n                                              │\n                                              ▼\n       ┌──────────────────────────────────────┴────────────────┐\n       │                                                       │\n       ▼                                                       ▼\n┌─────────────┐                                         ┌─────────────┐\n│   History   │                                         │  Portfolio  │\n│   Recorder  │                                         │   Update    │\n└──────┬──────┘                                         └─────────────┘\n       │\n       ▼\n┌─────────────┐\n│   Digest    │\n│   Builder   │\n└─────────────┘\n```\n\n## Core Data Models\n\n### Configuration\n\nUserRequest\n\n- `llm_model_config: LLMModelConfig` — AI model settings\n- `exchange_config: ExchangeConfig` — Trading mode, exchange, credentials\n- `trading_config: TradingConfig` — Strategy parameters\n\nTradingConfig\n\n- `strategy_name?: str` — Display name\n- `initial_capital: float` — Starting total cash in USD\n- `initial_free_cash: float` — Starting free cash in USD (same as initial_capital if there's no initial positions)\n- `max_leverage: float` — Maximum leverage allowed\n- `max_positions: int` — Concurrent position limit\n- `symbols: List[str]` — Instruments to trade (e.g., `[\"BTC-USDT\", \"ETH-USDT\"]`)\n- `decide_interval: int` — Seconds between cycles\n- `custom_prompt?: str` — Custom strategy prompt\n- `prompt_text?: str` — Additional prompt text\n\n### Market Data\n\nCandle\n\n- `ts: int` — Timestamp (milliseconds)\n- `instrument: InstrumentRef` — Symbol reference\n- `open, high, low, close, volume: float` — OHLCV data\n- `interval: str` — Timeframe (e.g., \"1m\", \"1h\")\n\nFeatureVector\n\n- `ts: int` — Feature timestamp\n- `instrument: InstrumentRef` — Associated symbol\n- `values: Dict[str, float]` — Feature key-value pairs\n- `meta?: Dict[str, Any]` — Optional metadata (interval, group_by_key, etc.)\n\n### Portfolio\n\nPositionSnapshot\n\n- `instrument: InstrumentRef`\n- `quantity: float` — Signed quantity (+long, -short)\n- `avg_price?: float` — Average entry price\n- `mark_price?: float` — Current market price\n- `unrealized_pnl?: float` — Unrealized profit/loss\n- `leverage?: float` — Applied leverage\n- `entry_ts?: int` — Entry timestamp\n\nPortfolioView\n\n- `strategy_id: str`\n- `ts: int` — Snapshot timestamp\n- `account_balance: float` — Cash balance\n- `positions: Dict[str, PositionSnapshot]` — Active positions by symbol\n- `total_value?: float` — Portfolio equity\n- `total_unrealized_pnl?: float` — Sum of position unrealized PnL\n- `buying_power?: float` — Available buying power\n- `constraints?: Constraints` — Position and leverage limits\n\n### Decision\n\nComposeContext\n\n- `ts: int` — Cycle timestamp\n- `compose_id: str` — Unique cycle identifier\n- `strategy_id: str`\n- `features: List[FeatureVector]` — Computed features\n- `portfolio: PortfolioView` — Current portfolio state\n- `digest: TradeDigest` — Historical performance summary\n\nTradeInstruction\n\n- `instruction_id: str` — Unique instruction ID\n- `compose_id: str` — Parent cycle ID\n- `instrument: InstrumentRef`\n- `side: TradeSide` — BUY or SELL\n- `quantity: float` — Order quantity\n- `leverage?: float` — Applied leverage\n- `max_slippage_bps?: int` — Maximum slippage (basis points)\n- `meta?: Dict` — Optional metadata\n\n### Execution\n\nTxResult\n\n- `instruction_id: str`\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `status: TxStatus` — FILLED, PARTIAL, REJECTED, ERROR\n- `requested_qty: float`\n- `filled_qty: float`\n- `avg_exec_price?: float`\n- `fee_cost?: float`\n- `leverage?: float`\n\n### History\n\nTradeHistoryEntry\n\n- `trade_id: str`\n- `compose_id: str` — Originating cycle\n- `instruction_id: str` — Originating instruction\n- `instrument: InstrumentRef`\n- `side: TradeSide`\n- `type: TradeType` — LONG or SHORT\n- `quantity: float`\n- `entry_price?, exit_price?: float`\n- `entry_ts?, exit_ts?: int`\n- `realized_pnl?: float` — Profit/loss on close\n- `holding_ms?: int` — Position duration\n\nTradeDigest\n\n- `ts: int`\n- `by_instrument: Dict[str, TradeDigestEntry]`\n- `sharpe_ratio?: float` — Portfolio Sharpe ratio\n\n**TradeDigestEntry** (per-symbol stats)\n\n- `trade_count: int`\n- `realized_pnl: float`\n- `win_rate?: float`\n- `avg_holding_ms?: int`\n- `last_trade_ts?: int`\n\n---\n\n## Integration Guide\n\n### Quick Start: Using the Default Agent\n\nThe simplest way to create a trading agent is to use `prompt_strategy_agent`, which provides default implementations for all components:\n\n```python\n# python/valuecell/agents/prompt_strategy_agent/__main__.py\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import StrategyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(StrategyAgent)\n    asyncio.run(agent.serve())\n```\n\n**StrategyAgent** (in `core.py`) extends `BaseStrategyAgent` and uses:\n\n- `DefaultFeaturesPipeline`: Fetches candles and computes technical indicators\n- `LlmComposer`: LLM-based decision making with guardrails\n\nTo run:\n\n```bash\ncd python/valuecell/agents/prompt_strategy_agent\npython -m valuecell.agents.prompt_strategy_agent\n```\n\n### Custom Agent: Override Specific Components\n\nCreate a custom agent by subclassing `BaseStrategyAgent` and overriding extension points:\n\n#### Example 1: Custom Feature Pipeline\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.features import BaseFeaturesPipeline\nfrom valuecell.agents.common.trading.models import (\n    FeaturesPipelineResult,\n    FeatureVector,\n    UserRequest,\n)\n\nclass MyFeaturesPipeline(BaseFeaturesPipeline):\n    \"\"\"Custom pipeline with specialized indicators.\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n        self.symbols = request.trading_config.symbols\n        # Initialize custom data sources, indicators, etc.\n    \n    async def build(self) -> FeaturesPipelineResult:\n        features = []\n        # Fetch data and compute custom features\n        # ... your logic here ...\n        return FeaturesPipelineResult(features=features)\n\n\nclass MyCustomAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom feature computation.\"\"\"\n    \n    async def _build_features_pipeline(\n        self, request: UserRequest\n    ) -> BaseFeaturesPipeline | None:\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Use default LLM composer\n        return None\n```\n\n#### Example 2: Custom Decision Composer\n\n```python\nfrom valuecell.agents.common.trading.decision import BaseComposer\nfrom valuecell.agents.common.trading.models import (\n    ComposeContext,\n    ComposeResult,\n    TradeInstruction,\n)\n\nclass RuleBasedComposer(BaseComposer):\n    \"\"\"Simple rule-based decision maker (no LLM).\"\"\"\n    \n    def __init__(self, request: UserRequest):\n        self.request = request\n    \n    async def compose(self, context: ComposeContext) -> ComposeResult:\n        instructions = []\n        # Implement your trading rules\n        # Example: Buy when RSI < 30, sell when RSI > 70\n        for fv in context.features:\n            rsi = fv.values.get(\"rsi\")\n            if rsi and rsi < 30:\n                # Create buy instruction\n                pass\n            elif rsi and rsi > 70:\n                # Create sell instruction\n                pass\n        \n        return ComposeResult(\n            instructions=instructions,\n            rationale=\"Rule-based signals\"\n        )\n\n\nclass RuleBasedAgent(BaseStrategyAgent):\n    \"\"\"Agent using rule-based decisions.\"\"\"\n    \n    async def _build_features_pipeline(self, request: UserRequest):\n        # Use default pipeline\n        return None\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        return RuleBasedComposer(request)\n```\n\n#### Example 3: Lifecycle Hooks\n\n```python\nclass MonitoredAgent(BaseStrategyAgent):\n    \"\"\"Agent with custom monitoring and logging.\"\"\"\n    \n    async def _on_start(self, runtime, request):\n        \"\"\"Called once after runtime creation.\"\"\"\n        self.cycle_count = 0\n        print(f\"Strategy {runtime.strategy_id} starting...\")\n    \n    async def _on_cycle_result(self, result, runtime, request):\n        \"\"\"Called after each cycle completes.\"\"\"\n        self.cycle_count += 1\n        print(f\"Cycle {self.cycle_count}: \"\n              f\"{len(result.trades)} trades, \"\n              f\"PnL: {result.strategy_summary.realized_pnl}\")\n        \n        # Send metrics to external monitoring\n        # ... custom logic ...\n    \n    async def _on_stop(self, runtime, request, reason):\n        \"\"\"Called before finalization.\"\"\"\n        print(f\"Strategy stopping: {reason}\")\n        print(f\"Total cycles: {self.cycle_count}\")\n    \n    async def _build_features_pipeline(self, request):\n        return None  # Use defaults\n    \n    async def _create_decision_composer(self, request):\n        return None  # Use defaults\n```\n\n### Creating a Complete Custom Agent Module\n\n**Directory Structure:**\n\n```text\npython/valuecell/agents/my_agent/\n├── __init__.py\n├── __main__.py          # Entry point\n├── core.py              # Agent implementation\n├── features.py          # Custom features (optional)\n├── composer.py          # Custom composer (optional)\n└── templates/\n    └── strategy.txt     # Strategy prompt template\n```\n\n**`__main__.py`:**\n\n```python\nimport asyncio\nfrom valuecell.core.agent import create_wrapped_agent\nfrom .core import MyAgent\n\nif __name__ == \"__main__\":\n    agent = create_wrapped_agent(MyAgent)\n    asyncio.run(agent.serve())\n```\n\n**`core.py`:**\n\n```python\nfrom valuecell.agents.common.trading.base_agent import BaseStrategyAgent\nfrom valuecell.agents.common.trading.models import UserRequest\nfrom .features import MyFeaturesPipeline  # if custom\nfrom .composer import MyComposer  # if custom\n\nclass MyAgent(BaseStrategyAgent):\n    async def _build_features_pipeline(self, request: UserRequest):\n        # Return custom pipeline or None for default\n        return MyFeaturesPipeline(request)\n    \n    async def _create_decision_composer(self, request: UserRequest):\n        # Return custom composer or None for default\n        return MyComposer(request)\n```\n\n**Run your agent:**\n\n```bash\ncd python/valuecell/agents/my_agent\npython -m valuecell.agents.my_agent\n```\n\n### Live Trading Setup\n\nFor live trading with real exchanges:\n\n**Set trading mode to LIVE:**\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"live\",\n    \"exchange_id\": \"binance\",\n    \"api_key\": \"YOUR_API_KEY\",\n    \"secret_key\": \"YOUR_SECRET_KEY\",\n    \"testnet\": true  // Use testnet first!\n  }\n}\n```\n\n**The runtime automatically:**\n\n- Fetches real account balance\n- Sets `initial_capital` to account total cash\n- Sets `initial_free_cash` to available cash\n- Uses `CCXTExecutionGateway` for order submission\n\n**Always test on testnet first** before using real funds\n\n### Testing Strategies\n\n#### Paper Trading (Default)\n\n```json\n{\n  \"exchange_config\": {\n    \"trading_mode\": \"virtual\",\n    \"fee_bps\": 10.0  // 0.1% simulated fees\n  }\n}\n```\n\nPaper trading uses `PaperExecutionGateway` which:\n\n- Simulates order fills at market price ± slippage\n- Applies configurable fees\n- No real exchange connection needed\n\n#### Backtesting\n\nCreate a custom `BaseMarketDataSource` that replays historical data:\n\n```python\nfrom valuecell.agents.common.trading.data import BaseMarketDataSource\nfrom valuecell.agents.common.trading.models import Candle\n\nclass BacktestDataSource(BaseMarketDataSource):\n    def __init__(self, historical_data):\n        self.data = historical_data\n        self.current_index = 0\n    \n    async def get_recent_candles(self, symbols, interval, lookback):\n        # Return historical candles for current timestamp\n        candles = self.data[self.current_index]\n        self.current_index += 1\n        return candles\n    \n    async def get_market_snapshot(self, symbols):\n        # Return snapshot from historical data\n        return {}\n```\n\nThen use it in your custom pipeline.\n\n### Extension Points Summary\n\n| Component | Method | Purpose |\n|-----------|--------|---------|\n| **Features** | `_build_features_pipeline()` | Define how market data is fetched and processed |\n| **Decision** | `_create_decision_composer()` | Customize trading logic (LLM, rules, ML) |\n| **Lifecycle** | `_on_start()` | Initialize resources after runtime creation |\n| **Lifecycle** | `_on_cycle_result()` | Monitor/log each cycle result |\n| **Lifecycle** | `_on_stop()` | Cleanup before finalization |\n\n### Best Practices\n\n1. **Start with defaults**: Use `prompt_strategy_agent` as a template\n2. **Override incrementally**: Only customize what you need\n3. **Type safety**: Use Pydantic models for all data contracts\n4. **Async operations**: Mark I/O operations as `async`\n5. **Error handling**: Hooks swallow exceptions to prevent crashes\n6. **Testnet first**: Always test live trading on testnet\n7. **Monitor carefully**: Use lifecycle hooks for observability\n\n### Common Patterns\n\n#### Adding Custom Indicators\n\n```python\nclass CustomFeaturesPipeline(BaseFeaturesPipeline):\n    async def build(self):\n        # Fetch candles\n        candles = await self.market_data.get_recent_candles(...)\n        \n        # Compute standard indicators\n        rsi = compute_rsi(candles)\n        macd = compute_macd(candles)\n        \n        # Add custom indicators\n        my_signal = compute_custom_indicator(candles)\n        \n        features = []\n        for symbol in symbols:\n            features.append(FeatureVector(\n                ts=timestamp,\n                instrument=InstrumentRef(symbol=symbol),\n                values={\n                    \"rsi\": rsi[symbol],\n                    \"macd\": macd[symbol],\n                    \"custom_signal\": my_signal[symbol],\n                }\n            ))\n        \n        return FeaturesPipelineResult(features=features)\n```\n\n#### Combining LLM with Rules\n\n```python\nclass HybridComposer(BaseComposer):\n    def __init__(self, request):\n        self.llm_composer = LlmComposer(request)\n        self.request = request\n    \n    async def compose(self, context):\n        # Get LLM suggestions\n        llm_result = await self.llm_composer.compose(context)\n        \n        # Apply additional rule filters\n        filtered_instructions = []\n        for inst in llm_result.instructions:\n            if self._passes_risk_check(inst, context):\n                filtered_instructions.append(inst)\n        \n        return ComposeResult(\n            instructions=filtered_instructions,\n            rationale=f\"LLM + risk filters: {llm_result.rationale}\"\n        )\n    \n    def _passes_risk_check(self, inst, context):\n        # Custom risk rules\n        return True\n```\n\n### Debugging\n\nEnable detailed logging:\n\n```python\nimport logging\nfrom loguru import logger\n\nlogger.add(\"strategy_{time}.log\", level=\"DEBUG\")\n```\n\nThe framework logs:\n\n- Cycle start/end with compose_id\n- Instruction count and details\n- Execution results and fills\n- Portfolio updates\n- Error traces with context\n\n---\n\n## Advanced Topics\n\n### Custom Execution Gateway\n\nImplement `BaseExecutionGateway` to integrate custom execution logic:\n\n```python\nfrom valuecell.agents.common.trading.execution import BaseExecutionGateway\nfrom valuecell.agents.common.trading.models import (\n    TradeInstruction,\n    TxResult,\n    TxStatus,\n)\n\nclass MyExecutionGateway(BaseExecutionGateway):\n    async def execute(self, instructions, market_features):\n        results = []\n        for inst in instructions:\n            # Your execution logic\n            result = TxResult(\n                instruction_id=inst.instruction_id,\n                instrument=inst.instrument,\n                side=inst.side,\n                status=TxStatus.FILLED,\n                requested_qty=inst.quantity,\n                filled_qty=inst.quantity,\n                avg_exec_price=100.0,  # from your system\n            )\n            results.append(result)\n        return results\n```\n\n### Custom Portfolio Service\n\nOverride portfolio management for complex accounting:\n\n```python\nfrom valuecell.agents.common.trading.portfolio import BasePortfolioService\n\nclass CustomPortfolioService(BasePortfolioService):\n    def get_view(self):\n        # Return custom PortfolioView\n        pass\n    \n    def apply_trades(self, trades, market_features):\n        # Update internal state\n        pass\n```\n\n### Persistence Integration\n\nUse `StreamController` to persist strategy state to your database. The framework already handles:\n\n- Initial portfolio snapshot\n- Cycle results (compose cycles, instructions, execution details)\n- Final cleanup and status updates\n\nSee `_internal/stream_controller.py` for persistence logic.\n</yakaai_skills>"}