mirror of
https://github.com/Xe138/AI-Trader.git
synced 2026-04-02 01:27:24 -04:00
Compare commits
6 Commits
v0.3.0-alp
...
v0.3.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| 96f6b78a93 | |||
| 6c395f740d | |||
| 618943b278 | |||
| 1c19eea29a | |||
| e968434062 | |||
| 4c1d23a7c8 |
@@ -221,7 +221,7 @@ class BaseAgent:
|
||||
|
||||
print(f"✅ Agent {self.signature} initialization completed")
|
||||
|
||||
def set_context(self, context_injector: "ContextInjector") -> None:
|
||||
async def set_context(self, context_injector: "ContextInjector") -> None:
|
||||
"""
|
||||
Inject ContextInjector after initialization.
|
||||
|
||||
@@ -232,14 +232,24 @@ class BaseAgent:
|
||||
context_injector: Configured ContextInjector instance with
|
||||
correct signature, today_date, job_id, session_id
|
||||
"""
|
||||
print(f"[DEBUG] set_context() ENTRY: Received context_injector with signature={context_injector.signature}, date={context_injector.today_date}, job_id={context_injector.job_id}, session_id={context_injector.session_id}")
|
||||
|
||||
self.context_injector = context_injector
|
||||
print(f"[DEBUG] set_context(): Set self.context_injector, id={id(self.context_injector)}")
|
||||
|
||||
# Recreate MCP client with the interceptor
|
||||
# Note: We need to recreate because MultiServerMCPClient doesn't have add_interceptor()
|
||||
print(f"[DEBUG] set_context(): Creating new MCP client with interceptor, id={id(context_injector)}")
|
||||
self.client = MultiServerMCPClient(
|
||||
self.mcp_config,
|
||||
tool_interceptors=[context_injector]
|
||||
)
|
||||
print(f"[DEBUG] set_context(): MCP client created")
|
||||
|
||||
# CRITICAL: Reload tools from new client so they use the interceptor
|
||||
print(f"[DEBUG] set_context(): Reloading tools...")
|
||||
self.tools = await self.client.get_tools()
|
||||
print(f"[DEBUG] set_context(): Tools reloaded, count={len(self.tools)}")
|
||||
|
||||
print(f"✅ Context injected: signature={context_injector.signature}, "
|
||||
f"date={context_injector.today_date}, job_id={context_injector.job_id}, "
|
||||
|
||||
@@ -49,14 +49,16 @@ class ContextInjector:
|
||||
"""
|
||||
# Inject context parameters for trade tools
|
||||
if request.name in ["buy", "sell"]:
|
||||
# Add signature and today_date to args if not present
|
||||
if "signature" not in request.args:
|
||||
request.args["signature"] = self.signature
|
||||
if "today_date" not in request.args:
|
||||
request.args["today_date"] = self.today_date
|
||||
if "job_id" not in request.args and self.job_id:
|
||||
# Debug: Log self attributes BEFORE injection
|
||||
print(f"[ContextInjector.__call__] ENTRY: id={id(self)}, self.signature={self.signature}, self.today_date={self.today_date}, self.job_id={self.job_id}, self.session_id={self.session_id}")
|
||||
print(f"[ContextInjector.__call__] Args BEFORE injection: {request.args}")
|
||||
|
||||
# ALWAYS inject/override context parameters (don't trust AI-provided values)
|
||||
request.args["signature"] = self.signature
|
||||
request.args["today_date"] = self.today_date
|
||||
if self.job_id:
|
||||
request.args["job_id"] = self.job_id
|
||||
if "session_id" not in request.args and self.session_id:
|
||||
if self.session_id:
|
||||
request.args["session_id"] = self.session_id
|
||||
|
||||
# Debug logging
|
||||
|
||||
@@ -7,7 +7,6 @@ project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, project_root)
|
||||
from tools.price_tools import get_open_prices
|
||||
import json
|
||||
from tools.deployment_config import get_db_path
|
||||
from api.database import get_db_connection
|
||||
from datetime import datetime
|
||||
mcp = FastMCP("TradeTools")
|
||||
@@ -30,7 +29,7 @@ def get_current_position_from_db(job_id: str, model: str, date: str) -> Tuple[Di
|
||||
Raises:
|
||||
Exception: If database query fails
|
||||
"""
|
||||
db_path = get_db_path()
|
||||
db_path = "data/jobs.db"
|
||||
conn = get_db_connection(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -83,24 +82,13 @@ def get_current_position_from_db(job_id: str, model: str, date: str) -> Tuple[Di
|
||||
conn.close()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def buy(symbol: str, amount: int, signature: str = None, today_date: str = None,
|
||||
job_id: str = None, session_id: int = None) -> Dict[str, Any]:
|
||||
def _buy_impl(symbol: str, amount: int, signature: str = None, today_date: str = None,
|
||||
job_id: str = None, session_id: int = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Buy stock function - writes to SQLite database.
|
||||
Internal buy implementation - accepts injected context parameters.
|
||||
|
||||
Args:
|
||||
symbol: Stock symbol (e.g., "AAPL", "MSFT")
|
||||
amount: Number of shares to buy (positive integer)
|
||||
signature: Model signature (injected by ContextInjector)
|
||||
today_date: Trading date YYYY-MM-DD (injected by ContextInjector)
|
||||
job_id: Job UUID (injected by ContextInjector)
|
||||
session_id: Trading session ID (injected by ContextInjector)
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]:
|
||||
- Success: {"CASH": amount, symbol: quantity, ...}
|
||||
- Failure: {"error": message, ...}
|
||||
This function is not exposed to the AI model. It receives runtime context
|
||||
(signature, today_date, job_id, session_id) from the ContextInjector.
|
||||
"""
|
||||
# Validate required parameters
|
||||
if not job_id:
|
||||
@@ -110,7 +98,7 @@ def buy(symbol: str, amount: int, signature: str = None, today_date: str = None,
|
||||
if not today_date:
|
||||
return {"error": "Missing required parameter: today_date"}
|
||||
|
||||
db_path = get_db_path()
|
||||
db_path = "data/jobs.db"
|
||||
conn = get_db_connection(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -207,8 +195,31 @@ def buy(symbol: str, amount: int, signature: str = None, today_date: str = None,
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def sell(symbol: str, amount: int, signature: str = None, today_date: str = None,
|
||||
job_id: str = None, session_id: int = None) -> Dict[str, Any]:
|
||||
def buy(symbol: str, amount: int, **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
Buy stock shares.
|
||||
|
||||
Args:
|
||||
symbol: Stock symbol (e.g., "AAPL", "MSFT", "GOOGL")
|
||||
amount: Number of shares to buy (positive integer)
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]:
|
||||
- Success: {"CASH": remaining_cash, "SYMBOL": shares, ...}
|
||||
- Failure: {"error": error_message, ...}
|
||||
"""
|
||||
# Extract injected parameters (added by ContextInjector, hidden from AI)
|
||||
signature = kwargs.get("signature")
|
||||
today_date = kwargs.get("today_date")
|
||||
job_id = kwargs.get("job_id")
|
||||
session_id = kwargs.get("session_id")
|
||||
|
||||
# Delegate to internal implementation
|
||||
return _buy_impl(symbol, amount, signature, today_date, job_id, session_id)
|
||||
|
||||
|
||||
def _sell_impl(symbol: str, amount: int, signature: str = None, today_date: str = None,
|
||||
job_id: str = None, session_id: int = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Sell stock function - writes to SQLite database.
|
||||
|
||||
@@ -233,7 +244,7 @@ def sell(symbol: str, amount: int, signature: str = None, today_date: str = None
|
||||
if not today_date:
|
||||
return {"error": "Missing required parameter: today_date"}
|
||||
|
||||
db_path = get_db_path()
|
||||
db_path = "data/jobs.db"
|
||||
conn = get_db_connection(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -328,6 +339,30 @@ def sell(symbol: str, amount: int, signature: str = None, today_date: str = None
|
||||
conn.close()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def sell(symbol: str, amount: int, **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
Sell stock shares.
|
||||
|
||||
Args:
|
||||
symbol: Stock symbol (e.g., "AAPL", "MSFT", "GOOGL")
|
||||
amount: Number of shares to sell (positive integer)
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]:
|
||||
- Success: {"CASH": remaining_cash, "SYMBOL": shares, ...}
|
||||
- Failure: {"error": error_message, ...}
|
||||
"""
|
||||
# Extract injected parameters (added by ContextInjector, hidden from AI)
|
||||
signature = kwargs.get("signature")
|
||||
today_date = kwargs.get("today_date")
|
||||
job_id = kwargs.get("job_id")
|
||||
session_id = kwargs.get("session_id")
|
||||
|
||||
# Delegate to internal implementation
|
||||
return _sell_impl(symbol, amount, signature, today_date, job_id, session_id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
port = int(os.getenv("TRADE_HTTP_PORT", "8002"))
|
||||
mcp.run(transport="streamable-http", port=port)
|
||||
|
||||
@@ -140,7 +140,10 @@ class ModelDayExecutor:
|
||||
job_id=self.job_id,
|
||||
session_id=session_id
|
||||
)
|
||||
agent.set_context(context_injector)
|
||||
logger.info(f"[DEBUG] ModelDayExecutor: Created ContextInjector with signature={self.model_sig}, date={self.date}, job_id={self.job_id}, session_id={session_id}")
|
||||
logger.info(f"[DEBUG] ModelDayExecutor: Calling await agent.set_context()")
|
||||
await agent.set_context(context_injector)
|
||||
logger.info(f"[DEBUG] ModelDayExecutor: set_context() completed")
|
||||
|
||||
# Run trading session
|
||||
logger.info(f"Running trading session for {self.model_sig} on {self.date}")
|
||||
@@ -155,10 +158,13 @@ class ModelDayExecutor:
|
||||
# Update session summary
|
||||
await self._update_session_summary(cursor, session_id, conversation, agent)
|
||||
|
||||
# Store positions (pass session_id)
|
||||
self._write_results_to_db(agent, session_id)
|
||||
|
||||
# Commit and close connection before _write_results_to_db opens a new one
|
||||
conn.commit()
|
||||
conn.close()
|
||||
conn = None # Mark as closed
|
||||
|
||||
# Store positions (pass session_id) - this opens its own connection
|
||||
self._write_results_to_db(agent, session_id)
|
||||
|
||||
# Update status to completed
|
||||
self.job_manager.update_job_detail_status(
|
||||
|
||||
@@ -320,12 +320,11 @@ def get_today_init_position_from_db(
|
||||
If no position exists: {"CASH": 10000.0} (initial cash)
|
||||
"""
|
||||
import logging
|
||||
from tools.deployment_config import get_db_path
|
||||
from api.database import get_db_connection
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
db_path = get_db_path()
|
||||
db_path = "data/jobs.db"
|
||||
conn = get_db_connection(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -385,14 +384,13 @@ def add_no_trade_record_to_db(
|
||||
session_id: Trading session ID
|
||||
"""
|
||||
import logging
|
||||
from tools.deployment_config import get_db_path
|
||||
from api.database import get_db_connection
|
||||
from agent_tools.tool_trade import get_current_position_from_db
|
||||
from datetime import datetime
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
db_path = get_db_path()
|
||||
db_path = "data/jobs.db"
|
||||
conn = get_db_connection(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user