Skip to content

Commit

Permalink
Major update
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanramoscfa committed Sep 8, 2024
1 parent 0fa584e commit 4cc2025
Show file tree
Hide file tree
Showing 45 changed files with 1,057 additions and 345 deletions.
334 changes: 178 additions & 156 deletions examples/monetary_policy_rules/monetary_policy_rules.ipynb

Large diffs are not rendered by default.

Binary file modified media/bar_rule_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified media/taylor_rule_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 17 additions & 5 deletions pyeconomics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# pyeconomics/__init__.py

# AI imports
from pyeconomics.ai import ai_regression_analysis

# API imports
from pyeconomics.api import (
bitcoin_s2f_data,
load_bitcoin_data,
FredClient,
bitcoin_s2f_data,
fred_client,
load_bitcoin_data,
load_from_cache,
save_to_cache
)

# Data imports
from pyeconomics.data import (
BalancedApproachRuleParameters,
ChatGPTParameters,
EconomicIndicators,
FirstDifferenceRuleParameters,
TaylorRuleParameters,
Expand Down Expand Up @@ -55,7 +59,9 @@
from pyeconomics.models.stock_to_flow import (
bitcoin_s2f_forecast,
calculate_model_values,
fit_model,
fit_regression_model,
plot_s2f_model,
plot_s2f_prediction_model,
power_law_function
)

Expand All @@ -73,10 +79,12 @@
fetch_historical_fed_funds_rate,
print_fred_series_names
)
from pyeconomics.utils.utils import get_forecast_tickers

# Exported symbols
__all__ = [
'BalancedApproachRuleParameters',
'ChatGPTParameters',
'EconomicIndicators',
'FirstDifferenceRuleParameters',
'TaylorRuleParameters',
Expand All @@ -94,15 +102,18 @@
'historical_balanced_approach_rule',
'historical_first_difference_rule',
'historical_taylor_rule',
'ai_regression_analysis',
'plot_historical_rule_estimates',
'plot_historical_bar_basr_rule',
'plot_historical_fdr',
'plot_historical_taylor_rule',
'plot_s2f_model',
'plot_s2f_prediction_model',
'verbose_monetary_policy_rules',
'taylor_rule',
'bitcoin_s2f_forecast',
'calculate_model_values',
'fit_model',
'fit_regression_model',
'power_law_function',
'verbose_balanced_approach_rule',
'verbose_first_difference_rule',
Expand All @@ -121,5 +132,6 @@
'variance_inflation_factor_test',
'verbose_model_diagnostics',
'fetch_historical_fed_funds_rate',
'print_fred_series_names'
'print_fred_series_names',
'get_forecast_tickers'
]
7 changes: 7 additions & 0 deletions pyeconomics/ai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# pyeconomics/ai/__init__.py

from .ai_regression_analysis import ai_regression_analysis

__all__ = [
'ai_regression_analysis'
]
120 changes: 120 additions & 0 deletions pyeconomics/ai/ai_regression_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# pyeconomics/ai/ai_regression_analysis.py

import os
import openai
from statsmodels.regression.linear_model import RegressionResults
from statsmodels.stats.diagnostic import het_breuschpagan, linear_reset
from statsmodels.stats.stattools import durbin_watson, jarque_bera
from statsmodels.stats.stattools import omni_normtest
from typing import Union
from IPython.display import display, Markdown

from pyeconomics.api.openai_api import load_prompt, initialize_openai_client
from ..data.model_parameters import ChatGPTParameters


def ai_regression_analysis(
model: RegressionResults,
ai_params: ChatGPTParameters = ChatGPTParameters()
) -> Union[None, str]:
"""
Generate an AI-based analysis of the OLS regression results.
Args:
model (RegressionResults): A statsmodels OLS Regression Results object.
ai_params (ChatGPTParameters): Instance containing the AI parameters.
Returns:
Union[None, str]: AI-generated analysis paragraph or None if Markdown
output is enabled.
"""
# Ensure the OpenAI client is initialized only when this function is called
initialize_openai_client()

