feat: add costs per trade into trading decisions

This commit is contained in:
kevin-bruton 2025-09-27 21:31:57 +02:00
parent b3054e73a4
commit 309a105465
13 changed files with 88 additions and 53 deletions

View File

@ -393,6 +393,11 @@ def update_display(layout, spinner_text=None):
layout["footer"].update(Panel(stats_table, border_style="grey50"))
def get_cost_per_trade():
"""Get trading cost from user input."""
return typer.prompt("What is the trading cost per operation?", type=float, default=0.0)
def get_user_position():
"""Get user's current position from user input."""
return typer.prompt("What is your current position on this ticker? (long, short, none)", default="none")
@ -448,21 +453,29 @@ def get_user_selections():
)
selected_position = get_user_position()
# Step 3: Analysis date
# Step 3: Trading cost
console.print(
create_question_box(
"Step 3: Trading Cost", "Enter the trading cost per operation", "0.0"
)
)
selected_cost_per_trade = get_cost_per_trade()
# Step 4: Analysis date
default_date = datetime.datetime.now().strftime("%Y-%m-%d")
console.print(
create_question_box(
"Step 3: Analysis Date",
"Step 4: Analysis Date",
"Enter the analysis date (YYYY-MM-DD)",
default_date,
)
)
analysis_date = get_analysis_date()
# Step 4: Select analysts
# Step 5: Select analysts
console.print(
create_question_box(
"Step 4: Analysts Team", "Select your LLM analyst agents for the analysis"
"Step 5: Analysts Team", "Select your LLM analyst agents for the analysis"
)
)
selected_analysts = select_analysts()
@ -470,26 +483,26 @@ def get_user_selections():
f"[green]Selected analysts:[/green] {', '.join(analyst.value for analyst in selected_analysts)}"
)
# Step 5: Research depth
# Step 6: Research depth
console.print(
create_question_box(
"Step 5: Research Depth", "Select your research depth level"
"Step 6: Research Depth", "Select your research depth level"
)
)
selected_research_depth = select_research_depth()
# Step 6: LLM Provider
# Step 7: LLM Provider
console.print(
create_question_box(
"Step 6: LLM Provider", "Select which service to talk to"
"Step 7: LLM Provider", "Select which service to talk to"
)
)
selected_llm_provider, backend_url = select_llm_provider()
# Step 7: Thinking agents
# Step 8: Thinking agents
console.print(
create_question_box(
"Step 7: Thinking Agents", "Select your thinking agents for analysis"
"Step 8: Thinking Agents", "Select your thinking agents for analysis"
)
)
selected_shallow_thinker = select_shallow_thinking_agent(selected_llm_provider)
@ -498,6 +511,7 @@ def get_user_selections():
return {
"ticker": selected_ticker,
"user_position": selected_position,
"cost_per_trade": selected_cost_per_trade,
"analysis_date": analysis_date,
"analysts": selected_analysts,
"research_depth": selected_research_depth,
@ -538,7 +552,8 @@ def display_complete_report(final_state):
# User Position
user_position = final_state.get("user_position", "none")
console.print(Panel(f"User's current position: [bold]{user_position}[/bold]", title="User Position", border_style="yellow", padding=(1, 2)))
cost_per_trade = final_state.get("cost_per_trade", 0.0)
console.print(Panel(f"User's current position: [bold]{user_position}[/bold]\nTrading cost per operation: [bold]{cost_per_trade}[/bold]", title="User Information", border_style="yellow", padding=(1, 2)))
# I. Analyst Team Reports
analyst_reports = []
@ -764,6 +779,7 @@ def run_analysis():
config["backend_url"] = selections["backend_url"]
config["llm_provider"] = selections["llm_provider"].lower()
config["user_position"] = selections["user_position"]
config["cost_per_trade"] = selections["cost_per_trade"]
# Initialize the graph
graph = TradingAgentsGraph(
@ -858,7 +874,7 @@ def run_analysis():
# Initialize state and get graph args
init_agent_state = graph.propagator.create_initial_state(
selections["ticker"], selections["analysis_date"], selections["user_position"]
selections["ticker"], selections["analysis_date"], selections["user_position"], selections["cost_per_trade"]
)
args = graph.propagator.get_graph_args()

View File

@ -20,18 +20,20 @@ def create_research_manager(llm, memory):
past_memory_str += rec["recommendation"] + "\n\n"
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""As the portfolio manager and debate facilitator, your role is to critically evaluate this round of debate and make a definitive decision. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""As the portfolio manager and debate facilitator, your role is to critically evaluate this round of debate and make a definitive decision. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
Summarize the key points from both sides concisely, focusing on the most compelling evidence or reasoning. Your recommendation must be clear and actionable. Avoid defaulting to a neutral stance simply because both sides have valid points; commit to a stance grounded in the debate's strongest arguments.
Summarize the key points from both sides concisely, focusing on the most compelling evidence or reasoning. Your recommendation must be clear and actionable. Avoid defaulting to a neutral stance simply because both sides have valid points; commit to a stance grounded in the debate's strongest arguments. Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Additionally, develop a detailed investment plan for the trader. This should include:
Your Recommendation: A decisive stance supported by the most convincing arguments, tailored to the user's position of '{user_position}'.
Your Recommendation: A decisive stance supported by the most convincing arguments, tailored to the user's position of '{user_position}' and the trading cost of {cost_per_trade}.
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.

View File

@ -23,14 +23,16 @@ def create_risk_manager(llm, memory):
past_memory_str += rec["recommendation"] + "\n\n"
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""As the Risk Management Judge and Debate Facilitator, your goal is to evaluate the debate between three risk analysts—Risky, Neutral, and Safe/Conservative—and determine the best course of action for the trader. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""As the Risk Management Judge and Debate Facilitator, your goal is to evaluate the debate between three risk analysts—Risky, Neutral, and Safe/Conservative—and determine the best course of action for the trader. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
Your decision must result in a clear recommendation. Choose a neutral stance only if strongly justified by specific arguments, not as a fallback when all sides seem valid. Strive for clarity and decisiveness.
Your decision must result in a clear recommendation. Choose a neutral stance only if strongly justified by specific arguments, not as a fallback when all sides seem valid. Strive for clarity and decisiveness. Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Guidelines for Decision-Making:
1. **Summarize Key Arguments**: Extract the strongest points from each analyst, focusing on relevance to the context.

View File

@ -23,14 +23,16 @@ def create_bear_researcher(llm, memory):
past_memory_str += rec["recommendation"] + "\n\n"
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""You are a Bear Analyst making the case against investing in the stock. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""You are a Bear Analyst making the case against investing in the stock. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
Your goal is to present a well-reasoned argument emphasizing risks, challenges, and negative indicators. Leverage the provided research and data to highlight potential downsides and counter bullish arguments effectively.
Your goal is to present a well-reasoned argument emphasizing risks, challenges, and negative indicators. Leverage the provided research and data to highlight potential downsides and counter bullish arguments effectively. Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Key points to focus on:

View File

@ -23,14 +23,16 @@ def create_bull_researcher(llm, memory):
past_memory_str += rec["recommendation"] + "\n\n"
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""You are a Bull Analyst advocating for investing in the stock. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""You are a Bull Analyst advocating for investing in the stock. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
Your task is to build a strong, evidence-based case emphasizing growth potential, competitive advantages, and positive market indicators. Leverage the provided research and data to address concerns and counter bearish arguments effectively.
Your task is to build a strong, evidence-based case emphasizing growth potential, competitive advantages, and positive market indicators. Leverage the provided research and data to address concerns and counter bearish arguments effectively. Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Key points to focus on:
- Growth Potential: Highlight the company's market opportunities, revenue projections, and scalability.

View File

@ -19,18 +19,20 @@ def create_risky_debator(llm):
trader_decision = state["trader_investment_plan"]
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""As the Risky Risk Analyst, your role is to actively champion high-reward, high-risk opportunities, emphasizing bold strategies and competitive advantages. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""As the Risky Risk Analyst, your role is to actively champion high-reward, high-risk opportunities, emphasizing bold strategies and competitive advantages. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
When evaluating the trader's decision or plan, focus intently on the potential upside, growth potential, and innovative benefits—even when these come with elevated risk. Use the provided market data and sentiment analysis to strengthen your arguments and challenge the opposing views. Specifically, respond directly to each point made by the conservative and neutral analysts, countering with data-driven rebuttals and persuasive reasoning. Highlight where their caution might miss critical opportunities or where their assumptions may be overly conservative. Here is the trader's decision:
{trader_decision}
Your task is to create a compelling case for the trader's decision by questioning and critiquing the conservative and neutral stances to demonstrate why your high-reward perspective offers the best path forward. Incorporate insights from the following sources into your arguments:
Your task is to create a compelling case for the trader's decision by questioning and critiquing the conservative and neutral stances to demonstrate why your high-reward perspective offers the best path forward. Incorporate insights from the following sources into your arguments: Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Market Research Report: {market_research_report}
Social Media Sentiment Report: {sentiment_report}

View File

@ -20,18 +20,20 @@ def create_safe_debator(llm):
trader_decision = state["trader_investment_plan"]
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""As the Safe/Conservative Risk Analyst, your primary objective is to protect assets, minimize volatility, and ensure steady, reliable growth. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""As the Safe/Conservative Risk Analyst, your primary objective is to protect assets, minimize volatility, and ensure steady, reliable growth. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
You prioritize stability, security, and risk mitigation, carefully assessing potential losses, economic downturns, and market volatility. When evaluating the trader's decision or plan, critically examine high-risk elements, pointing out where the decision may expose the firm to undue risk and where more cautious alternatives could secure long-term gains. Here is the trader's decision:
{trader_decision}
Your task is to actively counter the arguments of the Risky and Neutral Analysts, highlighting where their views may overlook potential threats or fail to prioritize sustainability. Respond directly to their points, drawing from the following data sources to build a convincing case for a low-risk approach adjustment to the trader's decision:
Your task is to actively counter the arguments of the Risky and Neutral Analysts, highlighting where their views may overlook potential threats or fail to prioritize sustainability. Respond directly to their points, drawing from the following data sources to build a convincing case for a low-risk approach adjustment to the trader's decision: Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Market Research Report: {market_research_report}
Social Media Sentiment Report: {sentiment_report}

View File

@ -19,18 +19,20 @@ def create_neutral_debator(llm):
trader_decision = state["trader_investment_plan"]
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
prompt = f"""As the Neutral Risk Analyst, your role is to provide a balanced perspective, weighing both the potential benefits and risks of the trader's decision or plan. Your recommendation will depend on the user's current position on the ticker.
prompt = f"""As the Neutral Risk Analyst, your role is to provide a balanced perspective, weighing both the potential benefits and risks of the trader's decision or plan. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
You prioritize a well-rounded approach, evaluating the upsides and downsides while factoring in broader market trends, potential economic shifts, and diversification strategies.Here is the trader's decision:
{trader_decision}
Your task is to challenge both the Risky and Safe Analysts, pointing out where each perspective may be overly optimistic or overly cautious. Use insights from the following data sources to support a moderate, sustainable strategy to adjust the trader's decision:
Your task is to challenge both the Risky and Safe Analysts, pointing out where each perspective may be overly optimistic or overly cautious. Use insights from the following data sources to support a moderate, sustainable strategy to adjust the trader's decision: Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost.
Market Research Report: {market_research_report}
Social Media Sentiment Report: {sentiment_report}

View File

@ -23,6 +23,7 @@ def create_trader(llm, memory):
past_memory_str = "No past memories found."
user_position = state.get("user_position", "none")
cost_per_trade = state.get("cost_per_trade", 0.0)
context = {
"role": "user",
@ -32,13 +33,14 @@ def create_trader(llm, memory):
messages = [
{
"role": "system",
"content": f"""You are a trading agent analyzing market data to make investment decisions. Your recommendation will depend on the user's current position on the ticker.
"content": f"""You are a trading agent analyzing market data to make investment decisions. Your recommendation will depend on the user's current position on the ticker and the trading cost per operation.
- If the user has an open long position (user's position is '{user_position}'), your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position (user's position is '{user_position}'), your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position (user's position is '{user_position}'), your recommendation can be to do nothing, open a long position, or open a short position.
- The user has a current position of '{user_position}' and the cost per trade is {cost_per_trade}.
- If the user has an open long position, your recommendation can be to maintain the long position, close the long position, or close the long position and open a short position.
- If the user has an open short position, your recommendation can be to maintain the short position, close the short position, or close the short position and open a long position.
- If the user has no open position, your recommendation can be to do nothing, open a long position, or open a short position.
Based on your analysis, provide a specific recommendation. End with a firm decision and always conclude your response with 'FINAL TRANSACTION PROPOSAL: **YOUR_RECOMMENDATION**' 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}""",
Based on your analysis, provide a specific recommendation. End with a firm decision and always conclude your response with 'FINAL TRANSACTION PROPOSAL: **YOUR_RECOMMENDATION**' to confirm your recommendation. Take into account that any transaction will incur a cost of {cost_per_trade}, so the potential profit of a transaction must be greater than this cost. 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}""",
},
context,
]

View File

@ -49,6 +49,7 @@ class RiskDebateState(TypedDict):
class AgentState(MessagesState):
user_position: Annotated[str, "User's current position on the ticker. Can be long, short or none"]
cost_per_trade: Annotated[float, "Trading cost per operation"]
company_of_interest: Annotated[str, "Company that we are interested in trading"]
trade_date: Annotated[str, "What date we are trading at"]

View File

@ -25,4 +25,5 @@ DEFAULT_CONFIG = {
# Tool settings
"online_tools": True,
"user_position": "none",
"cost_per_trade": 0.0,
}

View File

@ -16,7 +16,7 @@ class Propagator:
self.max_recur_limit = max_recur_limit
def create_initial_state(
self, company_name: str, trade_date: str, user_position: str = "none"
self, company_name: str, trade_date: str, user_position: str = "none", cost_per_trade: float = 0.0
) -> Dict[str, Any]:
"""Create the initial state for the agent graph."""
return {
@ -24,6 +24,7 @@ class Propagator:
"company_of_interest": company_name,
"trade_date": str(trade_date),
"user_position": user_position,
"cost_per_trade": cost_per_trade,
"investment_debate_state": InvestDebateState(
{"history": "", "current_response": "", "count": 0}
),

View File

@ -182,14 +182,14 @@ class TradingAgentsGraph:
),
}
def propagate(self, company_name, trade_date, user_position="none"):
def propagate(self, company_name, trade_date, user_position="none", cost_per_trade=0.0):
"""Run the trading agents graph for a company on a specific date."""
self.ticker = company_name
# Initialize state
init_agent_state = self.propagator.create_initial_state(
company_name, trade_date, user_position
company_name, trade_date, user_position, cost_per_trade
)
args = self.propagator.get_graph_args()