Arrechenash commited on
Commit
4fef3fe
·
1 Parent(s): d865808

Support more timeframes in charts

Browse files
Files changed (2) hide show
  1. src/datasource.py +17 -2
  2. src/pages/chart.py +56 -32
src/datasource.py CHANGED
@@ -53,10 +53,25 @@ def get_client():
53
  return StockHistoricalDataClient(ALPACA_API_KEY, ALPACA_SECRET_KEY)
54
 
55
 
56
- def get_stock_bars(symbol_or_symbols, date_start, date_end, interval=1):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  req = StockBarsRequest(
58
  symbol_or_symbols=symbol_or_symbols,
59
- timeframe=TimeFrame(amount=interval, unit=TimeFrameUnit.Minute),
60
  start=str(date_start),
61
  end=str(date_end),
62
  )
 
53
  return StockHistoricalDataClient(ALPACA_API_KEY, ALPACA_SECRET_KEY)
54
 
55
 
56
+ def parse_timeframe(timeframe_str):
57
+ """Parse timeframe string and return TimeFrame object"""
58
+ timeframe_mapping = {
59
+ "1m": TimeFrame(amount=1, unit=TimeFrameUnit.Minute),
60
+ "5m": TimeFrame(amount=5, unit=TimeFrameUnit.Minute),
61
+ "15m": TimeFrame(amount=15, unit=TimeFrameUnit.Minute),
62
+ "30m": TimeFrame(amount=30, unit=TimeFrameUnit.Minute),
63
+ "1h": TimeFrame(amount=1, unit=TimeFrameUnit.Hour),
64
+ "1d": TimeFrame(amount=1, unit=TimeFrameUnit.Day),
65
+ }
66
+ return timeframe_mapping.get(
67
+ timeframe_str, TimeFrame(amount=1, unit=TimeFrameUnit.Minute)
68
+ )
69
+
70
+
71
+ def get_stock_bars(symbol_or_symbols, date_start, date_end, interval="1min"):
72
  req = StockBarsRequest(
73
  symbol_or_symbols=symbol_or_symbols,
74
+ timeframe=parse_timeframe(interval),
75
  start=str(date_start),
76
  end=str(date_end),
77
  )
src/pages/chart.py CHANGED
@@ -1,11 +1,17 @@
1
  from datetime import datetime, timedelta
2
-
3
  import pandas as pd
4
  import plotly.graph_objs as go
5
  import streamlit as st
 
6
 
7
  from datasource import get_stock_bars
8
 
 
 
 
 
 
 
9
  st.set_page_config(layout="wide")
10
  st.title("Candlestick Chart")
11
  st.sidebar.title("Filters")
@@ -13,14 +19,23 @@ st.sidebar.title("Filters")
13
  symbol = st.sidebar.text_input("Ticker symbol", value="TSLA").upper()
14
  date_start = st.sidebar.date_input(
15
  "Start date",
16
- datetime.today() - timedelta(days=1),
17
- max_value=datetime.today() - timedelta(days=1),
 
 
 
18
  )
19
- timeframe = st.sidebar.selectbox("Timeframe", options=["1", "5", "15"], index=2)
20
 
21
  try:
 
 
 
 
 
 
 
22
  bars = get_stock_bars(
23
- symbol, date_start, date_start + timedelta(days=1), interval=int(timeframe)
24
  )
25
  if bars.empty:
26
  st.warning("No data. Check symbol and dates.")
@@ -35,10 +50,13 @@ try:
35
  "volume"
36
  ].cumsum()
37
 
38
- premarket_mask = bars.index.time < pd.to_datetime("09:30:00").time()
39
- premarket_high = (
40
- bars.loc[premarket_mask, "high"].max() if premarket_mask.any() else None
41
- )
 
 
 
42
 
43
  timestamps = [ts.strftime("%Y-%m-%d %H:%M:%S") for ts in bars.index]
44
  open_vals = bars["open"].tolist()
@@ -71,7 +89,7 @@ try:
71
  if premarket_high is not None and pd.notna(premarket_high):
72
  fig.add_trace(
73
  go.Scatter(
74
- x=[timestamps[0], timestamps[-1]],
75
  y=[premarket_high, premarket_high],
76
  mode="lines",
77
  line=dict(color="red", width=1, dash="dash"),
@@ -89,30 +107,36 @@ try:
89
  )
90
  )
91
 
