Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -11,54 +11,59 @@ POLYMARKET_API = "https://api.polymarket.com/graphql"
|
|
11 |
|
12 |
# Function to fetch Polymarket data
|
13 |
def fetch_polymarket_data(search_term="S&P"):
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
|
|
|
|
|
|
24 |
}
|
25 |
}
|
26 |
}
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
return None
|
33 |
-
|
34 |
-
markets = data["data"]["markets"]["edges"]
|
35 |
-
if not markets:
|
36 |
return None
|
37 |
-
|
38 |
-
# Parse the first relevant market
|
39 |
-
for market in markets:
|
40 |
-
node = market["node"]
|
41 |
-
outcomes = node["outcomes"]
|
42 |
-
if len(outcomes) >= 2: # Ensure there's at least Yes/No or similar
|
43 |
-
return {
|
44 |
-
"question": node["question"],
|
45 |
-
"outcomes": {outcome["name"]: float(outcome["price"]) for outcome in outcomes}
|
46 |
-
}
|
47 |
-
return None
|
48 |
|
49 |
# Function to fetch Yahoo Finance data and calculate drift/volatility
|
50 |
def fetch_yahoo_data(ticker):
|
51 |
try:
|
52 |
stock = yf.download(ticker, period="1y", auto_adjust=False, progress=False)
|
53 |
-
if stock.empty:
|
54 |
-
return None, None, None
|
55 |
-
daily_returns = stock["Close"].pct_change().dropna()
|
|
|
|
|
56 |
mu = daily_returns.mean() * 252 # Annualized drift
|
57 |
sigma = daily_returns.std() * np.sqrt(252) # Annualized volatility
|
58 |
last_price = stock["Close"][-1] # Use most recent unadjusted Close
|
59 |
-
return mu, sigma, last_price
|
60 |
-
except Exception:
|
61 |
-
return None, None, None
|
62 |
|
63 |
# Monte Carlo Simulation with GBM
|
64 |
def monte_carlo_simulation(S0, mu, sigma, T, N, sims, risk_factor, pm_data):
|
@@ -88,10 +93,14 @@ def monte_carlo_simulation(S0, mu, sigma, T, N, sims, risk_factor, pm_data):
|
|
88 |
|
89 |
# Main simulation function
|
90 |
def run_simulation(investment, ticker, horizon, num_sims, risk_factor):
|
|
|
|
|
|
|
|
|
91 |
# Fetch data
|
92 |
-
mu, sigma, S0 = fetch_yahoo_data(ticker)
|
93 |
if mu is None:
|
94 |
-
return None,
|
95 |
|
96 |
pm_data = fetch_polymarket_data("S&P") # Search for S&P-related markets
|
97 |
|
@@ -116,14 +125,15 @@ def run_simulation(investment, ticker, horizon, num_sims, risk_factor):
|
|
116 |
# Prepare summary text
|
117 |
summary = f"Market Data (Yahoo Finance):\n"
|
118 |
summary += f"- Drift (μ): {mu:.4f} (based on unadjusted Close)\n"
|
119 |
-
summary += f"- Volatility (σ): {sigma:.4f}\n
|
|
|
120 |
if pm_data:
|
121 |
summary += f"Polymarket Data:\n- Question: {pm_data['question']}\n"
|
122 |
for outcome, prob in pm_data["outcomes"].items():
|
123 |
summary += f"- {outcome}: {prob*100:.1f}%\n"
|
124 |
else:
|
125 |
-
summary += "Polymarket Data: No relevant market found.\n"
|
126 |
-
summary += f"\nSimulation Results:\n"
|
127 |
summary += f"- Mean Final Value: ${mean_val:.2f}\n"
|
128 |
summary += f"- Min Final Value: ${min_val:.2f}\n"
|
129 |
summary += f"- Max Final Value: ${max_val:.2f}\n"
|
@@ -147,7 +157,7 @@ with gr.Blocks(title="Investment Simulation Platform") as demo:
|
|
147 |
|
148 |
with gr.Column():
|
149 |
plot_output = gr.Plot(label="Final Value Distribution")
|
150 |
-
text_output = gr.Textbox(label="Simulation Summary", lines=
|
151 |
|
152 |
submit_btn.click(
|
153 |
fn=run_simulation,
|
|
|
11 |
|
12 |
# Function to fetch Polymarket data
|
13 |
def fetch_polymarket_data(search_term="S&P"):
|
14 |
+
try:
|
15 |
+
query = """
|
16 |
+
query {
|
17 |
+
markets(first: 5, searchTerm: "%s") {
|
18 |
+
edges {
|
19 |
+
node {
|
20 |
+
id
|
21 |
+
question
|
22 |
+
outcomes {
|
23 |
+
name
|
24 |
+
price
|
25 |
+
}
|
26 |
+
}
|
27 |
}
|
28 |
}
|
29 |
}
|
30 |
+
""" % search_term
|
31 |
+
response = requests.post(POLYMARKET_API, json={"query": query}, timeout=10)
|
32 |
+
if response.status_code != 200:
|
33 |
+
return None
|
34 |
+
data = response.json()
|
35 |
+
markets = data["data"]["markets"]["edges"]
|
36 |
+
if not markets:
|
37 |
+
return None
|
38 |
+
|
39 |
+
# Parse the first relevant market
|
40 |
+
for market in markets:
|
41 |
+
node = market["node"]
|
42 |
+
outcomes = node["outcomes"]
|
43 |
+
if len(outcomes) >= 2: # Ensure there's at least Yes/No or similar
|
44 |
+
return {
|
45 |
+
"question": node["question"],
|
46 |
+
"outcomes": {outcome["name"]: float(outcome["price"]) for outcome in outcomes}
|
47 |
+
}
|
48 |
return None
|
49 |
+
except Exception as e:
|
|
|
|
|
50 |
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
# Function to fetch Yahoo Finance data and calculate drift/volatility
|
53 |
def fetch_yahoo_data(ticker):
|
54 |
try:
|
55 |
stock = yf.download(ticker, period="1y", auto_adjust=False, progress=False)
|
56 |
+
if stock.empty or len(stock) < 2: # Check for empty or insufficient data
|
57 |
+
return None, None, None, f"No data returned for ticker '{ticker}'. It may be invalid or lack sufficient history."
|
58 |
+
daily_returns = stock["Close"].pct_change().dropna()
|
59 |
+
if daily_returns.empty:
|
60 |
+
return None, None, None, f"No valid returns calculated for ticker '{ticker}'. Insufficient price data."
|
61 |
mu = daily_returns.mean() * 252 # Annualized drift
|
62 |
sigma = daily_returns.std() * np.sqrt(252) # Annualized volatility
|
63 |
last_price = stock["Close"][-1] # Use most recent unadjusted Close
|
64 |
+
return mu, sigma, last_price, None
|
65 |
+
except Exception as e:
|
66 |
+
return None, None, None, f"Error fetching data for ticker '{ticker}': {str(e)}"
|
67 |
|
68 |
# Monte Carlo Simulation with GBM
|
69 |
def monte_carlo_simulation(S0, mu, sigma, T, N, sims, risk_factor, pm_data):
|
|
|
93 |
|
94 |
# Main simulation function
|
95 |
def run_simulation(investment, ticker, horizon, num_sims, risk_factor):
|
96 |
+
# Validate inputs
|
97 |
+
if not ticker or investment <= 0 or horizon <= 0 or num_sims <= 0:
|
98 |
+
return None, "Please provide valid inputs: positive investment, horizon, and simulations, and a ticker."
|
99 |
+
|
100 |
# Fetch data
|
101 |
+
mu, sigma, S0, error_msg = fetch_yahoo_data(ticker)
|
102 |
if mu is None:
|
103 |
+
return None, error_msg
|
104 |
|
105 |
pm_data = fetch_polymarket_data("S&P") # Search for S&P-related markets
|
106 |
|
|
|
125 |
# Prepare summary text
|
126 |
summary = f"Market Data (Yahoo Finance):\n"
|
127 |
summary += f"- Drift (μ): {mu:.4f} (based on unadjusted Close)\n"
|
128 |
+
summary += f"- Volatility (σ): {sigma:.4f}\n"
|
129 |
+
summary += f"- Last Close Price: ${S0:.2f}\n\n"
|
130 |
if pm_data:
|
131 |
summary += f"Polymarket Data:\n- Question: {pm_data['question']}\n"
|
132 |
for outcome, prob in pm_data["outcomes"].items():
|
133 |
summary += f"- {outcome}: {prob*100:.1f}%\n"
|
134 |
else:
|
135 |
+
summary += "Polymarket Data: No relevant market found or API unavailable.\n"
|
136 |
+
summary += f"\nSimulation Results ({num_sims} runs):\n"
|
137 |
summary += f"- Mean Final Value: ${mean_val:.2f}\n"
|
138 |
summary += f"- Min Final Value: ${min_val:.2f}\n"
|
139 |
summary += f"- Max Final Value: ${max_val:.2f}\n"
|
|
|
157 |
|
158 |
with gr.Column():
|
159 |
plot_output = gr.Plot(label="Final Value Distribution")
|
160 |
+
text_output = gr.Textbox(label="Simulation Summary", lines=12)
|
161 |
|
162 |
submit_btn.click(
|
163 |
fn=run_simulation,
|