quantalogic 0.35.0__py3-none-any.whl → 0.40.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quantalogic/__init__.py +0 -4
- quantalogic/agent.py +603 -363
- quantalogic/agent_config.py +233 -46
- quantalogic/agent_factory.py +34 -22
- quantalogic/coding_agent.py +16 -14
- quantalogic/config.py +2 -1
- quantalogic/console_print_events.py +4 -8
- quantalogic/console_print_token.py +2 -2
- quantalogic/docs_cli.py +15 -10
- quantalogic/event_emitter.py +258 -83
- quantalogic/flow/__init__.py +23 -0
- quantalogic/flow/flow.py +595 -0
- quantalogic/flow/flow_extractor.py +672 -0
- quantalogic/flow/flow_generator.py +89 -0
- quantalogic/flow/flow_manager.py +407 -0
- quantalogic/flow/flow_manager_schema.py +169 -0
- quantalogic/flow/flow_yaml.md +419 -0
- quantalogic/generative_model.py +109 -77
- quantalogic/get_model_info.py +5 -5
- quantalogic/interactive_text_editor.py +100 -73
- quantalogic/main.py +17 -21
- quantalogic/model_info_list.py +3 -3
- quantalogic/model_info_litellm.py +14 -14
- quantalogic/prompts.py +2 -1
- quantalogic/{llm.py → quantlitellm.py} +29 -39
- quantalogic/search_agent.py +4 -4
- quantalogic/server/models.py +4 -1
- quantalogic/task_file_reader.py +5 -5
- quantalogic/task_runner.py +20 -20
- quantalogic/tool_manager.py +10 -21
- quantalogic/tools/__init__.py +98 -68
- quantalogic/tools/composio/composio.py +416 -0
- quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py} +4 -9
- quantalogic/tools/database/sql_query_tool_advanced.py +261 -0
- quantalogic/tools/document_tools/markdown_to_docx_tool.py +620 -0
- quantalogic/tools/document_tools/markdown_to_epub_tool.py +438 -0
- quantalogic/tools/document_tools/markdown_to_html_tool.py +362 -0
- quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +319 -0
- quantalogic/tools/document_tools/markdown_to_latex_tool.py +420 -0
- quantalogic/tools/document_tools/markdown_to_pdf_tool.py +623 -0
- quantalogic/tools/document_tools/markdown_to_pptx_tool.py +319 -0
- quantalogic/tools/duckduckgo_search_tool.py +2 -4
- quantalogic/tools/finance/alpha_vantage_tool.py +440 -0
- quantalogic/tools/finance/ccxt_tool.py +373 -0
- quantalogic/tools/finance/finance_llm_tool.py +387 -0
- quantalogic/tools/finance/google_finance.py +192 -0
- quantalogic/tools/finance/market_intelligence_tool.py +520 -0
- quantalogic/tools/finance/technical_analysis_tool.py +491 -0
- quantalogic/tools/finance/tradingview_tool.py +336 -0
- quantalogic/tools/finance/yahoo_finance.py +236 -0
- quantalogic/tools/git/bitbucket_clone_repo_tool.py +181 -0
- quantalogic/tools/git/bitbucket_operations_tool.py +326 -0
- quantalogic/tools/git/clone_repo_tool.py +189 -0
- quantalogic/tools/git/git_operations_tool.py +532 -0
- quantalogic/tools/google_packages/google_news_tool.py +480 -0
- quantalogic/tools/grep_app_tool.py +123 -186
- quantalogic/tools/{dalle_e.py → image_generation/dalle_e.py} +37 -27
- quantalogic/tools/jinja_tool.py +6 -10
- quantalogic/tools/language_handlers/__init__.py +22 -9
- quantalogic/tools/list_directory_tool.py +131 -42
- quantalogic/tools/llm_tool.py +45 -15
- quantalogic/tools/llm_vision_tool.py +59 -7
- quantalogic/tools/markitdown_tool.py +17 -5
- quantalogic/tools/nasa_packages/models.py +47 -0
- quantalogic/tools/nasa_packages/nasa_apod_tool.py +232 -0
- quantalogic/tools/nasa_packages/nasa_neows_tool.py +147 -0
- quantalogic/tools/nasa_packages/services.py +82 -0
- quantalogic/tools/presentation_tools/presentation_llm_tool.py +396 -0
- quantalogic/tools/product_hunt/product_hunt_tool.py +258 -0
- quantalogic/tools/product_hunt/services.py +63 -0
- quantalogic/tools/rag_tool/__init__.py +48 -0
- quantalogic/tools/rag_tool/document_metadata.py +15 -0
- quantalogic/tools/rag_tool/query_response.py +20 -0
- quantalogic/tools/rag_tool/rag_tool.py +566 -0
- quantalogic/tools/rag_tool/rag_tool_beta.py +264 -0
- quantalogic/tools/read_html_tool.py +24 -38
- quantalogic/tools/replace_in_file_tool.py +10 -10
- quantalogic/tools/safe_python_interpreter_tool.py +10 -24
- quantalogic/tools/search_definition_names.py +2 -2
- quantalogic/tools/sequence_tool.py +14 -23
- quantalogic/tools/sql_query_tool.py +17 -19
- quantalogic/tools/tool.py +39 -15
- quantalogic/tools/unified_diff_tool.py +1 -1
- quantalogic/tools/utilities/csv_processor_tool.py +234 -0
- quantalogic/tools/utilities/download_file_tool.py +179 -0
- quantalogic/tools/utilities/mermaid_validator_tool.py +661 -0
- quantalogic/tools/utils/__init__.py +1 -4
- quantalogic/tools/utils/create_sample_database.py +24 -38
- quantalogic/tools/utils/generate_database_report.py +74 -82
- quantalogic/tools/wikipedia_search_tool.py +17 -21
- quantalogic/utils/ask_user_validation.py +1 -1
- quantalogic/utils/async_utils.py +35 -0
- quantalogic/utils/check_version.py +3 -5
- quantalogic/utils/get_all_models.py +2 -1
- quantalogic/utils/git_ls.py +21 -7
- quantalogic/utils/lm_studio_model_info.py +9 -7
- quantalogic/utils/python_interpreter.py +113 -43
- quantalogic/utils/xml_utility.py +178 -0
- quantalogic/version_check.py +1 -1
- quantalogic/welcome_message.py +7 -7
- quantalogic/xml_parser.py +0 -1
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/METADATA +41 -1
- quantalogic-0.40.0.dist-info/RECORD +148 -0
- quantalogic-0.35.0.dist-info/RECORD +0 -102
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,440 @@
|
|
1
|
+
import asyncio
|
2
|
+
import json
|
3
|
+
import time
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
5
|
+
from dataclasses import dataclass
|
6
|
+
from enum import Enum
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import Any, ClassVar, Dict, List
|
9
|
+
|
10
|
+
import numpy as np
|
11
|
+
import pandas as pd
|
12
|
+
import requests
|
13
|
+
import ta
|
14
|
+
from loguru import logger
|
15
|
+
from pydantic import model_validator
|
16
|
+
|
17
|
+
from quantalogic.tools import Tool, ToolArgument
|
18
|
+
|
19
|
+
|
20
|
+
class AssetType(str, Enum):
|
21
|
+
STOCK = "stock"
|
22
|
+
FOREX = "forex"
|
23
|
+
CRYPTO = "crypto"
|
24
|
+
COMMODITY = "commodity"
|
25
|
+
ETF = "etf"
|
26
|
+
INDEX = "index"
|
27
|
+
|
28
|
+
class DataType(str, Enum):
|
29
|
+
INTRADAY = "intraday"
|
30
|
+
DAILY = "daily"
|
31
|
+
WEEKLY = "weekly"
|
32
|
+
MONTHLY = "monthly"
|
33
|
+
QUOTE = "quote"
|
34
|
+
SEARCH = "search"
|
35
|
+
FUNDAMENTAL = "fundamental"
|
36
|
+
ECONOMIC = "economic"
|
37
|
+
NEWS = "news"
|
38
|
+
|
39
|
+
@dataclass
|
40
|
+
class MarketData:
|
41
|
+
"""Container for market data and analysis."""
|
42
|
+
symbol: str
|
43
|
+
asset_type: AssetType
|
44
|
+
interval: str
|
45
|
+
data: pd.DataFrame
|
46
|
+
metadata: Dict[str, Any] = None
|
47
|
+
indicators: Dict[str, pd.Series] = None
|
48
|
+
fundamental_data: Dict[str, Any] = None
|
49
|
+
news_sentiment: Dict[str, Any] = None
|
50
|
+
economic_data: Dict[str, Any] = None
|
51
|
+
|
52
|
+
class AlphaVantageTool(Tool):
|
53
|
+
"""Advanced multi-asset financial data and analysis tool using Alpha Vantage."""
|
54
|
+
|
55
|
+
name: ClassVar[str] = "alpha_vantage_tool"
|
56
|
+
description: ClassVar[str] = "Enhanced multi-asset financial data and analysis tool using Alpha Vantage API"
|
57
|
+
|
58
|
+
INTERVALS: ClassVar[List[str]] = ['1min', '5min', '15min', '30min', '60min', 'daily', 'weekly', 'monthly']
|
59
|
+
|
60
|
+
# Rate limiting settings
|
61
|
+
MAX_REQUESTS_PER_MINUTE: ClassVar[int] = 5
|
62
|
+
last_request_time: float = 0
|
63
|
+
|
64
|
+
arguments: ClassVar[list[ToolArgument]] = [
|
65
|
+
ToolArgument(
|
66
|
+
name="symbols",
|
67
|
+
arg_type="string",
|
68
|
+
description="Comma-separated list of symbols (e.g., 'AAPL,MSFT,GOOGL')",
|
69
|
+
required=True
|
70
|
+
),
|
71
|
+
ToolArgument(
|
72
|
+
name="asset_type",
|
73
|
+
arg_type="string",
|
74
|
+
description="Type of asset (stock/forex/crypto)",
|
75
|
+
required=True
|
76
|
+
),
|
77
|
+
ToolArgument(
|
78
|
+
name="function",
|
79
|
+
arg_type="string",
|
80
|
+
description="Alpha Vantage function (TIME_SERIES_INTRADAY/DAILY/WEEKLY/MONTHLY)",
|
81
|
+
required=True
|
82
|
+
),
|
83
|
+
ToolArgument(
|
84
|
+
name="interval",
|
85
|
+
arg_type="string",
|
86
|
+
description="Time interval (1min/5min/15min/30min/60min) - only for intraday",
|
87
|
+
required=False,
|
88
|
+
default="5min"
|
89
|
+
),
|
90
|
+
ToolArgument(
|
91
|
+
name="outputsize",
|
92
|
+
arg_type="string",
|
93
|
+
description="Output size (compact/full)",
|
94
|
+
required=False,
|
95
|
+
default="compact"
|
96
|
+
),
|
97
|
+
ToolArgument(
|
98
|
+
name="api_key",
|
99
|
+
arg_type="string",
|
100
|
+
description="Alpha Vantage API key",
|
101
|
+
required=True
|
102
|
+
),
|
103
|
+
ToolArgument(
|
104
|
+
name="indicators",
|
105
|
+
arg_type="string",
|
106
|
+
description="Comma-separated technical indicators to calculate (e.g., 'SMA,RSI,MACD')",
|
107
|
+
required=False,
|
108
|
+
default="all"
|
109
|
+
),
|
110
|
+
ToolArgument(
|
111
|
+
name="lookback_periods",
|
112
|
+
arg_type="string",
|
113
|
+
description="Number of periods to analyze",
|
114
|
+
required=False,
|
115
|
+
default="500"
|
116
|
+
)
|
117
|
+
]
|
118
|
+
|
119
|
+
@model_validator(mode='before')
|
120
|
+
def validate_arguments(cls, values):
|
121
|
+
"""Validate tool arguments."""
|
122
|
+
try:
|
123
|
+
# Validate interval format
|
124
|
+
if 'interval' in values and values['interval'] not in cls.INTERVALS:
|
125
|
+
raise ValueError(f"Invalid interval: {values['interval']}")
|
126
|
+
|
127
|
+
# Validate symbols and asset types match
|
128
|
+
if len(values.get('symbols', '').split(',')) != len(values.get('asset_type', '').split(',')):
|
129
|
+
raise ValueError("Number of symbols must match number of asset types")
|
130
|
+
|
131
|
+
return values
|
132
|
+
except Exception as e:
|
133
|
+
logger.error(f"Error validating arguments: {e}")
|
134
|
+
raise
|
135
|
+
|
136
|
+
def __init__(self, **kwargs):
|
137
|
+
super().__init__(**kwargs)
|
138
|
+
self.api_key = None
|
139
|
+
self.base_url = "https://www.alphavantage.co/query"
|
140
|
+
self.cache = {}
|
141
|
+
self.executor = ThreadPoolExecutor(max_workers=4)
|
142
|
+
|
143
|
+
def _load_api_key(self, api_key_path: str) -> None:
|
144
|
+
"""Load Alpha Vantage API key from config file."""
|
145
|
+
try:
|
146
|
+
config_path = Path(api_key_path)
|
147
|
+
if config_path.exists():
|
148
|
+
with open(config_path) as f:
|
149
|
+
config = json.load(f)
|
150
|
+
self.api_key = config.get('api_key')
|
151
|
+
if not self.api_key:
|
152
|
+
raise ValueError("API key not found in config file")
|
153
|
+
except Exception as e:
|
154
|
+
logger.error(f"Error loading API key: {e}")
|
155
|
+
raise
|
156
|
+
|
157
|
+
async def _make_request(self, params: Dict[str, str]) -> Dict:
|
158
|
+
"""Make rate-limited request to Alpha Vantage API."""
|
159
|
+
try:
|
160
|
+
# Implement rate limiting
|
161
|
+
current_time = time.time()
|
162
|
+
time_since_last_request = current_time - self.last_request_time
|
163
|
+
if time_since_last_request < (60 / self.MAX_REQUESTS_PER_MINUTE):
|
164
|
+
await asyncio.sleep((60 / self.MAX_REQUESTS_PER_MINUTE) - time_since_last_request)
|
165
|
+
|
166
|
+
params['apikey'] = self.api_key
|
167
|
+
|
168
|
+
# Make request using ThreadPoolExecutor for blocking IO
|
169
|
+
response = await asyncio.get_event_loop().run_in_executor(
|
170
|
+
self.executor,
|
171
|
+
lambda: requests.get(self.base_url, params=params)
|
172
|
+
)
|
173
|
+
response.raise_for_status()
|
174
|
+
|
175
|
+
self.last_request_time = time.time()
|
176
|
+
return response.json()
|
177
|
+
|
178
|
+
except Exception as e:
|
179
|
+
logger.error(f"Error making API request: {e}")
|
180
|
+
raise
|
181
|
+
|
182
|
+
async def _fetch_time_series(
|
183
|
+
self,
|
184
|
+
symbol: str,
|
185
|
+
asset_type: AssetType,
|
186
|
+
interval: str,
|
187
|
+
output_size: str
|
188
|
+
) -> MarketData:
|
189
|
+
"""Fetch time series data for any asset type."""
|
190
|
+
try:
|
191
|
+
# Determine the appropriate API function
|
192
|
+
function = self._get_time_series_function(asset_type, interval)
|
193
|
+
|
194
|
+
params = {
|
195
|
+
'function': function,
|
196
|
+
'symbol': symbol,
|
197
|
+
'outputsize': output_size
|
198
|
+
}
|
199
|
+
|
200
|
+
if 'INTRADAY' in function:
|
201
|
+
params['interval'] = interval
|
202
|
+
|
203
|
+
data = await self._make_request(params)
|
204
|
+
|
205
|
+
# Parse the response into a DataFrame
|
206
|
+
time_series_key = [k for k in data.keys() if 'Time Series' in k][0]
|
207
|
+
df = pd.DataFrame.from_dict(data[time_series_key], orient='index')
|
208
|
+
|
209
|
+
# Clean up column names and convert to numeric
|
210
|
+
df.columns = [col.split('. ')[1].lower() for col in df.columns]
|
211
|
+
for col in df.columns:
|
212
|
+
df[col] = pd.to_numeric(df[col])
|
213
|
+
|
214
|
+
df.index = pd.to_datetime(df.index)
|
215
|
+
|
216
|
+
return MarketData(
|
217
|
+
symbol=symbol,
|
218
|
+
asset_type=asset_type,
|
219
|
+
interval=interval,
|
220
|
+
data=df,
|
221
|
+
metadata=data.get('Meta Data')
|
222
|
+
)
|
223
|
+
|
224
|
+
except Exception as e:
|
225
|
+
logger.error(f"Error fetching time series data for {symbol}: {e}")
|
226
|
+
raise
|
227
|
+
|
228
|
+
async def _fetch_fundamental_data(self, symbol: str) -> Dict[str, Any]:
|
229
|
+
"""Fetch comprehensive fundamental data for stocks."""
|
230
|
+
try:
|
231
|
+
fundamental_data = {}
|
232
|
+
|
233
|
+
# Company Overview
|
234
|
+
overview = await self._make_request({
|
235
|
+
'function': 'OVERVIEW',
|
236
|
+
'symbol': symbol
|
237
|
+
})
|
238
|
+
fundamental_data['overview'] = overview
|
239
|
+
|
240
|
+
# Income Statement
|
241
|
+
income_stmt = await self._make_request({
|
242
|
+
'function': 'INCOME_STATEMENT',
|
243
|
+
'symbol': symbol
|
244
|
+
})
|
245
|
+
fundamental_data['income_statement'] = income_stmt
|
246
|
+
|
247
|
+
# Balance Sheet
|
248
|
+
balance_sheet = await self._make_request({
|
249
|
+
'function': 'BALANCE_SHEET',
|
250
|
+
'symbol': symbol
|
251
|
+
})
|
252
|
+
fundamental_data['balance_sheet'] = balance_sheet
|
253
|
+
|
254
|
+
# Cash Flow
|
255
|
+
cash_flow = await self._make_request({
|
256
|
+
'function': 'CASH_FLOW',
|
257
|
+
'symbol': symbol
|
258
|
+
})
|
259
|
+
fundamental_data['cash_flow'] = cash_flow
|
260
|
+
|
261
|
+
# Earnings
|
262
|
+
earnings = await self._make_request({
|
263
|
+
'function': 'EARNINGS',
|
264
|
+
'symbol': symbol
|
265
|
+
})
|
266
|
+
fundamental_data['earnings'] = earnings
|
267
|
+
|
268
|
+
return fundamental_data
|
269
|
+
|
270
|
+
except Exception as e:
|
271
|
+
logger.error(f"Error fetching fundamental data for {symbol}: {e}")
|
272
|
+
raise
|
273
|
+
|
274
|
+
async def _fetch_economic_data(self, indicators: List[str]) -> Dict[str, pd.DataFrame]:
|
275
|
+
"""Fetch economic indicators data."""
|
276
|
+
try:
|
277
|
+
economic_data = {}
|
278
|
+
|
279
|
+
for indicator in indicators:
|
280
|
+
data = await self._make_request({
|
281
|
+
'function': indicator
|
282
|
+
})
|
283
|
+
|
284
|
+
# Convert to DataFrame
|
285
|
+
df = pd.DataFrame.from_dict(data['data'], orient='index')
|
286
|
+
df.index = pd.to_datetime(df.index)
|
287
|
+
economic_data[indicator] = df
|
288
|
+
|
289
|
+
return economic_data
|
290
|
+
|
291
|
+
except Exception as e:
|
292
|
+
logger.error(f"Error fetching economic data: {e}")
|
293
|
+
raise
|
294
|
+
|
295
|
+
async def _fetch_news_sentiment(self, symbols: List[str]) -> Dict[str, Any]:
|
296
|
+
"""Fetch news and sentiment data."""
|
297
|
+
try:
|
298
|
+
params = {
|
299
|
+
'function': 'NEWS_SENTIMENT',
|
300
|
+
'tickers': ','.join(symbols)
|
301
|
+
}
|
302
|
+
|
303
|
+
news_data = await self._make_request(params)
|
304
|
+
return news_data
|
305
|
+
|
306
|
+
except Exception as e:
|
307
|
+
logger.error(f"Error fetching news sentiment: {e}")
|
308
|
+
raise
|
309
|
+
|
310
|
+
def _calculate_technical_indicators(self, market_data: MarketData) -> None:
|
311
|
+
"""Calculate comprehensive technical indicators."""
|
312
|
+
df = market_data.data
|
313
|
+
indicators = {}
|
314
|
+
|
315
|
+
try:
|
316
|
+
# Trend Indicators
|
317
|
+
indicators['sma_20'] = ta.trend.sma_indicator(df['close'], 20)
|
318
|
+
indicators['sma_50'] = ta.trend.sma_indicator(df['close'], 50)
|
319
|
+
indicators['sma_200'] = ta.trend.sma_indicator(df['close'], 200)
|
320
|
+
indicators['ema_12'] = ta.trend.ema_indicator(df['close'], 12)
|
321
|
+
indicators['ema_26'] = ta.trend.ema_indicator(df['close'], 26)
|
322
|
+
indicators['macd'] = ta.trend.macd(df['close'])
|
323
|
+
indicators['macd_signal'] = ta.trend.macd_signal(df['close'])
|
324
|
+
indicators['adx'] = ta.trend.adx(df['high'], df['low'], df['close'])
|
325
|
+
|
326
|
+
# Momentum Indicators
|
327
|
+
indicators['rsi'] = ta.momentum.rsi(df['close'])
|
328
|
+
indicators['stoch'] = ta.momentum.stoch(df['high'], df['low'], df['close'])
|
329
|
+
indicators['stoch_signal'] = ta.momentum.stoch_signal(df['high'], df['low'], df['close'])
|
330
|
+
indicators['williams_r'] = ta.momentum.williams_r(df['high'], df['low'], df['close'])
|
331
|
+
|
332
|
+
# Volatility Indicators
|
333
|
+
indicators['bbands_upper'] = ta.volatility.bollinger_hband(df['close'])
|
334
|
+
indicators['bbands_lower'] = ta.volatility.bollinger_lband(df['close'])
|
335
|
+
indicators['atr'] = ta.volatility.average_true_range(df['high'], df['low'], df['close'])
|
336
|
+
|
337
|
+
# Volume Indicators
|
338
|
+
if 'volume' in df.columns:
|
339
|
+
indicators['obv'] = ta.volume.on_balance_volume(df['close'], df['volume'])
|
340
|
+
indicators['mfi'] = ta.volume.money_flow_index(df['high'], df['low'], df['close'], df['volume'])
|
341
|
+
|
342
|
+
market_data.indicators = indicators
|
343
|
+
|
344
|
+
except Exception as e:
|
345
|
+
logger.error(f"Error calculating technical indicators: {e}")
|
346
|
+
raise
|
347
|
+
|
348
|
+
def _get_time_series_function(self, asset_type: AssetType, interval: str) -> str:
|
349
|
+
"""Get the appropriate Alpha Vantage API function based on asset type and interval."""
|
350
|
+
if interval in ['1min', '5min', '15min', '30min', '60min']:
|
351
|
+
suffix = '_INTRADAY'
|
352
|
+
elif interval == 'daily':
|
353
|
+
suffix = '_DAILY'
|
354
|
+
elif interval == 'weekly':
|
355
|
+
suffix = '_WEEKLY'
|
356
|
+
else:
|
357
|
+
suffix = '_MONTHLY'
|
358
|
+
|
359
|
+
if asset_type == AssetType.STOCK:
|
360
|
+
return f'TIME_SERIES{suffix}'
|
361
|
+
elif asset_type == AssetType.FOREX:
|
362
|
+
return f'FX{suffix}'
|
363
|
+
elif asset_type == AssetType.CRYPTO:
|
364
|
+
return f'CRYPTO{suffix}'
|
365
|
+
elif asset_type == AssetType.COMMODITY:
|
366
|
+
return f'COMMODITY{suffix}'
|
367
|
+
else:
|
368
|
+
return f'TIME_SERIES{suffix}'
|
369
|
+
|
370
|
+
async def execute(self, **kwargs) -> Dict[str, Any]:
|
371
|
+
"""Execute the Alpha Vantage tool with comprehensive analysis."""
|
372
|
+
try:
|
373
|
+
# Load API key
|
374
|
+
self._load_api_key(kwargs.get('api_key_path', 'config/alphavantage_config.json'))
|
375
|
+
|
376
|
+
symbols = kwargs['symbols'].split(',')
|
377
|
+
asset_type = AssetType(kwargs['asset_type'])
|
378
|
+
function = kwargs['function']
|
379
|
+
interval = kwargs.get('interval', '5min')
|
380
|
+
outputsize = kwargs.get('outputsize', 'compact')
|
381
|
+
lookback_periods = int(kwargs.get('lookback_periods', '500'))
|
382
|
+
indicators = kwargs.get('indicators', 'all').split(',')
|
383
|
+
|
384
|
+
results = {}
|
385
|
+
|
386
|
+
# Fetch time series data for each symbol
|
387
|
+
for symbol in symbols:
|
388
|
+
if any(dt in [DataType.INTRADAY, DataType.DAILY, DataType.WEEKLY, DataType.MONTHLY] for dt in [DataType(function)]):
|
389
|
+
market_data = await self._fetch_time_series(
|
390
|
+
symbol, asset_type, interval, outputsize
|
391
|
+
)
|
392
|
+
|
393
|
+
# Calculate technical indicators
|
394
|
+
self._calculate_technical_indicators(market_data)
|
395
|
+
|
396
|
+
# Fetch fundamental data for stocks
|
397
|
+
if asset_type == AssetType.STOCK and function == 'FUNDAMENTAL':
|
398
|
+
market_data.fundamental_data = await self._fetch_fundamental_data(symbol)
|
399
|
+
|
400
|
+
results[symbol] = {
|
401
|
+
'market_data': market_data.data.to_dict(orient='records'),
|
402
|
+
'metadata': market_data.metadata,
|
403
|
+
'indicators': {k: v.to_dict() for k, v in market_data.indicators.items()} if market_data.indicators else None,
|
404
|
+
'fundamental_data': market_data.fundamental_data
|
405
|
+
}
|
406
|
+
|
407
|
+
# Fetch news sentiment if requested
|
408
|
+
if function == 'NEWS':
|
409
|
+
news_data = await self._fetch_news_sentiment(symbols)
|
410
|
+
for symbol in symbols:
|
411
|
+
if symbol in results:
|
412
|
+
results[symbol]['news_sentiment'] = news_data
|
413
|
+
|
414
|
+
# Fetch economic data if requested
|
415
|
+
if function == 'ECONOMIC':
|
416
|
+
economic_indicators = [
|
417
|
+
'REAL_GDP',
|
418
|
+
'REAL_GDP_PER_CAPITA',
|
419
|
+
'TREASURY_YIELD',
|
420
|
+
'FEDERAL_FUNDS_RATE',
|
421
|
+
'CPI',
|
422
|
+
'INFLATION',
|
423
|
+
'RETAIL_SALES',
|
424
|
+
'DURABLES',
|
425
|
+
'UNEMPLOYMENT',
|
426
|
+
'NONFARM_PAYROLL'
|
427
|
+
]
|
428
|
+
economic_data = await self._fetch_economic_data(economic_indicators)
|
429
|
+
for symbol in results:
|
430
|
+
results[symbol]['economic_data'] = economic_data
|
431
|
+
|
432
|
+
return results
|
433
|
+
|
434
|
+
except Exception as e:
|
435
|
+
logger.error(f"Error executing Alpha Vantage tool: {e}")
|
436
|
+
raise
|
437
|
+
|
438
|
+
def validate_arguments(self, **kwargs) -> bool:
|
439
|
+
"""Validate the provided arguments."""
|
440
|
+
return super().validate_arguments(**kwargs)
|