Skip to content

Commit 303e58c

Browse files
add financial conditions index
1 parent a12e88f commit 303e58c

7 files changed

Lines changed: 578 additions & 24 deletions

File tree

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Import all agent modules
2+
# Import order matters - base modules first, then modules that depend on them
23
from .analysis_agent import *
3-
from .asset_allocation_analyzer import *
4-
from .economic_cycle_analyzer import *
5-
from .economic_dashboard import *
6-
from .backtesting import *
74
from .dspy_evaluation import *
5+
from .economic_cycle_analyzer import *
86
from .enhanced_economic_cycle_analyzer import *
9-
from .model_improvement_pipeline import *
7+
from .asset_allocation_analyzer import *
8+
from .backtesting import *
9+
from .economic_dashboard import *
1010
from .backtesting_visualization import *
11+
from .model_improvement_pipeline import *
1112

macro_agents/src/macro_agents/defs/agents/asset_allocation_analyzer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from macro_agents.defs.resources.motherduck import MotherDuckResource
1010
from macro_agents.defs.agents.economic_cycle_analyzer import economic_cycle_analysis
11-
from macro_agents.defs.agents.asset_allocation_analyzer import asset_allocation_recommendations
1211

1312

1413
class AssetAllocationSignature(dspy.Signature):

macro_agents/src/macro_agents/defs/agents/backtesting.py

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ def extract_asset_recommendations(analysis_text: str) -> List[Dict[str, Any]]:
9797
'rationale': f"{percentage}% allocation"
9898
})
9999

100+
# If no recommendations found with patterns, try to extract any mentioned symbols
101+
if not recommendations:
102+
# Look for any mentioned symbols in the text
103+
for symbol in asset_symbols:
104+
if symbol in analysis_text:
105+
recommendations.append({
106+
'symbol': symbol,
107+
'action': 'MENTIONED',
108+
'confidence': 'low',
109+
'rationale': f"Symbol {symbol} mentioned in analysis"
110+
})
111+
100112
return recommendations
101113

102114

