Skip to content

Commit

Permalink
v1.24 - New Feature: IPO Base Breakout Pattern Screening
Browse files Browse the repository at this point in the history
[Screenipy Test] New Features Added - Test Passed - Merge OK
  • Loading branch information
pranjal-joshi authored Aug 2, 2021
2 parents 283da9d + 9ee2f1f commit 225371f
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 24 deletions.
8 changes: 7 additions & 1 deletion src/classes/Changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from classes.ColorText import colorText

VERSION = "1.23"
VERSION = "1.24"

changelog = colorText.BOLD + '[ChangeLog]\n' + colorText.END + colorText.BLUE + '''
[1.00 - Beta]
Expand Down Expand Up @@ -113,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
2 changes: 1 addition & 1 deletion src/classes/Fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down
28 changes: 20 additions & 8 deletions src/classes/ParallelProcessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand All @@ -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,
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
21 changes: 19 additions & 2 deletions src/classes/Screener.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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):
Expand Down
5 changes: 4 additions & 1 deletion src/classes/Utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
15 changes: 8 additions & 7 deletions src/release.md
Original file line number Diff line number Diff line change
@@ -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?

Expand Down
14 changes: 10 additions & 4 deletions src/screenipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def main(testing=False):
minRSI = 0
maxRSI = 100
insideBarToLookback = 7
respBullBear = 1
respChartPattern = 1
daysForLowestVolume = 30
reversalOption = None

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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]

Expand Down Expand Up @@ -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
Expand All @@ -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)',
Expand Down

0 comments on commit 225371f

Please sign in to comment.