92
- bars_dates = pd.to_datetime(bars.index.date).unique()
93
- for day in bars_dates:
94
- dm = pd.Timestamp(day).strftime("%Y-%m-%d")
95
- fig.add_vrect(
96
- x0=f"{dm} 04:00:00",
97
- x1=f"{dm} 09:30:00",
98
- fillcolor="rgba(0, 200, 255, 0.10)",
99
- layer="below",
100
- line_width=0,
101
- annotation_text="Pre-market",
102
- annotation_position="top left",
103
- )
104
- fig.add_vrect(
105
- x0=f"{dm} 16:00:00",
106
- x1=f"{dm} 20:00:00",
107
- fillcolor="rgba(255, 200, 0, 0.08)",
108
- layer="below",
109
- line_width=0,
110
- annotation_text="After-hours",
111
- annotation_position="top left",
112
- )
 
 
 
 
 
 
113
 
114
  fig.update_layout(
115
- title=f"{symbol} - {timeframe}m",
116
  xaxis_title="Date/Time",
117
  yaxis_title="Price",
118
  xaxis_rangeslider_visible=False,
 
1
  from datetime import datetime, timedelta
 
2
  import pandas as pd
3
  import plotly.graph_objs as go
4
  import streamlit as st
5
+ import pytz
6
 
7
  from datasource import get_stock_bars
8
 
9
+
10
+ def get_ny_today():
11
+ ny_tz = pytz.timezone("America/New_York")
12
+ return datetime.now(ny_tz).date()
13
+
14
+
15
  st.set_page_config(layout="wide")
16
  st.title("Candlestick Chart")
17
  st.sidebar.title("Filters")
 
19
  symbol = st.sidebar.text_input("Ticker symbol", value="TSLA").upper()
20
  date_start = st.sidebar.date_input(
21
  "Start date",
22
+ get_ny_today() - timedelta(days=1),
23
+ max_value=get_ny_today() - timedelta(days=1),
24
+ )
25
+ timeframe = st.sidebar.selectbox(
26
+ "Timeframe", options=["1m", "5m", "15m", "30m", "1h", "1d"], index=2
27
  )
 
28
 
29
  try:
30
+ if timeframe == "1d":
31
+ actual_start_date = date_start - timedelta(days=29) # 29 + 1 = 30 days total
32
+ actual_end_date = date_start + timedelta(days=1)
33
+ else:
34
+ actual_start_date = date_start
35
+ actual_end_date = date_start + timedelta(days=1)
36
+
37
  bars = get_stock_bars(
38
+ symbol, actual_start_date, actual_end_date, interval=timeframe
39
  )
40
  if bars.empty:
41
  st.warning("No data. Check symbol and dates.")
 
50
  "volume"
51
  ].cumsum()
52
 
53
+ if timeframe != "1d":
54
+ premarket_mask = bars.index.time < pd.to_datetime("09:30:00").time()
55
+ premarket_high = (
56
+ bars.loc[premarket_mask, "high"].max() if premarket_mask.any() else None
57
+ )
58
+ else:
59
+ premarket_high = None
60
 
61
  timestamps = [ts.strftime("%Y-%m-%d %H:%M:%S") for ts in bars.index]
62
  open_vals = bars["open"].tolist()
 
89
  if premarket_high is not None and pd.notna(premarket_high):
90
  fig.add_trace(
91
  go.Scatter(
92
+ x=[timestamps, timestamps[-1]],
93
  y=[premarket_high, premarket_high],
94
  mode="lines",
95
  line=dict(color="red", width=1, dash="dash"),
 
107
  )
108
  )
109
 
110
+ if timeframe != "1d":
111
+ bars_dates = pd.to_datetime(bars.index.date).unique()
112
+ for day in bars_dates:
113
+ dm = pd.Timestamp(day).strftime("%Y-%m-%d")
114
+ fig.add_vrect(
115
+ x0=f"{dm} 04:00:00",
116
+ x1=f"{dm} 09:30:00",
117
+ fillcolor="rgba(0, 200, 255, 0.10)",
118
+ layer="below",
119
+ line_width=0,
120
+ annotation_text="Pre-market",
121
+ annotation_position="top left",
122
+ )
123
+ fig.add_vrect(
124
+ x0=f"{dm} 16:00:00",
125
+ x1=f"{dm} 20:00:00",
126
+ fillcolor="rgba(255, 200, 0, 0.08)",
127
+ layer="below",
128
+ line_width=0,
129
+ annotation_text="After-hours",
130
+ annotation_position="top left",
131
+ )
132
+
133
+ if timeframe == "1d":
134
+ title = f"{symbol} - {timeframe} ({actual_start_date.strftime('%Y-%m-%d')} to {date_start.strftime('%Y-%m-%d')})"
135
+ else:
136
+ title = f"{symbol} - {timeframe}"
137
 
138
  fig.update_layout(
139
+ title=title,
140
  xaxis_title="Date/Time",
141
  yaxis_title="Price",
142
  xaxis_rangeslider_visible=False,