# Extract the needed estimates from the ai_model
slope_name = model.params.index[1]
estimates = {
'R_squared': model.rsquared,
'Adj_R_squared': model.rsquared_adj,
'F_statistic': model.fvalue,
'Prob_F_statistic': model.f_pvalue,
't_statistic': model.tvalues[slope_name],
'P_value': model.pvalues[slope_name],
'Omnibus': omni_normtest(model.resid)[0],
'Prob(Omnibus)': omni_normtest(model.resid)[1],
'Jarque-Bera': jarque_bera(model.resid)[0],
'Prob(JB)': jarque_bera(model.resid)[1],
'Skewness': model.resid.skew(),
'Kurtosis': model.resid.kurtosis() + 3,
'Breusch_Pagan': het_breuschpagan(model.resid, model.model.exog)[0],
'Prob(BP)': het_breuschpagan(model.resid, model.model.exog)[1],
'Durbin_Watson': durbin_watson(model.resid),
'Condition_Number': model.condition_number,
'Intercept': model.params['const'],
'Slope': model.params[slope_name],
'Slope_Name': slope_name,
'Ramsey_Reset': linear_reset(model, power=2, use_f=True).fvalue,
'Prob(RR)': linear_reset(model, power=2, use_f=True).pvalue
}

# Load the prompt template
prompt_filepath = 'ai_regression_analysis.txt'
prompt_file_path = os.path.join(
os.path.dirname(__file__),
'prompts',
prompt_filepath
)
prompt_template = load_prompt(prompt_file_path)

# Format the prompt with data
prompt = prompt_template.format(
r_squared=round(estimates['R_squared'], 3),
adj_r_squared=round(estimates['Adj_R_squared'], 3),
f_statistic=round(estimates['F_statistic'], 2),
prob_f_statistic=round(estimates['Prob_F_statistic'], 2),
t_statistic=round(estimates['t_statistic'], 3),
p_value=round(estimates['P_value'], 3),
omnibus=round(estimates['Omnibus'], 3),
prob_omnibus=round(estimates['Prob(Omnibus)'], 3),
jarque_bera=round(estimates['Jarque-Bera'], 3),
prob_jb=round(estimates['Prob(JB)'], 3),
skewness=round(estimates['Skewness'], 3),
kurtosis=round(estimates['Kurtosis'], 3),
breusch_pagan=round(estimates['Breusch_Pagan'], 3),
prob_breusch_pagan=round(estimates['Breusch_Pagan'], 3),
ramsey_reset=round(estimates['Ramsey_Reset'], 3),
prob_ramsey_reset=round(estimates['Prob(RR)'], 3),
durbin_watson=round(estimates['Durbin_Watson'], 3),
condition_number=round(estimates['Condition_Number'], 2),
intercept=round(estimates['Intercept'], 4),
slope=round(estimates['Slope'], 4),
slope_name=estimates['Slope_Name'],
ai_model=ai_params.ai_model,
)

# Generate the AI analysis
response = openai.chat.completions.create(
model=ai_params.ai_model,
messages=[
{"role": "system",
"content": "You are an expert data scientist. Your task is to "
"analyze the OLS regression results and provide a "
"detailed interpretation in markdown format for a "
"Jupyter notebook."
},
{"role": "user", "content": prompt}
],
max_tokens=ai_params.max_tokens
)

# Remove the ```markdown``` delimiters from the response content
analysis = response.choices[0].message.content.strip()
if analysis.startswith("```markdown"):
analysis = analysis[len("```markdown"):].strip()
if analysis.endswith("```"):
analysis = analysis[:-len("```")].strip()

if ai_params.markdown:
display(Markdown(analysis))
else:
return analysis
9 changes: 6 additions & 3 deletions pyeconomics/ai/balanced_approach_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import openai

from pyeconomics.api.openai_api import load_prompt
from pyeconomics.api.openai_api import load_prompt, initialize_openai_client
from pyeconomics.utils.utils import encode_image


