mirror of
https://github.com/Xe138/AI-Trader.git
synced 2026-04-01 17:17:24 -04:00
refactor: migrate trade tools from file-based to SQLite position storage
Complete rewrite of position management in MCP trade tools: **Trade Tools (agent_tools/tool_trade.py)** - Replace file-based position.jsonl reads with SQLite queries - Add get_current_position_from_db() to query positions and holdings tables - Rewrite buy() and sell() to write directly to database - Calculate portfolio value and P&L metrics in tools - Accept job_id and session_id parameters via ContextInjector - Return errors with proper context for debugging - Use deployment-aware database path resolution **Context Injection (agent/context_injector.py)** - Add job_id and session_id to constructor - Inject job_id and session_id into buy/sell tool calls - Support optional parameters (None in standalone mode) **BaseAgent (agent/base_agent/base_agent.py)** - Read JOB_ID from runtime config - Pass job_id to ContextInjector during initialization - Enable automatic context injection for API mode **ModelDayExecutor (api/model_day_executor.py)** - Add _initialize_starting_position() method - Create initial position record before agent runs - Load initial_cash from config - Update context_injector.session_id after session creation - Link positions to sessions automatically **Architecture Changes:** - Eliminates file-based position tracking entirely - Single source of truth: SQLite database - Positions automatically linked to trading sessions - Concurrent execution safe (no file system conflicts) - Deployment mode aware (prod vs dev databases) This completes the migration to database-only position storage. File-based position.jsonl is no longer used or created. Fixes context injection errors in concurrent simulations.
This commit is contained in:
@@ -122,12 +122,20 @@ class ModelDayExecutor:
|
||||
session_id = self._create_trading_session(cursor)
|
||||
conn.commit()
|
||||
|
||||
# Initialize starting position if this is first day
|
||||
self._initialize_starting_position(cursor, session_id)
|
||||
conn.commit()
|
||||
|
||||
# Set environment variable for agent to use isolated config
|
||||
os.environ["RUNTIME_ENV_PATH"] = self.runtime_config_path
|
||||
|
||||
# Initialize agent
|
||||
agent = await self._initialize_agent()
|
||||
|
||||
# Update context injector with session_id
|
||||
if hasattr(agent, 'context_injector') and agent.context_injector:
|
||||
agent.context_injector.session_id = session_id
|
||||
|
||||
# Run trading session
|
||||
logger.info(f"Running trading session for {self.model_sig} on {self.date}")
|
||||
session_result = await agent.run_trading_session(self.date)
|
||||
@@ -287,6 +295,51 @@ class ModelDayExecutor:
|
||||
|
||||
return cursor.lastrowid
|
||||
|
||||
def _initialize_starting_position(self, cursor, session_id: int) -> None:
|
||||
"""
|
||||
Initialize starting position if no prior positions exist for this job+model.
|
||||
|
||||
Creates action_id=0 position with initial_cash and zero stock holdings.
|
||||
|
||||
Args:
|
||||
cursor: Database cursor
|
||||
session_id: Trading session ID
|
||||
"""
|
||||
# Check if any positions exist for this job+model
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM positions
|
||||
WHERE job_id = ? AND model = ?
|
||||
""", (self.job_id, self.model_sig))
|
||||
|
||||
if cursor.fetchone()[0] > 0:
|
||||
# Positions already exist, no initialization needed
|
||||
return
|
||||
|
||||
# Load config to get initial_cash
|
||||
import json
|
||||
with open(self.config_path, 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
agent_config = config.get("agent_config", {})
|
||||
initial_cash = agent_config.get("initial_cash", 10000.0)
|
||||
|
||||
# Create initial position record
|
||||
from datetime import datetime
|
||||
created_at = datetime.utcnow().isoformat() + "Z"
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO positions (
|
||||
job_id, date, model, action_id, action_type,
|
||||
cash, portfolio_value, session_id, created_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
self.job_id, self.date, self.model_sig, 0, "init",
|
||||
initial_cash, initial_cash, session_id, created_at
|
||||
))
|
||||
|
||||
logger.info(f"Initialized starting position for {self.model_sig} with ${initial_cash}")
|
||||
|
||||
async def _store_reasoning_logs(
|
||||
self,
|
||||
cursor,
|
||||
|
||||
Reference in New Issue
Block a user