This commit is contained in:
parent
75a94c421b
commit
0a203fa475
|
|
@ -47,40 +47,26 @@ async def run_analysis(
|
||||||
service: TradingService = Depends(get_trading_service),
|
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
|
Requires OpenAI API key to be provided in the request.
|
||||||
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.
|
|
||||||
"""
|
"""
|
||||||
logger.info(f"Received analysis request for {request.ticker} on {request.analysis_date}")
|
logger.info(f"Received analysis request for {request.ticker} on {request.analysis_date}")
|
||||||
|
|
||||||
try:
|
# Run analysis with all provided parameters including API keys
|
||||||
# Run analysis
|
result = await trading_service.run_analysis(
|
||||||
result = await service.run_analysis(
|
ticker=request.ticker,
|
||||||
ticker=request.ticker,
|
analysis_date=request.analysis_date,
|
||||||
analysis_date=request.analysis_date,
|
openai_api_key=request.openai_api_key,
|
||||||
analysts=request.analysts,
|
openai_base_url=request.openai_base_url,
|
||||||
research_depth=request.research_depth,
|
alpha_vantage_api_key=request.alpha_vantage_api_key,
|
||||||
deep_think_llm=request.deep_think_llm,
|
analysts=request.analysts,
|
||||||
quick_think_llm=request.quick_think_llm,
|
research_depth=request.research_depth,
|
||||||
)
|
deep_think_llm=request.deep_think_llm,
|
||||||
|
quick_think_llm=request.quick_think_llm,
|
||||||
# Return response
|
)
|
||||||
return AnalysisResponse(**result)
|
|
||||||
|
return 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)}")
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/tickers")
|
@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)")
|
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")
|
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")
|
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):
|
class AnalysisResponse(BaseModel):
|
||||||
|
|
|
||||||
|
|
@ -42,17 +42,23 @@ class TradingService:
|
||||||
self,
|
self,
|
||||||
ticker: str,
|
ticker: str,
|
||||||
analysis_date: 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,
|
analysts: Optional[List[str]] = None,
|
||||||
research_depth: int = 1,
|
research_depth: int = 1,
|
||||||
deep_think_llm: str = "gpt-4o-mini",
|
deep_think_llm: str = "gpt-4o-mini",
|
||||||
quick_think_llm: str = "gpt-4o-mini",
|
quick_think_llm: str = "gpt-4o-mini",
|
||||||
) -> Dict[str, Any]:
|
) -> 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:
|
Args:
|
||||||
ticker: Stock ticker symbol
|
ticker: Stock ticker symbol
|
||||||
analysis_date: Date in YYYY-MM-DD format
|
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
|
analysts: List of analyst types to include
|
||||||
research_depth: Research depth (1-5)
|
research_depth: Research depth (1-5)
|
||||||
deep_think_llm: Deep thinking LLM model
|
deep_think_llm: Deep thinking LLM model
|
||||||
|
|
@ -66,37 +72,64 @@ class TradingService:
|
||||||
if analysts is None:
|
if analysts is None:
|
||||||
analysts = ["market", "sentiment", "news", "fundamentals"]
|
analysts = ["market", "sentiment", "news", "fundamentals"]
|
||||||
|
|
||||||
# Create configuration
|
# Dynamically set environment variables for this request
|
||||||
config = self.create_config(research_depth, deep_think_llm, quick_think_llm)
|
import os
|
||||||
|
original_openai_key = os.environ.get("OPENAI_API_KEY")
|
||||||
|
original_alpha_key = os.environ.get("ALPHA_VANTAGE_API_KEY")
|
||||||
|
|
||||||
# Initialize TradingAgents graph
|
try:
|
||||||
logger.info(f"Initializing TradingAgents for {ticker} on {analysis_date}")
|
# Set API keys for this request
|
||||||
graph = TradingAgentsGraph(analysts, config=config, debug=True)
|
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
|
# Extract reports from final state
|
||||||
logger.info(f"Running analysis for {ticker}")
|
reports = {
|
||||||
final_state, decision = graph.propagate(ticker, analysis_date)
|
"market_report": final_state.get("market_report"),
|
||||||
|
"sentiment_report": final_state.get("sentiment_report"),
|
||||||
# Extract reports from final state
|
"news_report": final_state.get("news_report"),
|
||||||
reports = {
|
"fundamentals_report": final_state.get("fundamentals_report"),
|
||||||
"market_report": final_state.get("market_report"),
|
"investment_plan": final_state.get("investment_plan"),
|
||||||
"sentiment_report": final_state.get("sentiment_report"),
|
"trader_investment_plan": final_state.get("trader_investment_plan"),
|
||||||
"news_report": final_state.get("news_report"),
|
"final_trade_decision": final_state.get("final_trade_decision"),
|
||||||
"fundamentals_report": final_state.get("fundamentals_report"),
|
"investment_debate_state": final_state.get("investment_debate_state"),
|
||||||
"investment_plan": final_state.get("investment_plan"),
|
"risk_debate_state": final_state.get("risk_debate_state"),
|
||||||
"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"),
|
return {
|
||||||
"risk_debate_state": final_state.get("risk_debate_state"),
|
"status": "success",
|
||||||
}
|
"ticker": ticker,
|
||||||
|
"analysis_date": analysis_date,
|
||||||
return {
|
"decision": decision,
|
||||||
"status": "success",
|
"reports": reports,
|
||||||
"ticker": ticker,
|
}
|
||||||
"analysis_date": analysis_date,
|
|
||||||
"decision": decision,
|
finally:
|
||||||
"reports": reports,
|
# 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:
|
except Exception as e:
|
||||||
logger.error(f"Analysis failed for {ticker}: {str(e)}", exc_info=True)
|
logger.error(f"Analysis failed for {ticker}: {str(e)}", exc_info=True)
|
||||||
|
|
@ -111,23 +144,17 @@ class TradingService:
|
||||||
"""Get list of available analyst types"""
|
"""Get list of available analyst types"""
|
||||||
return ["market", "sentiment", "news", "fundamentals"]
|
return ["market", "sentiment", "news", "fundamentals"]
|
||||||
|
|
||||||
def get_available_llms(self) -> Dict[str, List[str]]:
|
def get_available_llms(self) -> List[str]:
|
||||||
"""Get list of available LLM models by provider"""
|
"""Get list of available OpenAI LLM models"""
|
||||||
return {
|
return [
|
||||||
"openai": [
|
"gpt-5.1-2025-11-13",
|
||||||
"gpt-4o",
|
"gpt-5-mini-2025-08-07",
|
||||||
"gpt-4o-mini",
|
"gpt-5-nano-2025-08-07",
|
||||||
"gpt-4-turbo",
|
"gpt-4.1-mini",
|
||||||
"gpt-4",
|
"gpt-4.1-nano",
|
||||||
"gpt-3.5-turbo",
|
"gpt-4o",
|
||||||
],
|
"gpt-4o-mini",
|
||||||
"anthropic": [
|
]
|
||||||
"claude-3-5-sonnet-20241022",
|
|
||||||
"claude-3-opus-20240229",
|
|
||||||
"claude-3-sonnet-20240229",
|
|
||||||
"claude-3-haiku-20240307",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_default_config(self) -> Dict[str, Any]:
|
def get_default_config(self) -> Dict[str, Any]:
|
||||||
"""Get default configuration"""
|
"""Get default configuration"""
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,11 @@ const formSchema = z.object({
|
||||||
research_depth: z.number().min(1).max(5),
|
research_depth: z.number().min(1).max(5),
|
||||||
deep_think_llm: z.string(),
|
deep_think_llm: z.string(),
|
||||||
quick_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 {
|
interface AnalysisFormProps {
|
||||||
|
|
@ -52,6 +57,9 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
|
||||||
research_depth: 1,
|
research_depth: 1,
|
||||||
deep_think_llm: "gpt-4o-mini",
|
deep_think_llm: "gpt-4o-mini",
|
||||||
quick_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>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<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">GPT-4o</SelectItem>
|
||||||
<SelectItem value="gpt-4o-mini">GPT-4o Mini</SelectItem>
|
<SelectItem value="gpt-4o-mini">GPT-4o Mini</SelectItem>
|
||||||
<SelectItem value="gpt-4-turbo">GPT-4 Turbo</SelectItem>
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
|
|
@ -167,6 +179,62 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<Button type="submit" className="w-full" disabled={loading} size="lg">
|
||||||
{loading ? "執行分析中..." : "執行分析"}
|
{loading ? "執行分析中..." : "執行分析"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@ export interface AnalysisRequest {
|
||||||
research_depth?: number;
|
research_depth?: number;
|
||||||
deep_think_llm?: string;
|
deep_think_llm?: string;
|
||||||
quick_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 {
|
export interface AnalysisResponse {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue