finalize profile nalyst, add it to cli and all other scripts
This commit is contained in:
parent
f7bee7d1bb
commit
8788cceb5c
4
READ.MD
4
READ.MD
|
|
@ -54,6 +54,10 @@ The system supports multiple data vendors with flexible routing:
|
|||
- Uses sentiment scoring algorithms
|
||||
- Gauges short-term market mood and retail investor sentiment
|
||||
|
||||
- **Profile Analyst** (`nalysts/profile_abalyst.py`):
|
||||
- Analyzez users balance including total equity and free margin
|
||||
- Analyzez users open orders, locked assets, stop losses, and take profits
|
||||
|
||||
##### **Research & Decision Making**
|
||||
- **Bull Researcher** (`researchers/bull_researcher.py`): Argues for positive investment opportunities
|
||||
- **Bear Researcher** (`researchers/bear_researcher.py`): Identifies risks and potential downsides
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ Our framework decomposes complex trading tasks into specialized roles. This ensu
|
|||
- Sentiment Analyst: Analyzes social media and public sentiment using sentiment scoring algorithms to gauge short-term market mood.
|
||||
- News Analyst: Monitors global news and macroeconomic indicators, interpreting the impact of events on market conditions.
|
||||
- Technical Analyst: Utilizes technical indicators (like MACD and RSI) to detect trading patterns and forecast price movements.
|
||||
- Profile Analyst: Analyzes users portfolio, balance, and active open orders.
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/analyst.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
||||
|
|
|
|||
33
cli/main.py
33
cli/main.py
|
|
@ -51,6 +51,7 @@ class MessageBuffer:
|
|||
"Social Analyst": "pending",
|
||||
"News Analyst": "pending",
|
||||
"Fundamentals Analyst": "pending",
|
||||
"Profile Analyst": "pending",
|
||||
# Research Team
|
||||
"Bull Researcher": "pending",
|
||||
"Bear Researcher": "pending",
|
||||
|
|
@ -70,6 +71,7 @@ class MessageBuffer:
|
|||
"sentiment_report": None,
|
||||
"news_report": None,
|
||||
"fundamentals_report": None,
|
||||
"profile_report": None,
|
||||
"investment_plan": None,
|
||||
"trader_investment_plan": None,
|
||||
"final_trade_decision": None,
|
||||
|
|
@ -111,6 +113,7 @@ class MessageBuffer:
|
|||
"sentiment_report": "Social Sentiment",
|
||||
"news_report": "News Analysis",
|
||||
"fundamentals_report": "Fundamentals Analysis",
|
||||
"profile_report": "Profile Analysis",
|
||||
"investment_plan": "Research Team Decision",
|
||||
"trader_investment_plan": "Trading Team Plan",
|
||||
"final_trade_decision": "Portfolio Management Decision",
|
||||
|
|
@ -133,6 +136,7 @@ class MessageBuffer:
|
|||
"sentiment_report",
|
||||
"news_report",
|
||||
"fundamentals_report",
|
||||
"profile_report",
|
||||
]
|
||||
):
|
||||
report_parts.append("## Analyst Team Reports")
|
||||
|
|
@ -152,6 +156,10 @@ class MessageBuffer:
|
|||
report_parts.append(
|
||||
f"### Fundamentals Analysis\n{self.report_sections['fundamentals_report']}"
|
||||
)
|
||||
if self.report_sections["profile_report"]:
|
||||
report_parts.append(
|
||||
f"### Profile Analysis\n{self.report_sections['profile_report']}"
|
||||
)
|
||||
|
||||
# Research Team Reports
|
||||
if self.report_sections["investment_plan"]:
|
||||
|
|
@ -224,6 +232,7 @@ def update_display(layout, spinner_text=None):
|
|||
"Social Analyst",
|
||||
"News Analyst",
|
||||
"Fundamentals Analyst",
|
||||
"Profile Analyst",
|
||||
],
|
||||
"Research Team": ["Bull Researcher", "Bear Researcher", "Research Manager"],
|
||||
"Trading Team": ["Trader"],
|
||||
|
|
@ -571,6 +580,19 @@ def display_complete_report(final_state):
|
|||
)
|
||||
)
|
||||
|
||||
# Profile Analyst Report
|
||||
if final_state.get("profile_report"):
|
||||
analyst_reports.append(
|
||||
Panel(
|
||||
Markdown(final_state["profile_report"]),
|
||||
title="Profile Analyst",
|
||||
border_style="blue",
|
||||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
|
||||
# Display all analyst reports in a single panel
|
||||
|
||||
if analyst_reports:
|
||||
console.print(
|
||||
Panel(
|
||||
|
|
@ -916,6 +938,17 @@ def run_analysis():
|
|||
message_buffer.update_agent_status(
|
||||
"Fundamentals Analyst", "completed"
|
||||
)
|
||||
# Set next analyst to in_progress
|
||||
if "profile" in selections["analysts"]:
|
||||
message_buffer.update_agent_status(
|
||||
"Profile Analyst", "in_progress"
|
||||
)
|
||||
|
||||
if "profile_report" in chunk and chunk["profile_report"]:
|
||||
message_buffer.update_report_section(
|
||||
"profile_report", chunk["profile_report"]
|
||||
)
|
||||
message_buffer.update_agent_status("Profile Analyst", "completed")
|
||||
# Set all research team members to in_progress
|
||||
update_research_team_status("in_progress")
|
||||
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ class AnalystType(str, Enum):
|
|||
SOCIAL = "social"
|
||||
NEWS = "news"
|
||||
FUNDAMENTALS = "fundamentals"
|
||||
PROFILE = "profile"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ ANALYST_ORDER = [
|
|||
("Social Media Analyst", AnalystType.SOCIAL),
|
||||
("News Analyst", AnalystType.NEWS),
|
||||
("Fundamentals Analyst", AnalystType.FUNDAMENTALS),
|
||||
("Profile Analyst", AnalystType.PROFILE),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
737
playground.ipynb
737
playground.ipynb
|
|
@ -2,273 +2,39 @@
|
|||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 1,
|
||||
"id": "ab4c0304",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Crypto data for BTC/USDT from 2025-12-20 to 2025-12-25\n",
|
||||
"# Total records: 7\n",
|
||||
"# Data retrieved on: 2025-12-30 23:12:08 UTC\n",
|
||||
"\n",
|
||||
"Date,Open,High,Low,Close,Volume\n",
|
||||
"2025-12-19,85506.9,89404.6,85104.9,88141.3,9324\n",
|
||||
"2025-12-20,88141.3,88570.1,87797.9,88356,2252\n",
|
||||
"2025-12-21,88356,89085.4,87587.8,88660.8,3438\n",
|
||||
"2025-12-22,88660.8,90599.9,87888.9,88623.8,9026\n",
|
||||
"2025-12-23,88623.8,88949.6,86595,87486.5,7168\n",
|
||||
"2025-12-24,87486.5,88051.1,86412.6,87675,6033\n",
|
||||
"2025-12-25,87675,88598.6,86953.4,87216.7,3872\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.binance import get_market_data\n",
|
||||
"from tradingagents.dataflows.bybit import *\n",
|
||||
"\n",
|
||||
"print(get_market_data('BTC/USDT', '2025-12-20', '2025-12-25'))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a58bb868",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.taapi import get_crypto_stats_indicators_window\n",
|
||||
"print(get_crypto_stats_indicators_window('BTC/USDT', 'macd', '2025-12-20', 3))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "60a3bc38",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.taapi import get_crypto_stats_indicators\n",
|
||||
"print(get_crypto_stats_indicators('BTC/USDT', ['rsi', 'macd'], '2025-12-25', 30))\n",
|
||||
" # 08:42:55 [Tool Call] get_indicators_bulk(symbol=BTCUSDT, indicators=['sma', 'rsi', 'macd', 'bbands', 'atr'], curr_date=2025-12-26, look_back_days=30))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3f341582",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.openai import get_whitepaper_openai\n",
|
||||
"whitepaper = get_whitepaper_openai('BTC/USDT')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6db71e93",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(whitepaper.output[0].content[0].text)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c00b90b8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.openai import get_fundamentals_openai\n",
|
||||
"fundamentals = get_fundamentals_openai('BTC/USDT', '2025-12-25')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "01b03899",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(fundamentals)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "15fd34ce",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Clean test of market_analyst only\n",
|
||||
"print(\"=== CLEAN MARKET ANALYST TEST ===\")\n",
|
||||
"print()\n",
|
||||
"\n",
|
||||
"# Import required modules\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"from langchain_core.messages import HumanMessage\n",
|
||||
"from tradingagents.agents.analysts.market_analyst import create_market_analyst\n",
|
||||
"from datetime import date\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Create LLM client\n",
|
||||
"llm = ChatOpenAI(\n",
|
||||
" model=\"gpt-4o-mini\", \n",
|
||||
" temperature=0.1,\n",
|
||||
" api_key=os.getenv(\"OPENAI_API_KEY\")\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Create market analyst\n",
|
||||
"market_analyst = create_market_analyst(llm)\n",
|
||||
"\n",
|
||||
"# Correct test state with proper message format\n",
|
||||
"test_state = {\n",
|
||||
" \"trade_date\": \"2025-12-25\",\n",
|
||||
" \"ticker_of_interest\": \"BTC/USDT\",\n",
|
||||
" \"messages\": [HumanMessage(content=\"Analyze BTC/USDT market conditions\")]\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"print(f\"Testing market analyst for: {test_state['ticker_of_interest']}\")\n",
|
||||
"print(f\"Date: {test_state['trade_date']}\")\n",
|
||||
"print(\"\\nRunning market analysis...\")\n",
|
||||
"print(\"-\" * 40)\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Run the market analyst\n",
|
||||
" result = market_analyst(test_state)\n",
|
||||
" \n",
|
||||
" print(\"✅ SUCCESS! Market analysis completed.\")\n",
|
||||
" \n",
|
||||
" # Print the analysis result\n",
|
||||
" if \"messages\" in result and result[\"messages\"]:\n",
|
||||
" latest_message = result[\"messages\"][-1]\n",
|
||||
" \n",
|
||||
" # Check if it made tool calls\n",
|
||||
" if hasattr(latest_message, 'tool_calls') and latest_message.tool_calls:\n",
|
||||
" print(f\"\\n📊 Tools called: {len(latest_message.tool_calls)}\")\n",
|
||||
" for i, call in enumerate(latest_message.tool_calls):\n",
|
||||
" tool_name = call.get('name', 'unknown')\n",
|
||||
" print(f\" {i+1}. {tool_name}\")\n",
|
||||
" \n",
|
||||
" # Print the content/analysis\n",
|
||||
" if hasattr(latest_message, 'content') and latest_message.content:\n",
|
||||
" print(f\"\\n📝 Market Analysis:\")\n",
|
||||
" print(\"=\" * 50)\n",
|
||||
" print(latest_message.content)\n",
|
||||
" \n",
|
||||
" # Print market report if available\n",
|
||||
" if \"market_report\" in result and result[\"market_report\"]:\n",
|
||||
" print(f\"\\n📋 Market Report:\")\n",
|
||||
" print(\"=\" * 50)\n",
|
||||
" print(result[\"market_report\"])\n",
|
||||
" \n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"❌ ERROR: {e}\")\n",
|
||||
" import traceback\n",
|
||||
" traceback.print_exc()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "fcf9fe21",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"5000.62453368\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.bybit import get_wallet_balance\n",
|
||||
"balance = get_wallet_balance('USDT')\n",
|
||||
"print(balance)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "1dfa3165",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ValueError",
|
||||
"evalue": "Failed to place order: Bybit API error: An unknown parameter was sent.",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
||||
"\u001b[31mValueError\u001b[39m Traceback (most recent call last)",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/projects/halalquant/TradingAgents/tradingagents/dataflows/bybit.py:292\u001b[39m, in \u001b[36mplace_order\u001b[39m\u001b[34m(symbol, side, order_type, qty, price, stop_loss, take_profit, time_in_force, account_type, category, order_link_id, reduce_only, close_on_trigger)\u001b[39m\n\u001b[32m 291\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m292\u001b[39m data = \u001b[43mbybit_v5_request\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mPOST\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43m/v5/order/create\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[43m=\u001b[49m\u001b[43mbody\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 293\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m data.get(\u001b[33m\"\u001b[39m\u001b[33mresult\u001b[39m\u001b[33m\"\u001b[39m, {})\n",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/projects/halalquant/TradingAgents/tradingagents/dataflows/bybit.py:61\u001b[39m, in \u001b[36mbybit_v5_request\u001b[39m\u001b[34m(method, path, params, body)\u001b[39m\n\u001b[32m 60\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m data.get(\u001b[33m\"\u001b[39m\u001b[33mretCode\u001b[39m\u001b[33m\"\u001b[39m) != \u001b[32m0\u001b[39m:\n\u001b[32m---> \u001b[39m\u001b[32m61\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mBybit API error: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdata.get(\u001b[33m'\u001b[39m\u001b[33mretMsg\u001b[39m\u001b[33m'\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 63\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m data\n",
|
||||
"\u001b[31mValueError\u001b[39m: Bybit API error: An unknown parameter was sent.",
|
||||
"\nDuring handling of the above exception, another exception occurred:\n",
|
||||
"\u001b[31mValueError\u001b[39m Traceback (most recent call last)",
|
||||
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mtradingagents\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mdataflows\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mbybit\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m place_order, place_spot_order_with_sl_tp\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Place a spot limit order with stop loss and take profit\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m result = \u001b[43mplace_spot_order_with_sl_tp\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 4\u001b[39m \u001b[43m \u001b[49m\u001b[43msymbol\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mBTCUSDT\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 5\u001b[39m \u001b[43m \u001b[49m\u001b[43mside\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mBuy\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 6\u001b[39m \u001b[43m \u001b[49m\u001b[43mqty\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m0.001\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 7\u001b[39m \u001b[43m \u001b[49m\u001b[43mprice\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m88000.0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 8\u001b[39m \u001b[43m \u001b[49m\u001b[43mstop_loss_price\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m85000.0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 9\u001b[39m \u001b[43m \u001b[49m\u001b[43mtake_profit_price\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m90000.0\u001b[39;49m\n\u001b[32m 10\u001b[39m \u001b[43m)\u001b[49m\n\u001b[32m 12\u001b[39m \u001b[38;5;66;03m# # Place a market order\u001b[39;00m\n\u001b[32m 13\u001b[39m \u001b[38;5;66;03m# result = place_order(\u001b[39;00m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# symbol=\"BTCUSDT\",\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 18\u001b[39m \u001b[38;5;66;03m# category=\"spot\"\u001b[39;00m\n\u001b[32m 19\u001b[39m \u001b[38;5;66;03m# )\u001b[39;00m\n",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/projects/halalquant/TradingAgents/tradingagents/dataflows/bybit.py:322\u001b[39m, in \u001b[36mplace_spot_order_with_sl_tp\u001b[39m\u001b[34m(symbol, side, qty, price, stop_loss_price, take_profit_price, order_type)\u001b[39m\n\u001b[32m 298\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mplace_spot_order_with_sl_tp\u001b[39m(\n\u001b[32m 299\u001b[39m symbol: \u001b[38;5;28mstr\u001b[39m,\n\u001b[32m 300\u001b[39m side: \u001b[38;5;28mstr\u001b[39m,\n\u001b[32m (...)\u001b[39m\u001b[32m 305\u001b[39m order_type: \u001b[38;5;28mstr\u001b[39m = \u001b[33m\"\u001b[39m\u001b[33mLimit\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 306\u001b[39m ) -> Dict:\n\u001b[32m 307\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 308\u001b[39m \u001b[33;03m Convenience function to place a spot order with stop loss and take profit.\u001b[39;00m\n\u001b[32m 309\u001b[39m \u001b[33;03m \u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 320\u001b[39m \u001b[33;03m Dict containing order result\u001b[39;00m\n\u001b[32m 321\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mplace_order\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 323\u001b[39m \u001b[43m \u001b[49m\u001b[43msymbol\u001b[49m\u001b[43m=\u001b[49m\u001b[43msymbol\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 324\u001b[39m \u001b[43m \u001b[49m\u001b[43mside\u001b[49m\u001b[43m=\u001b[49m\u001b[43mside\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 325\u001b[39m \u001b[43m \u001b[49m\u001b[43morder_type\u001b[49m\u001b[43m=\u001b[49m\u001b[43morder_type\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 326\u001b[39m \u001b[43m \u001b[49m\u001b[43mqty\u001b[49m\u001b[43m=\u001b[49m\u001b[43mqty\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 327\u001b[39m \u001b[43m \u001b[49m\u001b[43mprice\u001b[49m\u001b[43m=\u001b[49m\u001b[43mprice\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 328\u001b[39m \u001b[43m \u001b[49m\u001b[43mstop_loss\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstop_loss_price\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 329\u001b[39m \u001b[43m \u001b[49m\u001b[43mtake_profit\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtake_profit_price\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 330\u001b[39m \u001b[43m \u001b[49m\u001b[43mcategory\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mspot\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\n\u001b[32m 331\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/projects/halalquant/TradingAgents/tradingagents/dataflows/bybit.py:295\u001b[39m, in \u001b[36mplace_order\u001b[39m\u001b[34m(symbol, side, order_type, qty, price, stop_loss, take_profit, time_in_force, account_type, category, order_link_id, reduce_only, close_on_trigger)\u001b[39m\n\u001b[32m 293\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m data.get(\u001b[33m\"\u001b[39m\u001b[33mresult\u001b[39m\u001b[33m\"\u001b[39m, {})\n\u001b[32m 294\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m--> \u001b[39m\u001b[32m295\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFailed to place order: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n",
|
||||
"\u001b[31mValueError\u001b[39m: Failed to place order: Bybit API error: An unknown parameter was sent."
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.bybit import place_order, place_spot_order_with_sl_tp\n",
|
||||
"# Place a spot limit order with stop loss and take profit\n",
|
||||
"result = place_spot_order_with_sl_tp(\n",
|
||||
" symbol=\"BTCUSDT\",\n",
|
||||
" side=\"Buy\",\n",
|
||||
" qty=0.001,\n",
|
||||
" price=88000.0,\n",
|
||||
" stop_loss_price=85000.0,\n",
|
||||
" take_profit_price=90000.0\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# # Place a market order\n",
|
||||
"# result = place_order(\n",
|
||||
"# symbol=\"BTCUSDT\",\n",
|
||||
"# side=\"Buy\",\n",
|
||||
"# order_type=\"Market\",\n",
|
||||
"# qty=0.001,\n",
|
||||
"# category=\"spot\"\n",
|
||||
"# )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "03bdc3c4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Order result: {'orderId': '2113891849709292800', 'orderLinkId': '2113891849709292801'}\n",
|
||||
"Order status: {'symbol': 'BTCUSDT', 'orderType': 'Limit', 'orderLinkId': '2113891849709292801', 'slLimitPrice': '27500', 'orderId': '2113891849709292800', 'cancelType': 'UNKNOWN', 'avgPrice': '0.0', 'stopOrderType': '', 'lastPriceOnCreated': '', 'orderStatus': 'New', 'takeProfit': '35000', 'cumExecValue': '0.0000000', 'smpType': 'None', 'triggerDirection': 0, 'blockTradeId': '', 'cumFeeDetail': {}, 'isLeverage': '0', 'rejectReason': 'EC_NoError', 'price': '28000.0', 'orderIv': '', 'createdTime': '1766731545590', 'tpTriggerBy': '', 'positionIdx': 0, 'trailingPercentage': '0', 'timeInForce': 'PostOnly', 'leavesValue': '280.0000000', 'basePrice': '89223.5', 'updatedTime': '1766731545591', 'side': 'Buy', 'smpGroup': 0, 'triggerPrice': '0.0', 'tpLimitPrice': '36000', 'trailingValue': '0', 'cumExecFee': '0', 'leavesQty': '0.01', 'slTriggerBy': '', 'closeOnTrigger': False, 'placeType': '', 'cumExecQty': '0', 'reduceOnly': False, 'activationPrice': '0', 'qty': '0.010000', 'stopLoss': '27000', 'marketUnit': '', 'smpOrderId': '', 'triggerBy': ''}\n",
|
||||
"Open orders: {'nextPageCursor': '2113891849709292800%3A1766731545590%2C2113891849709292800%3A1766731545590', 'category': 'spot', 'list': [{'symbol': 'BTCUSDT', 'orderType': 'Limit', 'orderLinkId': '2113891849709292801', 'slLimitPrice': '27500', 'orderId': '2113891849709292800', 'cancelType': 'UNKNOWN', 'avgPrice': '0.0', 'stopOrderType': '', 'lastPriceOnCreated': '', 'orderStatus': 'New', 'takeProfit': '35000', 'cumExecValue': '0.0000000', 'smpType': 'None', 'triggerDirection': 0, 'blockTradeId': '', 'cumFeeDetail': {}, 'isLeverage': '0', 'rejectReason': 'EC_NoError', 'price': '28000.0', 'orderIv': '', 'createdTime': '1766731545590', 'tpTriggerBy': '', 'positionIdx': 0, 'trailingPercentage': '0', 'timeInForce': 'PostOnly', 'leavesValue': '280.0000000', 'basePrice': '89223.5', 'updatedTime': '1766731545591', 'side': 'Buy', 'smpGroup': 0, 'triggerPrice': '0.0', 'tpLimitPrice': '36000', 'trailingValue': '0', 'cumExecFee': '0', 'leavesQty': '0.01', 'slTriggerBy': '', 'closeOnTrigger': False, 'placeType': '', 'cumExecQty': '0', 'reduceOnly': False, 'activationPrice': '0', 'qty': '0.010000', 'stopLoss': '27000', 'marketUnit': '', 'smpOrderId': '', 'triggerBy': ''}]}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Fixed version with correct Bybit parameters\n",
|
||||
"from tradingagents.dataflows.bybit import place_order, place_spot_order_with_sl_tp, get_order_status, get_open_orders\n",
|
||||
"\n",
|
||||
"# Place a spot limit order with stop loss and take profit - like the example\n",
|
||||
"# result = place_spot_order_with_sl_tp(\n",
|
||||
"# symbol=\"BTCUSDT\",\n",
|
||||
"# side=\"Buy\",\n",
|
||||
"# qty=0.01,\n",
|
||||
"# price=28000.0,\n",
|
||||
"# stop_loss_price=27000.0,\n",
|
||||
"# take_profit_price=35000.0,\n",
|
||||
"# sl_limit_price=27500.0, # Stop loss limit price\n",
|
||||
"# tp_limit_price=36000.0, # Take profit limit price\n",
|
||||
"# sl_order_type=\"Limit\", # Stop loss as limit order\n",
|
||||
"# tp_order_type=\"Limit\", # Take profit as limit order\n",
|
||||
"# time_in_force=\"PostOnly\" # Post only for maker orders\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"print(\"Order result:\", result)\n",
|
||||
"# Check order status\n",
|
||||
"status = get_order_status(order_id=result.get(\"orderId\", \"2113891849709292800\"), category=\"spot\")\n",
|
||||
"\n",
|
||||
"print(\"Order status:\", status)\n",
|
||||
"\n",
|
||||
"# Get open orders\n",
|
||||
"open_orders = get_open_orders(symbol=\"BTCUSDT\", category=\"spot\")\n",
|
||||
"print(\"Open orders:\", open_orders)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "330f7261",
|
||||
"execution_count": 2,
|
||||
"id": "c4d08861",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -277,65 +43,20 @@
|
|||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 1,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from dotenv import load_dotenv\n",
|
||||
"\n",
|
||||
"load_dotenv()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "153dc726",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.bybit import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "124d7e03",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Open Order Report for BTCUSDT\n",
|
||||
"- Total Orders: 1\n",
|
||||
"- Capital/Asset Value Locked: $0.00\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Conditional / Trigger Orders:\n",
|
||||
"- (Buy): Trigger @ $0.00 | Qty: 0.01 — Created: 3.9d ago\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(get_open_orders(\"BTC\", \"USDT\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "d497b56a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"a = get_account_balance(\"BTC\", quote_coin=\"USDT\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "83f29137",
|
||||
"id": "3744edd7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -343,190 +64,320 @@
|
|||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Account Balance Report for BTC/USDT\n",
|
||||
"- Total Equity: $7919.6209963500005\n",
|
||||
"** Total Equity: $7965.89736959 **\n",
|
||||
"## USDT (Quote) Details:\n",
|
||||
"- Free Margin: 4722.44462368 USDT\n",
|
||||
"- Locked Capital: 280.0 USDT\n",
|
||||
"{\n",
|
||||
" \"spotBorrow\": 0.0,\n",
|
||||
" \"availableToBorrow\": 0.0,\n",
|
||||
" \"bonus\": 0.0,\n",
|
||||
" \"accruedInterest\": 0.0,\n",
|
||||
" \"availableToWithdraw\": 0.0,\n",
|
||||
" \"totalOrderIM\": 0.0,\n",
|
||||
" \"equity\": 5002.44462368,\n",
|
||||
" \"totalPositionMM\": 0.0,\n",
|
||||
" \"usdValue\": 4997.1670446,\n",
|
||||
" \"unrealisedPnl\": 0.0,\n",
|
||||
" \"collateralSwitch\": 1.0,\n",
|
||||
" \"spotHedgingQty\": 0.0,\n",
|
||||
" \"borrowAmount\": 0.0,\n",
|
||||
" \"totalPositionIM\": 0.0,\n",
|
||||
" \"walletBalance\": 5002.44462368,\n",
|
||||
" \"cumRealisedPnl\": -138.82418652,\n",
|
||||
" \"locked\": 280.0,\n",
|
||||
" \"marginCollateral\": 1.0\n",
|
||||
"}\n",
|
||||
"## BTC (Base) Details:\n",
|
||||
"- Holding Size: 4e-07 BTC\n",
|
||||
"- Locked Asset: 0.0 BTC\n",
|
||||
"{\n",
|
||||
" \"spotBorrow\": 0.0,\n",
|
||||
" \"availableToBorrow\": 0.0,\n",
|
||||
" \"bonus\": 0.0,\n",
|
||||
" \"accruedInterest\": 0.0,\n",
|
||||
" \"availableToWithdraw\": 0.0,\n",
|
||||
" \"totalOrderIM\": 0.0,\n",
|
||||
" \"equity\": 4e-07,\n",
|
||||
" \"totalPositionMM\": 0.0,\n",
|
||||
" \"usdValue\": 0.03615499,\n",
|
||||
" \"unrealisedPnl\": 0.0,\n",
|
||||
" \"collateralSwitch\": 0.0,\n",
|
||||
" \"spotHedgingQty\": 0.0,\n",
|
||||
" \"borrowAmount\": 0.0,\n",
|
||||
" \"totalPositionIM\": 0.0,\n",
|
||||
" \"walletBalance\": 4e-07,\n",
|
||||
" \"cumRealisedPnl\": -0.00056459,\n",
|
||||
" \"locked\": 0.0,\n",
|
||||
" \"marginCollateral\": 1.0\n",
|
||||
"}\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(a)"
|
||||
"print(get_account_balance('BTC/USDT'))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "6ca5af0f",
|
||||
"execution_count": 4,
|
||||
"id": "4d338e6c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Open Orders for BTCUSDT\n",
|
||||
"[\n",
|
||||
" {\n",
|
||||
" \"symbol\": \"BTCUSDT\",\n",
|
||||
" \"orderType\": \"Limit\",\n",
|
||||
" \"orderLinkId\": \"2113891849709292801\",\n",
|
||||
" \"slLimitPrice\": 27500.0,\n",
|
||||
" \"orderId\": \"2113891849709292800\",\n",
|
||||
" \"cancelType\": \"UNKNOWN\",\n",
|
||||
" \"avgPrice\": 0.0,\n",
|
||||
" \"stopOrderType\": \"\",\n",
|
||||
" \"lastPriceOnCreated\": \"\",\n",
|
||||
" \"orderStatus\": \"New\",\n",
|
||||
" \"takeProfit\": 35000.0,\n",
|
||||
" \"cumExecValue\": 0.0,\n",
|
||||
" \"smpType\": \"None\",\n",
|
||||
" \"triggerDirection\": 0.0,\n",
|
||||
" \"blockTradeId\": \"\",\n",
|
||||
" \"cumFeeDetail\": {},\n",
|
||||
" \"isLeverage\": 0.0,\n",
|
||||
" \"rejectReason\": \"EC_NoError\",\n",
|
||||
" \"price\": 28000.0,\n",
|
||||
" \"orderIv\": \"\",\n",
|
||||
" \"createdTime\": \"2025-12-26 06:45:45\",\n",
|
||||
" \"tpTriggerBy\": \"\",\n",
|
||||
" \"positionIdx\": 0.0,\n",
|
||||
" \"trailingPercentage\": 0.0,\n",
|
||||
" \"timeInForce\": \"PostOnly\",\n",
|
||||
" \"leavesValue\": 280.0,\n",
|
||||
" \"basePrice\": 89223.5,\n",
|
||||
" \"updatedTime\": \"2025-12-26 06:45:45\",\n",
|
||||
" \"side\": \"Buy\",\n",
|
||||
" \"smpGroup\": 0.0,\n",
|
||||
" \"triggerPrice\": 0.0,\n",
|
||||
" \"tpLimitPrice\": 36000.0,\n",
|
||||
" \"trailingValue\": 0.0,\n",
|
||||
" \"cumExecFee\": 0.0,\n",
|
||||
" \"leavesQty\": 0.01,\n",
|
||||
" \"slTriggerBy\": \"\",\n",
|
||||
" \"closeOnTrigger\": 0.0,\n",
|
||||
" \"placeType\": \"\",\n",
|
||||
" \"cumExecQty\": 0.0,\n",
|
||||
" \"reduceOnly\": 0.0,\n",
|
||||
" \"activationPrice\": 0.0,\n",
|
||||
" \"qty\": 0.01,\n",
|
||||
" \"stopLoss\": 27000.0,\n",
|
||||
" \"marketUnit\": \"\",\n",
|
||||
" \"smpOrderId\": \"\",\n",
|
||||
" \"triggerBy\": \"\"\n",
|
||||
" }\n",
|
||||
"]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(get_open_orders('BTC/USDT'))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "f2782eb4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"b = get_open_position(\"BTCUSDT\", category=\"linear\")"
|
||||
"from tradingagents.dataflows.y_finance import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "b7ea9491",
|
||||
"execution_count": 6,
|
||||
"id": "fdd7515f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"## close_10_ema values from 2025-12-15 to 2025-12-25:\n",
|
||||
"\n",
|
||||
"2025-12-25: N/A: Not a trading day (weekend or holiday)\n",
|
||||
"2025-12-24: 273.957107566544\n",
|
||||
"2025-12-23: 273.9897986794218\n",
|
||||
"2025-12-22: 274.35197941894614\n",
|
||||
"2025-12-21: N/A: Not a trading day (weekend or holiday)\n",
|
||||
"2025-12-20: N/A: Not a trading day (weekend or holiday)\n",
|
||||
"2025-12-19: 275.1035301296668\n",
|
||||
"2025-12-18: 275.42208939676294\n",
|
||||
"2025-12-17: 276.1403309423977\n",
|
||||
"2025-12-16: 277.0959608545104\n",
|
||||
"2025-12-15: 277.64839985516545\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"10 EMA: A responsive short-term average. Usage: Capture quick shifts in momentum and potential entry points. Tips: Prone to noise in choppy markets; use alongside longer averages for filtering false signals.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(get_stock_stats_indicators_window(symbol='AAPL', indicator='close_10_ema', curr_date='2025-12-25', look_back_days=10))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "e469bf97",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"## close_200_sma values for BTCUSDT from 2025-12-15 to 2025-12-25:\n",
|
||||
"\n",
|
||||
"2025-12-25: 107547.3955\n",
|
||||
"2025-12-24: 107639.8590\n",
|
||||
"2025-12-23: 107729.1770\n",
|
||||
"2025-12-22: 107813.0945\n",
|
||||
"2025-12-21: 107877.4790\n",
|
||||
"2025-12-20: 107957.4840\n",
|
||||
"2025-12-19: 108042.5335\n",
|
||||
"2025-12-18: 108131.1640\n",
|
||||
"2025-12-17: 108231.8855\n",
|
||||
"2025-12-16: 108323.7295\n",
|
||||
"2025-12-15: 108404.5060\n",
|
||||
"\n",
|
||||
"200 SMA: A long-term trend benchmark. Usage: Confirm overall market trend and identify golden/death cross setups. Tips: It reacts slowly; best for strategic trend confirmation rather than frequent trading entries.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(get_crypto_indicator_window('BTC/USDT', indicator='close_200_sma', curr_date='2025-12-25', look_back_days=10))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "2ec4396d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Technical Indicators Report for BTC/USDT\n",
|
||||
"\n",
|
||||
"**Current Date:** 2025-12-25\n",
|
||||
"**Lookback Days:** 10\n",
|
||||
"\n",
|
||||
"## Simple Moving Average (SMA)\n",
|
||||
"\n",
|
||||
"**Value:** 89244.9917\n",
|
||||
"\n",
|
||||
"*SMA (Simple Moving Average): A basic trend-following indicator that smooths out price data. Usage: Identify trend direction and serve as dynamic support/resistance levels. Tips: Use multiple SMAs for crossover signals; combines well with volume analysis for confirmation.*\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Exponential Moving Average (EMA)\n",
|
||||
"\n",
|
||||
"**Value:** 90757.8592\n",
|
||||
"\n",
|
||||
"*EMA (Exponential Moving Average): A trend-following indicator that gives more weight to recent prices. Usage: More responsive than SMA for trend changes and crossover signals. Tips: Better for short-term trading; reacts faster to price changes than SMA.*\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from tradingagents.dataflows.taapi import *\n",
|
||||
"\n",
|
||||
"print(get_crypto_stats_indicators(symbol='BTC/USDT', indicators=['sma', 'ema'], curr_date='2025-12-25', look_back_days=10))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "71414822",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'status': 'No Open Position',\n",
|
||||
" 'symbol': 'BTCUSDT',\n",
|
||||
" 'size': 0.0,\n",
|
||||
" 'pnl_usd': 0.0}"
|
||||
"'BTCUSDT'"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"b"
|
||||
"get_symbol(\"BTC\", \"USDT\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "6ead1651",
|
||||
"id": "3b52bac5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'nextPageCursor': '2113891849709292800%3A1766731545590%2C2113891849709292800%3A1766731545590',\n",
|
||||
" 'category': 'spot',\n",
|
||||
" 'list': [{'symbol': 'BTCUSDT',\n",
|
||||
" 'orderType': 'Limit',\n",
|
||||
" 'orderLinkId': '2113891849709292801',\n",
|
||||
" 'slLimitPrice': '27500',\n",
|
||||
" 'orderId': '2113891849709292800',\n",
|
||||
" 'cancelType': 'UNKNOWN',\n",
|
||||
" 'avgPrice': '0.0',\n",
|
||||
" 'stopOrderType': '',\n",
|
||||
" 'lastPriceOnCreated': '',\n",
|
||||
" 'orderStatus': 'New',\n",
|
||||
" 'takeProfit': '35000',\n",
|
||||
" 'cumExecValue': '0.0000000',\n",
|
||||
" 'smpType': 'None',\n",
|
||||
" 'triggerDirection': 0,\n",
|
||||
" 'blockTradeId': '',\n",
|
||||
" 'cumFeeDetail': {},\n",
|
||||
" 'isLeverage': '0',\n",
|
||||
" 'rejectReason': 'EC_NoError',\n",
|
||||
" 'price': '28000.0',\n",
|
||||
" 'orderIv': '',\n",
|
||||
" 'createdTime': '1766731545590',\n",
|
||||
" 'tpTriggerBy': '',\n",
|
||||
" 'positionIdx': 0,\n",
|
||||
" 'trailingPercentage': '0',\n",
|
||||
" 'timeInForce': 'PostOnly',\n",
|
||||
" 'leavesValue': '280.0000000',\n",
|
||||
" 'basePrice': '89223.5',\n",
|
||||
" 'updatedTime': '1766731545591',\n",
|
||||
" 'side': 'Buy',\n",
|
||||
" 'smpGroup': 0,\n",
|
||||
" 'triggerPrice': '0.0',\n",
|
||||
" 'tpLimitPrice': '36000',\n",
|
||||
" 'trailingValue': '0',\n",
|
||||
" 'cumExecFee': '0',\n",
|
||||
" 'leavesQty': '0.01',\n",
|
||||
" 'slTriggerBy': '',\n",
|
||||
" 'closeOnTrigger': False,\n",
|
||||
" 'placeType': '',\n",
|
||||
" 'cumExecQty': '0',\n",
|
||||
" 'reduceOnly': False,\n",
|
||||
" 'activationPrice': '0',\n",
|
||||
" 'qty': '0.010000',\n",
|
||||
" 'stopLoss': '27000',\n",
|
||||
" 'marketUnit': '',\n",
|
||||
" 'smpOrderId': '',\n",
|
||||
" 'triggerBy': ''}]}"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Technical Indicators Report for BTCUSDT\n",
|
||||
"\n",
|
||||
"----------------------------------------\n",
|
||||
"\n",
|
||||
"## close_50_sma values for BTCUSDT from 2025-12-15 to 2025-12-25:\n",
|
||||
"\n",
|
||||
"2025-12-25: 91694.1440\n",
|
||||
"2025-12-24: 92027.2860\n",
|
||||
"2025-12-23: 92303.3980\n",
|
||||
"2025-12-22: 92685.2460\n",
|
||||
"2025-12-21: 93123.5500\n",
|
||||
"2025-12-20: 93551.8900\n",
|
||||
"2025-12-19: 93976.5280\n",
|
||||
"2025-12-18: 94379.7400\n",
|
||||
"2025-12-17: 94869.3140\n",
|
||||
"2025-12-16: 95402.0880\n",
|
||||
"2025-12-15: 95926.8880\n",
|
||||
"\n",
|
||||
"Description: 50 SMA: A medium-term trend indicator. Usage: Identify trend direction and serve as dynamic support/resistance. Tips: It lags price; combine with faster indicators for timely signals.\n",
|
||||
"----------------------------------------\n",
|
||||
"\n",
|
||||
"## close_200_sma values for BTCUSDT from 2025-12-15 to 2025-12-25:\n",
|
||||
"\n",
|
||||
"2025-12-25: 107547.3955\n",
|
||||
"2025-12-24: 107639.8590\n",
|
||||
"2025-12-23: 107729.1770\n",
|
||||
"2025-12-22: 107813.0945\n",
|
||||
"2025-12-21: 107877.4790\n",
|
||||
"2025-12-20: 107957.4840\n",
|
||||
"2025-12-19: 108042.5335\n",
|
||||
"2025-12-18: 108131.1640\n",
|
||||
"2025-12-17: 108231.8855\n",
|
||||
"2025-12-16: 108323.7295\n",
|
||||
"2025-12-15: 108404.5060\n",
|
||||
"\n",
|
||||
"Description: 200 SMA: A long-term trend benchmark. Usage: Confirm overall market trend and identify golden/death cross setups. Tips: It reacts slowly; best for strategic trend confirmation rather than frequent trading entries.\n",
|
||||
"----------------------------------------\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"get_open_orders(symbol=\"BTCUSDT\", category=\"spot\")"
|
||||
"print(get_crypto_indicators_bulk(symbol='BTC/USDT', indicators=['close_50_sma', 'close_200_sma'], curr_date='2025-12-25', look_back_days=10))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "50f72edb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_symbol(base_coin: str, quote_coin: str, category: str = \"linear\") -> str:\n",
|
||||
" \"\"\"\n",
|
||||
" Safely retrieves the correct Bybit symbol (e.g., \"BTCUSDT\") for a given base/quote pair.\n",
|
||||
" \n",
|
||||
" Args:\n",
|
||||
" base_coin: The asset (e.g., \"BTC\")\n",
|
||||
" quote_coin: The currency (e.g., \"USDT\")\n",
|
||||
" category: \"linear\", \"spot\", or \"inverse\"\n",
|
||||
" \n",
|
||||
" Returns:\n",
|
||||
" The valid symbol string (e.g., \"BTCUSDT\") or None if not found.\n",
|
||||
" \"\"\"\n",
|
||||
" # 1. Query the API specifically for this Base Coin\n",
|
||||
" # This filters the search on the server side, which is much faster.\n",
|
||||
" params = {\n",
|
||||
" \"category\": category,\n",
|
||||
" \"baseCoin\": base_coin.upper(),\n",
|
||||
" \"limit\": 20 # We only expect a few matches (e.g., BTCUSDT, BTC-PERP)\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" data = bybit_v5_request(\"GET\", \"/v5/market/instruments-info\", params)\n",
|
||||
"\n",
|
||||
" result = data.get(\"result\", {})\n",
|
||||
" instruments = result.get(\"list\", [])\n",
|
||||
"\n",
|
||||
" # 2. Find the exact match for the Quote Coin\n",
|
||||
" # This handles cases where BTC might pair with USDT, USDC, or DAI\n",
|
||||
" for item in instruments:\n",
|
||||
" if item.get(\"quoteCoin\") == quote_coin.upper() and item.get(\"baseCoin\") == base_coin.upper():\n",
|
||||
" return item.get(\"symbol\")\n",
|
||||
"\n",
|
||||
" # 3. Fallback/Error handling\n",
|
||||
" return None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 37,
|
||||
"id": "6aa1fd5e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'ETHBTC'"
|
||||
]
|
||||
},
|
||||
"execution_count": 37,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"get_symbol(\"ETH\", \"BTC\", category=\"spot\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "61815a34",
|
||||
"id": "9e9206ba",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||
from tradingagents.agents.utils.agent_utils import get_crypto_data, get_indicators_bulk
|
||||
from tradingagents.agents.utils.agent_utils import get_crypto_data, get_indicators_bulk, get_account_balance, get_open_orders
|
||||
|
||||
|
||||
def create_market_analyst(llm):
|
||||
|
|
@ -11,25 +11,36 @@ def create_market_analyst(llm):
|
|||
tools = [
|
||||
get_crypto_data,
|
||||
get_indicators_bulk,
|
||||
get_account_balance,
|
||||
get_open_orders,
|
||||
]
|
||||
|
||||
system_message = (
|
||||
"""You are a crypto trading assistant tasked with analyzing cryptocurrency markets. Your role is to select the **most relevant indicators** for a given crypto market condition or trading strategy from the following list. The goal is to choose the **most effective indicators** that provide complementary insights without redundancy. Available indicators are:
|
||||
|
||||
Moving Averages:
|
||||
- sma: Simple Moving Average: A basic trend-following indicator that smooths out price data. Usage: Identify trend direction and serve as dynamic support/resistance levels. Tips: Use multiple SMAs for crossover signals; combines well with volume analysis for confirmation.
|
||||
- close_50_sma: 50 SMA: A medium-term trend indicator. Usage: Identify trend direction and serve as dynamic support/resistance. Tips: It lags price; combine with faster indicators for timely signals.
|
||||
- close_200_sma: 200 SMA: A long-term trend benchmark. Usage: Confirm overall market trend and identify golden/death cross setups. Tips: It reacts slowly; best for strategic trend confirmation rather than frequent trading entries.
|
||||
- close_10_ema: 10 EMA: A responsive short-term average. Usage: Capture quick shifts in momentum and potential entry points. Tips: Prone to noise in choppy markets; use alongside longer averages for filtering false signals.
|
||||
|
||||
MACD Related:
|
||||
- macd: MACD (Moving Average Convergence Divergence): Measures momentum via differences between fast and slow EMAs. Usage: Look for signal line crossovers, centerline crossovers, and divergence patterns for trend changes. Tips: Most effective in trending markets; combine with RSI to avoid false signals in sideways markets.
|
||||
- macd: MACD: Computes momentum via differences of EMAs. Usage: Look for crossovers and divergence as signals of trend changes. Tips: Confirm with other indicators in low-volatility or sideways markets.
|
||||
- macds: MACD Signal: An EMA smoothing of the MACD line. Usage: Use crossovers with the MACD line to trigger trades. Tips: Should be part of a broader strategy to avoid false positives.
|
||||
- macdh: MACD Histogram: Shows the gap between the MACD line and its signal. Usage: Visualize momentum strength and spot divergence early. Tips: Can be volatile; complement with additional filters in fast-moving markets.
|
||||
|
||||
Momentum Indicators:
|
||||
- rsi: RSI (Relative Strength Index): Oscillator measuring momentum to identify overbought (>70) and oversold (<30) conditions. Usage: Look for reversal signals at extreme levels and divergence with price action. Tips: In strong crypto trends, RSI can remain extreme for extended periods; always confirm with trend analysis.
|
||||
- rsi: RSI: Measures momentum to flag overbought/oversold conditions. Usage: Apply 70/30 thresholds and watch for divergence to signal reversals. Tips: In strong trends, RSI may remain extreme; always cross-check with trend analysis.
|
||||
|
||||
Volatility Indicators:
|
||||
- bbands: Bollinger Bands: Volatility indicator consisting of upper, middle (SMA), and lower bands based on standard deviations. Usage: Identify overbought/oversold conditions, volatility expansion/contraction, and potential breakout zones. Tips: Price touching bands doesn't guarantee reversal; use band squeeze for volatility breakout trades.
|
||||
- atr: ATR (Average True Range): Measures market volatility by calculating the average of true ranges over a period. Usage: Set stop-loss levels, position sizing, and identify high/low volatility periods for strategy adjustment. Tips: Higher ATR indicates more volatile conditions; use for risk management rather than directional signals.
|
||||
- boll: Bollinger Middle: A 20 SMA serving as the basis for Bollinger Bands. Usage: Acts as a dynamic benchmark for price movement. Tips: Combine with the upper and lower bands to effectively spot breakouts or reversals.
|
||||
- boll_ub: Bollinger Upper Band: Typically 2 standard deviations above the middle line. Usage: Signals potential overbought conditions and breakout zones. Tips: Confirm signals with other tools; prices may ride the band in strong trends.
|
||||
- boll_lb: Bollinger Lower Band: Typically 2 standard deviations below the middle line. Usage: Indicates potential oversold conditions. Tips: Use additional analysis to avoid false reversal signals.
|
||||
- atr: ATR: Averages true range to measure volatility. Usage: Set stop-loss levels and adjust position sizes based on current market volatility. Tips: It's a reactive measure, so use it as part of a broader risk management strategy.
|
||||
|
||||
- Select indicators that provide diverse and complementary information. Avoid redundancy and focus on the most effective combination for crypto market analysis. Also briefly explain why they are suitable for the given crypto market context. When you tool call, please use the exact name of the indicators provided above as they are defined parameters, otherwise your call will fail. Please make sure to call get_crypto_data first to retrieve the cryptocurrency price data. Then use get_indicators_bulk with a list of the specific indicator names (e.g., ["sma", "rsi", "macd"]). 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 crypto traders make decisions."""
|
||||
Volume-Based Indicators:
|
||||
- vwma: VWMA: A moving average weighted by volume. Usage: Confirm trends by integrating price action with volume data. Tips: Watch for skewed results from volume spikes; use in combination with other volume analyses.
|
||||
|
||||
- Select indicators that provide diverse and complementary information. Avoid redundancy and focus on the most effective combination for crypto market analysis. Also briefly explain why they are suitable for the given crypto market context. When you tool call, please use the exact name of the indicators provided above as they are defined parameters, otherwise your call will fail. Please make sure to call get_crypto_data first to retrieve the cryptocurrency price data. Then use get_indicators_bulk with a list of the specific indicator names (e.g., ["close_50_sma", "rsi", "macd"]). 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 crypto traders make decisions."""
|
||||
+ """ 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."""
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ def create_profile_analyst(llm):
|
|||
system_message = (
|
||||
"You are a Profile and Portfolio Analyst tasked with providing a deep-dive assessment of the user's personal trading account and financial health. \
|
||||
You will be given access to the user's portfolio data, your objective is to write a comprehensive long report detailing your analysis, insights, and implications for the user's trading capacity after assessing their buying power, asset allocation, risk exposure, and active market participation. \
|
||||
Use the `get_account_balance(base_coin, quote_coin)` tool (e.g., base_coin='BTC', quote_coin='USDT') to determine total equity, free margin, and locked capital. Use the `get_open_orders(base_coin, quote_coin)` tool (e.g., base_coin='BTC', quote_coin='USDT') to identify capital tied up in pending limit orders or stop-losses. \
|
||||
Use the `get_account_balance(symbol)` tool (e.g., symbol='BTC/USDT') to determine total equity, free margin, and locked capital. Use the `get_open_orders(symbol)` tool (e.g., symbol='BTC/USDT') to identify capital tied up in pending limit orders or stop-losses. \
|
||||
Do not simply list the user's balances or holdings, provide detailed and finegrained analysis and insights. For instance, warn the user if they are overexposed to a single volatile asset, point out if they have too many 'stale' open orders locking up funds, or analyze if their current cash position allows for aggressive moves. Your report should serve as a risk management check before any new trades are executed."
|
||||
+ """ Make sure to append a Markdown table at the end of the report to organize key portfolio metrics (Total Equity, Free Margin, Top Holdings, Risk Level) and actionable recommendations, organized and easy to read.""",
|
||||
)
|
||||
|
|
@ -55,7 +55,7 @@ def create_profile_analyst(llm):
|
|||
|
||||
return {
|
||||
"messages": [result],
|
||||
"news_report": report,
|
||||
"profile_report": report,
|
||||
}
|
||||
|
||||
return profile_analyst_node
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ def create_research_manager(llm, memory):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
investment_debate_state = state["investment_debate_state"]
|
||||
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}\n\n{profile_report}"
|
||||
past_memories = memory.get_memories(curr_situation, n_matches=2)
|
||||
|
||||
past_memory_str = ""
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@ def create_risk_manager(llm, memory):
|
|||
risk_debate_state = state["risk_debate_state"]
|
||||
market_research_report = state["market_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
sentiment_report = state["sentiment_report"]
|
||||
profile_report = state["profile_report"]
|
||||
trader_plan = state["investment_plan"]
|
||||
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}\n\n{profile_report}"
|
||||
past_memories = memory.get_memories(curr_situation, n_matches=2)
|
||||
|
||||
past_memory_str = ""
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ def create_bear_researcher(llm, memory):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}\n\n{profile_report}"
|
||||
past_memories = memory.get_memories(curr_situation, n_matches=2)
|
||||
|
||||
past_memory_str = ""
|
||||
|
|
@ -38,6 +39,7 @@ Market research report: {market_research_report}
|
|||
Social media sentiment report: {sentiment_report}
|
||||
Latest world affairs news: {news_report}
|
||||
Company fundamentals report: {fundamentals_report}
|
||||
Profile analysis report: {profile_report}
|
||||
Conversation history of the debate: {history}
|
||||
Last bull argument: {current_response}
|
||||
Reflections from similar situations and lessons learned: {past_memory_str}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ def create_bull_researcher(llm, memory):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}\n\n{profile_report}"
|
||||
past_memories = memory.get_memories(curr_situation, n_matches=2)
|
||||
|
||||
past_memory_str = ""
|
||||
|
|
@ -36,6 +37,7 @@ Market research report: {market_research_report}
|
|||
Social media sentiment report: {sentiment_report}
|
||||
Latest world affairs news: {news_report}
|
||||
Company fundamentals report: {fundamentals_report}
|
||||
Profile analysis report: {profile_report}
|
||||
Conversation history of the debate: {history}
|
||||
Last bear argument: {current_response}
|
||||
Reflections from similar situations and lessons learned: {past_memory_str}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ def create_risky_debator(llm):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
trader_decision = state["trader_investment_plan"]
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ Market Research Report: {market_research_report}
|
|||
Social Media Sentiment Report: {sentiment_report}
|
||||
Latest World Affairs Report: {news_report}
|
||||
Fundamentals Report: {fundamentals_report}
|
||||
Profile Report: {profile_report}
|
||||
Here is the current conversation history: {history} Here are the last arguments from the conservative analyst: {current_safe_response} Here are the last arguments from the neutral analyst: {current_neutral_response}. If there are no responses from the other viewpoints, do not halluncinate and just present your point.
|
||||
|
||||
Engage actively by addressing any specific concerns raised, refuting the weaknesses in their logic, and asserting the benefits of risk-taking to outpace market norms. Maintain a focus on debating and persuading, not just presenting data. Challenge each counterpoint to underscore why a high-risk approach is optimal. Output conversationally as if you are speaking without any special formatting."""
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ def create_safe_debator(llm):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
trader_decision = state["trader_investment_plan"]
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ Market Research Report: {market_research_report}
|
|||
Social Media Sentiment Report: {sentiment_report}
|
||||
Latest World Affairs Report: {news_report}
|
||||
Fundamentals Report: {fundamentals_report}
|
||||
Profile Report: {profile_report}
|
||||
Here is the current conversation history: {history} Here is the last response from the risky analyst: {current_risky_response} Here is the last response from the neutral analyst: {current_neutral_response}. If there are no responses from the other viewpoints, do not halluncinate and just present your point.
|
||||
|
||||
Engage by questioning their optimism and emphasizing the potential downsides they may have overlooked. Address each of their counterpoints to showcase why a conservative stance is ultimately the safest path for the firm's assets. Focus on debating and critiquing their arguments to demonstrate the strength of a low-risk strategy over their approaches. Output conversationally as if you are speaking without any special formatting."""
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ def create_neutral_debator(llm):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
trader_decision = state["trader_investment_plan"]
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ Market Research Report: {market_research_report}
|
|||
Social Media Sentiment Report: {sentiment_report}
|
||||
Latest World Affairs Report: {news_report}
|
||||
Fundamentals Report: {fundamentals_report}
|
||||
Profile Report: {profile_report}
|
||||
Here is the current conversation history: {history} Here is the last response from the risky analyst: {current_risky_response} Here is the last response from the safe analyst: {current_safe_response}. If there are no responses from the other viewpoints, do not halluncinate and just present your point.
|
||||
|
||||
Engage actively by analyzing both sides critically, addressing weaknesses in the risky and conservative arguments to advocate for a more balanced approach. Challenge each of their points to illustrate why a moderate risk strategy might offer the best of both worlds, providing growth potential while safeguarding against extreme volatility. Focus on debating rather than simply presenting data, aiming to show that a balanced view can lead to the most reliable outcomes. Output conversationally as if you are speaking without any special formatting."""
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ def create_trader(llm, memory):
|
|||
sentiment_report = state["sentiment_report"]
|
||||
news_report = state["news_report"]
|
||||
fundamentals_report = state["fundamentals_report"]
|
||||
profile_report = state["profile_report"]
|
||||
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
|
||||
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}\n\n{profile_report}"
|
||||
past_memories = memory.get_memories(curr_situation, n_matches=2)
|
||||
|
||||
past_memory_str = ""
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class AgentState(MessagesState):
|
|||
str, "Report from the News Researcher of current world affairs"
|
||||
]
|
||||
fundamentals_report: Annotated[str, "Report from the Fundamentals Researcher"]
|
||||
profile_report: Annotated[str, "Report from the Profile Analyst"]
|
||||
|
||||
# researcher team discussion step
|
||||
investment_debate_state: Annotated[
|
||||
|
|
|
|||
|
|
@ -4,30 +4,26 @@ from tradingagents.dataflows.interface import route_to_vendor
|
|||
|
||||
@tool
|
||||
def get_account_balance(
|
||||
base_coin: Annotated[str, "The base coin symbol, e.g., 'USDT'"],
|
||||
quote_coin: Annotated[str, "The quote coin symbol, e.g., 'BTC'"],
|
||||
symbol: Annotated[str, "The trading pair symbol, e.g., 'BTC/USDT'"],
|
||||
) -> str:
|
||||
"""
|
||||
Fetches the account balance for a specific trading pair.
|
||||
Args:
|
||||
base_coin (str): The base coin symbol, e.g., 'USDT'
|
||||
quote_coin (str): The quote coin symbol, e.g., 'BTC'
|
||||
symbol (str): The trading pair symbol, e.g., 'BTC/USDT'
|
||||
Returns:
|
||||
str: A formatted string containing account balance details
|
||||
"""
|
||||
return route_to_vendor("get_account_balance", base_coin, quote_coin)
|
||||
return route_to_vendor("get_account_balance", symbol)
|
||||
|
||||
@tool
|
||||
def get_open_orders(
|
||||
base_coin: Annotated[str, "The base coin symbol, e.g., 'USDT'"],
|
||||
quote_coin: Annotated[str, "The quote coin symbol, e.g., 'BTC'"],
|
||||
symbol: Annotated[str, "The trading pair symbol, e.g., 'BTC/USDT'"],
|
||||
) -> str:
|
||||
"""
|
||||
Fetches the list of open orders for a specific trading pair.
|
||||
Args:
|
||||
base_coin (str): The base coin symbol, e.g., 'USDT'
|
||||
quote_coin (str): The quote coin symbol, e.g., 'BTC'
|
||||
symbol (str): The trading pair symbol, e.g., 'BTC/USDT'
|
||||
Returns:
|
||||
str: A formatted string containing open orders details
|
||||
"""
|
||||
return route_to_vendor("get_open_orders", base_coin, quote_coin)
|
||||
return route_to_vendor("get_open_orders", symbol)
|
||||
|
|
@ -34,7 +34,7 @@ def get_market_data(symbol: str, start_date: str, end_date: str):
|
|||
start_epoch = int(datetime.strptime(start_date, "%Y-%m-%d").timestamp() * 1000)
|
||||
end_epoch = int(datetime.strptime(end_date, "%Y-%m-%d").timestamp() * 1000)
|
||||
|
||||
print(f"DEBUG: Fetching data for {formatted_symbol} from {start_date} to {end_date}")
|
||||
# print(f"DEBUG: Fetching data for {formatted_symbol} from {start_date} to {end_date}")
|
||||
try:
|
||||
response = client.rest_api.klines(
|
||||
symbol=formatted_symbol,
|
||||
|
|
@ -44,7 +44,7 @@ def get_market_data(symbol: str, start_date: str, end_date: str):
|
|||
)
|
||||
|
||||
rate_limits = response.rate_limits
|
||||
print(f"DEBUG: klines() rate limits: {rate_limits}")
|
||||
# print(f"DEBUG: klines() rate limits: {rate_limits}")
|
||||
|
||||
data = response.data()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@ import hashlib
|
|||
import hmac
|
||||
import json
|
||||
import time
|
||||
from typing import Dict, Optional
|
||||
from typing import Dict, Optional, List
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import requests
|
||||
from .config import get_config
|
||||
|
||||
import json
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import pandas as pd
|
||||
from stockstats import StockDataFrame
|
||||
|
||||
|
||||
def bybit_v5_request(method: str, path: str, params: Optional[Dict] = None, body: Optional[Dict] = None) -> Dict:
|
||||
|
|
@ -64,14 +67,17 @@ def bybit_v5_request(method: str, path: str, params: Optional[Dict] = None, body
|
|||
|
||||
return data
|
||||
|
||||
def get_account_balance(base_coin: str, quote_coin: str = "USDT") -> dict:
|
||||
def get_account_balance(symbol: str) -> dict:
|
||||
"""
|
||||
To determine total equity, available free margin for new trades, and locked capital.
|
||||
|
||||
Args:
|
||||
base_coin: The asset being analyzed (e.g., "BTC")
|
||||
symbol: Format "BASE/QUOTE" (e.g., "BTC/USDT")
|
||||
quote_coin: The currency used for buying (e.g., "USDT")
|
||||
"""
|
||||
if "/" not in symbol:
|
||||
return f"Error: Symbol '{symbol}' is not in the correct format. Please use 'BASE/QUOTE' format, e.g., 'BTC/USDT'."
|
||||
base_coin, quote_coin = symbol.split("/")
|
||||
# 1. Fetch all assets from Bybit (omitting 'coin' gets everything)
|
||||
data = bybit_v5_request("GET", "/v5/account/wallet-balance", {
|
||||
"accountType": "UNIFIED"
|
||||
|
|
@ -133,10 +139,13 @@ def get_symbol(base_coin: str, quote_coin: str) -> str:
|
|||
# 3. Fallback/Error handling
|
||||
return None
|
||||
|
||||
def get_open_orders(base_coin: str, quote_coin: str) -> str:
|
||||
def get_open_orders(symbol: str) -> str:
|
||||
"""
|
||||
Fetches active orders and returns a text report analyzing capital lock-up and order age.
|
||||
"""
|
||||
if "/" not in symbol:
|
||||
return f"Error: Symbol '{symbol}' is not in the correct format. Please use 'BASE/QUOTE' format, e.g., 'BTC/USDT'."
|
||||
base_coin, quote_coin = symbol.split("/")
|
||||
symbol = get_symbol(base_coin, quote_coin)
|
||||
if not symbol:
|
||||
return f"Error: No valid spot symbol found for {base_coin}/{quote_coin}"
|
||||
|
|
@ -168,6 +177,457 @@ def get_open_orders(base_coin: str, quote_coin: str) -> str:
|
|||
|
||||
return report
|
||||
|
||||
|
||||
def get_market_data(symbol:str, start_date: str, end_date: str) -> str:
|
||||
"""
|
||||
Fetches historical Daily (1D) OHLCV data for a specific date range.
|
||||
|
||||
Args:
|
||||
symbol: Format "BASE/QUOTE" (e.g., "BTC/USDT").
|
||||
start_date: Format "YYYY-MM-DD" (Inclusive).
|
||||
end_date: Format "YYYY-MM-DD" (Inclusive).
|
||||
|
||||
Returns:
|
||||
A formatted CSV-style string report.
|
||||
"""
|
||||
if "/" not in symbol:
|
||||
return f"Error: Symbol '{symbol}' is not in the correct format. Please use 'BASE/QUOTE' format, e.g., 'BTC/USDT'."
|
||||
# 1. Convert Date Strings to Timestamps (ms)
|
||||
try:
|
||||
# Start of the start_date (00:00:00)
|
||||
dt_start = datetime.strptime(start_date, "%Y-%m-%d")
|
||||
ts_start = int(dt_start.timestamp() * 1000)
|
||||
|
||||
# End of the end_date (23:59:59) - Bybit 'end' parameter is inclusive if valid candle exists
|
||||
dt_end = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
|
||||
ts_end = int(dt_end.timestamp() * 1000)
|
||||
except ValueError:
|
||||
return "Error: Invalid date format. Please use YYYY-MM-DD."
|
||||
|
||||
# 2. Request Data from Bybit
|
||||
# We use interval "D" for Daily. Limit 1000 covers ~2.7 years of daily data in one call.
|
||||
base_coin, quote_coin = symbol.split("/")
|
||||
symbol2 = get_symbol(base_coin, quote_coin)
|
||||
if not symbol2:
|
||||
return f"# Error: No valid spot symbol found for {base_coin}/{quote_coin}."
|
||||
params = {
|
||||
"category": "spot",
|
||||
"symbol": symbol2.upper(),
|
||||
"interval": "D",
|
||||
"start": ts_start,
|
||||
"end": ts_end,
|
||||
"limit": 1000
|
||||
}
|
||||
|
||||
data = bybit_v5_request("GET", "/v5/market/kline", params)
|
||||
|
||||
result = data.get("result", {})
|
||||
raw_candles = result.get("list", []) # Returns [timestamp, open, high, low, close, volume, turnover]
|
||||
|
||||
if not raw_candles:
|
||||
return f"# No market data found for {symbol.upper()} from {start_date} to {end_date}."
|
||||
|
||||
# 3. Format Data
|
||||
# Bybit returns Newest -> Oldest. We reverse it to get chronological order (Oldest -> Newest).
|
||||
raw_candles.reverse()
|
||||
|
||||
csv_lines = []
|
||||
|
||||
for candle in raw_candles:
|
||||
# Parse Timestamp
|
||||
ts_ms = int(candle[0])
|
||||
date_str = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc).strftime('%Y-%m-%d')
|
||||
|
||||
# Parse Values
|
||||
open_p = candle[1]
|
||||
high_p = candle[2]
|
||||
low_p = candle[3]
|
||||
close_p = candle[4]
|
||||
volume = float(candle[5]) # Volume in Base Currency (e.g. BTC)
|
||||
|
||||
# Format Line: Date,Open,High,Low,Close,Volume
|
||||
# Note: We omit Dividends/Stock Splits as requested
|
||||
line = f"{date_str},{open_p},{high_p},{low_p},{close_p},{int(volume)}"
|
||||
csv_lines.append(line)
|
||||
|
||||
# 4. Construct Final Report Header
|
||||
current_time = datetime.now(tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
|
||||
|
||||
header = [
|
||||
f"# Crypto data for {symbol.upper()} from {start_date} to {end_date}",
|
||||
f"# Total records: {len(csv_lines)}",
|
||||
f"# Data retrieved on: {current_time}",
|
||||
"",
|
||||
"Date,Open,High,Low,Close,Volume"
|
||||
]
|
||||
|
||||
return "\n".join(header + csv_lines)
|
||||
|
||||
def get_crypto_indicator_window(
|
||||
symbol: str,
|
||||
indicator: str,
|
||||
curr_date: str,
|
||||
look_back_days: int
|
||||
) -> str:
|
||||
"""
|
||||
Calculates technical indicators for a crypto pair using Bybit data.
|
||||
Fix: Uses index lookup for dates since stockstats sets 'date' as the index.
|
||||
"""
|
||||
if "/" not in symbol:
|
||||
return f"Error: Symbol '{symbol}' is not in the correct format. Please use 'BASE/QUOTE' format, e.g., 'BTC/USDT'."
|
||||
base_coin, quote_coin = symbol.split("/")
|
||||
symbol2 = get_symbol(base_coin, quote_coin)
|
||||
|
||||
# 1. Define Supported Indicators (Same as before)
|
||||
best_ind_params = {
|
||||
"close_50_sma": (
|
||||
"50 SMA: A medium-term trend indicator. "
|
||||
"Usage: Identify trend direction and serve as dynamic support/resistance. "
|
||||
"Tips: It lags price; combine with faster indicators for timely signals."
|
||||
),
|
||||
"close_200_sma": (
|
||||
"200 SMA: A long-term trend benchmark. "
|
||||
"Usage: Confirm overall market trend and identify golden/death cross setups. "
|
||||
"Tips: It reacts slowly; best for strategic trend confirmation rather than frequent trading entries."
|
||||
),
|
||||
"close_10_ema": (
|
||||
"10 EMA: A responsive short-term average. "
|
||||
"Usage: Capture quick shifts in momentum and potential entry points. "
|
||||
"Tips: Prone to noise in choppy markets; use alongside longer averages for filtering false signals."
|
||||
),
|
||||
# MACD Related
|
||||
"macd": (
|
||||
"MACD: Computes momentum via differences of EMAs. "
|
||||
"Usage: Look for crossovers and divergence as signals of trend changes. "
|
||||
"Tips: Confirm with other indicators in low-volatility or sideways markets."
|
||||
),
|
||||
"macds": (
|
||||
"MACD Signal: An EMA smoothing of the MACD line. "
|
||||
"Usage: Use crossovers with the MACD line to trigger trades. "
|
||||
"Tips: Should be part of a broader strategy to avoid false positives."
|
||||
),
|
||||
"macdh": (
|
||||
"MACD Histogram: Shows the gap between the MACD line and its signal. "
|
||||
"Usage: Visualize momentum strength and spot divergence early. "
|
||||
"Tips: Can be volatile; complement with additional filters in fast-moving markets."
|
||||
),
|
||||
# Momentum Indicators
|
||||
"rsi": (
|
||||
"RSI: Measures momentum to flag overbought/oversold conditions. "
|
||||
"Usage: Apply 70/30 thresholds and watch for divergence to signal reversals. "
|
||||
"Tips: In strong trends, RSI may remain extreme; always cross-check with trend analysis."
|
||||
),
|
||||
# Volatility Indicators
|
||||
"boll": (
|
||||
"Bollinger Middle: A 20 SMA serving as the basis for Bollinger Bands. "
|
||||
"Usage: Acts as a dynamic benchmark for price movement. "
|
||||
"Tips: Combine with the upper and lower bands to effectively spot breakouts or reversals."
|
||||
),
|
||||
"boll_ub": (
|
||||
"Bollinger Upper Band: Typically 2 standard deviations above the middle line. "
|
||||
"Usage: Signals potential overbought conditions and breakout zones. "
|
||||
"Tips: Confirm signals with other tools; prices may ride the band in strong trends."
|
||||
),
|
||||
"boll_lb": (
|
||||
"Bollinger Lower Band: Typically 2 standard deviations below the middle line. "
|
||||
"Usage: Indicates potential oversold conditions. "
|
||||
"Tips: Use additional analysis to avoid false reversal signals."
|
||||
),
|
||||
"atr": (
|
||||
"ATR: Averages true range to measure volatility. "
|
||||
"Usage: Set stop-loss levels and adjust position sizes based on current market volatility. "
|
||||
"Tips: It's a reactive measure, so use it as part of a broader risk management strategy."
|
||||
),
|
||||
# Volume-Based Indicators
|
||||
"vwma": (
|
||||
"VWMA: A moving average weighted by volume. "
|
||||
"Usage: Confirm trends by integrating price action with volume data. "
|
||||
"Tips: Watch for skewed results from volume spikes; use in combination with other volume analyses."
|
||||
),
|
||||
"mfi": (
|
||||
"MFI: The Money Flow Index is a momentum indicator that uses both price and volume to measure buying and selling pressure. "
|
||||
"Usage: Identify overbought (>80) or oversold (<20) conditions and confirm the strength of trends or reversals. "
|
||||
"Tips: Use alongside RSI or MACD to confirm signals; divergence between price and MFI can indicate potential reversals."
|
||||
),
|
||||
}
|
||||
|
||||
# 2. Calculate Date Range
|
||||
target_date_dt = datetime.strptime(curr_date, "%Y-%m-%d")
|
||||
start_window_dt = target_date_dt - timedelta(days=look_back_days)
|
||||
|
||||
# Buffer: Fetch 250 extra days before start_window for lagging indicators (like 200 SMA)
|
||||
buffer_days = 250
|
||||
fetch_start_dt = start_window_dt - timedelta(days=buffer_days)
|
||||
|
||||
# Convert to timestamps for Bybit (ms)
|
||||
ts_start = int(fetch_start_dt.timestamp() * 1000)
|
||||
ts_end = int((target_date_dt + timedelta(days=1)).timestamp() * 1000)
|
||||
|
||||
# 3. Fetch Data from Bybit
|
||||
params = {
|
||||
"category": "linear",
|
||||
"symbol": symbol2.upper(),
|
||||
"interval": "D",
|
||||
"start": ts_start,
|
||||
"end": ts_end,
|
||||
"limit": 1000
|
||||
}
|
||||
|
||||
# Ensure 'bybit_v5_request' is defined in your scope
|
||||
data = bybit_v5_request("GET", "/v5/market/kline", params)
|
||||
raw_list = data.get("result", {}).get("list", [])
|
||||
|
||||
if not raw_list:
|
||||
return f"Error: No data found for {symbol2}."
|
||||
|
||||
# 4. Prepare DataFrame
|
||||
parsed_data = []
|
||||
for row in raw_list:
|
||||
parsed_data.append({
|
||||
# Standardize date format for the Index
|
||||
"date": datetime.fromtimestamp(int(row[0])/1000).strftime('%Y-%m-%d'),
|
||||
"open": float(row[1]),
|
||||
"high": float(row[2]),
|
||||
"low": float(row[3]),
|
||||
"close": float(row[4]),
|
||||
"volume": float(row[5])
|
||||
})
|
||||
|
||||
df = pd.DataFrame(parsed_data)
|
||||
# Sort Ascending (Oldest -> Newest) is CRITICAL for stockstats
|
||||
df = df.sort_values("date").reset_index(drop=True)
|
||||
|
||||
# 5. Calculate Indicator
|
||||
# retype(df) sets 'date' column as the Index!
|
||||
stock = StockDataFrame.retype(df)
|
||||
|
||||
try:
|
||||
# Trigger calculation
|
||||
_ = stock[indicator]
|
||||
except KeyError:
|
||||
return f"Error: Could not calculate {indicator}. Check if supported."
|
||||
|
||||
# 6. Build Report
|
||||
report_lines = []
|
||||
current_check_date = target_date_dt
|
||||
|
||||
while current_check_date >= start_window_dt:
|
||||
date_str = current_check_date.strftime('%Y-%m-%d')
|
||||
|
||||
# --- FIX: Use .loc to find the row by Index (Date) ---
|
||||
try:
|
||||
# Locate the row using the date string index
|
||||
val = stock.loc[date_str][indicator]
|
||||
|
||||
# Format value
|
||||
if isinstance(val, (float, int)):
|
||||
val_str = f"{val:.4f}"
|
||||
else:
|
||||
val_str = str(val)
|
||||
|
||||
report_lines.append(f"{date_str}: {val_str}")
|
||||
|
||||
except KeyError:
|
||||
# Date not found in index
|
||||
report_lines.append(f"{date_str}: N/A (No Data)")
|
||||
except Exception as e:
|
||||
report_lines.append(f"{date_str}: Error ({str(e)})")
|
||||
|
||||
current_check_date -= timedelta(days=1)
|
||||
|
||||
# 7. Final Output
|
||||
description = best_ind_params.get(indicator, "No description available.")
|
||||
|
||||
result_str = (
|
||||
f"## {indicator} values for {symbol2} from {start_window_dt.strftime('%Y-%m-%d')} to {curr_date}:\n\n"
|
||||
+ "\n".join(report_lines)
|
||||
+ "\n\n"
|
||||
+ description
|
||||
)
|
||||
|
||||
return result_str
|
||||
|
||||
def get_crypto_indicators_bulk(
|
||||
symbol: str,
|
||||
indicators: List[str],
|
||||
curr_date: str,
|
||||
look_back_days: int
|
||||
) -> str:
|
||||
"""
|
||||
Calculates multiple technical indicators for a crypto pair in one go.
|
||||
|
||||
Args:
|
||||
symbol: e.g., "BTC/USDT"
|
||||
indicators: List of keys, e.g. ["rsi", "close_200_sma", "macd"]
|
||||
curr_date: "YYYY-MM-DD"
|
||||
look_back_days: Days of history to show in the report.
|
||||
"""
|
||||
if "/" not in symbol:
|
||||
return f"Error: Symbol '{symbol}' is not in the correct format. Please use 'BASE/QUOTE' format, e.g., 'BTC/USDT'."
|
||||
base_coin, quote_coin = symbol.split("/")
|
||||
symbol2 = get_symbol(base_coin, quote_coin)
|
||||
|
||||
# 1. Define Descriptions
|
||||
best_ind_params = {
|
||||
"close_50_sma": (
|
||||
"50 SMA: A medium-term trend indicator. "
|
||||
"Usage: Identify trend direction and serve as dynamic support/resistance. "
|
||||
"Tips: It lags price; combine with faster indicators for timely signals."
|
||||
),
|
||||
"close_200_sma": (
|
||||
"200 SMA: A long-term trend benchmark. "
|
||||
"Usage: Confirm overall market trend and identify golden/death cross setups. "
|
||||
"Tips: It reacts slowly; best for strategic trend confirmation rather than frequent trading entries."
|
||||
),
|
||||
"close_10_ema": (
|
||||
"10 EMA: A responsive short-term average. "
|
||||
"Usage: Capture quick shifts in momentum and potential entry points. "
|
||||
"Tips: Prone to noise in choppy markets; use alongside longer averages for filtering false signals."
|
||||
),
|
||||
# MACD Related
|
||||
"macd": (
|
||||
"MACD: Computes momentum via differences of EMAs. "
|
||||
"Usage: Look for crossovers and divergence as signals of trend changes. "
|
||||
"Tips: Confirm with other indicators in low-volatility or sideways markets."
|
||||
),
|
||||
"macds": (
|
||||
"MACD Signal: An EMA smoothing of the MACD line. "
|
||||
"Usage: Use crossovers with the MACD line to trigger trades. "
|
||||
"Tips: Should be part of a broader strategy to avoid false positives."
|
||||
),
|
||||
"macdh": (
|
||||
"MACD Histogram: Shows the gap between the MACD line and its signal. "
|
||||
"Usage: Visualize momentum strength and spot divergence early. "
|
||||
"Tips: Can be volatile; complement with additional filters in fast-moving markets."
|
||||
),
|
||||
# Momentum Indicators
|
||||
"rsi": (
|
||||
"RSI: Measures momentum to flag overbought/oversold conditions. "
|
||||
"Usage: Apply 70/30 thresholds and watch for divergence to signal reversals. "
|
||||
"Tips: In strong trends, RSI may remain extreme; always cross-check with trend analysis."
|
||||
),
|
||||
# Volatility Indicators
|
||||
"boll": (
|
||||
"Bollinger Middle: A 20 SMA serving as the basis for Bollinger Bands. "
|
||||
"Usage: Acts as a dynamic benchmark for price movement. "
|
||||
"Tips: Combine with the upper and lower bands to effectively spot breakouts or reversals."
|
||||
),
|
||||
"boll_ub": (
|
||||
"Bollinger Upper Band: Typically 2 standard deviations above the middle line. "
|
||||
"Usage: Signals potential overbought conditions and breakout zones. "
|
||||
"Tips: Confirm signals with other tools; prices may ride the band in strong trends."
|
||||
),
|
||||
"boll_lb": (
|
||||
"Bollinger Lower Band: Typically 2 standard deviations below the middle line. "
|
||||
"Usage: Indicates potential oversold conditions. "
|
||||
"Tips: Use additional analysis to avoid false reversal signals."
|
||||
),
|
||||
"atr": (
|
||||
"ATR: Averages true range to measure volatility. "
|
||||
"Usage: Set stop-loss levels and adjust position sizes based on current market volatility. "
|
||||
"Tips: It's a reactive measure, so use it as part of a broader risk management strategy."
|
||||
),
|
||||
# Volume-Based Indicators
|
||||
"vwma": (
|
||||
"VWMA: A moving average weighted by volume. "
|
||||
"Usage: Confirm trends by integrating price action with volume data. "
|
||||
"Tips: Watch for skewed results from volume spikes; use in combination with other volume analyses."
|
||||
),
|
||||
"mfi": (
|
||||
"MFI: The Money Flow Index is a momentum indicator that uses both price and volume to measure buying and selling pressure. "
|
||||
"Usage: Identify overbought (>80) or oversold (<20) conditions and confirm the strength of trends or reversals. "
|
||||
"Tips: Use alongside RSI or MACD to confirm signals; divergence between price and MFI can indicate potential reversals."
|
||||
),
|
||||
}
|
||||
|
||||
# 2. Fetch Data (ONLY ONCE)
|
||||
# ---------------------------------------------------------
|
||||
target_date_dt = datetime.strptime(curr_date, "%Y-%m-%d")
|
||||
start_window_dt = target_date_dt - timedelta(days=look_back_days)
|
||||
|
||||
# Buffer for lagging indicators
|
||||
buffer_days = 250
|
||||
fetch_start_dt = start_window_dt - timedelta(days=buffer_days)
|
||||
|
||||
ts_start = int(fetch_start_dt.timestamp() * 1000)
|
||||
ts_end = int((target_date_dt + timedelta(days=1)).timestamp() * 1000)
|
||||
|
||||
params = {
|
||||
"category": "linear",
|
||||
"symbol": symbol2.upper(),
|
||||
"interval": "D",
|
||||
"start": ts_start,
|
||||
"end": ts_end,
|
||||
"limit": 1000
|
||||
}
|
||||
|
||||
data = bybit_v5_request("GET", "/v5/market/kline", params)
|
||||
raw_list = data.get("result", {}).get("list", [])
|
||||
|
||||
if not raw_list:
|
||||
return f"Error: No data found for {symbol2}."
|
||||
|
||||
parsed_data = []
|
||||
for row in raw_list:
|
||||
parsed_data.append({
|
||||
"date": datetime.fromtimestamp(int(row[0])/1000).strftime('%Y-%m-%d'),
|
||||
"open": float(row[1]),
|
||||
"high": float(row[2]),
|
||||
"low": float(row[3]),
|
||||
"close": float(row[4]),
|
||||
"volume": float(row[5])
|
||||
})
|
||||
|
||||
df = pd.DataFrame(parsed_data)
|
||||
df = df.sort_values("date").reset_index(drop=True)
|
||||
stock = StockDataFrame.retype(df)
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# 3. Process Each Indicator
|
||||
final_report = [f"# Technical Indicators Report for {symbol2}\n" + '-' * 40]
|
||||
|
||||
for ind in indicators:
|
||||
# Pre-calculation check
|
||||
try:
|
||||
# Trigger calculation of the specific column
|
||||
_ = stock[ind]
|
||||
except (KeyError, ValueError):
|
||||
final_report.append(f"## Error: Indicator '{ind}' is not supported or failed to calculate.\n")
|
||||
continue
|
||||
|
||||
# Generate Block Report
|
||||
report_lines = []
|
||||
current_check_date = target_date_dt
|
||||
|
||||
while current_check_date >= start_window_dt:
|
||||
date_str = current_check_date.strftime('%Y-%m-%d')
|
||||
try:
|
||||
# Use .loc because 'date' is the index
|
||||
val = stock.loc[date_str][ind]
|
||||
|
||||
if isinstance(val, (float, int)):
|
||||
val_str = f"{val:.4f}"
|
||||
else:
|
||||
val_str = str(val)
|
||||
report_lines.append(f"{date_str}: {val_str}")
|
||||
except KeyError:
|
||||
report_lines.append(f"{date_str}: N/A")
|
||||
|
||||
current_check_date -= timedelta(days=1)
|
||||
|
||||
description = best_ind_params.get(ind, "No description available.")
|
||||
|
||||
block = (
|
||||
f"## {ind} values for {symbol2} from {start_window_dt.strftime('%Y-%m-%d')} to {curr_date}:\n\n"
|
||||
+ "\n".join(report_lines)
|
||||
+ "\n\n"
|
||||
+ f"Description: {description}\n"
|
||||
+ "-" * 40 # Separator line
|
||||
)
|
||||
final_report.append(block)
|
||||
|
||||
return "\n\n".join(final_report)
|
||||
|
||||
def get_order_status(order_id: str, category: str = "spot") -> Dict:
|
||||
"""
|
||||
Get order status by order ID.
|
||||
|
|
@ -213,28 +673,6 @@ def cancel_order(order_id: str, symbol: str, category: str = "spot") -> Dict:
|
|||
return data.get("result", {})
|
||||
|
||||
|
||||
# def get_open_orders(symbol: Optional[str] = None, category: str = "spot") -> Dict:
|
||||
# """
|
||||
# Get all open orders.
|
||||
|
||||
# Args:
|
||||
# symbol: Optional trading pair to filter by
|
||||
# category: Trading category ("spot", "linear", "inverse")
|
||||
|
||||
# Returns:
|
||||
# Dict containing list of open orders
|
||||
# """
|
||||
# params = {
|
||||
# "category": category.lower()
|
||||
# }
|
||||
|
||||
# if symbol:
|
||||
# params["symbol"] = symbol.upper()
|
||||
|
||||
# data = bybit_v5_request("GET", "/v5/order/realtime", params=params)
|
||||
# return data.get("result", {})
|
||||
|
||||
|
||||
def get_order_history(
|
||||
symbol: Optional[str] = None,
|
||||
category: str = "spot",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ from .taapi import get_crypto_stats_indicators_window, get_crypto_stats_indicato
|
|||
|
||||
# Configuration and routing logic
|
||||
from .config import get_config
|
||||
from .bybit import (
|
||||
get_account_balance,
|
||||
get_open_orders,
|
||||
get_market_data as get_bybit_crypto_data,
|
||||
get_crypto_indicator_window as get_bybit_crypto_indicator_window,
|
||||
get_crypto_indicators_bulk as get_bybit_crypto_indicators_bulk
|
||||
)
|
||||
|
||||
# Tools organized by category
|
||||
TOOLS_CATEGORIES = {
|
||||
|
|
@ -65,6 +72,13 @@ TOOLS_CATEGORIES = {
|
|||
"get_insider_transactions",
|
||||
"get_fear_and_greed"
|
||||
]
|
||||
},
|
||||
"profile_data": {
|
||||
"description": "User profile related data",
|
||||
"tools": [
|
||||
"get_account_balance",
|
||||
"get_open_orders",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +91,8 @@ VENDOR_LIST = [
|
|||
"telegram",
|
||||
"coin_gecko",
|
||||
"alpha_vantage",
|
||||
"taapi"
|
||||
"taapi",
|
||||
"bybit"
|
||||
]
|
||||
|
||||
# Mapping of methods to their vendor-specific implementations
|
||||
|
|
@ -90,16 +105,19 @@ VENDOR_METHODS = {
|
|||
# core_crypto_apis
|
||||
"get_crypto_data": {
|
||||
"binance": get_binance_crypto_data,
|
||||
"bybit": get_bybit_crypto_data,
|
||||
},
|
||||
# technical_indicators
|
||||
"get_indicators": {
|
||||
"taapi": get_crypto_stats_indicators_window,
|
||||
# "taapi": get_crypto_stats_indicators_window,
|
||||
"bybit" : get_bybit_crypto_indicator_window
|
||||
# "alpha_vantage": get_alpha_vantage_indicator,
|
||||
# "yfinance": get_stock_stats_indicators_window,
|
||||
# "local": get_stock_stats_indicators_window
|
||||
},
|
||||
"get_indicators_bulk": {
|
||||
"taapi": get_crypto_stats_indicators,
|
||||
# "taapi": get_crypto_stats_indicators,
|
||||
"bybit": get_bybit_crypto_indicators_bulk
|
||||
},
|
||||
# fundamental_data
|
||||
"get_fundamentals": {
|
||||
|
|
@ -150,6 +168,12 @@ VENDOR_METHODS = {
|
|||
"get_fear_and_greed": {
|
||||
"local": get_fear_and_greed,
|
||||
},
|
||||
"get_account_balance": {
|
||||
"bybit": get_account_balance,
|
||||
},
|
||||
"get_open_orders": {
|
||||
"bybit": get_open_orders,
|
||||
},
|
||||
}
|
||||
|
||||
def get_category_for_method(method: str) -> str:
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ DEFAULT_CONFIG = {
|
|||
# Data vendor configuration
|
||||
# Category-level configuration (default for all tools in category)
|
||||
"data_vendors": {
|
||||
"core_crypto_apis": "binance", # Options: binance
|
||||
"core_crypto_apis": "bybit", # Options: binance, bybit
|
||||
"core_stock_apis": "yfinance", # Options: yfinance, alpha_vantage, local
|
||||
"technical_indicators": "taapi", # Options: taapi
|
||||
"technical_indicators": "bybit", # Options: bybit
|
||||
"fundamental_data": "alpha_vantage", # Options: openai, alpha_vantage, local
|
||||
"news_data": "openai", # Options: openai, alpha_vantage, google, local
|
||||
"profile_data": "bybit", # Options: bybit, local
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@ class ConditionalLogic:
|
|||
if last_message.tool_calls:
|
||||
return "tools_fundamentals"
|
||||
return "Msg Clear Fundamentals"
|
||||
|
||||
def should_continue_profile(self, state: AgentState):
|
||||
"""Determine if profile analysis should continue."""
|
||||
messages = state["messages"]
|
||||
last_message = messages[-1]
|
||||
if last_message.tool_calls:
|
||||
return "tools_profile"
|
||||
return "Msg Clear Profile"
|
||||
|
||||
def should_continue_debate(self, state: AgentState) -> str:
|
||||
"""Determine if debate should continue."""
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class Propagator:
|
|||
"fundamentals_report": "",
|
||||
"sentiment_report": "",
|
||||
"news_report": "",
|
||||
"profile_report": "",
|
||||
}
|
||||
|
||||
def get_graph_args(self) -> Dict[str, Any]:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Your goal is to deliver detailed insights into investment decisions and highligh
|
|||
- Price movement analysis.
|
||||
- Overall market data analysis
|
||||
- News analysis.
|
||||
- Sentiment analysis.
|
||||
- Social media and sentiment analysis.
|
||||
- Fundamental data analysis.
|
||||
- Weight the importance of each factor in the decision-making process.
|
||||
|
|
@ -52,8 +53,9 @@ Adhere strictly to these instructions, and ensure your output is detailed, accur
|
|||
curr_sentiment_report = current_state["sentiment_report"]
|
||||
curr_news_report = current_state["news_report"]
|
||||
curr_fundamentals_report = current_state["fundamentals_report"]
|
||||
curr_profile_report = current_state["profile_report"]
|
||||
|
||||
return f"{curr_market_report}\n\n{curr_sentiment_report}\n\n{curr_news_report}\n\n{curr_fundamentals_report}"
|
||||
return f"{curr_market_report}\n\n{curr_sentiment_report}\n\n{curr_news_report}\n\n{curr_fundamentals_report}\n\n{curr_profile_report}"
|
||||
|
||||
def _reflect_on_component(
|
||||
self, component_type: str, report: str, situation: str, returns_losses
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class GraphSetup:
|
|||
self.conditional_logic = conditional_logic
|
||||
|
||||
def setup_graph(
|
||||
self, selected_analysts=["market", "social", "news", "fundamentals"]
|
||||
self, selected_analysts=["market", "social", "news", "fundamentals", "profile"]
|
||||
):
|
||||
"""Set up and compile the agent workflow graph.
|
||||
|
||||
|
|
@ -48,6 +48,7 @@ class GraphSetup:
|
|||
- "social": Social media analyst
|
||||
- "news": News analyst
|
||||
- "fundamentals": Fundamentals analyst
|
||||
- "profile": Profile analyst
|
||||
"""
|
||||
if len(selected_analysts) == 0:
|
||||
raise ValueError("Trading Agents Graph Setup Error: no analysts selected!")
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ class TradingAgentsGraph:
|
|||
# Crypto data tools
|
||||
get_crypto_data,
|
||||
# Core stock data tools
|
||||
get_stock_data,
|
||||
# get_stock_data,
|
||||
# Technical indicators
|
||||
get_indicators,
|
||||
get_indicators_bulk,
|
||||
|
|
@ -221,6 +221,7 @@ class TradingAgentsGraph:
|
|||
"sentiment_report": final_state["sentiment_report"],
|
||||
"news_report": final_state["news_report"],
|
||||
"fundamentals_report": final_state["fundamentals_report"],
|
||||
"profile_report": final_state["profile_report"],
|
||||
"investment_debate_state": {
|
||||
"bull_history": final_state["investment_debate_state"]["bull_history"],
|
||||
"bear_history": final_state["investment_debate_state"]["bear_history"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue