This commit is contained in:
MarkLo 2025-11-20 22:36:58 +08:00
parent 75a94c421b
commit 0a203fa475
5 changed files with 175 additions and 78 deletions

View File

@ -47,40 +47,26 @@ async def run_analysis(
service: TradingService = Depends(get_trading_service),
):
"""
Run trading analysis for a given ticker and date
Run a comprehensive trading analysis for a given ticker and date.
This endpoint initiates a comprehensive trading analysis using the TradingAgents
multi-agent system. The analysis includes:
- Market technical analysis
- Sentiment analysis
- News analysis
- Fundamental analysis
- Research team debate
- Trading decision
- Risk assessment
- Portfolio management decision
The process may take several minutes depending on the research depth.
Requires OpenAI API key to be provided in the request.
"""
logger.info(f"Received analysis request for {request.ticker} on {request.analysis_date}")
try:
# Run analysis
result = await service.run_analysis(
ticker=request.ticker,
analysis_date=request.analysis_date,
analysts=request.analysts,
research_depth=request.research_depth,
deep_think_llm=request.deep_think_llm,
quick_think_llm=request.quick_think_llm,
)
# Return response
return AnalysisResponse(**result)
except Exception as e:
logger.error(f"Analysis failed: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
# Run analysis with all provided parameters including API keys
result = await trading_service.run_analysis(
ticker=request.ticker,
analysis_date=request.analysis_date,
openai_api_key=request.openai_api_key,
openai_base_url=request.openai_base_url,
alpha_vantage_api_key=request.alpha_vantage_api_key,
analysts=request.analysts,
research_depth=request.research_depth,
deep_think_llm=request.deep_think_llm,
quick_think_llm=request.quick_think_llm,
)
return result
@router.get("/tickers")

View File

@ -17,6 +17,17 @@ class AnalysisRequest(BaseModel):
research_depth: Optional[int] = Field(default=1, ge=1, le=5, description="Research depth (1-5)")
deep_think_llm: Optional[str] = Field(default="gpt-4o-mini", description="Deep thinking LLM model")
quick_think_llm: Optional[str] = Field(default="gpt-4o-mini", description="Quick thinking LLM model")
# API Configuration
openai_api_key: str = Field(..., description="OpenAI API Key (required)", min_length=10)
openai_base_url: Optional[str] = Field(
default="https://api.openai.com/v1",
description="OpenAI API Base URL (optional)"
)
alpha_vantage_api_key: Optional[str] = Field(
None,
description="Alpha Vantage API Key (optional, for enhanced data)"
)
class AnalysisResponse(BaseModel):

View File

@ -42,17 +42,23 @@ class TradingService:
self,
ticker: str,
analysis_date: str,
openai_api_key: str,
openai_base_url: str = "https://api.openai.com/v1",
alpha_vantage_api_key: Optional[str] = None,
analysts: Optional[List[str]] = None,
research_depth: int = 1,
deep_think_llm: str = "gpt-4o-mini",
quick_think_llm: str = "gpt-4o-mini",
) -> Dict[str, Any]:
"""
Run trading analysis for a given ticker and date
Run trading analysis for a given ticker and date with user-provided API keys
Args:
ticker: Stock ticker symbol
analysis_date: Date in YYYY-MM-DD format
openai_api_key: OpenAI API Key (required)
openai_base_url: OpenAI API Base URL (optional)
alpha_vantage_api_key: Alpha Vantage API Key (optional)
analysts: List of analyst types to include
research_depth: Research depth (1-5)
deep_think_llm: Deep thinking LLM model
@ -66,37 +72,64 @@ class TradingService:
if analysts is None:
analysts = ["market", "sentiment", "news", "fundamentals"]
# Create configuration
config = self.create_config(research_depth, deep_think_llm, quick_think_llm)
# Dynamically set environment variables for this request
import os
original_openai_key = os.environ.get("OPENAI_API_KEY")
original_alpha_key = os.environ.get("ALPHA_VANTAGE_API_KEY")
# Initialize TradingAgents graph
logger.info(f"Initializing TradingAgents for {ticker} on {analysis_date}")
graph = TradingAgentsGraph(analysts, config=config, debug=True)
try:
# Set API keys for this request
os.environ["OPENAI_API_KEY"] = openai_api_key
if alpha_vantage_api_key:
os.environ["ALPHA_VANTAGE_API_KEY"] = alpha_vantage_api_key
# Create configuration
logger.info(f"Initializing TradingAgents for {ticker} on {analysis_date}")
config = self.create_config(research_depth, deep_think_llm, quick_think_llm)
# Override with user-provided settings
config["llm_provider"] = "openai"
config["backend_url"] = openai_base_url
# Initialize TradingAgents graph
graph = TradingAgentsGraph(analysts, config=config, debug=True)
# Run analysis
logger.info(f"Running analysis for {ticker}")
final_state, decision = graph.propagate(ticker, analysis_date)
# Run analysis
logger.info(f"Running analysis for {ticker}")
final_state, decision = graph.propagate(ticker, analysis_date)
# Extract reports from final state
reports = {
"market_report": final_state.get("market_report"),
"sentiment_report": final_state.get("sentiment_report"),
"news_report": final_state.get("news_report"),
"fundamentals_report": final_state.get("fundamentals_report"),
"investment_plan": final_state.get("investment_plan"),
"trader_investment_plan": final_state.get("trader_investment_plan"),
"final_trade_decision": final_state.get("final_trade_decision"),
"investment_debate_state": final_state.get("investment_debate_state"),
"risk_debate_state": final_state.get("risk_debate_state"),
}
return {
"status": "success",
"ticker": ticker,
"analysis_date": analysis_date,
"decision": decision,
"reports": reports,
}
# Extract reports from final state
reports = {
"market_report": final_state.get("market_report"),
"sentiment_report": final_state.get("sentiment_report"),
"news_report": final_state.get("news_report"),
"fundamentals_report": final_state.get("fundamentals_report"),
"investment_plan": final_state.get("investment_plan"),
"trader_investment_plan": final_state.get("trader_investment_plan"),
"final_trade_decision": final_state.get("final_trade_decision"),
"investment_debate_state": final_state.get("investment_debate_state"),
"risk_debate_state": final_state.get("risk_debate_state"),
}
return {
"status": "success",
"ticker": ticker,
"analysis_date": analysis_date,
"decision": decision,
"reports": reports,
}
finally:
# Clean up environment variables after request
if original_openai_key is not None:
os.environ["OPENAI_API_KEY"] = original_openai_key
elif "OPENAI_API_KEY" in os.environ:
del os.environ["OPENAI_API_KEY"]
if original_alpha_key is not None:
os.environ["ALPHA_VANTAGE_API_KEY"] = original_alpha_key
elif "ALPHA_VANTAGE_API_KEY" in os.environ:
del os.environ["ALPHA_VANTAGE_API_KEY"]
except Exception as e:
logger.error(f"Analysis failed for {ticker}: {str(e)}", exc_info=True)
@ -111,23 +144,17 @@ class TradingService:
"""Get list of available analyst types"""
return ["market", "sentiment", "news", "fundamentals"]
def get_available_llms(self) -> Dict[str, List[str]]:
"""Get list of available LLM models by provider"""
return {
"openai": [
"gpt-4o",
"gpt-4o-mini",
"gpt-4-turbo",
"gpt-4",
"gpt-3.5-turbo",
],
"anthropic": [
"claude-3-5-sonnet-20241022",
"claude-3-opus-20240229",
"claude-3-sonnet-20240229",
"claude-3-haiku-20240307",
],
}
def get_available_llms(self) -> List[str]:
"""Get list of available OpenAI LLM models"""
return [
"gpt-5.1-2025-11-13",
"gpt-5-mini-2025-08-07",
"gpt-5-nano-2025-08-07",
"gpt-4.1-mini",
"gpt-4.1-nano",
"gpt-4o",
"gpt-4o-mini",
]
def get_default_config(self) -> Dict[str, Any]:
"""Get default configuration"""

View File

@ -36,6 +36,11 @@ const formSchema = z.object({
research_depth: z.number().min(1).max(5),
deep_think_llm: z.string(),
quick_think_llm: z.string(),
// API Configuration
openai_api_key: z.string().min(20, "請輸入有效的 OpenAI API Key"),
openai_base_url: z.string().url("請輸入有效的 URL").optional().or(z.literal("")),
alpha_vantage_api_key: z.string().optional().or(z.literal("")),
});
interface AnalysisFormProps {
@ -52,6 +57,9 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
research_depth: 1,
deep_think_llm: "gpt-4o-mini",
quick_think_llm: "gpt-4o-mini",
openai_api_key: "",
openai_base_url: "https://api.openai.com/v1",
alpha_vantage_api_key: "",
},
});
@ -153,9 +161,13 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="gpt-5.1-2025-11-13">GPT-5.1</SelectItem>
<SelectItem value="gpt-5-mini-2025-08-07">GPT-5 Mini</SelectItem>
<SelectItem value="gpt-5-nano-2025-08-07">GPT-5 Nano</SelectItem>
<SelectItem value="gpt-4.1-mini">GPT-4.1 Mini</SelectItem>
<SelectItem value="gpt-4.1-nano">GPT-4.1 Nano</SelectItem>
<SelectItem value="gpt-4o">GPT-4o</SelectItem>
<SelectItem value="gpt-4o-mini">GPT-4o Mini</SelectItem>
<SelectItem value="gpt-4-turbo">GPT-4 Turbo</SelectItem>
</SelectContent>
</Select>
<FormDescription>
@ -167,6 +179,62 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
/>
</div>
{/* API Configuration Section */}
<div className="space-y-4 border-t pt-6 mt-6">
<h3 className="text-lg font-semibold">API </h3>
<FormField
control={form.control}
name="openai_api_key"
render={({ field }) => (
<FormItem>
<FormLabel>OpenAI API Key</FormLabel>
<FormControl>
<Input type="password" placeholder="sk-..." {...field} />
</FormControl>
<FormDescription>
OpenAI API Key LLM
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="openai_base_url"
render={({ field }) => (
<FormItem>
<FormLabel>OpenAI Base URL</FormLabel>
<FormControl>
<Input placeholder="https://api.openai.com/v1" {...field} />
</FormControl>
<FormDescription>
API OpenAI
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="alpha_vantage_api_key"
render={({ field }) => (
<FormItem>
<FormLabel>Alpha Vantage API Key</FormLabel>
<FormControl>
<Input type="password" placeholder="選填,用於更詳細的數據" {...field} />
</FormControl>
<FormDescription>
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>
<Button type="submit" className="w-full" disabled={loading} size="lg">
{loading ? "執行分析中..." : "執行分析"}
</Button>

View File

@ -9,6 +9,11 @@ export interface AnalysisRequest {
research_depth?: number;
deep_think_llm?: string;
quick_think_llm?: string;
// API Configuration
openai_api_key: string;
openai_base_url?: string;
alpha_vantage_api_key?: string;
}
export interface AnalysisResponse {