| | ''' |
| | * Project : Screenipy |
| | * Author : Pranjal Joshi |
| | * Created : 28/04/2021 |
| | * Description : Class for managing the user configuration |
| | ''' |
| |
|
| | import sys |
| | import os |
| | import glob |
| | import re |
| | import configparser |
| | from datetime import date |
| | from classes.ColorText import colorText |
| |
|
| | parser = configparser.ConfigParser(strict=False) |
| |
|
| | |
| | default_period = '300d' |
| | default_duration = '1d' |
| |
|
| | |
| | class tools: |
| |
|
| | def __init__(self): |
| | self.consolidationPercentage = 10 |
| | self.volumeRatio = 2 |
| | self.minLTP = 20.0 |
| | self.maxLTP = 50000 |
| | self.period = '300d' |
| | self.duration = '1d' |
| | self.daysToLookback = 30 |
| | self.shuffleEnabled = True |
| | self.cacheEnabled = True |
| | self.stageTwo = False |
| | self.useEMA = False |
| |
|
| | def deleteStockData(self,excludeFile=None): |
| | for f in glob.glob('stock_data*.pkl'): |
| | if excludeFile is not None: |
| | if not f.endswith(excludeFile): |
| | os.remove(f) |
| | else: |
| | os.remove(f) |
| |
|
| | |
| |
|
| | def setConfig(self, parser, default=False, showFileCreatedText=True): |
| | if default: |
| | parser.add_section('config') |
| | parser.set('config', 'period', self.period) |
| | parser.set('config', 'daysToLookback', str(self.daysToLookback)) |
| | parser.set('config', 'duration', self.duration) |
| | parser.set('config', 'minPrice', str(self.minLTP)) |
| | parser.set('config', 'maxPrice', str(self.maxLTP)) |
| | parser.set('config', 'volumeRatio', str(self.volumeRatio)) |
| | parser.set('config', 'consolidationPercentage', |
| | str(self.consolidationPercentage)) |
| | parser.set('config', 'shuffle', 'y') |
| | parser.set('config', 'cacheStockData', 'y') |
| | parser.set('config', 'onlyStageTwoStocks', 'y' if self.stageTwo else 'n') |
| | parser.set('config', 'useEMA', 'y' if self.useEMA else 'n') |
| | try: |
| | fp = open('screenipy.ini', 'w') |
| | parser.write(fp) |
| | fp.close() |
| | if showFileCreatedText: |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] Default configuration generated as user configuration is not found!' + colorText.END) |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] Use Option > 5 to edit in future.' + colorText.END) |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] Close and Restart the program now.' + colorText.END) |
| | input('') |
| | sys.exit(0) |
| | except IOError: |
| | print(colorText.BOLD + colorText.FAIL + |
| | '[+] Failed to save user config. Exiting..' + colorText.END) |
| | input('') |
| | sys.exit(1) |
| | else: |
| | parser = configparser.ConfigParser(strict=False) |
| | parser.add_section('config') |
| | print('') |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] Screeni-py User Configuration:' + colorText.END) |
| | self.period = input( |
| | '[+] Enter number of days for which stock data to be downloaded (Days)(Optimal = 365): ') |
| | self.daysToLookback = input( |
| | '[+] Number of recent days (TimeFrame) to screen for Breakout/Consolidation (Days)(Optimal = 20): ') |
| | self.duration = input( |
| | '[+] Enter Duration of each candle (Days)(Optimal = 1): ') |
| | self.minLTP = input( |
| | '[+] Minimum Price of Stock to Buy (in RS)(Optimal = 20): ') |
| | self.maxLTP = input( |
| | '[+] Maximum Price of Stock to Buy (in RS)(Optimal = 50000): ') |
| | self.volumeRatio = input( |
| | '[+] How many times the volume should be more than average for the breakout? (Number)(Optimal = 2.5): ') |
| | self.consolidationPercentage = input( |
| | '[+] How many % the price should be in range to consider it as consolidation? (Number)(Optimal = 10): ') |
| | self.shuffle = str(input( |
| | '[+] Shuffle stocks rather than screening alphabetically? (Y/N): ')).lower() |
| | self.cacheStockData = str(input( |
| | '[+] Enable High-Performance and Data-Saver mode? (This uses little bit more CPU but performs High Performance Screening) (Y/N): ')).lower() |
| | self.stageTwoPrompt = str(input( |
| | '[+] Screen only for Stage-2 stocks?\n(What are the stages? => https://www.investopedia.com/articles/trading/08/stock-cycle-trend-price.asp)\n(Y/N): ')).lower() |
| | self.useEmaPrompt = str(input( |
| | '[+] Use EMA instead of SMA? (EMA is good for Short-term & SMA for Mid/Long-term trades)[Y/N]: ')).lower() |
| | parser.set('config', 'period', self.period + "d") |
| | parser.set('config', 'daysToLookback', self.daysToLookback) |
| | parser.set('config', 'duration', self.duration + "d") |
| | parser.set('config', 'minPrice', self.minLTP) |
| | parser.set('config', 'maxPrice', self.maxLTP) |
| | parser.set('config', 'volumeRatio', self.volumeRatio) |
| | parser.set('config', 'consolidationPercentage', |
| | self.consolidationPercentage) |
| | parser.set('config', 'shuffle', self.shuffle) |
| | parser.set('config', 'cacheStockData', self.cacheStockData) |
| | parser.set('config', 'onlyStageTwoStocks', self.stageTwoPrompt) |
| | parser.set('config', 'useEMA', self.useEmaPrompt) |
| |
|
| | |
| | self.deleteStockData() |
| | print(colorText.BOLD + colorText.FAIL + "[+] Cached Stock Data Deleted." + colorText.END) |
| |
|
| | try: |
| | fp = open('screenipy.ini', 'w') |
| | parser.write(fp) |
| | fp.close() |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] User configuration saved.' + colorText.END) |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] Restart the Program to start Screening...' + colorText.END) |
| | input('') |
| | sys.exit(0) |
| | except IOError: |
| | print(colorText.BOLD + colorText.FAIL + |
| | '[+] Failed to save user config. Exiting..' + colorText.END) |
| | input('') |
| | sys.exit(1) |
| |
|
| | |
| | def getConfig(self, parser): |
| | if len(parser.read('screenipy.ini')): |
| | try: |
| | self.duration = parser.get('config', 'duration') |
| | self.period = parser.get('config', 'period') |
| | self.minLTP = float(parser.get('config', 'minprice')) |
| | self.maxLTP = float(parser.get('config', 'maxprice')) |
| | self.volumeRatio = float(parser.get('config', 'volumeRatio')) |
| | self.consolidationPercentage = float( |
| | parser.get('config', 'consolidationPercentage')) |
| | self.daysToLookback = int( |
| | parser.get('config', 'daysToLookback')) |
| | if 'n' not in str(parser.get('config', 'shuffle')).lower(): |
| | self.shuffleEnabled = True |
| | if 'n' not in str(parser.get('config', 'cachestockdata')).lower(): |
| | self.cacheEnabled = True |
| | if 'n' not in str(parser.get('config', 'onlyStageTwoStocks')).lower(): |
| | self.stageTwo = True |
| | else: |
| | self.stageTwo = False |
| | if 'y' not in str(parser.get('config', 'useEMA')).lower(): |
| | self.useEMA = False |
| | else: |
| | self.useEMA = True |
| | except configparser.NoOptionError: |
| | input(colorText.BOLD + colorText.FAIL + |
| | '[+] Screenipy requires user configuration again. Press enter to continue..' + colorText.END) |
| | parser.remove_section('config') |
| | self.setConfig(parser, default=False) |
| | else: |
| | self.setConfig(parser, default=True) |
| |
|
| | |
| | def showConfigFile(self): |
| | try: |
| | f = open('screenipy.ini', 'r') |
| | print(colorText.BOLD + colorText.GREEN + |
| | '[+] Screeni-py User Configuration:' + colorText.END) |
| | print("\n"+f.read()) |
| | f.close() |
| | input('') |
| | except: |
| | print(colorText.BOLD + colorText.FAIL + |
| | "[+] User Configuration not found!" + colorText.END) |
| | print(colorText.BOLD + colorText.WARN + |
| | "[+] Configure the limits to continue." + colorText.END) |
| | self.setConfig(parser) |
| |
|
| | |
| | def checkConfigFile(self): |
| | try: |
| | f = open('screenipy.ini','r') |
| | f.close() |
| | return True |
| | except FileNotFoundError: |
| | return False |
| | |
| | |
| | def getPeriodNumeric(self): |
| | import re |
| | pattern = re.compile(r'\d+') |
| | result = [int(match.group()) for match in pattern.finditer(self.period)][0] |
| | return result |
| |
|
| |
|