feat: provide investment preferences

This commit is contained in:
Tomortec 2025-07-02 09:19:52 +08:00
parent 691f2835e1
commit 038b348b17
14 changed files with 119 additions and 21 deletions

View File

@ -0,0 +1,5 @@
- 交易资产:期货,可多空
- 投资风格:激进
- 交易周期短期1 天到 3 天
- 杠杆:最小 25x最大 100x
- 最大能接受的损失50%

View File

@ -467,20 +467,28 @@ def get_user_selections():
)
external_reports = get_external_reports()
# Step 6: OpenAI backend
# Step 6: Investment preferences
console.print(
create_question_box(
get_lang("step6_title"), get_lang("step6_prompt")
)
)
selected_llm_provider, backend_url = select_llm_provider()
# Step 7: Thinking agents
investment_preferences = get_investment_preferences()
# Step 7: OpenAI backend
console.print(
create_question_box(
get_lang("step7_title"), get_lang("step7_prompt")
)
)
selected_llm_provider, backend_url = select_llm_provider()
# Step 8: Thinking agents
console.print(
create_question_box(
get_lang("step8_title"), get_lang("step8_prompt")
)
)
selected_shallow_thinker = select_shallow_thinking_agent(selected_llm_provider)
selected_deep_thinker = select_deep_thinking_agent(selected_llm_provider)
@ -489,6 +497,7 @@ def get_user_selections():
"analysis_date": analysis_date,
"analysts": selected_analysts,
"research_depth": selected_research_depth,
"investment_preferences": investment_preferences,
"llm_provider": selected_llm_provider.lower(),
"backend_url": backend_url,
"external_reports": external_reports,
@ -520,6 +529,30 @@ def get_analysis_date():
"[red]Error: Invalid date format. Please use YYYY-MM-DD[/red]"
)
def get_investment_preferences():
need_preferences = typer.confirm(
get_lang("step6_prompt"), default=True
)
if need_preferences:
# check if `investment_preferences` file exists
try:
with open("./cli/investment_preferences", "r") as f:
preferences = f.read()
if preferences:
use_saved = typer.confirm(
get_lang("step6_pref_found_prompt"), default=True
)
if use_saved:
return preferences
else:
preferences = typer.edit(require_save=False)
return preferences if preferences else ""
except FileNotFoundError:
console.print("[yellow]No file named 'investment_preferences' found.[/yellow]")
preferences = typer.edit(require_save=False)
return preferences if preferences else ""
return ""
def get_external_reports():
"""Get external reports from user input."""
need_external = typer.confirm(
@ -779,6 +812,10 @@ def run_analysis():
"System",
f"Selected analysts: {', '.join(analyst.value for analyst in selections['analysts'])}",
)
message_buffer.add_message(
"User",
f"User preferences: {selections['investment_preferences'] if selections['investment_preferences'] else 'None'}",
)
message_buffer.add_message(
"User",
f"External reports: {'<END>\n'.join(selections['external_reports']) if selections['external_reports'] else 'None'}",
@ -808,7 +845,9 @@ def run_analysis():
# Initialize state and get graph args
init_agent_state = graph.propagator.create_initial_state(
selections["ticker"], selections["analysis_date"], selections["external_reports"]
selections["ticker"], selections["analysis_date"],
selections["investment_preferences"],
selections["external_reports"]
)
args = graph.propagator.get_graph_args()

View File

@ -10,6 +10,7 @@ def create_market_analyst(llm, toolkit):
current_date = state["trade_date"]
ticker = state["asset_of_interest"]
asset_name = state["asset_of_interest"]
investment_preferences = state.get("investment_preferences", "")
tools = [
toolkit.get_binance_data,
@ -27,6 +28,11 @@ def create_market_analyst(llm, toolkit):
"system",
get_prompts("analysts", "template")
),
(
"system",
get_prompts("user_preferences", "system_message")
.replace("{investment_preferences}", investment_preferences)
),
MessagesPlaceholder(variable_name="messages"),
]
)

View File

