Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions quantcoder/core/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,33 @@ def split_into_sections(self, text: str, headings: List[str]) -> Dict[str, str]:
return sections


class CodeValidator:
"""Validates Python code syntax."""

def __init__(self):
self.logger = logging.getLogger(self.__class__.__name__)

def validate_code(self, code: str) -> bool:
"""
Validate Python code syntax.

Args:
code: Python code string to validate

Returns:
True if code is syntactically valid, False otherwise
"""
try:
ast.parse(code)
return True
except SyntaxError as e:
self.logger.debug(f"Syntax error in code: {e}")
return False
except Exception as e:
self.logger.error(f"Validation error: {e}")
return False


class KeywordAnalyzer:
"""Analyzes text sections to categorize sentences based on keywords."""

Expand Down
129 changes: 118 additions & 11 deletions quantcoder/mcp/quantconnect_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,58 @@ async def get_api_docs(self, topic: str) -> str:
Returns:
Documentation text
"""
# This would integrate with QC docs or use web scraping
# For now, return placeholder
return f"Documentation for {topic}: See https://www.quantconnect.com/docs/"
import aiohttp

# Map topics to documentation endpoints
topic_map = {
"indicators": "indicators/supported-indicators",
"universe": "algorithm-reference/universes",
"universe selection": "algorithm-reference/universes",
"risk management": "algorithm-reference/risk-management",
"portfolio": "algorithm-reference/portfolio-construction",
"execution": "algorithm-reference/execution-models",
"alpha": "algorithm-reference/alpha-models",
"data": "datasets",
"orders": "algorithm-reference/trading-and-orders",
"securities": "algorithm-reference/securities-and-portfolio",
"history": "algorithm-reference/historical-data",
"scheduling": "algorithm-reference/scheduled-events",
"charting": "algorithm-reference/charting",
"logging": "algorithm-reference/logging-and-debug",
}

# Find matching topic
topic_lower = topic.lower()
doc_path = None
for key, path in topic_map.items():
if key in topic_lower:
doc_path = path
break

if not doc_path:
doc_path = "algorithm-reference"

doc_url = f"https://www.quantconnect.com/docs/v2/{doc_path}"

try:
async with aiohttp.ClientSession() as session:
async with session.get(doc_url, timeout=10) as resp:
if resp.status == 200:
# Return URL and basic info
return (
f"QuantConnect Documentation for '{topic}':\n"
f"URL: {doc_url}\n\n"
f"Key topics covered:\n"
f"- API Reference and usage examples\n"
f"- Code samples in Python and C#\n"
f"- Best practices and common patterns\n\n"
f"Visit the URL above for detailed documentation."
)
else:
return f"Documentation for '{topic}': {doc_url}"
except Exception as e:
self.logger.warning(f"Failed to fetch docs: {e}")
return f"Documentation for '{topic}': {doc_url}"

async def deploy_live(
self,
Expand Down Expand Up @@ -345,14 +394,72 @@ def __init__(self, api_key: str, user_id: str):
self.logger = logging.getLogger(self.__class__.__name__)

async def start(self):
"""Start MCP server."""
# This would use the MCP SDK to expose tools
# For now, this is a placeholder
self.logger.info("QuantConnect MCP Server started")

# Register tools with MCP framework
# Each method becomes an MCP tool
pass
"""
Start MCP server and register available tools.

This initializes the server and makes tools available for MCP clients.
Tools are exposed via the handle_tool_call method.
"""
self.logger.info("Initializing QuantConnect MCP Server")

# Define available tools with their schemas
self.tools = {
"validate_code": {
"description": "Validate QuantConnect algorithm code",
"parameters": {
"code": {"type": "string", "description": "Main algorithm code"},
"files": {"type": "object", "description": "Additional files (optional)"},
},
"required": ["code"],
},
"backtest": {
"description": "Run backtest on QuantConnect",
"parameters": {
"code": {"type": "string", "description": "Main algorithm code"},
"start_date": {"type": "string", "description": "Start date (YYYY-MM-DD)"},
"end_date": {"type": "string", "description": "End date (YYYY-MM-DD)"},
"files": {"type": "object", "description": "Additional files (optional)"},
"name": {"type": "string", "description": "Backtest name (optional)"},
},
"required": ["code", "start_date", "end_date"],
},
"get_api_docs": {
"description": "Get QuantConnect API documentation",
"parameters": {
"topic": {"type": "string", "description": "Documentation topic"},
},
"required": ["topic"],
},
"deploy_live": {
"description": "Deploy algorithm to live trading",
"parameters": {
"project_id": {"type": "string", "description": "Project ID"},
"compile_id": {"type": "string", "description": "Compile ID"},
"node_id": {"type": "string", "description": "Live node ID"},
"brokerage": {"type": "string", "description": "Brokerage name"},
},
"required": ["project_id", "compile_id", "node_id"],
},
}

self._running = True
self.logger.info(
f"QuantConnect MCP Server started with {len(self.tools)} tools: "
f"{', '.join(self.tools.keys())}"
)

def get_tools(self) -> dict:
"""Return available tools and their schemas."""
return self.tools if hasattr(self, 'tools') else {}

def is_running(self) -> bool:
"""Check if server is running."""
return getattr(self, '_running', False)

async def stop(self):
"""Stop the MCP server."""
self._running = False
self.logger.info("QuantConnect MCP Server stopped")

async def handle_tool_call(self, tool_name: str, arguments: Dict) -> Any:
"""Handle MCP tool call."""
Expand Down
Loading
Loading