diff --git a/.github/dependencies/sqlite3.dll b/.github/dependencies/sqlite3.dll new file mode 100644 index 00000000..e1230593 Binary files /dev/null and b/.github/dependencies/sqlite3.dll differ diff --git a/.github/workflows/workflow-build-matrix.yml b/.github/workflows/workflow-build-matrix.yml index 56d35732..6763eee7 100644 --- a/.github/workflows/workflow-build-matrix.yml +++ b/.github/workflows/workflow-build-matrix.yml @@ -24,7 +24,7 @@ jobs: - os: windows-latest TARGET: Windows CMD_BUILD: | - pyinstaller --onefile --icon=src\icon.ico src\screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import alive_progress + pyinstaller --onefile --icon=src\icon.ico src\screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import alive_progress --hidden-import chromadb DEP_BUILD: | python -m pip install --upgrade pip echo Installing TA-lib... @@ -44,7 +44,7 @@ jobs: - os: ubuntu-20.04 TARGET: Linux CMD_BUILD: | - pyinstaller --onefile --icon=src/icon.ico src/screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import alive_progress + pyinstaller --onefile --icon=src/icon.ico src/screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import alive_progress --hidden-import chromadb mv /home/runner/work/Screeni-py/Screeni-py/dist/screenipy /home/runner/work/Screeni-py/Screeni-py/dist/screenipy.bin chmod +x /home/runner/work/Screeni-py/Screeni-py/dist/screenipy.bin DEP_BUILD: | @@ -68,7 +68,7 @@ jobs: - os: macos-latest TARGET: MacOS CMD_BUILD: | - pyinstaller --onefile --windowed --icon=src/icon.ico src/screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import alive_progress + pyinstaller --onefile --windowed --icon=src/icon.ico src/screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import alive_progress --hidden-import chromadb mv /Users/runner/work/Screeni-py/Screeni-py/dist/screenipy /Users/runner/work/Screeni-py/Screeni-py/dist/screenipy.run DEP_BUILD: | brew install ta-lib diff --git a/requirements.txt b/requirements.txt index c852a3a9..b8521039 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ pyinstaller==5.6.2 pytest-mock pytoml retrying -scipy==1.7.3 +scipy==1.11.2 ta-lib tabulate yfinance==0.1.87 @@ -61,4 +61,5 @@ pandas_ta # protobuf==3.19.6 protobuf streamlit==1.26.0 -tensorflow \ No newline at end of file +tensorflow +chromadb==0.4.10 \ No newline at end of file diff --git a/src/classes/Changelog.py b/src/classes/Changelog.py index 88b02db4..e7f9ee0e 100644 --- a/src/classes/Changelog.py +++ b/src/classes/Changelog.py @@ -7,7 +7,7 @@ from classes.ColorText import colorText -VERSION = "2.02" +VERSION = "2.03" changelog = colorText.BOLD + '[ChangeLog]\n' + colorText.END + colorText.BLUE + ''' [1.00 - Beta] @@ -216,4 +216,8 @@ 3. Cosmetic improvements 4. YouTube Video added to docs +[2.03] +1. AI based Nifty-50 Gap up/down prediction added to GUI +2. Cosmetic updates and minor bug-fixes. + ''' + colorText.END diff --git a/src/classes/OtaUpdater.py b/src/classes/OtaUpdater.py index 3dd1cfb1..3220e2ee 100644 --- a/src/classes/OtaUpdater.py +++ b/src/classes/OtaUpdater.py @@ -85,7 +85,8 @@ def showWhatsNew(): md = requests.get(url) txt = md.text txt = txt.split("New?")[1] - txt = txt.split("## Downloads")[0] + # txt = txt.split("## Downloads")[0] + txt = txt.split("## Installation Guide")[0] txt = txt.replace('**','').replace('`','').strip() return (txt+"\n") diff --git a/src/classes/ParallelProcessing.py b/src/classes/ParallelProcessing.py index 54a94a26..6fdf7459 100644 --- a/src/classes/ParallelProcessing.py +++ b/src/classes/ParallelProcessing.py @@ -59,7 +59,7 @@ def run(self): sys.exit(0) def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respChartPattern, insideBarToLookback, totalSymbols, - configManager, fetcher, screener, candlePatterns, stock, newlyListedOnly, downloadOnly, printCounter=False): + configManager, fetcher, screener, candlePatterns, stock, newlyListedOnly, downloadOnly, vectorSearch, printCounter=False): screenResults = pd.DataFrame(columns=[ 'Stock', 'Consolidating', 'Breaking-Out', 'MA-Signal', 'Volume', 'LTP', 'RSI', 'Trend', 'Pattern']) screeningDictionary = {'Stock': "", 'Consolidating': "", 'Breaking-Out': "", @@ -105,6 +105,11 @@ def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVol fullData, processedData = screener.preprocessData( data, daysToLookback=configManager.daysToLookback) + + if type(vectorSearch) != bool and type(vectorSearch) and vectorSearch[2] == True: + executeOption = 0 + with self.screenCounter.get_lock(): + screener.addVector(fullData, stock, vectorSearch[1]) if newlyListedOnly: if not screener.validateNewlyListed(fullData, period): diff --git a/src/classes/Screener.py b/src/classes/Screener.py index 7dd242c3..ecc3830e 100644 --- a/src/classes/Screener.py +++ b/src/classes/Screener.py @@ -9,16 +9,22 @@ import math import numpy as np import pandas as pd -# import talib import joblib import keras +import time import classes.Utility as Utility +from classes.Utility import isGui from sklearn.preprocessing import StandardScaler from scipy.signal import argrelextrema from scipy.stats import linregress from classes.ColorText import colorText from classes.SuppressOutput import SuppressOutput from classes.ScreenipyTA import ScreenerTA +try: + import chromadb + CHROMA_AVAILABLE = True +except: + CHROMA_AVAILABLE = False # Exception for newly listed stocks with candle nos < daysToLookback @@ -592,9 +598,11 @@ def getNiftyPrediction(self, data, proxyServer): out = colorText.BOLD + colorText.GREEN + "BULLISH" + colorText.END + colorText.BOLD sug = "Stay Bullish!" if not Utility.tools.isClosingHour(): - print(colorText.BOLD + colorText.WARN + "Note: The AI prediction should be executed After 3 PM or Near to Closing time as the Prediction Accuracy is based on the Closing price!" + colorText.END) + print(colorText.BOLD + colorText.WARN + "Note: The AI prediction should be executed After 3 PM Around the Closing hours as the Prediction Accuracy is based on the Closing price!" + colorText.END) print(colorText.BOLD + colorText.BLUE + "\n" + "[+] Nifty AI Prediction -> " + colorText.END + colorText.BOLD + "Market may Open {} next day! {}".format(out, sug) + colorText.END) print(colorText.BOLD + colorText.BLUE + "\n" + "[+] Nifty AI Prediction -> " + colorText.END + "Probability/Strength of Prediction = {}%".format(Utility.tools.getSigmoidConfidence(pred[0]))) + if isGui(): + return pred, 'BULLISH' if pred <= 0.5 else 'BEARISH', Utility.tools.getSigmoidConfidence(pred[0]) return pred def monitorFiveEma(self, proxyServer, fetcher, result_df, last_signal, risk_reward = 3): @@ -668,7 +676,27 @@ def monitorFiveEma(self, proxyServer, fetcher, result_df, last_signal, risk_rewa result_df.drop_duplicates(keep='last', inplace=True) result_df.sort_values(by='Time', inplace=True) return result_df[::-1] - + + # Add data to vector database + def addVector(self, data, stockCode, daysToLookback): + data = data[::-1] # Reinverting preprocessedData for pct_change + data = data.pct_change() + # data = data[::-1] # Do we need to invert again? No we dont - See operation after flatten + data = data[['Open', 'High', 'Low', 'Close']] + data = data.reset_index(drop=True) + data = data.dropna() + data = data.to_numpy().flatten().tolist() + data = data[(-4 * daysToLookback):] # Keep only OHLC * daysToLookback samples + if len(data) == (4 * daysToLookback): + chroma_client = chromadb.PersistentClient(path="./chromadb_store/") + collection = chroma_client.get_or_create_collection(name="nse_stocks") + collection.upsert( + embeddings=[data], + documents=[stockCode], + ids=[stockCode] + ) + return data + ''' # Find out trend for days to lookback diff --git a/src/classes/Utility.py b/src/classes/Utility.py index e037f910..42789412 100644 --- a/src/classes/Utility.py +++ b/src/classes/Utility.py @@ -286,6 +286,19 @@ def promptChartPatterns(): input(colorText.BOLD + colorText.FAIL + "\n[+] Invalid Option Selected. Press Any Key to Continue..." + colorText.END) return (None, None) + + # Prompt for Similar stock search + def promptSimilarStockSearch(): + try: + stockCode = str(input(colorText.BOLD + colorText.WARN + + "\n[+] Enter the Name of the stock to search similar stocks for: " + colorText.END)).upper() + candles = int(input(colorText.BOLD + colorText.WARN + + "\n[+] How many candles (TimeFrame) to look back for similarity? : " + colorText.END)) + return stockCode, candles + except ValueError: + input(colorText.BOLD + colorText.FAIL + + "\n[+] Invalid Option Selected. Press Any Key to Continue..." + colorText.END) + return None, None def getProgressbarStyle(): bar = 'smooth' diff --git a/src/release.md b/src/release.md index ef588070..2d85dbcb 100644 --- a/src/release.md +++ b/src/release.md @@ -16,12 +16,13 @@ Celebrating more than 7K+ Downloads - Thank You for your support :tada: [![Screeni-py - Detailed Installation Guide](https://markdown-videos-api.jorgenkh.no/url?url=https%3A%2F%2Fyoutu.be%2F2HMN0ac4H20)](https://youtu.be/2HMN0ac4H20) -## Downloads +## Downloads +#### Deprycated - Use Docker Method mentioned in next section | Operating System | Executable File | | :-: | --- | -| ![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white) | **[screenipy.exe](https://github.com/pranjal-joshi/Screeni-py/releases/download/2.02/screenipy.exe)** | -| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black) | **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/2.02/screenipy.bin)** | -| ![Mac OS](https://img.shields.io/badge/mac%20os-D3D3D3?style=for-the-badge&logo=apple&logoColor=000000) | **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/2.02/screenipy.run)** ([Read Installation Guide](https://github.com/pranjal-joshi/Screeni-py/blob/main/INSTALLATION.md#for-macos)) | +| ![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white) | **[screenipy.exe](https://github.com/pranjal-joshi/Screeni-py/releases/download/2.03/screenipy.exe)** | +| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black) | **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/2.03/screenipy.bin)** | +| ![Mac OS](https://img.shields.io/badge/mac%20os-D3D3D3?style=for-the-badge&logo=apple&logoColor=000000) | **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/2.03/screenipy.run)** ([Read Installation Guide](https://github.com/pranjal-joshi/Screeni-py/blob/main/INSTALLATION.md#for-macos)) | ## [Docker Releases](https://hub.docker.com/r/joshipranjal/screeni-py/tags) diff --git a/src/screenipy.py b/src/screenipy.py index f5d37031..c15d105f 100644 --- a/src/screenipy.py +++ b/src/screenipy.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 -# Pyinstaller compile Windows: pyinstaller --onefile --icon=src\icon.ico src\screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress -# Pyinstaller compile Linux : pyinstaller --onefile --icon=src/icon.ico src/screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress +# Pyinstaller compile Windows: pyinstaller --onefile --icon=src\icon.ico src\screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import chromadb +# Pyinstaller compile Linux : pyinstaller --onefile --icon=src/icon.ico src/screenipy.py --hidden-import cmath --hidden-import talib.stream --hidden-import numpy --hidden-import pandas --hidden-import alive-progress --hidden-import chromadb # Keep module imports prior to classes import os @@ -28,6 +28,11 @@ from tabulate import tabulate import multiprocessing multiprocessing.freeze_support() +try: + import chromadb + CHROMA_AVAILABLE = True +except: + CHROMA_AVAILABLE = False # Argument Parsing for test purpose argParser = argparse.ArgumentParser() @@ -51,6 +56,9 @@ loadCount = 0 maLength = None newlyListedOnly = False +vectorSearch = False + +CHROMADB_PATH = "chromadb_store/" configManager = ConfigManager.tools() fetcher = Fetcher.tools(configManager) @@ -63,6 +71,15 @@ except KeyError: proxyServer = "" +# Clear chromadb store initially +if CHROMA_AVAILABLE: + chroma_client = chromadb.PersistentClient(path=CHROMADB_PATH) + try: + chroma_client.delete_collection("nse_stocks") + except: + pass + + # Manage Execution flow @@ -74,6 +91,7 @@ def initExecution(): W > Screen stocks from my own Watchlist N > Nifty Prediction using Artifical Intelligence (Use for Gap-Up/Gap-Down/BTST/STBT) E > Live Index Scan : 5 EMA for Intraday + S > Search for Similar Stocks (forming Similar Chart Pattern) 0 > Screen stocks by the stock names (NSE Stock Code) 1 > Nifty 50 2 > Nifty Next 50 3 > Nifty 100 @@ -108,7 +126,7 @@ def initExecution(): Utility.tools.clearScreen() return initExecution() - if tickerOption == 'N' or tickerOption == 'E': + if tickerOption == 'N' or tickerOption == 'E' or tickerOption == 'S': return tickerOption, 0 if tickerOption and tickerOption != 'W': @@ -153,7 +171,7 @@ def initExecution(): # Main function def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list = []): - global screenCounter, screenResultsCounter, stockDict, loadedStockData, keyboardInterruptEvent, loadCount, maLength, newlyListedOnly + global screenCounter, screenResultsCounter, stockDict, loadedStockData, keyboardInterruptEvent, loadCount, maLength, newlyListedOnly, vectorSearch screenCounter = multiprocessing.Value('i', 1) screenResultsCounter = multiprocessing.Value('i', 0) keyboardInterruptEvent = multiprocessing.Manager().Event() @@ -184,7 +202,10 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list if execute_inputs != []: if not configManager.checkConfigFile(): configManager.setConfig(ConfigManager.parser, default=True, showFileCreatedText=False) - tickerOption, executeOption = int(execute_inputs[0]), int(execute_inputs[1]) + try: + tickerOption, executeOption = int(execute_inputs[0]), int(execute_inputs[1]) + except: + tickerOption, executeOption = str(execute_inputs[0]), int(execute_inputs[1]) if tickerOption == 13: newlyListedOnly = True tickerOption = 12 @@ -268,7 +289,7 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list "[+] Press any key to Exit!" + colorText.END) sys.exit(0) - if tickerOption == 'W' or tickerOption == 'N' or tickerOption == 'E' or (tickerOption >= 0 and tickerOption < 15): + if tickerOption == 'W' or tickerOption == 'N' or tickerOption == 'E' or tickerOption == 'S' or (tickerOption >= 0 and tickerOption < 15): configManager.getConfig(ConfigManager.parser) try: if tickerOption == 'W': @@ -316,6 +337,18 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list if not isGui(): input('\nPress any key to Continue...\n') return + elif tickerOption == 'S': + if not CHROMA_AVAILABLE: + print(colorText.BOLD + colorText.FAIL + + "\n\n[+] ChromaDB not available in your environment! You can't use this feature!\n" + colorText.END) + else: + if execute_inputs != []: + stockCode, candles = execute_inputs[2], execute_inputs[3] + else: + stockCode, candles = Utility.tools.promptSimilarStockSearch() + vectorSearch = [stockCode, candles, True] + tickerOption, executeOption = 12, 1 + listStockCodes = fetcher.fetchStockCodes(tickerOption, proxyServer=proxyServer) else: if tickerOption == 14: # Override config for F&O Stocks configManager.stageTwo = False @@ -338,7 +371,7 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list "[+] Starting Stock Screening.. Press Ctrl+C to stop!\n") items = [(executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respChartPattern, insideBarToLookback, len(listStockCodes), - configManager, fetcher, screener, candlePatterns, stock, newlyListedOnly, downloadOnly) + configManager, fetcher, screener, candlePatterns, stock, newlyListedOnly, downloadOnly, vectorSearch) for stock in listStockCodes] tasks_queue = multiprocessing.JoinableQueue() @@ -416,6 +449,25 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list except Exception as e: break + if CHROMA_AVAILABLE and type(vectorSearch) == list and vectorSearch[2]: + chroma_client = chromadb.PersistentClient(path=CHROMADB_PATH) + collection = chroma_client.get_collection(name="nse_stocks") + query_embeddings= collection.get(ids = [stockCode], include=["embeddings"])["embeddings"] + results = collection.query( + query_embeddings=query_embeddings, + n_results=4 + )['ids'][0] + try: + results.remove(stockCode) + except ValueError: + pass + matchedScreenResults, matchedSaveResults = pd.DataFrame(columns=screenResults.columns), pd.DataFrame(columns=saveResults.columns) + for stk in results: + matchedScreenResults = matchedScreenResults.append(screenResults[screenResults['Stock'].str.contains(stk)]) + matchedSaveResults = matchedSaveResults.append(saveResults[saveResults['Stock'].str.contains(stk)]) + screenResults, saveResults = matchedScreenResults, matchedSaveResults + + screenResults.sort_values(by=['Stock'], ascending=True, inplace=True) saveResults.sort_values(by=['Stock'], ascending=True, inplace=True) screenResults.set_index('Stock', inplace=True) @@ -456,6 +508,7 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list if not isGui(): input('') newlyListedOnly = False + vectorSearch = False if __name__ == "__main__": @@ -474,7 +527,7 @@ def main(testing=False, testBuild=False, downloadOnly=False, execute_inputs:list while True: main() except Exception as e: - # raise e + raise e if isDevVersion == OTAUpdater.developmentVersion: raise(e) input(colorText.BOLD + colorText.FAIL + diff --git a/src/streamlit_app.py b/src/streamlit_app.py index 8ba42d07..d1ce7f42 100644 --- a/src/streamlit_app.py +++ b/src/streamlit_app.py @@ -31,6 +31,23 @@ execute_inputs = [] +def show_df_as_result_table(): + try: + df = pd.read_pickle('last_screened_unformatted_results.pkl') + st.markdown(f'#### 🔍 Found {len(df)} Results') + df.index = df.index.map(lambda x: "https://in.tradingview.com/chart?symbol=NSE%3A" + x) + df.index = df.index.map(lambda x: f'{x.split("%3A")[-1]}') + df['Stock'] = df.index + stock_column = df.pop('Stock') # Remove 'Age' column and store it separately + df.insert(0, 'Stock', stock_column) + st.write(df.to_html(escape=False, index=False, index_names=False), unsafe_allow_html=True) + st.write(' ') + except FileNotFoundError: + st.error('Last Screened results are not available at the moment') + except Exception as e: + st.error('No Dataframe found for last_screened_results.pkl') + st.exception(e) + def on_config_change(): configManager = ConfigManager.tools() configManager.period = period @@ -55,6 +72,40 @@ def on_start_button_click(): except StopIteration: pass +def nifty_predict(col): + with col.container(): + with st.spinner('🔮 Taking a Look into the Future, Please wait...'): + import classes.Fetcher as Fetcher + import classes.Screener as Screener + configManager = ConfigManager.tools() + fetcher = Fetcher.tools(configManager) + screener = Screener.tools(configManager) + os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' + prediction, trend, confidence = screener.getNiftyPrediction( + data=fetcher.fetchLatestNiftyDaily(proxyServer=proxyServer), + proxyServer=proxyServer + ) + if 'BULLISH' in trend: + col.success(f'Market may Open **Gap Up** next day!\n\nProbability/Strength of Prediction = {confidence}%', icon='📈') + elif 'BEARISH' in trend: + col.error(f'Market may Open **Gap Down** next day!\n\nProbability/Strength of Prediction = {confidence}%', icon='📉') + else: + col.info("Couldn't determine the Trend. Try again later!") + col.warning('The AI prediction should be executed After 3 PM or Around the Closing hours as the Prediction Accuracy is based on the Closing price!\n\nThis is Just a Statistical Prediction and There are Chances of **False** Predictions!', icon='⚠️') + +def find_similar_stocks(stockCode:str, candles:int): + global execute_inputs + stockCode = stockCode.upper() + if ',' in stockCode or ' ' in stockCode or stockCode == '': + st.error('Invalid Character in Stock Name!', icon='😾') + return False + else: + execute_inputs = ['S', 0, stockCode, candles, 'N'] + on_start_button_click() + st.toast('Screening Completed!', icon='🎉') + sleep(2) + return True + def get_extra_inputs(tickerOption, executeOption, c_index=None, c_criteria=None, start_button=None): global execute_inputs if not tickerOption.isnumeric(): @@ -135,7 +186,7 @@ def get_extra_inputs(tickerOption, executeOption, c_index=None, c_criteria=None, bc.divider() bc.image(telegram_url, width=96) -tab_screen, tab_config, tab_about = st.tabs(['Screen Stocks', 'Configuration', 'About']) +tab_screen, tab_similar, tab_nifty, tab_config, tab_about = st.tabs(['Screen Stocks', 'Search Similar Stocks', 'Nifty-50 Gap Prediction', 'Configuration', 'About']) with tab_screen: st.markdown(""" @@ -265,28 +316,15 @@ def get_extra_inputs(tickerOption, executeOption, c_index=None, c_criteria=None, sleep(2) with st.container(): - try: - df = pd.read_pickle('last_screened_unformatted_results.pkl') - st.markdown(f'#### Found {len(df)} Results') - df.index = df.index.map(lambda x: "https://in.tradingview.com/chart?symbol=NSE%3A" + x) - df.index = df.index.map(lambda x: f'{x.split("%3A")[-1]}') - df['Stock'] = df.index - stock_column = df.pop('Stock') # Remove 'Age' column and store it separately - df.insert(0, 'Stock', stock_column) - st.write(df.to_html(escape=False, index=False, index_names=False), unsafe_allow_html=True) - st.write(' ') - except FileNotFoundError: - st.error('Last Screened results are not available at the moment') - except Exception as e: - st.error('No Dataframe found for last_screened_results.pkl') - st.exception(e) + show_df_as_result_table() + with tab_config: configManager = ConfigManager.tools() configManager.getConfig(parser=ConfigManager.parser) ac, bc = st.columns([10,2]) - ac.markdown('### Screening Configuration') + ac.markdown('### 🔧 Screening Configuration') bc.download_button( label="Export Configuration", data=Path('screenipy.ini').read_text(), @@ -327,6 +365,27 @@ def get_extra_inputs(tickerOption, executeOption, c_index=None, c_criteria=None, f.write(bytes_data) st.toast('Configuration Imported', icon='⚙️') +with tab_nifty: + ac, bc = st.columns([9,1]) + + ac.subheader('🧠 AI-based prediction for Next Day Nifty-50 Gap Up / Gap Down') + bc.button('**Predict**', type='primary', on_click=nifty_predict, args=(ac,), use_container_width=True) + +with tab_similar: + + st.subheader('🕵🏻 Find Stocks forming Similar Chart Patterns') + ac, bc, cc = st.columns([4,2,1]) + + stockCode = ac.text_input('Enter Stock Name and Press Enter', placeholder='HDFCBANK') + candles = bc.number_input('Lookback Period (No. of Candles)', min_value=1, step=1, value=int(configManager.daysToLookback)) + similar_search_button = cc.button('**Search**', type='primary', use_container_width=True) + + if similar_search_button: + result = find_similar_stocks(stockCode, candles) + if result: + with st.container(): + show_df_as_result_table() + with tab_about: from classes.Changelog import VERSION, changelog