Expand All @@ -23,14 +23,17 @@ def balanced_approach_rule(
max_tokens (int): Maximum number of tokens for the AI response.
Defaults to 500 which may cost a few cents per call. Adjust as
needed. See https://openai.com/api/pricing/ for details.
model (str): The OpenAI model to use for the analysis. Defaults to
model (str): The OpenAI ai_model to use for the analysis. Defaults to
'gpt-4o'. Other models are available, such as 'gpt-4-turbo' and
'gpt-3.5-turbo'. See https://platform.openai.com/docs/models for
more information.
Returns:
str: AI-generated analysis paragraph.
"""
# Ensure the OpenAI client is initialized only when this function is called
initialize_openai_client()

# Construct the full path to the prompt file
prompt_file_path = os.path.join(
os.path.dirname(__file__),
Expand Down Expand Up @@ -89,7 +92,7 @@ def plot_interpretation(
max_tokens (int): Maximum number of tokens for the AI response. Defaults
to 500 which may cost a few cents per call. Adjust as needed. See
https://openai.com/api/pricing/ for details.
model (str): The OpenAI model to use for the analysis. Defaults to
model (str): The OpenAI ai_model to use for the analysis. Defaults to
'gpt-4o'. Other models are available, such as 'gpt-4-turbo' and
'gpt-3.5-turbo'. See https://platform.openai.com/docs/models for
more information.
Expand Down
9 changes: 6 additions & 3 deletions pyeconomics/ai/first_difference_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import openai

from pyeconomics.api.openai_api import load_prompt
from pyeconomics.api.openai_api import load_prompt, initialize_openai_client
from pyeconomics.utils.utils import encode_image


Expand All @@ -21,14 +21,17 @@ def first_difference_rule(
max_tokens (int): Maximum number of tokens for the AI response. Defaults
to 500 which may cost a few cents per call. Adjust as needed. See
https://openai.com/api/pricing/ for details.
model (str): The OpenAI model to use for the analysis. Defaults to
model (str): The OpenAI ai_model to use for the analysis. Defaults to
'gpt-4o'. Other models are available, such as 'gpt-4-turbo' and
'gpt-3.5-turbo'. See https://platform.openai.com/docs/models for
more information.
Returns:
str: AI-generated analysis paragraph.
"""
# Ensure the OpenAI client is initialized only when this function is called
initialize_openai_client()

# Construct the full path to the prompt file
prompt_file_path = os.path.join(
os.path.dirname(__file__),
Expand Down Expand Up @@ -89,7 +92,7 @@ def plot_interpretation(
max_tokens (int): Maximum number of tokens for the AI response. Defaults
to 500 which may cost a few cents per call. Adjust as needed. See
https://openai.com/api/pricing/ for details.
model (str): The OpenAI model to use for the analysis. Defaults to
model (str): The OpenAI ai_model to use for the analysis. Defaults to
'gpt-4o'. Other models are available, such as 'gpt-4-turbo' and
'gpt-3.5-turbo'. See https://platform.openai.com/docs/models for
more information.
Expand Down
34 changes: 27 additions & 7 deletions pyeconomics/ai/monetary_policy_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import openai

from pyeconomics.api.openai_api import load_prompt
from pyeconomics.api.openai_api import load_prompt, initialize_openai_client
from pyeconomics.data.economic_indicators import EconomicIndicators
from pyeconomics.data.model_parameters import MonetaryPolicyRulesParameters

Expand All @@ -29,6 +29,9 @@ def monetary_policy_rules(
Returns:
str: AI-generated analysis paragraph.
"""
# Ensure the OpenAI client is initialized only when this function is called
initialize_openai_client()

if params.rho > 0.0 or params.apply_elb:
prompt_filepath = 'adjusted_monetary_policy_rules.txt'
else:
Expand All @@ -46,25 +49,42 @@ def monetary_policy_rules(

# Format the prompt with data
prompt = prompt_template.format(
taylor_rule=round(estimates['Taylor Rule (TR)'], 2),
taylor_rule=round(
estimates['Taylor Rule (TR)'], 2),
balanced_approach_rule=round(
estimates['Balanced Approach Rule (BAR)'], 2),
balanced_approach_shortfalls_rule=round(
estimates['Balanced Approach Shortfalls Rule (BASR)'], 2),
first_difference_rule=round(
estimates['First Difference Rule (FDR)'], 2),
current_fed_rate=round(indicators.current_fed_rate, 2),
current_fed_rate=round(
indicators.current_fed_rate, 2),
current_inflation_rate=round(
indicators.current_inflation_rate, 2),
inflation_target=round(
params.inflation_target, 2),
current_unemployment_rate=round(
indicators.current_unemployment_rate, 2),
natural_unemployment_rate=round(
indicators.natural_unemployment_rate, 2),
long_term_real_interest_rate=round(
indicators.long_term_real_interest_rate, 2),
inflation_gap=round(
indicators.current_inflation_rate - params.inflation_target, 2),
unemployment_gap=round(
indicators.natural_unemployment_rate -
indicators.current_unemployment_rate, 2),
rho=params.rho
)

response = openai.chat.completions.create(
model=params.model,
messages=[
{"role": "system",
"content": "You are the Federal Open Market Committee (FOMC) of "
"the Federal Reserve System. Your task is to analyze "
"monetary policy rule estimates and provide a policy "
"prescription based on the given data."
"content": "Act as the Federal Open Market Committee (FOMC) of "
"the Federal Reserve System (the Fed) that is charged "
"with making key decisions about interest rates and "
"the growth of the United States money supply."
},
{"role": "user", "content": prompt}
],
Expand Down
Loading

0 comments on commit 4cc2025

Please sign in to comment.