AmirTrader commited on
Commit
c83b2fb
·
verified ·
1 Parent(s): 059818e

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +244 -0
  2. utils.py +85 -0
app.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # streamlit
2
+
3
+ import streamlit as st
4
+ import pandas as pd
5
+ import numpy as np
6
+ import plotly.express as px
7
+
8
+ import os
9
+ import time
10
+
11
+ from dotenv import load_dotenv
12
+ from datetime import datetime
13
+
14
+ from utils import upload_to_hf_dataset, download_from_hf_dataset, load_hf_dataset
15
+
16
+ # Get current date and time
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
+
24
+ # Get the name of the HuggingFace dataset for TradingView to read from
25
+ dataset_name_TradingView_input = os.getenv("dataset_name_TradingView_input")
26
+
27
+ # Get the name of the HuggingFace dataset for YfOptions to export
28
+ dataset_name_YfOptions_output = os.getenv("dataset_name_YfOptions_output")
29
+
30
+ # Get the Hugging Face API token from the environment; either set in .env file or in the environment directly in GitHub
31
+ HF_TOKEN_YfOptions = os.getenv("HF_TOKEN_YfOptions")
32
+
33
+ # Set page configuration
34
+ st.set_page_config(
35
+ page_title="Option Data Screener App",
36
+ page_icon="📊",
37
+ layout="wide"
38
+ )
39
+
40
+
41
+ @st.cache_data
42
+ def get_TD_DF(current_datetime):
43
+ # Load lastest TradingView DataSet from HuggingFace Dataset which is always america.csv
44
+ # download_from_hf_dataset("america.csv", "AmirTrader/TradingViewData", HF_TOKEN_YfOptions)
45
+ DF = load_hf_dataset("america.csv", HF_TOKEN_YfOptions, dataset_name_TradingView_input)
46
+
47
+ # get ticker list by filtering only above 1 billion dollar company
48
+ # DF = pd.read_csv(f'america_2024-03-01.csv')
49
+ tickerlst = list(DF.query("`Market Capitalization`>10e9").Ticker)
50
+ # tickerlist = ['INDO', 'TSLA', 'AAPL', 'MSFT', 'GOOGL', 'AMZN', 'NFLX', 'META', 'NVDA', 'AMD', 'INTC', 'IBM', 'CSCO', 'ORCL', 'QCOM', 'TXN', 'AVGO', 'ADBE', 'CRM', 'NFLX', 'PYPL', 'SNAP']
51
+ return DF, tickerlst
52
+
53
+ @st.cache_data
54
+ def get_options_DF(current_datetime):
55
+ DF = load_hf_dataset("optionchain.csv", HF_TOKEN_YfOptions, dataset_name_YfOptions_output)
56
+ return DF
57
+
58
+ @st.cache_data
59
+ def convert_df(df):
60
+ return df.to_csv().encode('utf-8')
61
+
62
+
63
+ @st.cache_data
64
+ def get_options_merge(current_datetime):
65
+
66
+ DF, tickerlst = get_TD_DF(current_datetime)
67
+
68
+ DF_options_origin = get_options_DF(current_datetime)
69
+
70
+ DF_options_origin['Volume_OpenInterest_Ratio'] = DF_options_origin['volume'] / DF_options_origin['openInterest']
71
+
72
+ # Extract ticker from contractSymbol and merge dataframes
73
+ DF_options_origin['Ticker'] = DF_options_origin['contractSymbol'].str.extract(r'([A-Z]+)')
74
+ TD_interestedColumns = ['Ticker', 'Market Capitalization', 'Relative Volume']
75
+ DF_options_merged = pd.merge(DF_options_origin, DF[TD_interestedColumns], on='Ticker', how='left')
76
+
77
+
78
+ # Pivot the DataFrame to separate 'Call' and 'Put' for volume
79
+ volume_pivot = DF_options_merged.groupby(['Ticker', 'Type'])['volume'].sum().unstack()
80
+ volume_pivot.columns = ['Call_Volume', 'Put_Volume']
81
+
82
+
83
+ # Pivot the DataFrame to separate 'Call' and 'Put' for openInterest
84
+ openInterest_pivot = DF_options_merged.groupby(['Ticker', 'Type'])['openInterest'].sum().unstack()
85
+ openInterest_pivot.columns = ['Call_openInterest', 'Put_openInterest']
86
+
87
+ # Merge the volume and open interest DataFrames
88
+ merged_df = volume_pivot.merge(openInterest_pivot, left_index=True, right_index=True)
89
+
90
+ # Calculate Put/Call Volume Ratio
91
+ merged_df['Put_Call_Volume_Ratio'] = merged_df['Put_Volume'] / merged_df['Call_Volume'] #.replace(0, pd.NA)
92
+
93
+ # Calculate Put/Call Open Interest Ratio
94
+ merged_df['Put_Call_OI_Ratio'] = merged_df['Put_openInterest'] / merged_df['Call_openInterest'] #.replace(0, pd.NA)
95
+
96
+ DFtotal = pd.merge(DF_options_merged, merged_df, left_on='Ticker', right_index=True, how='left')
97
+
98
+ return DFtotal, tickerlst
99
+
100
+ DF_options, tickerlst = get_options_merge(current_datetime)
101
+
102
+
103
+
104
+
105
+
106
+
107
+ # Title
108
+ st.title("📊 Options Data Dashboard")
109
+
110
+
111
+
112
+ st.write(f'Number of avialable tickers: {len(tickerlst)}')
113
+
114
+
115
+ st.write(f'Number of options records: {len(DF_options)}')
116
+
117
+ # Display options data
118
+ st.header("Options Data")
119
+
120
+ # Sidebar
121
+ st.sidebar.header("Controls")
122
+ st.sidebar.markdown("### Filter Options Data")
123
+ # Add volume and open interest filters in sidebar
124
+ min_volume = st.sidebar.number_input("Minimum Volume", min_value=0, value=100)
125
+ min_open_interest = st.sidebar.number_input("Minimum Open Interest", min_value=0, value=100)
126
+ min_vol_oi_ratio = st.sidebar.number_input("Minimum Volume/Open Interest Ratio", min_value=0.0, value=0.5, step=0.1)
127
+
128
+
129
+ st.sidebar.markdown("---") # Add a horizontal line as a visual separator
130
+
131
+ st.sidebar.markdown("### Filter Stock Data")
132
+ min_relative_volume = st.sidebar.number_input("Minimum Relative Volume", min_value=0.0, value=1.5, step=0.1)
133
+ min_put_call_volume = st.sidebar.number_input("Minimum Put/Call Volume Ratio", min_value=0.0, value=0.0, step=0.1)
134
+ min_put_call_oi = st.sidebar.number_input("Minimum Put/Call OI Ratio", min_value=0.0, value=0.0, step=0.1)
135
+
136
+ # Filter the dataframe
137
+ filtered_df = DF_options[
138
+ (DF_options['volume'] >= min_volume) &
139
+ (DF_options['openInterest'] >= min_open_interest) &
140
+ (DF_options['Relative Volume'] >= min_relative_volume) &
141
+ (DF_options['Put_Call_Volume_Ratio'] >= min_put_call_volume) &
142
+ (DF_options['Put_Call_OI_Ratio'] >= min_put_call_oi) &
143
+ (DF_options['Volume_OpenInterest_Ratio'] >= min_vol_oi_ratio)
144
+ ]
145
+
146
+ st.write(f"Filtered records: {len(filtered_df)} rows")
147
+
148
+
149
+ interestedColumns = ['contractSymbol' , 'volume', 'openInterest', 'impliedVolatility', 'Volume_OpenInterest_Ratio' , 'Relative Volume' , 'Put_Call_Volume_Ratio' , 'Put_Call_OI_Ratio' , ]
150
+
151
+ selected_columns = st.multiselect(
152
+ "Select columns to display",
153
+ options=filtered_df.columns.tolist(),
154
+ default=interestedColumns
155
+ )
156
+
157
+ if selected_columns:
158
+ st.dataframe(filtered_df[selected_columns])
159
+
160
+ # Download button for the DataFrame
161
+ csv = convert_df(filtered_df)
162
+ st.download_button(
163
+ label="Download Options Data as CSV",
164
+ data=csv,
165
+ file_name=f'options_data_{current_datetime}.csv',
166
+ mime='text/csv',
167
+ )
168
+
169
+ st.write(f"Filtered Tickers: {filtered_df['Ticker'].unique()} ")
170
+
171
+
172
+
173
+
174
+ st.sidebar.markdown("---") # Add a horizontal line as a visual separator
175
+ st.sidebar.header("Advanced")
176
+ # **Daily Change in Open Interest**
177
+ # Monitoring the increase or decrease in Open Interest compared to the previous day can indicate the inflow (rising OI) or outflow (declining OI) of capital. This factor helps assess the strength of the current trend.
178
+ st.sidebar.button("Daily Change in Open Interest ")
179
+ # contractSymbol
180
+ # lastTradeDate
181
+ # strike
182
+ # lastPrice
183
+ # bid
184
+ # ask
185
+ # change
186
+ # percentChange
187
+ # volume
188
+ # openInterest
189
+ # impliedVolatility
190
+ # inTheMoney
191
+ # contractSize
192
+ # currency
193
+ # Type
194
+ # expirationDate
195
+ # daysleft
196
+ # mark
197
+ # pricepercent
198
+ # pricepercentstrike
199
+ # interinsicvalue
200
+ # interinsicvalue%
201
+ # timevalue
202
+ # timevalue%
203
+ # breakevenprice
204
+
205
+ # # Create sample data
206
+ # np.random.seed(42)
207
+ # data = pd.DataFrame({
208
+ # 'x': np.random.randn(100),
209
+ # 'y': np.random.randn(100),
210
+ # 'category': np.random.choice(['A', 'B', 'C'], 100)
211
+ # })
212
+
213
+ # # Create two columns
214
+ # col1, col2 = st.columns(2)
215
+
216
+ # # First column - Scatter plot
217
+ # with col1:
218
+ # st.subheader("Scatter Plot")
219
+ # fig = px.scatter(data, x='x', y='y', color='category')
220
+ # st.plotly_chart(fig, use_container_width=True)
221
+
222
+ # # Second column - Bar chart
223
+ # with col2:
224
+ # st.subheader("Bar Chart")
225
+ # category_counts = data['category'].value_counts()
226
+ # fig = px.bar(x=category_counts.index, y=category_counts.values)
227
+ # st.plotly_chart(fig, use_container_width=True)
228
+
229
+ # # Add a checkbox
230
+ # if st.checkbox("Show raw data"):
231
+ # st.dataframe(data)
232
+
233
+ # # Add a download button
234
+ # @st.cache_data
235
+ # def convert_df(df):
236
+ # return df.to_csv().encode('utf-8')
237
+
238
+ # csv = convert_df(data)
239
+ # st.download_button(
240
+ # label="Download data as CSV",
241
+ # data=csv,
242
+ # file_name='sample_data.csv',
243
+ # mime='text/csv',
244
+ # )
utils.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def upload_to_hf_dataset(file_path, dataset_name, token, repo_type="dataset"):
2
+ """
3
+ Upload a file to a Hugging Face dataset repository.
4
+
5
+ Args:
6
+ file_path (str): Path to the file to upload
7
+ dataset_name (str): Name of the dataset in format 'username/dataset-name'
8
+ token (str): Hugging Face API token
9
+ repo_type (str): Repository type, defaults to 'dataset'
10
+ """
11
+ from huggingface_hub import HfApi
12
+ import os
13
+
14
+ # Initialize the Hugging Face API client
15
+ api = HfApi()
16
+
17
+ try:
18
+ # Upload the file to the dataset repository
19
+ api.upload_file(
20
+ path_or_fileobj=file_path,
21
+ path_in_repo=os.path.basename(file_path), # Use filename as path in repo
22
+ repo_id=dataset_name,
23
+ repo_type=repo_type,
24
+ token=token,
25
+ commit_message=f"Upload {os.path.basename(file_path)}",
26
+ commit_description=f"Automated upload of {os.path.basename(file_path)} to dataset",
27
+ )
28
+ print(f"Successfully uploaded {file_path} to {dataset_name}")
29
+ except Exception as e:
30
+ print(f"Error uploading file: {str(e)}")
31
+
32
+
33
+ def download_from_hf_dataset(file_path, dataset_name, token, repo_type="dataset"):
34
+ """
35
+ Download a file from a Hugging Face dataset repository.
36
+
37
+ Args:
38
+ file_path (str): Path in the repository to download from
39
+ dataset_name (str): Name of the dataset in format 'username/dataset-name'
40
+ token (str): Hugging Face API token
41
+ repo_type (str): Repository type, defaults to 'dataset'
42
+ """
43
+ from huggingface_hub import HfApi
44
+ import os
45
+
46
+ # Initialize the Hugging Face API client
47
+ api = HfApi()
48
+
49
+ try:
50
+ # Download the file from the dataset repository
51
+ api.hf_hub_download(
52
+ repo_id=dataset_name,
53
+ filename=file_path,
54
+ repo_type=repo_type,
55
+ local_dir=".",
56
+ token=token,
57
+ )
58
+ print(f"Successfully downloaded {file_path} from {dataset_name}")
59
+ except Exception as e:
60
+ print(f"Error downloading file: {str(e)}")
61
+
62
+
63
+ def load_hf_dataset(csv_filename, token, dataset_name_input):
64
+ """
65
+ Load a CSV dataset from Hugging Face and return as pandas DataFrame
66
+
67
+ Args:
68
+ csv_filename (str): Name of the CSV file in the dataset
69
+ token (str): Hugging Face authentication token
70
+
71
+ Returns:
72
+ pandas.DataFrame: DataFrame containing the dataset
73
+ """
74
+ from datasets import load_dataset
75
+
76
+ try:
77
+ dataset = load_dataset(
78
+ dataset_name_input, data_files=csv_filename, split="train", token=token
79
+ )
80
+ return dataset.to_pandas()
81
+ except Exception as e:
82
+ print(f"Error loading dataset: {e}")
83
+ return None
84
+
85
+