@@ -179,7 +191,7 @@ def get_historical_analysis(self, md_resource: MotherDuckResource, as_of_date: s
179191
query = """
180192
SELECT analysis_content, analysis_type, analysis_timestamp
181193
FROM economic_cycle_analysis
182-
WHERE analysis_timestamp <= ?
194+
WHERE DATE(analysis_timestamp) <= ?
183195
ORDER BY analysis_timestamp DESC
184196
LIMIT 2
185197
"""
@@ -203,7 +215,7 @@ def get_asset_allocation_analysis(self, md_resource: MotherDuckResource, as_of_d
203215
query = """
204216
SELECT analysis_content
205217
FROM asset_allocation_recommendations
206-
WHERE analysis_timestamp <= ?
218+
WHERE DATE(analysis_timestamp) <= ?
207219
ORDER BY analysis_timestamp DESC
208220
LIMIT 1
209221
"""
@@ -307,20 +319,30 @@ def run_backtest(self,
307319
if context:
308320
context.log.info(f"Running backtest for prediction date: {prediction_date}")
309321

310-
# Calculate end date
311-
pred_dt = datetime.strptime(prediction_date, '%Y-%m-%d')
322+
# Calculate end date - handle both string and date inputs
323+
if isinstance(prediction_date, str):
324+
pred_dt = datetime.strptime(prediction_date, '%Y-%m-%d')
325+
elif isinstance(prediction_date, datetime.date):
326+
pred_dt = datetime.combine(prediction_date, datetime.min.time())
327+
else:
328+
# Convert to string first, then parse
329+
pred_dt = datetime.strptime(str(prediction_date), '%Y-%m-%d')
330+
312331
end_dt = pred_dt + timedelta(days=prediction_horizon_days)
313332
end_date = end_dt.strftime('%Y-%m-%d')
314333

334+
# Convert prediction_date to string for the database queries
335+
prediction_date_str = pred_dt.strftime('%Y-%m-%d')
336+
315337
# Get historical analysis
316-
analysis = self.get_historical_analysis(md_resource, prediction_date)
338+
analysis = self.get_historical_analysis(md_resource, prediction_date_str)
317339
if not analysis:
318-
raise ValueError(f"No analysis found for date {prediction_date}")
340+
raise ValueError(f"No analysis found for date {prediction_date_str}")
319341

320342
# Get asset allocation recommendations
321-
allocation_analysis = self.get_asset_allocation_analysis(md_resource, prediction_date)
343+
allocation_analysis = self.get_asset_allocation_analysis(md_resource, prediction_date_str)
322344
if not allocation_analysis:
323-
raise ValueError(f"No asset allocation analysis found for date {prediction_date}")
345+
raise ValueError(f"No asset allocation analysis found for date {prediction_date_str}")
324346

325347
# Extract predictions
326348
extractor = PredictionExtractor()
@@ -337,15 +359,15 @@ def run_backtest(self,
337359

338360
# Get historical prices
339361
price_data = self.get_historical_prices(
340-
md_resource, symbols, prediction_date, end_date
362+
md_resource, symbols, prediction_date_str, end_date
341363
)
342364

343365
if price_data.is_empty():
344366
raise ValueError(f"No price data found for symbols: {symbols}")
345367

346368
# Calculate actual returns
347369
calculator = PerformanceCalculator()
348-
actual_returns = calculator.calculate_returns(price_data, prediction_date, end_date)
370+
actual_returns = calculator.calculate_returns(price_data, prediction_date_str, end_date)
349371

350372
# Calculate performance metrics
351373
returns_list = list(actual_returns.values())
@@ -356,7 +378,7 @@ def run_backtest(self,
356378

357379
# Create backtest result
358380
result = BacktestResult(
359-
prediction_date=prediction_date,
381+
prediction_date=prediction_date_str,
360382
prediction_horizon_days=prediction_horizon_days,
361383
predicted_assets=predicted_assets,
362384
actual_returns=actual_returns,
@@ -575,10 +597,53 @@ def batch_backtest_analysis(
575597
if df.is_empty():
576598
raise ValueError("No historical analysis found for batch backtesting")
577599

578-
prediction_dates = [row[0] for row in df.iter_rows()]
600+
prediction_dates = [str(row[0]) for row in df.iter_rows()]
579601

580602
context.log.info(f"Found {len(prediction_dates)} prediction dates for batch backtesting")
581603

604+
context.log.info(f"Sample prediction dates: {prediction_dates[:3]}")
605+
606+
# Test the first prediction date
607+
if prediction_dates:
608+
test_date = prediction_dates[0]
609+
context.log.info(f"Testing data availability for date: {test_date}")
610+
611+
# Test analysis data
612+
test_analysis = backtesting_engine.get_historical_analysis(md, test_date)
613+
context.log.info(f"Analysis data available: {test_analysis is not None}")
614+
615+
# Test allocation data
616+
test_allocation = backtesting_engine.get_asset_allocation_analysis(md, test_date)
617+
context.log.info(f"Allocation data available: {test_allocation is not None}")
618+
619+
if test_allocation:
620+
context.log.info(f"Sample allocation text: {test_allocation[:200]}...")
621+
# Test extraction
622+
extractor = PredictionExtractor()
623+
test_recommendations = extractor.extract_asset_recommendations(test_allocation)
624+
context.log.info(f"Extracted recommendations: {len(test_recommendations)}")
625+
if test_recommendations:
626+
context.log.info(f"Sample recommendation: {test_recommendations[0]}")
627+
628+
# Add this right after context.log.info("Starting batch backtesting analysis...")
629+
# Around line 582
630+
631+
# Validate that all required tables exist with data
632+
validation_query = """
633+
SELECT
634+
(SELECT COUNT(*) FROM economic_cycle_analysis) as cycle_count,
635+
(SELECT COUNT(*) FROM asset_allocation_recommendations) as allocation_count,
636+
(SELECT COUNT(*) FROM us_sector_etfs_raw) as sectors_count,
637+
(SELECT COUNT(*) FROM major_indices_raw) as indices_count
638+
"""
639+
validation_df = md.execute_query(validation_query, read_only=True)
640+
if not validation_df.is_empty():
641+
row = validation_df[0]
642+
context.log.info(f"Data availability - Cycle: {row[0]}, Allocation: {row[1]}, Sectors: {row[2]}, Indices: {row[3]}")
643+
644+
if row[0] == 0 or row[1] == 0:
645+
raise ValueError(f"Missing required analysis data - Cycle: {row[0]}, Allocation: {row[1]}")
646+
582647
# Run backtests for each date
583648
batch_results = []
584649
successful_backtests = 0
@@ -604,6 +669,8 @@ def batch_backtest_analysis(
604669

605670
except Exception as e:
606671
context.log.warning(f"Failed to backtest {pred_date}: {str(e)}")
672+
context.log.warning(f"Exception type: {type(e).__name__}")
673+
context.log.warning(f"Exception details: {str(e)}")
607674
continue
608675

609676
if not batch_results:

macro_agents/src/macro_agents/defs/agents/model_improvement_pipeline.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
FinancialMetrics,
1515
FinancialPredictionModule
1616
)
17-
from macro_agents.defs.agents.backtesting import BacktestingEngine
17+
from macro_agents.defs.agents.backtesting import BacktestingEngine, batch_backtest_analysis
1818
from macro_agents.defs.agents.enhanced_economic_cycle_analyzer import enhanced_economic_cycle_analysis
19-
from macro_agents.defs.agents.backtesting import batch_backtest_analysis
2019

2120

2221
class ModelImprovementPipeline(dg.ConfigurableResource):

macro_agents/src/macro_agents/defs/constants/fred_series_lists.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@
4545
# Interest Rates & Yield Curve
4646
interest_rates_series = [
4747
("FEDFUNDS", "Effective Federal Funds Rate"),
48+
("DFF", "Federal Funds Effective Rate"), # ADDED: Alternative Fed Funds Rate
4849
("TB3MS", "3-Month Treasury Constant Maturity Rate"),
4950
("TB6MS", "6-Month Treasury Constant Maturity Rate"),
5051
("TB1YR", "1-Year Treasury Constant Maturity Rate"),
5152
("TB2YR", "2-Year Treasury Constant Maturity Rate"),
5253
("TB5YR", "5-Year Treasury Constant Maturity Rate"),
5354
("TB10YR", "10-Year Treasury Constant Maturity Rate"),
55+
("DGS10", "10 year Treasury Rate"), # ADDED: Alternative 10-Year Treasury Rate
5456
("TB30YR", "30-Year Treasury Constant Maturity Rate"),
5557
(
5658
"T10Y2Y",
@@ -133,6 +135,7 @@
133135
("NHSDPTS", "New Home Sales in the United States"),
134136
("MORTGAGE30US", "30-Year Fixed Rate Mortgage Average in the United States"),
135137
("COMPUTSA", "New Private Housing Units Under Construction"),
138+
("USAUCSFRCONDOSMSAMID", "Zillow Housing Index"), # ADDED: Zillow Housing Index
136139
]
137140

138141
# International Trade & Global Linkages
@@ -174,6 +177,7 @@
174177
"Net Percentage of Domestic Banks Tightening Standards for Commercial and Industrial Loans to Small Firms",
175178
),
176179
("SP500", "S&P 500"),
180+
("DJIA", "Dow Jones Industrial Average"), # ADDED: Dow Jones Industrial Average
177181
]
178182

179183
# ============================================================================
@@ -215,4 +219,4 @@
215219
("NAPMII", "ISM Manufacturing: Inventories Index"),
216220
("NAPMNOI", "ISM Manufacturing: New Orders Index"),
217221
("NAPMSDI", "ISM Manufacturing: Supplier Deliveries Index"),
218-
]
222+
]

macro_agents/src/macro_agents/defs/resources/motherduck.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,15 @@ def write_results_to_table(
299299
if conn:
300300
conn.close()
301301

302-
def execute_query(self, query: str, read_only: bool = True) -> pl.DataFrame:
302+
def execute_query(self, query: str, read_only: bool = True, params: Optional[List[Any]] = None) -> pl.DataFrame:
303303
"""Execute a SQL query and return results as Polars DataFrame."""
304304
conn = None
305305
try:
306306
conn = self.get_connection()
307-
result = conn.execute(query)
307+
if params:
308+
result = conn.execute(query, params)
309+
else:
310+
result = conn.execute(query)
308311
return result.pl()
309312
finally:
310313
if conn:

0 commit comments

Comments
 (0)