From 9484ddb193d20a09fe42beaff0659a14647b975d Mon Sep 17 00:00:00 2001 From: Pranjal Joshi Date: Sun, 6 Jun 2021 21:58:42 +0530 Subject: [PATCH] v1.19 - Search for Stocks reversed at MA --- src/classes/Changelog.py | 4 +++- src/classes/ParallelProcessing.py | 7 ++++++- src/classes/Screener.py | 17 +++++++++++++++++ src/classes/Utility.py | 13 ++++++++++--- src/release.md | 18 +++++++++--------- src/screenipy.ini | 2 +- src/screenipy.py | 7 ++++--- 7 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/classes/Changelog.py b/src/classes/Changelog.py index 1dec895d..9314fb9e 100644 --- a/src/classes/Changelog.py +++ b/src/classes/Changelog.py @@ -7,7 +7,7 @@ from classes.ColorText import colorText -VERSION = "1.18" +VERSION = "1.19" changelog = colorText.BOLD + '[ChangeLog]\n' + colorText.END + colorText.BLUE + ''' [1.00 - Beta] @@ -97,5 +97,7 @@ 1. Cache and Performance fixes. 2. Breakout Calculation Enhanced. +[1.19] +1. New Feature: Search for Bullish Reversal at MA. Option > 6 > 4 --- END --- ''' + colorText.END diff --git a/src/classes/ParallelProcessing.py b/src/classes/ParallelProcessing.py index 0ec05330..7238b2c3 100644 --- a/src/classes/ParallelProcessing.py +++ b/src/classes/ParallelProcessing.py @@ -56,7 +56,7 @@ def run(self): except Exception as e: sys.exit(0) - def screenStocks(self, executeOption, reversalOption, daysForLowestVolume, minRSI, maxRSI, respBullBear, insideBarToLookback, totalSymbols, + def screenStocks(self, executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respBullBear, insideBarToLookback, totalSymbols, configManager, fetcher, screener, candlePatterns, stock, printCounter=False): screenResults = pd.DataFrame(columns=[ 'Stock', 'Consolidating', 'Breaking-Out', 'MA-Signal', 'Volume', 'LTP', 'RSI', 'Trend', 'Pattern']) @@ -129,6 +129,8 @@ def screenStocks(self, executeOption, reversalOption, daysForLowestVolume, minRS isInsideBar = screener.validateInsideBar( processedData, screeningDictionary, saveDictionary, bullBear=respBullBear, daysToLookback=insideBarToLookback) isMomentum = screener.validateMomentum(processedData, screeningDictionary, saveDictionary) + if maLength is not None and executeOption == 6: + isMaSupport = screener.findReversalMA(fullData, screeningDictionary, saveDictionary, maLength) with self.screenResultsCounter.get_lock(): if executeOption == 0 or executeOption == 'W': @@ -158,6 +160,9 @@ def screenStocks(self, executeOption, reversalOption, daysForLowestVolume, minRS elif reversalOption == 3 and isMomentum: self.screenResultsCounter.value += 1 return screeningDictionary, saveDictionary + 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 diff --git a/src/classes/Screener.py b/src/classes/Screener.py index 215ca32f..d5238684 100644 --- a/src/classes/Screener.py +++ b/src/classes/Screener.py @@ -331,6 +331,23 @@ def validateMomentum(self, data, screenDict, saveDict): traceback.print_exc() return False + # Find stock reversing at given MA + def findReversalMA(self, data, screenDict, saveDict, maLength, percentage=0.015): + if maLength is None: + maLength = 20 + data = data[::-1] + if self.configManager.useEMA: + maRev = talib.EMA(data['Close'],timeperiod=maLength) + else: + maRev = talib.MA(data['Close'],timeperiod=maLength) + data.insert(10,'maRev',maRev) + data = data[::-1].head(3) + if data.equals(data[(data.Close >= (data.maRev - (data.maRev*percentage))) & (data.Close <= (data.maRev + (data.maRev*percentage)))]) and data.head(1)['Close'][0] >= data.head(1)['maRev'][0]: + screenDict['MA-Signal'] = colorText.BOLD + colorText.GREEN + f'Reversal-{maLength}MA' + colorText.END + saveDict['MA-Signal'] = f'Reversal-{maLength}MA' + 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 cf1d1aac..ed330dd0 100644 --- a/src/classes/Utility.py +++ b/src/classes/Utility.py @@ -167,13 +167,20 @@ def promptReversalScreening(): 1 > Screen for Buy Signal (Bullish Reversal) 2 > Screen for Sell Signal (Bearish Reversal) 3 > Screen for Momentum Gainers (Rising Bullish Momentum) + 4 > Screen for Reversal at Moving Average (Bullish Reversal) 0 > Cancel [+] Select option: """ + colorText.END)) - if resp >= 0 and resp <= 3: - return resp + if resp >= 0 and resp <= 4: + if resp == 4: + try: + maLength = int(input(colorText.BOLD + colorText.WARN + '\n[+] Enter MA Length (E.g. 20/50): ' + colorText.END)) + return resp, maLength + except ValueError: + raise ValueError + return resp, None raise ValueError except ValueError: - return None + return None, None # Prompt for Reversal screening def promptChartPatterns(): diff --git a/src/release.md b/src/release.md index 61c58d54..cd9a9a5c 100644 --- a/src/release.md +++ b/src/release.md @@ -1,17 +1,17 @@ # 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 **Create Your Own Watchlist** in Excel and screen for only those stocks! Try `Option > W` :chart_with_upwards_trend: -2. New Improved **Breakout Detection.** :rocket: -3. New **Chart Pattern** **`Bullish Momentum Gainer`** added! Try `Option > 6 > 3` :tada: -4. **Data Saver & High Performance Mode**: Intellegently Stores Stock Data for After-Market hours screening without using extra bandwidth. Also, uses multiple CPU cores available on your computer for supperfast screening! :sparkles: (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) -5. Cosmetic Updates - Progressbar for showing screening process! :lipstick: -6. Performance Upgrades! :gear: +1. Search stocks which are **Reversed** by taking Support at Moving Average! Try `Option > 6 > 4`. +2. Now **Create Your Own Watchlist** in Excel and screen for only those stocks! Try `Option > W` :chart_with_upwards_trend: +3. New Improved **Breakout Detection.** :rocket: +4. New **Chart Pattern** **`Bullish Momentum Gainer`** added! Try `Option > 6 > 3` :tada: +5. **Data Saver & High Performance Mode**: Intellegently Stores Stock Data for After-Market hours screening without using extra bandwidth. Also, uses multiple CPU cores available on your computer for supperfast screening! :sparkles: (Thanks to [**swarpatel23**](https://github.com/swarpatel23)) +6. 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.18/screenipy.exe)** -* For :penguin: **Linux** users, download **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.18/screenipy.bin)** -* For :apple: **MacOS** users, download **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.18/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.19/screenipy.exe)** +* For :penguin: **Linux** users, download **[screenipy.bin](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.19/screenipy.bin)** +* For :apple: **MacOS** users, download **[screenipy.run](https://github.com/pranjal-joshi/Screeni-py/releases/download/1.19/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.ini b/src/screenipy.ini index acf41f7d..144bd6d8 100644 --- a/src/screenipy.ini +++ b/src/screenipy.ini @@ -9,5 +9,5 @@ consolidationpercentage = 10 shuffle = y cachestockdata = y onlystagetwostocks = y -useema = y +useema = n diff --git a/src/screenipy.py b/src/screenipy.py index cb838ae1..d343cd9d 100644 --- a/src/screenipy.py +++ b/src/screenipy.py @@ -39,6 +39,7 @@ keyboardInterruptEvent = None loadedStockData = False loadCount = 0 +maLength = None configManager = ConfigManager.tools() fetcher = Fetcher.tools(configManager) @@ -94,7 +95,7 @@ def initExecution(): def main(testing=False): - global screenCounter, screenResultsCounter, stockDict, loadedStockData, keyboardInterruptEvent, loadCount + global screenCounter, screenResultsCounter, stockDict, loadedStockData, keyboardInterruptEvent, loadCount, maLength screenCounter = multiprocessing.Value('i', 1) screenResultsCounter = multiprocessing.Value('i', 0) keyboardInterruptEvent = multiprocessing.Manager().Event() @@ -141,7 +142,7 @@ def main(testing=False): input('') main() if executeOption == 6: - reversalOption = Utility.tools.promptReversalScreening() + reversalOption, maLength = Utility.tools.promptReversalScreening() if reversalOption is None or reversalOption == 0: main() if executeOption == 7: @@ -188,7 +189,7 @@ def main(testing=False): print(colorText.BOLD + colorText.WARN + "[+] Starting Stock Screening.. Press Ctrl+C to stop!\n") - items = [(executeOption, reversalOption, daysForLowestVolume, minRSI, maxRSI, respBullBear, insideBarToLookback, len(listStockCodes), + items = [(executeOption, reversalOption, maLength, daysForLowestVolume, minRSI, maxRSI, respBullBear, insideBarToLookback, len(listStockCodes), configManager, fetcher, screener, candlePatterns, stock) for stock in listStockCodes]