From ce67e8bf250469febda6ea1797f05b480a0f7dec Mon Sep 17 00:00:00 2001 From: Pranjal-Office Date: Thu, 24 Jun 2021 10:24:14 +0530 Subject: [PATCH 1/2] TradingView hyperlink added for the stock symbol --- src/classes/Changelog.py | 5 ++++- src/classes/ParallelProcessing.py | 4 +++- src/release.md | 14 ++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/classes/Changelog.py b/src/classes/Changelog.py index a0f0d9c2..eff2da54 100644 --- a/src/classes/Changelog.py +++ b/src/classes/Changelog.py @@ -7,7 +7,7 @@ from classes.ColorText import colorText -VERSION = "1.20" +VERSION = "1.21" changelog = colorText.BOLD + '[ChangeLog]\n' + colorText.END + colorText.BLUE + ''' [1.00 - Beta] @@ -103,5 +103,8 @@ [1.20] 1. Screen stocks as per your favorite index. (Thanks to @swarpatel23) +[1.21] +1. TradingView Hyperlink added for stock symbol. + --- END --- ''' + colorText.END diff --git a/src/classes/ParallelProcessing.py b/src/classes/ParallelProcessing.py index 1036b069..6156c9da 100644 --- a/src/classes/ParallelProcessing.py +++ b/src/classes/ParallelProcessing.py @@ -97,8 +97,10 @@ def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVol with self.screenCounter.get_lock(): self.screenCounter.value += 1 if not processedData.empty: + # screeningDictionary['Stock'] = colorText.BOLD + \ + # colorText.BLUE + stock + colorText.END screeningDictionary['Stock'] = colorText.BOLD + \ - colorText.BLUE + stock + colorText.END + colorText.BLUE + f'\x1B]8;;https://in.tradingview.com/chart?symbol=NSE%3A{stock}\x1B\\{stock}\x1B]8;;\x1B\\' + colorText.END saveDictionary['Stock'] = stock consolidationValue = screener.validateConsolidation( processedData, screeningDictionary, saveDictionary, percentage=configManager.consolidationPercentage) diff --git a/src/release.md b/src/release.md index 2e467383..5f433452 100644 --- a/src/release.md +++ b/src/release.md @@ -1,17 +1,15 @@ # Make sure to download the latest release! ![GitHub release (latest by date)](https://img.shields.io/github/v/release/pranjal-joshi/Screeni-py) ## What's New? -1. Now Screen for the Stocks in the Index that you :heart:. Index-wise Screening is here! (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) -2. Search stocks that are **Reversed** by taking Support at Moving Average! Try `Option > 6 > 4`. +1. Now, Open TradingView chart directly by clicking on the stock symbol! :tada: +2. Screen for the Stocks in the Index that you :heart:. Index-wise Screening is here! (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) 3. Now **Create Your Own Watchlist** in Excel and screen for only those stocks! Try `Option > W` :chart_with_upwards_trend: -4. New **Chart Pattern** **`Bullish Momentum Gainer`** added! Try `Option > 6 > 3` :tada: -5. **Data Saver & High-Performance Mode**: Intelligently Stores Stock Data for After-Market hours screening without using extra bandwidth. Also, uses multiple CPU cores available on your computer for superfast screening! :sparkles: (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) -6. Cosmetic Updates - Progressbar for showing screening process! :lipstick: +4. Cosmetic Updates - Progressbar for showing screening process! :lipstick: ## Downloads -* For :desktop_computer: **Windows** users, download **[screenipy.exe](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.20/screenipy.exe)** -* For :penguin: **Linux** users, download **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.20/screenipy.bin)** -* For :apple: **MacOS** users, download **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.20/screenipy.run)** ([Read Installation Guide](https://github.com/pranjal-joshi/Screeni-py/blob/main/INSTALLATION.md#for-macos)) +* For :desktop_computer: **Windows** users, download **[screenipy.exe](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.21/screenipy.exe)** +* For :penguin: **Linux** users, download **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.21/screenipy.bin)** +* For :apple: **MacOS** users, download **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.21/screenipy.run)** ([Read Installation Guide](https://github.com/pranjal-joshi/Screeni-py/blob/main/INSTALLATION.md#for-macos)) ## How to use? From 9ee2f1fbe11664d52f8fd391739da512844e196c Mon Sep 17 00:00:00 2001 From: Pranjal Joshi Date: Sun, 1 Aug 2021 20:28:48 +0530 Subject: [PATCH 2/2] v1.24 - New Feature: IPO Base Breakout Pattern Screening * Fetcher bugfix duration -> interval * IPO-Base Feature method added * IPO-base save cache enabled * Process termination fixed (winerror-5 resolved) * Result Table Index Dropped * Docs updated --- src/classes/Changelog.py | 12 +++++++----- src/classes/Fetcher.py | 2 +- src/classes/ParallelProcessing.py | 28 ++++++++++++++++++++-------- src/classes/Screener.py | 21 +++++++++++++++++++-- src/classes/Utility.py | 5 ++++- src/release.md | 15 ++++++++------- src/screenipy.py | 14 ++++++++++---- 7 files changed, 69 insertions(+), 28 deletions(-) diff --git a/src/classes/Changelog.py b/src/classes/Changelog.py index 62116719..e9e71849 100644 --- a/src/classes/Changelog.py +++ b/src/classes/Changelog.py @@ -7,11 +7,7 @@ from classes.ColorText import colorText -<<<<<<< HEAD -VERSION = "1.21" -======= -VERSION = "1.23" ->>>>>>> 2f698b7f93adaf980e29cf5939976aed5f60fba8 +VERSION = "1.24" changelog = colorText.BOLD + '[ChangeLog]\n' + colorText.END + colorText.BLUE + ''' [1.00 - Beta] @@ -117,5 +113,11 @@ 1. Bug fixed for DualCore CPU. 2. Dependencies updated. +[1.24] +1. IPO Base Breakout pattern added. Option > 7 > 3. +2. Data fetching interval fixed. +3. Permission bug-fixes for some windows users. +4. Result table optimized. + --- END --- ''' + colorText.END diff --git a/src/classes/Fetcher.py b/src/classes/Fetcher.py index be7456b9..abe8734d 100644 --- a/src/classes/Fetcher.py +++ b/src/classes/Fetcher.py @@ -111,7 +111,7 @@ def fetchStockData(self, stockCode, period, duration, proxyServer, screenResults data = yf.download( tickers=stockCode+".NS", period=period, - duration=duration, + interval=duration, proxy=proxyServer, progress=False, ) diff --git a/src/classes/ParallelProcessing.py b/src/classes/ParallelProcessing.py index 6156c9da..f7cc631b 100644 --- a/src/classes/ParallelProcessing.py +++ b/src/classes/ParallelProcessing.py @@ -57,7 +57,7 @@ def run(self): except Exception as e: sys.exit(0) - def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respBullBear, insideBarToLookback, totalSymbols, + def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respChartPattern, insideBarToLookback, totalSymbols, configManager, fetcher, screener, candlePatterns, stock, printCounter=False): screenResults = pd.DataFrame(columns=[ 'Stock', 'Consolidating', 'Breaking-Out', 'MA-Signal', 'Volume', 'LTP', 'RSI', 'Trend', 'Pattern']) @@ -67,9 +67,14 @@ def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVol 'MA-Signal': "", 'Volume': "", 'LTP': 0, 'RSI': 0, 'Trend': "", 'Pattern': ""} try: - if (self.stockDict.get(stock) is None) or (configManager.cacheEnabled is False) or self.isTradingTime: + period = configManager.period + # Data download adjustment for IPO Base feature + if executeOption == 7 and respChartPattern == 3: + period = 'max' + + if (self.stockDict.get(stock) is None) or (respChartPattern == 3) or (configManager.cacheEnabled is False) or self.isTradingTime: data = fetcher.fetchStockData(stock, - configManager.period, + period, configManager.duration, self.proxyServer, self.screenResultsCounter, @@ -130,9 +135,12 @@ def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVol isCandlePattern = candlePatterns.findPattern( processedData, screeningDictionary, saveDictionary) isInsideBar = screener.validateInsideBar( - processedData, screeningDictionary, saveDictionary, bullBear=respBullBear, daysToLookback=insideBarToLookback) - + processedData, screeningDictionary, saveDictionary, chartPattern=respChartPattern, daysToLookback=insideBarToLookback) isMomentum = screener.validateMomentum(processedData, screeningDictionary, saveDictionary) + + if respChartPattern == 3 and executeOption == 7: + isIpoBase = screener.validateIpoBase(stock, fullData, screeningDictionary, saveDictionary) + if maLength is not None and executeOption == 6: isMaSupport = screener.findReversalMA(fullData, screeningDictionary, saveDictionary, maLength) @@ -167,9 +175,13 @@ def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVol elif reversalOption == 4 and isMaSupport: self.screenResultsCounter.value += 1 return screeningDictionary, saveDictionary - if executeOption == 7 and isLtpValid and isInsideBar: - self.screenResultsCounter.value += 1 - return screeningDictionary, saveDictionary + if executeOption == 7 and isLtpValid: + if respChartPattern != 3 and isInsideBar: + self.screenResultsCounter.value += 1 + return screeningDictionary, saveDictionary + elif isIpoBase: + self.screenResultsCounter.value += 1 + return screeningDictionary, saveDictionary except KeyboardInterrupt: # Capturing Ctr+C Here isn't a great idea pass diff --git a/src/classes/Screener.py b/src/classes/Screener.py index d5238684..79c92908 100644 --- a/src/classes/Screener.py +++ b/src/classes/Screener.py @@ -211,12 +211,12 @@ def findBreakout(self, data, screenDict, saveDict, daysToLookback): return False # Validate 'Inside Bar' structure for recent days - def validateInsideBar(self, data, screenDict, saveDict, bullBear=1, daysToLookback=5): + def validateInsideBar(self, data, screenDict, saveDict, chartPattern=1, daysToLookback=5): orgData = data for i in range(daysToLookback, round(daysToLookback*0.5)-1, -1): if i == 2: return 0 # Exit if only last 2 candles are left - if bullBear == 1: + if chartPattern == 1: if "Up" in saveDict['Trend'] and ("Bull" in saveDict['MA-Signal'] or "Support" in saveDict['MA-Signal']): data = orgData.head(i) refCandle = data.tail(1) @@ -348,6 +348,23 @@ def findReversalMA(self, data, screenDict, saveDict, maLength, percentage=0.015) return True return False + # Find IPO base + def validateIpoBase(self, stock, data, screenDict, saveDict, percentage=0.3): + listingPrice = data[::-1].head(1)['Open'][0] + currentPrice = data.head(1)['Close'][0] + ATH = data.describe()['High']['max'] + if ATH > (listingPrice + (listingPrice * percentage)): + return False + away = round(((currentPrice - listingPrice)/listingPrice)*100, 1) + if((listingPrice - (listingPrice * percentage)) <= currentPrice <= (listingPrice + (listingPrice * percentage))): + if away > 0: + screenDict['Pattern'] = colorText.BOLD + colorText.GREEN + f'IPO Base ({away} %)' + colorText.END + else: + screenDict['Pattern'] = colorText.BOLD + colorText.GREEN + 'IPO Base ' + colorText.FAIL + f'({away} %)' + colorText.END + saveDict['Pattern'] = f'IPO Base ({away} %)' + return True + return False + ''' # Find out trend for days to lookback def validateVCP(data, screenDict, saveDict, daysToLookback=ConfigManager.daysToLookback, stockName=None): diff --git a/src/classes/Utility.py b/src/classes/Utility.py index 2a959c76..f3f97636 100644 --- a/src/classes/Utility.py +++ b/src/classes/Utility.py @@ -190,13 +190,16 @@ def promptChartPatterns(): resp = int(input(colorText.BOLD + colorText.WARN + """\n[+] Select Option: 1 > Screen for Bullish Inside Bar (Flag) Pattern 2 > Screen for Bearish Inside Bar (Flag) Pattern + 3 > Screen for IPO Base Breakout Pattern 0 > Cancel [+] Select option: """ + colorText.END)) if resp == 1 or resp == 2: candles = int(input(colorText.BOLD + colorText.WARN + "\n[+] How many candles (TimeFrame) to look back Inside Bar formation? : " + colorText.END)) return (resp, candles) - if resp >= 0 and resp <= 2: + if resp == 3: + return (resp, 1) + if resp >= 0 and resp <= 3: return resp raise ValueError except ValueError: diff --git a/src/release.md b/src/release.md index 959af5ab..fde999b4 100644 --- a/src/release.md +++ b/src/release.md @@ -1,15 +1,16 @@ # Make sure to download the latest release! ![GitHub release (latest by date)](https://img.shields.io/github/v/release/pranjal-joshi/Screeni-py) ## What's New? -1. Now, Open TradingView chart directly by clicking on the stock symbol! :tada: (Windows users should download and run the Application through the **Windows Terminal** from the Microsoft Store.) -2. Screen for the Stocks in the Index that you :heart:. Index-wise Screening is here! (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) -3. Now **Create Your Own Watchlist** in Excel and screen for only those stocks! Try `Option > W` :chart_with_upwards_trend: -4. Bug-fixes for MultiCore CPUs. :gear: +1. New **Chart Pattern** Added! **IPO Base Breakout** - Try `Option > 7 > 3` +2. Now, Open TradingView chart directly by clicking on the stock symbol! :tada: (Windows users should download and run the Application through the **Windows Terminal** from the Microsoft Store.) +3. Screen for the Stocks in the Index that you :heart:. Index-wise Screening is here! (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) +4. Now **Create Your Own Watchlist** in Excel and screen for only those stocks! Try `Option > W` :chart_with_upwards_trend: +5. Bug-fixes & Performance upgrades for MultiCore CPUs. :gear: ## Downloads -* For :desktop_computer: **Windows** users, download **[screenipy.exe](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.23/screenipy.exe)** -* For :penguin: **Linux** users, download **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.23/screenipy.bin)** -* For :apple: **MacOS** users, download **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.23/screenipy.run)** ([Read Installation Guide](https://github.com/pranjal-joshi/Screeni-py/blob/main/INSTALLATION.md#for-macos)) +* For :desktop_computer: **Windows** users, download **[screenipy.exe](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.24/screenipy.exe)** +* For :penguin: **Linux** users, download **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.24/screenipy.bin)** +* For :apple: **MacOS** users, download **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.24/screenipy.run)** ([Read Installation Guide](https://github.com/pranjal-joshi/Screeni-py/blob/main/INSTALLATION.md#for-macos)) ## How to use? diff --git a/src/screenipy.py b/src/screenipy.py index b3e90f89..e25fdd58 100644 --- a/src/screenipy.py +++ b/src/screenipy.py @@ -141,7 +141,7 @@ def main(testing=False): minRSI = 0 maxRSI = 100 insideBarToLookback = 7 - respBullBear = 1 + respChartPattern = 1 daysForLowestVolume = 30 reversalOption = None @@ -180,7 +180,7 @@ def main(testing=False): if reversalOption is None or reversalOption == 0: main() if executeOption == 7: - respBullBear, insideBarToLookback = Utility.tools.promptChartPatterns() + respChartPattern, insideBarToLookback = Utility.tools.promptChartPatterns() if insideBarToLookback is None: main() if executeOption == 8: @@ -225,7 +225,7 @@ def main(testing=False): print(colorText.BOLD + colorText.WARN + "[+] Starting Stock Screening.. Press Ctrl+C to stop!\n") - items = [(executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respBullBear, insideBarToLookback, len(listStockCodes), + items = [(executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respChartPattern, insideBarToLookback, len(listStockCodes), configManager, fetcher, screener, candlePatterns, stock) for stock in listStockCodes] @@ -293,7 +293,11 @@ def main(testing=False): print(colorText.END) # Exit all processes. Without this, it threw error in next screening session for worker in consumers: - worker.terminate() + try: + worker.terminate() + except OSError as e: + if e.winerror == 5: + pass # Flush the queue so depending processes will end from queue import Empty @@ -305,6 +309,8 @@ def main(testing=False): screenResults.sort_values(by=['Stock'], ascending=True, inplace=True) saveResults.sort_values(by=['Stock'], ascending=True, inplace=True) + screenResults.set_index('Stock', inplace=True) + saveResults.set_index('Stock', inplace=True) screenResults.rename( columns={ 'Trend': f'Trend ({configManager.daysToLookback}Days)',