AmirTrader commited on
Commit
a023d86
·
verified ·
1 Parent(s): b835338

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +225 -67
app.py CHANGED
@@ -17,7 +17,6 @@ from utils import upload_to_hf_dataset, download_from_hf_dataset, load_hf_datase
17
  # current_datetime = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
18
  current_datetime = datetime.now().strftime("%Y-%m-%d")
19
 
20
-
21
  # Load environment variables from .env file
22
  load_dotenv()
23
 
@@ -33,6 +32,9 @@ HF_TOKEN_YfOptions = os.getenv("HF_TOKEN_YfOptions")
33
  # Set page configuration
34
  st.set_page_config(page_title="Option Data Screener App", page_icon="📊", layout="wide")
35
 
 
 
 
36
 
37
  @st.cache_data
38
  def get_TD_DF(current_datetime):
@@ -57,11 +59,14 @@ def get_options_DF(current_datetime):
57
  return DF
58
 
59
 
60
- @st.cache_data
61
  def convert_df(df):
62
  return df.to_csv().encode("utf-8")
63
 
64
 
 
 
 
 
65
  @st.cache_data
66
  def get_options_merge(current_datetime):
67
  DF, tickerlst = get_TD_DF(current_datetime)
@@ -115,6 +120,9 @@ def get_options_merge(current_datetime):
115
  return DFtotal, tickerlst
116
 
117
 
 
 
 
118
  DF_options, tickerlst = get_options_merge(current_datetime)
119
 
120
 
