This commit is contained in:
parent
75a94c421b
commit
0a203fa475
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue