File size: 9,393 Bytes
9bf26a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
'''
 *  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 attributes for Downloading Cache from Git repo
default_period = '300d'
default_duration = '1d'

# This Class manages read/write of user configuration
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)

    # Handle user input and save config

    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)

            # delete stock data due to config change
            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)

    # Load user config from file
    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)

    # Print config file
    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)

    # Check if config file exists
    def checkConfigFile(self):
        try:
            f = open('screenipy.ini','r')
            f.close()
            return True
        except FileNotFoundError:
            return False
        
    # Get period as a numeric value
    def getPeriodNumeric(self):
        import re
        pattern = re.compile(r'\d+')
        result = [int(match.group()) for match in pattern.finditer(self.period)][0]
        return result