@@ -153,12 +161,12 @@ open_interest_range = st.sidebar.slider(
153
  vol_oi_ratio_range = st.sidebar.slider(
154
  "Volume/Open Interest Ratio Range",
155
  min_value=0.0,
156
- max_value=100.0, #np.nanmax(
157
  # DF_options["Volume_OpenInterest_Ratio"][
158
  # ~np.isinf(DF_options["Volume_OpenInterest_Ratio"])
159
  # ]
160
  # ),
161
- value=(0.0,10.0), #(
162
  # 0.5,
163
  # np.nanmax(
164
  # DF_options["Volume_OpenInterest_Ratio"][
@@ -190,54 +198,61 @@ put_call_oi_range = st.sidebar.slider(
190
  "Put/Call OI Ratio Range", min_value=0.0, max_value=10.0, value=(0.0, 3.0), step=0.1
191
  )
192
 
193
- # if st.sidebar.button("Filter"):
194
- # Filter the dataframe with the range
195
- filtered_df = DF_options[
196
- (DF_options["volume"] >= volume_range[0])
197
- & (DF_options["volume"] <= volume_range[1])
198
- & (DF_options["openInterest"] >= open_interest_range[0])
199
- & (DF_options["openInterest"] <= open_interest_range[1])
200
- & (DF_options["Relative Volume"] >= min_relative_volume)
201
- & (DF_options["Put_Call_Volume_Ratio"] >= put_call_volume_range[0])
202
- & (DF_options["Put_Call_Volume_Ratio"] <= put_call_volume_range[1])
203
- & (DF_options["Put_Call_OI_Ratio"] >= put_call_oi_range[0])
204
- & (DF_options["Put_Call_OI_Ratio"] <= put_call_oi_range[1])
205
- & (DF_options["Volume_OpenInterest_Ratio"] >= vol_oi_ratio_range[0])
206
- & (DF_options["Volume_OpenInterest_Ratio"] <= vol_oi_ratio_range[1])
207
- ]
208
-
209
- st.write(f"Filtered records: {len(filtered_df)} rows")
210
-
211
- interestedColumns = [
212
- "contractSymbol",
213
- "volume",
214
- "openInterest",
215
- "impliedVolatility",
216
- "Volume_OpenInterest_Ratio",
217
- "Relative Volume",
218
- "Put_Call_Volume_Ratio",
219
- "Put_Call_OI_Ratio",
220
- ]
221
-
222
- selected_columns = st.multiselect(
223
- "Select columns to display",
224
- options=filtered_df.columns.tolist(),
225
- default=interestedColumns,
226
- )
227
-
228
- if selected_columns:
229
- st.dataframe(filtered_df[selected_columns])
230
-
231
- # Download button for the DataFrame
232
- csv = convert_df(filtered_df)
233
- st.download_button(
234
- label="Download Options Data as CSV",
235
- data=csv,
236
- file_name=f"options_data_{current_datetime}.csv",
237
- mime="text/csv",
238
- )
239
 
240
- st.write(f"Filtered Tickers: {filtered_df['Ticker'].unique()} ")
 
 
 
 
 
 
 
241
 
242
 
243
  st.sidebar.markdown("---") # Add a horizontal line as a visual separator
@@ -249,26 +264,169 @@ selectedTicker = st.sidebar.selectbox(
249
  index=tickerlst.index("AAPL") if "AAPL" in tickerlst else 0,
250
  )
251
 
252
- if st.sidebar.button("Submit"):
253
  st.write(f"Ticker {selectedTicker}")
254
  # filter DF_options for selectedTicker
255
  filtered_ticker_df = DF_options[DF_options["Ticker"] == selectedTicker]
256
- # plot plotly3D scatter plot for filtered_ticker_df for volume, openInterest and impliedVolatility
257
- fig = px.scatter_3d(
258
- filtered_ticker_df,
259
- x="volume",
260
- y="openInterest",
261
- z="impliedVolatility",
262
- color="Type",
263
- title=f"3D Scatter Plot for {selectedTicker}",
264
- hover_data=["strike", "lastPrice", "mark", "daysleft", "contractSymbol", "expirationDate"],
265
- color_discrete_map={"CALL": "green", "PUT": "red"}
266
- )
267
- fig.update_layout(
268
- autosize=True, width=2560, height=600, margin=dict(l=50, r=50, b=50, t=50)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  )
270
- st.plotly_chart(fig) # , use_container_width=True)
271
- # Display the filtered DataFrame
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
 
274
  st.sidebar.markdown("---") # Add a horizontal line as a visual separator
 
17
  # current_datetime = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
18
  current_datetime = datetime.now().strftime("%Y-%m-%d")
19
 
 
20
  # Load environment variables from .env file
21
  load_dotenv()
22
 
 
32
  # Set page configuration
33
  st.set_page_config(page_title="Option Data Screener App", page_icon="📊", layout="wide")
34
 
35
+ ########################################################################################################
36
+ # Functions
37
+
38
 
39
  @st.cache_data
40
  def get_TD_DF(current_datetime):
 
59
  return DF
60
 
61
 
 
62
  def convert_df(df):
63
  return df.to_csv().encode("utf-8")
64
 
65
 
66
+ def convert_df_watchlist(df):
67
+ return ",".join(map(str, df["Ticker"].unique()))
68
+
69
+
70
  @st.cache_data
71
  def get_options_merge(current_datetime):
72
  DF, tickerlst = get_TD_DF(current_datetime)
 
120
  return DFtotal, tickerlst
121
 
122
 
123
+ ########################################################################################################
124
+ # Main
125
+
126
  DF_options, tickerlst = get_options_merge(current_datetime)
127
 
128
 
 
161
  vol_oi_ratio_range = st.sidebar.slider(
162
  "Volume/Open Interest Ratio Range",
163
  min_value=0.0,
164
+ max_value=100.0, # np.nanmax(
165
  # DF_options["Volume_OpenInterest_Ratio"][
166
  # ~np.isinf(DF_options["Volume_OpenInterest_Ratio"])
167
  # ]
168
  # ),
169
+ value=(0.0, 10.0), # (
170
  # 0.5,
171
  # np.nanmax(
172
  # DF_options["Volume_OpenInterest_Ratio"][
 
198
  "Put/Call OI Ratio Range", min_value=0.0, max_value=10.0, value=(0.0, 3.0), step=0.1
199
  )
200
 
201
+ if st.sidebar.button("Filter"):
202
+ # Filter the dataframe with the range
203
+ filtered_df = DF_options[
204
+ (DF_options["volume"] >= volume_range[0])
205
+ & (DF_options["volume"] <= volume_range[1])
206
+ & (DF_options["openInterest"] >= open_interest_range[0])
207
+ & (DF_options["openInterest"] <= open_interest_range[1])
208
+ & (DF_options["Relative Volume"] >= min_relative_volume)
209
+ & (DF_options["Put_Call_Volume_Ratio"] >= put_call_volume_range[0])
210
+ & (DF_options["Put_Call_Volume_Ratio"] <= put_call_volume_range[1])
211
+ & (DF_options["Put_Call_OI_Ratio"] >= put_call_oi_range[0])
212
+ & (DF_options["Put_Call_OI_Ratio"] <= put_call_oi_range[1])
213
+ & (DF_options["Volume_OpenInterest_Ratio"] >= vol_oi_ratio_range[0])
214
+ & (DF_options["Volume_OpenInterest_Ratio"] <= vol_oi_ratio_range[1])
215
+ ]
216
+
217
+ st.write(f"Filtered records: {len(filtered_df)} rows")
218
+
219
+ interestedColumns = [
220
+ "contractSymbol",
221
+ "volume",
222
+ "openInterest",
223
+ "impliedVolatility",
224
+ "Volume_OpenInterest_Ratio",
225
+ "Relative Volume",
226
+ "Put_Call_Volume_Ratio",
227
+ "Put_Call_OI_Ratio",
228
+ ]
229
+
230
+ # selected_columns = st.sidebar.multiselect(
231
+ # "Select columns to display",
232
+ # options=DF_options.columns.tolist(),
233
+ # default=interestedColumns,
234
+ # )
235
+
236
+ if interestedColumns:
237
+ st.dataframe(filtered_df[interestedColumns].reset_index(drop=True))
238
+
239
+ # Download button for the DataFrame
240
+ csv = convert_df(filtered_df)
241
+ st.download_button(
242
+ label="Download Options Data as CSV",
243
+ data=csv,
244
+ file_name=f"options_data_{current_datetime}.csv",
245
+ mime="text/csv",
246
+ )
247
 
248
+ csv = convert_df_watchlist(filtered_df)
249
+ st.download_button(
250
+ label="Download Stock WatchList for TradingView",
251
+ data=csv,
252
+ file_name=f"filtered_options_data_{current_datetime}.txt",
253
+ mime="text/csv",
254
+ )
255
+ st.write(f"Unique Filtered Tickers: **{csv}** ")
256
 
257
 
258
  st.sidebar.markdown("---") # Add a horizontal line as a visual separator
 
264
  index=tickerlst.index("AAPL") if "AAPL" in tickerlst else 0,
265
  )
266
 
267
+ if st.sidebar.button("Option Chain Visualization"):
268
  st.write(f"Ticker {selectedTicker}")
269
  # filter DF_options for selectedTicker
270
  filtered_ticker_df = DF_options[DF_options["Ticker"] == selectedTicker]
271
+
272
+ # Create two columns for the charts
273
+ col1, col2, col3 = st.columns(3)
274
+
275
+ with col1:
276
+ fig_3d = px.scatter_3d(
277
+ filtered_ticker_df,
278
+ x="volume",
279
+ y="openInterest",
280
+ z="impliedVolatility",
281
+ color="Type",
282
+ title=f"3D Scatter Plot for {selectedTicker}",
283
+ hover_data=[
284
+ "strike",
285
+ "lastPrice",
286
+ "mark",
287
+ "daysleft",
288
+ "contractSymbol",
289
+ "expirationDate",
290
+ ],
291
+ color_discrete_map={"CALL": "green", "PUT": "red"},
292
+ )
293
+ fig_3d.update_layout(
294
+ autosize=True, height=600, margin=dict(l=50, r=50, b=50, t=50)
295
+ )
296
+ st.plotly_chart(fig_3d, use_container_width=True)
297
+
298
+ with col2:
299
+ # 3D Volatility Surface: Implied Volatility by Strike and Days to Expiration
300
+ fig_surface = px.scatter_3d(
301
+ filtered_ticker_df,
302
+ x="strike",
303
+ y="daysleft",
304
+ z="impliedVolatility",
305
+ color="Type",
306
+ title=f"Implied Volatility Surface for {selectedTicker}",
307
+ hover_data=[
308
+ "volume",
309
+ "openInterest",
310
+ "lastPrice",
311
+ "mark",
312
+ "contractSymbol",
313
+ ],
314
+ color_discrete_map={"CALL": "green", "PUT": "red"},
315
+ )
316
+ fig_surface.update_traces(marker=dict(size=5))
317
+ fig_surface.update_layout(
318
+ scene=dict(
319
+ xaxis_title="Strike Price",
320
+ yaxis_title="Days to Expiration",
321
+ zaxis_title="Implied Volatility",
322
+ ),
323
+ autosize=True,
324
+ height=600,
325
+ margin=dict(l=50, r=50, b=50, t=50),
326
+ )
327
+ st.plotly_chart(fig_surface, use_container_width=True)
328
+
329
+ with col3:
330
+ # 3D Surface Plot: Option Price vs. Strike Price and Days to Expiration
331
+ fig_surface2 = px.scatter_3d(
332
+ filtered_ticker_df,
333
+ x="strike",
334
+ y="daysleft",
335
+ z="lastPrice",
336
+ color="Type",
337
+ title=f"Option Price Surface for {selectedTicker}",
338
+ hover_data=[
339
+ "volume",
340
+ "openInterest",
341
+ "impliedVolatility",
342
+ "mark",
343
+ "contractSymbol",
344
+ ],
345
+ color_discrete_map={"CALL": "green", "PUT": "red"},
346
+ )
347
+ fig_surface2.update_traces(marker=dict(size=5))
348
+ fig_surface2.update_layout(
349
+ scene=dict(
350
+ xaxis_title="Strike Price",
351
+ yaxis_title="Days to Expiration",
352
+ zaxis_title="Option Price",
353
+ ),
354
+ autosize=True,
355
+ height=600,
356
+ margin=dict(l=50, r=50, b=50, t=50),
357
+ )
358
+ st.plotly_chart(fig_surface2, use_container_width=True)
359
+
360
+ # Display the filtered DataFrame
361
+ st.dataframe(
362
+ filtered_ticker_df.query("Ticker ==@selectedTicker")[
363
+ [
364
+ "contractSymbol",
365
+ "daysleft",
366
+ "Type",
367
+ "strike",
368
+ "lastPrice",
369
+ "volume",
370
+ "openInterest",
371
+ "impliedVolatility",
372
+ "inTheMoney",
373
+ ]
374
+ ].reset_index(drop=True),
375
+ use_container_width=True,
376
+ hide_index=True,
377
+ height=600,
378
  )
379
+
380
+ # Create two columns for the charts
381
+ col1, col2, col3 = st.columns(3)
382
+
383
+ with col1:
384
+ # Bar chart for Volume by Strike Price
385
+ fig_bar = px.bar(
386
+ filtered_ticker_df,
387
+ x="strike",
388
+ y="volume",
389
+ color="Type",
390
+ title=f"Volume by Strike Price for {selectedTicker}",
391
+ barmode="group",
392
+ color_discrete_map={"CALL": "green", "PUT": "red"},
393
+ )
394
+ fig_bar.update_layout(
395
+ xaxis_title="Strike Price", yaxis_title="Volume", autosize=True, height=600
396
+ )
397
+ st.plotly_chart(fig_bar, use_container_width=True)
398
+
399
+ with col2:
400
+ # Bar chart for Open Interest by Expiration Date
401
+ fig_bar2 = px.bar(
402
+ filtered_ticker_df,
403
+ x="expirationDate",
404
+ y="openInterest",
405
+ color="Type",
406
+ title=f"Open Interest by Expiration Date for {selectedTicker}",
407
+ barmode="group",
408
+ color_discrete_map={"CALL": "green", "PUT": "red"},
409
+ )
410
+ fig_bar.update_layout(
411
+ xaxis_title="Expiration Date",
412
+ yaxis_title="Open Interest",
413
+ autosize=True,
414
+ height=600,
415
+ )
416
+ st.plotly_chart(fig_bar2, use_container_width=True)
417
+
418
+ with col3:
419
+ # mplied Volatility by Strike Price
420
+ fig_bar3 = px.bar(
421
+ filtered_ticker_df,
422
+ x="strike",
423
+ y="impliedVolatility",
424
+ color="Type",
425
+ title=f"Implied Volatility by Strike Price for {selectedTicker}",
426
+ barmode="group",
427
+ color_discrete_map={"CALL": "green", "PUT": "red"},
428
+ )
429
+ st.plotly_chart(fig_bar3, use_container_width=True)
430
 
431
 
432
  st.sidebar.markdown("---") # Add a horizontal line as a visual separator