Spaces:
Running
Running
Benjamin Consolvo
commited on
Commit
·
aa38941
1
Parent(s):
d67a5fd
session state streamlit
Browse files
app.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
st.set_page_config(layout="wide")
|
| 3 |
-
|
| 4 |
import yfinance as yf
|
| 5 |
# import alpaca as tradeapi
|
| 6 |
import alpaca_trade_api as alpaca
|
| 7 |
from newsapi import NewsApiClient
|
| 8 |
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 9 |
-
|
| 10 |
from datetime import datetime, timedelta
|
| 11 |
import streamlit as st
|
| 12 |
import pandas as pd
|
|
@@ -57,6 +55,14 @@ class AlpacaTrader:
|
|
| 57 |
return None
|
| 58 |
|
| 59 |
def sell(self, symbol, qty):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
try:
|
| 61 |
order = self.alpaca.submit_order(symbol=symbol, qty=qty, side='sell', type='market', time_in_force='day')
|
| 62 |
logger.info(f"Sold {qty} shares of {symbol}")
|
|
@@ -262,12 +268,32 @@ class TradingApp:
|
|
| 262 |
self.auto_trade_log = [] # Store automatic trade actions
|
| 263 |
|
| 264 |
def display_charts(self):
|
| 265 |
-
#
|
| 266 |
symbols = list(self.data.keys())
|
| 267 |
symbol_to_name = self.analyzer.symbol_to_name
|
| 268 |
n = len(symbols)
|
| 269 |
-
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
subplot_titles = [
|
| 272 |
f"{symbol} - {symbol_to_name.get(symbol, '')}" for symbol in symbols
|
| 273 |
]
|
|
@@ -290,9 +316,9 @@ class TradingApp:
|
|
| 290 |
)
|
| 291 |
fig.update_layout(
|
| 292 |
title="Top Volume Stocks - Price Charts (Since 2023)",
|
| 293 |
-
height=
|
| 294 |
showlegend=False,
|
| 295 |
-
dragmode=False,
|
| 296 |
)
|
| 297 |
# Enable scroll-zoom for each subplot (individual zoom)
|
| 298 |
fig.update_layout(
|
|
@@ -402,6 +428,9 @@ def load_auto_trade_log():
|
|
| 402 |
except Exception:
|
| 403 |
return None
|
| 404 |
|
|
|
|
|
|
|
|
|
|
| 405 |
def main():
|
| 406 |
st.title("Stock Trading Application")
|
| 407 |
|
|
@@ -409,9 +438,13 @@ def main():
|
|
| 409 |
st.error("Please configure your API keys in secrets.toml")
|
| 410 |
return
|
| 411 |
|
| 412 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 413 |
|
| 414 |
-
#
|
| 415 |
if "auto_trade_thread_started" not in st.session_state:
|
| 416 |
thread = threading.Thread(target=background_auto_trade, args=(app,), daemon=True)
|
| 417 |
thread.start()
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
st.set_page_config(layout="wide")
|
|
|
|
| 3 |
import yfinance as yf
|
| 4 |
# import alpaca as tradeapi
|
| 5 |
import alpaca_trade_api as alpaca
|
| 6 |
from newsapi import NewsApiClient
|
| 7 |
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
|
|
|
| 8 |
from datetime import datetime, timedelta
|
| 9 |
import streamlit as st
|
| 10 |
import pandas as pd
|
|
|
|
| 55 |
return None
|
| 56 |
|
| 57 |
def sell(self, symbol, qty):
|
| 58 |
+
# Check if position exists and has enough quantity before attempting to sell
|
| 59 |
+
positions = {p.symbol: float(p.qty) for p in self.alpaca.list_positions()}
|
| 60 |
+
if symbol not in positions:
|
| 61 |
+
logger.warning(f"No position in {symbol}. Sell not attempted.")
|
| 62 |
+
return None
|
| 63 |
+
if positions[symbol] < qty:
|
| 64 |
+
logger.warning(f"Not enough shares to sell: {qty} requested, {positions[symbol]} available for {symbol}. Sell not attempted.")
|
| 65 |
+
return None
|
| 66 |
try:
|
| 67 |
order = self.alpaca.submit_order(symbol=symbol, qty=qty, side='sell', type='market', time_in_force='day')
|
| 68 |
logger.info(f"Sold {qty} shares of {symbol}")
|
|
|
|
| 268 |
self.auto_trade_log = [] # Store automatic trade actions
|
| 269 |
|
| 270 |
def display_charts(self):
|
| 271 |
+
# Dynamically adjust columns based on number of stocks and available width
|
| 272 |
symbols = list(self.data.keys())
|
| 273 |
symbol_to_name = self.analyzer.symbol_to_name
|
| 274 |
n = len(symbols)
|
| 275 |
+
|
| 276 |
+
# Use Streamlit's layout to get available width and adjust columns accordingly
|
| 277 |
+
# Default to 3 columns, but adjust for small or large n
|
| 278 |
+
min_col_width = 350 # px, minimum width per plot for readability
|
| 279 |
+
max_cols = max(1, min(6, n)) # Don't exceed 6 columns for readability
|
| 280 |
+
|
| 281 |
+
# Try to get the container width from Streamlit (fallback to 1200px)
|
| 282 |
+
container_width = st.get_option("deprecation.showPyplotGlobalUse") # Not a real width, just placeholder
|
| 283 |
+
# Since Streamlit does not provide actual window width, use st.columns to adapt layout
|
| 284 |
+
# Calculate columns based on n for best fit
|
| 285 |
+
if n <= 3:
|
| 286 |
+
cols = n
|
| 287 |
+
elif n <= 6:
|
| 288 |
+
cols = 3
|
| 289 |
+
elif n <= 8:
|
| 290 |
+
cols = 4
|
| 291 |
+
elif n <= 12:
|
| 292 |
+
cols = 4
|
| 293 |
+
else:
|
| 294 |
+
cols = 5
|
| 295 |
+
|
| 296 |
+
rows = (n + cols - 1) // cols
|
| 297 |
subplot_titles = [
|
| 298 |
f"{symbol} - {symbol_to_name.get(symbol, '')}" for symbol in symbols
|
| 299 |
]
|
|
|
|
| 316 |
)
|
| 317 |
fig.update_layout(
|
| 318 |
title="Top Volume Stocks - Price Charts (Since 2023)",
|
| 319 |
+
height=max(400 * rows, 600),
|
| 320 |
showlegend=False,
|
| 321 |
+
dragmode=False,
|
| 322 |
)
|
| 323 |
# Enable scroll-zoom for each subplot (individual zoom)
|
| 324 |
fig.update_layout(
|
|
|
|
| 428 |
except Exception:
|
| 429 |
return None
|
| 430 |
|
| 431 |
+
# Add this at the top after imports to suppress Streamlit reruns on widget interaction
|
| 432 |
+
st.experimental_set_query_params() # This is a no-op but ensures Streamlit doesn't rerun due to query params
|
| 433 |
+
|
| 434 |
def main():
|
| 435 |
st.title("Stock Trading Application")
|
| 436 |
|
|
|
|
| 438 |
st.error("Please configure your API keys in secrets.toml")
|
| 439 |
return
|
| 440 |
|
| 441 |
+
# Prevent Streamlit from rerunning the script on every widget interaction
|
| 442 |
+
# Use session state to persist objects and only update when necessary
|
| 443 |
+
if "app_instance" not in st.session_state:
|
| 444 |
+
st.session_state["app_instance"] = TradingApp()
|
| 445 |
+
app = st.session_state["app_instance"]
|
| 446 |
|
| 447 |
+
# Only start the background thread once
|
| 448 |
if "auto_trade_thread_started" not in st.session_state:
|
| 449 |
thread = threading.Thread(target=background_auto_trade, args=(app,), daemon=True)
|
| 450 |
thread.start()
|