@ -10,6 +10,7 @@ def create_research_manager(llm, memory):
sentiment_report = state["sentiment_report"]
news_report = state["news_report"]
fundamentals_report = state["fundamentals_report"]
investment_preferences = state.get("investment_preferences", "")
external_reports = state.get("external_reports", [])
investment_debate_state = state["investment_debate_state"]
@ -25,8 +26,10 @@ def create_research_manager(llm, memory):
.replace("{max_tokens}", str(DEFAULT_CONFIG["max_tokens"])) \
.replace("{past_memory_str}", past_memory_str) \
.replace("{history}", history) \
.replace("{external_reports}", "\n".join(external_reports))
.replace("{external_reports}", "\n".join(external_reports)) \
+ "\n\n" \
+ get_prompts("investment_preferences", "system_message") \
.replace("{investment_preferences}", investment_preferences)
response = llm.invoke(prompt)
new_investment_debate_state = {

View File

@ -14,6 +14,7 @@ def create_risk_manager(llm, memory):
news_report = state["news_report"]
fundamentals_report = state["news_report"]
sentiment_report = state["sentiment_report"]
investment_preferences = state.get("investment_preferences", "")
external_reports = state.get("external_reports", [])
trader_plan = state["investment_plan"]
@ -29,7 +30,10 @@ def create_risk_manager(llm, memory):
.replace("{trader_plan}", trader_plan) \
.replace("{past_memory_str}", past_memory_str) \
.replace("{history}", history) \
.replace("{external_reports}", "\n".join(external_reports))
.replace("{external_reports}", "\n".join(external_reports)) \
+ "\n\n" \
+ get_prompts("investment_preferences", "system_message") \
.replace("{investment_preferences}", investment_preferences)
response = llm.invoke(prompt)

View File

@ -15,6 +15,7 @@ def create_bear_researcher(llm, memory):
sentiment_report = state["sentiment_report"]
news_report = state["news_report"]
fundamentals_report = state["fundamentals_report"]
investment_preferences = state.get("investment_preferences", "")
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
past_memories = memory.get_memories(curr_situation, n_matches=2)
@ -31,7 +32,10 @@ def create_bear_researcher(llm, memory):
.replace("{fundamentals_report}", fundamentals_report) \
.replace("{history}", history) \
.replace("{current_response}", current_response) \
.replace("{past_memory_str}", past_memory_str)
.replace("{past_memory_str}", past_memory_str) \
+ "\n\n" \
+ get_prompts("investment_preferences", "system_message") \
.replace("{investment_preferences}", investment_preferences)
response = llm.invoke(prompt)

View File

@ -15,6 +15,7 @@ def create_bull_researcher(llm, memory):
sentiment_report = state["sentiment_report"]
news_report = state["news_report"]
fundamentals_report = state["fundamentals_report"]
investment_preferences = state.get("investment_preferences", "")
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
past_memories = memory.get_memories(curr_situation, n_matches=2)
@ -31,8 +32,11 @@ def create_bull_researcher(llm, memory):
.replace("{fundamentals_report}", fundamentals_report) \
.replace("{history}", history) \
.replace("{current_response}", current_response) \
.replace("{past_memory_str}", past_memory_str)
.replace("{past_memory_str}", past_memory_str) \
+ "\n\n" \
+ get_prompts("investment_preferences", "system_message") \
.replace("{investment_preferences}", investment_preferences)
response = llm.invoke(prompt)
argument = f"Bull Analyst: {response.content}"

View File

@ -50,6 +50,7 @@ class RiskDebateState(TypedDict):
class AgentState(MessagesState):
asset_of_interest: Annotated[str, "Asset that we are interested in trading"]
trade_date: Annotated[str, "What date we are trading at"]
investment_preferences: Annotated[str, "User's investment preferences"]
sender: Annotated[str, "Agent that sent this message"]

View File

@ -18,7 +18,7 @@ DEFAULT_CONFIG = {
"quick_think_llm": "qwen-turbo",
"backend_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"api_key_env_name": "DASHSCOPE_API_KEY",
"max_tokens": 2000, # Maximum tokens for LLM responses
"max_tokens": 4096, # Maximum tokens for LLM responses
# Debate and discussion settings
"max_debate_rounds": 1,
"max_risk_discuss_rounds": 1,

View File

@ -16,13 +16,16 @@ class Propagator:
self.max_recur_limit = max_recur_limit
def create_initial_state(
self, asset_name: str, trade_date: str, external_reports: list[str] = []
self, asset_name: str, trade_date: str,
investment_preferences: str = "",
external_reports: list[str] = []
) -> Dict[str, Any]:
"""Create the initial state for the agent graph."""
return {
"messages": [("human", asset_name)],
"asset_of_interest": asset_name,
"trade_date": str(trade_date),
"investment_preferences": str(investment_preferences),
"investment_debate_state": InvestDebateState(
{"history": "", "current_response": "", "count": 0}
),

View File

@ -53,10 +53,13 @@ LANG = {
"step4_prompt": "Select your research depth level",
"step5_title": "Step 5: External Reports",
"step5_prompt": "Do you need to import external reports?",
"step6_title": "Step 6: Thinking Agents",
"step6_prompt": "Select your thinking agents for analysis",
"step6_title": "Step 6: Investment Preferences",
"step6_prompt": "Do you need to import investment preferences?",
"step6_pref_found_prompt": "Do you want to use the saved investment preferences:",
"step7_title": "Step 7: Thinking Agents",
"step7_prompt": "Select your thinking agents for analysis",
"step8_title": "Step 8: Thinking Agents",
"step8_prompt": "Select your thinking agents for analysis",
"default_ticker": "SPY",
"ticker_validate": "Please enter a valid ticker symbol.",
"date_validate": "Please enter a valid date in YYYY-MM-DD format.",

View File

@ -53,10 +53,13 @@ LANG = {
"step4_prompt": "请选择研究深度等级",
"step5_title": "步骤5外部报告",
"step5_prompt": "需要导入外部报告吗?",
"step6_title": "步骤6思考代理",
"step6_prompt": "请选择用于分析的思考代理",
"step6_title": "步骤6投资偏好",
"step6_prompt": "需要导入投资偏好吗?",
"step6_pref_found_prompt": "是否使用已保存的投资偏好:",
"step7_title": "步骤7思考代理",
"step7_prompt": "请选择用于分析的思考代理",
"step7_prompt": "请选择用于简单分析的思考代理",
"step8_title": "步骤8思考代理",
"step8_prompt": "请选择用于深度分析的思考代理",
"default_ticker": "SPY",
"ticker_validate": "请输入有效的资产代码。",
"date_validate": "请输入有效的日期格式为YYYY-MM-DD。",

View File

@ -56,6 +56,7 @@ The returned indicators include:
* `3blackcrows`: Three Black Crows, a bearish reversal pattern, suitable for exiting at the top of an uptrend.
Write a very detailed and nuanced report of the trends you observe. Do not simply state the trends are mixed, provide detailed and finegrained analysis and insights that may help traders make decisions. The report should not exceed {max_tokens}tokens.""" +
" Additionally, based on the user's investment preferences and the technical indicators, provide a **suggested entry price, support level, resistance level, take profit price, and stop loss price**." +
" Make sure to append a Markdown table at the end of the report to organize key points in the report, organized and easy to read."
)
},
@ -91,6 +92,7 @@ Your Recommendation: A decisive stance supported by the most convincing argument
Rationale: An explanation of why these arguments lead to your conclusion.
Strategic Actions: Concrete steps for implementing the recommendation.
Take into account your past mistakes on similar situations. Use these insights to refine your decision-making and ensure you are learning and improving. Present your analysis conversationally, as if speaking naturally, without special formatting.
In addition, please provide **suggested entry price, support level, resistance level, take-profit price, and stop-loss price** based on the user's investment preferences and the analysts' reports.
**Analysis from External Experts:**
{external_reports}
@ -115,6 +117,7 @@ Guidelines for Decision-Making:
Deliverables:
- A clear and actionable recommendation: Buy, Sell, or Hold.
- Detailed reasoning anchored in the debate and past reflections.
- Provide **suggested entry price, support level, resistance level, take-profit price, and stop-loss price** based on the user's investment preferences and the analysts' reports.
**Analysis from External Experts:**
{external_reports}
@ -136,6 +139,7 @@ Key points to focus on:
- Negative Indicators: Use evidence from financial data, market trends, or recent adverse news to support your position.
- Bull Counterpoints: Critically analyze the bull argument with specific data and sound reasoning, exposing weaknesses or over-optimistic assumptions.
- Engagement: Present your argument in a conversational style, directly engaging with the bull analyst's points and debating effectively rather than simply listing facts.
- Based on the user's investment preferences and the analysts' reports, provide **suggested entry price, support level, resistance level, take-profit price, and stop-loss price**.
Resources available:
@ -158,6 +162,7 @@ Key points to focus on:
- Positive Indicators: Use financial health, industry trends, and recent positive news as evidence.
- Bear Counterpoints: Critically analyze the bear argument with specific data and sound reasoning, addressing concerns thoroughly and showing why the bull perspective holds stronger merit.
- Engagement: Present your argument in a conversational style, engaging directly with the bear analyst's points and debating effectively rather than just listing data.
- Based on the user's investment preferences and the analysts' reports, provide **suggested entry price, support level, resistance level, take-profit price, and stop-loss price**.
Resources available:
Market research report: {market_research_report}
@ -221,7 +226,11 @@ Engage actively by analyzing both sides critically, addressing weaknesses in the
},
"trader": {
#region Trader
"user_message": "Based on a comprehensive analysis by a team of analysts, here is an investment plan tailored for {asset_name}. This plan incorporates insights from current technical market trends, macroeconomic indicators, and social media sentiment. Use this plan as a foundation for evaluating your next trading decision.\n\nProposed Investment Plan: {investment_plan}\n\nReports from External Experts: {external_reports}\n\nLeverage these insights to make an informed and strategic decision.",
"user_message": "Based on a comprehensive analysis by a team of analysts, here is an investment plan tailored for {asset_name}. This plan incorporates insights from current technical market trends, macroeconomic indicators, and social media sentiment. Use this plan as a foundation for evaluating your next trading decision.\n\n"
"Proposed Investment Plan: {investment_plan}\n\n"
"Reports from External Experts: {external_reports}\n\n"
"Please provide **suggested entry price, support level, resistance level, take-profit price, and stop-loss price** based on the user's investment preferences and the analysts' reports.\n\n"
"Leverage these insights to make an informed and strategic decision.",
"system_message": "You are a trading agent analyzing market data to make investment decisions. Based on your analysis, provide a specific recommendation to buy, sell, or hold. End with a firm decision and always conclude your response with 'FINAL TRANSACTION PROPOSAL: **BUY/HOLD/SELL**' to confirm your recommendation. Do not forget to utilize lessons from past decisions to learn from your mistakes. Here is some reflections from similar situatiosn you traded in and the lessons learned: {past_memory_str}"
#endregion
},
@ -263,5 +272,8 @@ Adhere strictly to these instructions, and ensure your output is detailed, accur
},
"signal_processor": {
"system_message": "You are an efficient assistant designed to analyze paragraphs or financial reports provided by a group of analysts. Your task is to extract the investment decision: SELL, BUY, or HOLD. Provide only the extracted decision (SELL, BUY, or HOLD) as your output, without adding any additional text or information."
},
"investment_preferences": {
"system_message": "The user's investment preferences are: \n{investment_preferences}.\nPlease tailor your analysis and recommendations accordingly."
}
}

View File

@ -21,7 +21,7 @@ PROMPTS = {
"system_message": (
"""你是一名交易助理,负责分析金融市场走势。请调用 get_binance_data 以获取资产的 K 线、深度、24 小时价格变化、多空比等数据,为了获取中短期的数据,传入 interval 参数时请保证其范围为5m至1d之间此外必须分析15m和1h的趋势。
你还必须调用 get_taapi_bulk_indicators 以获取并分析趋势动量指标波动率结构指标等传入 interval 参数时请保证其范围为5m至1d之间注意**get_taapi_bulk_indicators 工具只能调用一次**
返回的指标包括
工具指标包括
趋势类指标
- ema: 指数加权均线判断中短期趋势反应快但易被震荡干扰
@ -52,6 +52,7 @@ PROMPTS = {
- 3blackcrows: 三黑鸦空头反转形态适合高位反转波段出场
写一份详细但不超过 {max_tokens}tokens 的报告说明你观察到的趋势不要简单地说趋势是混合的提供详细和细粒度的分析和见解以帮助交易者做出决策""" +
" 此外,请根据用户的投资偏好和各项技术指标,给出**建议开仓价格、支撑位、阻力位、止盈价和止损价**。" +
" 最后请附上一张 Markdown 表格,总结并清晰地整理报告中的关键要点,便于阅读和参考。"
)
},
@ -83,6 +84,7 @@ PROMPTS = {
投资建议Buy / Sell / Hold三选一必须明确避免默认中立
推荐理由说明为何你支持该立场引用论据
策略行动基于建议提出具体的执行计划
此外请根据用户的投资偏好和分析师的报告给出**建议开仓价格支撑位阻力位止盈价和止损价**
考虑你过去在类似情况下的错误利用这些见解来完善你的决策并确保你正在学习和改进以对话的方式呈现你的分析就像自然地说话一样无需特殊的格式
@ -108,6 +110,7 @@ PROMPTS = {
输出要求
- 明确的投资建议Buy / Sell / Hold
- 基于辩论与反思的详细理由
- 根据用户的投资偏好和分析师的报告给出**建议开仓价格支撑位阻力位止盈价和止损价**
- 务必不超过{max_tokens}tokens
必须认真考虑外部分析师报告:
@ -126,6 +129,7 @@ PROMPTS = {
- 消极信号引用财务数据市场趋势或不利新闻
- 批驳多头观点针对其论据进行具体的数据反驳揭示其乐观假设的问题
- 交互性表达使用对话风格回应多头观点避免只是罗列事实
- 根据用户的投资偏好和分析师的报告给出**建议开仓价格支撑位阻力位止盈价和止损价**
你可以参考以下资源进行论证
Market research report: {market_research_report}
@ -147,6 +151,7 @@ Reflections from similar situations and lessons learned: {past_memory_str}
- 积极信号引用财务健康行业趋势利好新闻
- 批驳空头观点针对其忧虑进行数据支持的澄清与反驳
- 交互性表达以对话形式回应空头论点提升说服力
- 根据用户的投资偏好和分析师的报告给出**建议开仓价格支撑位阻力位止盈价和止损价**
你可以参考以下资源进行论证
Market research report: {market_research_report}
@ -205,7 +210,10 @@ Here is the current conversation history: {history} Here is the last response fr
},
"trader": {
#region Trader
"user_message": "以下是针对 {asset_name} 的投资建议方案,由多个分析师协作提供,涵盖了技术趋势、宏观指标与社交舆情。请将此方案作为下一步交易决策的参考依据:\n\n建议方案:{investment_plan}\n\n外部专家分析:{external_reports}\n\n请基于此作出合理而有策略的判断。",
"user_message": """以下是针对 {asset_name} 的投资建议方案,由多个分析师协作提供,涵盖了技术趋势、宏观指标与社交舆情。请将此方案作为下一步交易决策的参考依据:
建议方案{investment_plan}\n
外部专家分析{external_reports}\n
请基于此作出合理而有策略的判断并根据用户的投资偏好和分析师的报告给出**建议开仓价格支撑位阻力位止盈价和止损价**""",
"system_message": "你是一名交易代理,负责根据市场数据做出买入、卖出或持有的明确投资决策。分析结束后,请以 “最终投资建议BUY/HOLD/SELL” 结尾,明确表达立场。请结合历史经验做出更优判断。以下为你在类似情况中总结的教训:{past_memory_str}"
#endregion
},
@ -233,5 +241,8 @@ Here is the current conversation history: {history} Here is the last response fr
},
"signal_processor": {
"system_message": "你是一个高效的助手旨在分析一组分析师提供的段落或财务报告。你的任务是提取投资决策SELL、BUY或HOLD。仅提供提取的决策SELL/BUI/HOLD作为输出不添加任何其他文本或信息。"
},
"investment_preferences": {
"system_message": "用户的投资偏好为:\n{investment_preferences}\n请根据这些偏好来调整你的分析和建议。"
}
}