Skip to content

Commit

Permalink
Performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
pkjmesra committed Jan 31, 2021
1 parent fadf1d1 commit 94f83d2
Show file tree
Hide file tree
Showing 20 changed files with 85 additions and 70 deletions.
3 changes: 0 additions & 3 deletions nseta/common/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
global __trace__
global __filter__
global __DEBUG__
2 changes: 1 addition & 1 deletion nseta/common/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def level(self):

@level.setter
def level(self, level):
return self.logger.setlevel(level)
self.logger.setLevel(level)

@staticmethod
def getlogger(logger):
Expand Down
1 change: 0 additions & 1 deletion nseta/scanner/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
global __scan_counter__
21 changes: 7 additions & 14 deletions nseta/scanner/baseScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def __init__(self, scanner_type, stocks=[], indicator=None, background=False):
self._signal_columns = None
self._archiver = None
self._response_type = None
self._scanner_func = None
self._sortAscending = False

@property
Expand Down Expand Up @@ -81,26 +80,18 @@ def option(self):
def option(self, value):
self._option = value

@property
def scanner_func(self):
return self._scanner_func

@scanner_func.setter
def scanner_func(self, value):
self._scanner_func = value

@tracelog
def scan(self, option=None):
self.option = option
scannerinstance = scanner(indicator=self.indicator)
if self.background:
b = threading.Thread(name='scan_{}_background'.format(self.scanner_type.name),
target=self.scan_background, args=[], daemon=True)
target=self.scan_background, args=[scannerinstance], daemon=True)
b.start()
b.join()
else:
df, signaldf = self.load_archived_scan_results()
if df is None or len(df) == 0 and self.scanner_func is not None:
scannerinstance = scanner(indicator=self.indicator)
if df is None or len(df) == 0:
df, signaldf = scannerinstance.scan(self.stocks, self.scanner_type)
self.scan_results(df, signaldf)

Expand Down Expand Up @@ -171,7 +162,7 @@ def clear_cache(self, clear, force_clear=False):
self.archiver.clearcache(response_type=self.response_type, force_clear=force_clear)

@tracelog
def scan_background(self, terminate_after_iter=0, wait_time=0):
def scan_background(self, scannerinstance, terminate_after_iter=0, wait_time=0):
global RUN_IN_BACKGROUND
RUN_IN_BACKGROUND = True
iteration = 0
Expand All @@ -180,8 +171,10 @@ def scan_background(self, terminate_after_iter=0, wait_time=0):
if terminate_after_iter > 0 and iteration >= terminate_after_iter:
RUN_IN_BACKGROUND = False
break
if scannerinstance is None:
default_logger().debug('scannerinstance is None. Cannot proceed with background scanning')
break
self.clear_cache(True, force_clear=True)
scannerinstance = scanner(indicator=self.indicator)
df, signaldf = scannerinstance.scan(self.stocks, self.scanner_type)
self.scan_results(df, signaldf, should_cache= False)
time.sleep(wait_time)
Expand Down
22 changes: 14 additions & 8 deletions nseta/scanner/baseStockScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
from nseta.strategy.rsiSignalStrategy import rsiSignalStrategy
from nseta.strategy.bbandsSignalStrategy import bbandsSignalStrategy
from nseta.strategy.macdSignalStrategy import macdSignalStrategy
from nseta.common.commons import Recommendation
from nseta.common.tradingtime import *

__all__ = ['baseStockScanner', 'TECH_INDICATOR_KEYS', 'ScannerType']

__scan_counter__ = 0
TECH_INDICATOR_KEYS = ['rsi', 'smac', 'emac', 'macd', 'bbands', 'all']

class ScannerType(enum.Enum):
Expand All @@ -35,6 +34,7 @@ def __init__(self, indicator='all'):
indicator = 'all'
self._indicator = indicator
self._stocksdict = {}
self._instancedict = {}
self._total_counter = 0

@property
Expand All @@ -53,6 +53,10 @@ def indicator(self):
def indicator(self, value):
self._indicator = value

@property
def instancedict(self):
return self._instancedict

@property
def stocksdict(self):
return self._stocksdict
Expand All @@ -73,11 +77,12 @@ def stocks_list(self, stocks=[]):
def multithreadedScanner_callback(self, **kwargs):
scanner_type = kwargs['scanner_type']
del(kwargs['scanner_type'])
callback_func = self.get_func_name(scanner_type)
return callback_func(**kwargs)
callback_instance = self.get_instance(scanner_type=scanner_type)
callback_instance.total_counter = self.total_counter
return callback_instance.scan_quanta(**kwargs)

def get_func_name(self, scanner_type=ScannerType.Unknown):
default_logger().debug('Scanner will begin for scanner_type:{}'.format(scanner_type))
def get_instance(self, scanner_type=ScannerType.Unknown):
return self

@tracelog
def scan(self, stocks=[], scanner_type=ScannerType.Unknown):
Expand Down Expand Up @@ -219,9 +224,10 @@ def get_quick_recommendation(self, df, indicator):
default_logger().debug(summary.to_string(index=False))
if summary is not None and len(summary) > 0:
last_row = summary.tail(1)
return last_row['Recommendation'].iloc[0]
reco = last_row['Recommendation'].iloc[0]
return '-' if reco == 'Unknown' else reco
else:
return 'Unknown'
return '-'

def update_confidence_level(self, df):
rsi = round(df['RSI'].iloc[0],2)
Expand Down
4 changes: 2 additions & 2 deletions nseta/scanner/intradayScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ def scan(self, option=None):
self.sortAscending = True
super().scan(option='Symbol')

def scan_background(self, terminate_after_iter=0, wait_time=resources.scanner().background_scan_frequency_intraday):
return super().scan_background(terminate_after_iter=terminate_after_iter, wait_time=wait_time)
def scan_background(self, scannerinstance, terminate_after_iter=0, wait_time=resources.scanner().background_scan_frequency_intraday):
return super().scan_background(scannerinstance, terminate_after_iter=terminate_after_iter, wait_time=wait_time)
6 changes: 2 additions & 4 deletions nseta/scanner/intradayStockScanner.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pandas as pd
import numpy as np
import datetime

from nseta.common.ti import ti
Expand Down Expand Up @@ -46,11 +47,8 @@ class intradayStockScanner(baseStockScanner):
def __init__(self, indicator='all'):
super().__init__(indicator=indicator)

def get_func_name(self):
return self.scan_intraday_quanta

@tracelog
def scan_intraday_quanta(self, **kwargs):
def scan_quanta(self, **kwargs):
stocks = kwargs['items']
frames = []
signalframes = []
Expand Down
4 changes: 2 additions & 2 deletions nseta/scanner/liveScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ def scan(self, option=None):
super().scan(option='% Delivery')

@tracelog
def scan_background(self, terminate_after_iter=0, wait_time=resources.scanner().background_scan_frequency_live):
return super().scan_background(terminate_after_iter=terminate_after_iter, wait_time=wait_time)
def scan_background(self, scannerinstance, terminate_after_iter=0, wait_time=resources.scanner().background_scan_frequency_live):
return super().scan_background(scannerinstance, terminate_after_iter=terminate_after_iter, wait_time=wait_time)
6 changes: 1 addition & 5 deletions nseta/scanner/liveStockScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import talib as ta

from nseta.live.live import get_live_quote
from nseta.common.ti import ti
from nseta.resources.resources import *
from nseta.scanner.baseStockScanner import baseStockScanner
from nseta.archives.archiver import *
Expand All @@ -15,15 +14,12 @@ def __init__(self, indicator='all'):
super().__init__(indicator=indicator)
self._keys = ['symbol','previousClose', 'lastPrice', 'deliveryToTradedQuantity', 'BuySellDiffQty', 'totalTradedVolume', 'pChange']

def get_func_name(self):
return self.scan_live_quanta

@property
def keys(self):
return self._keys

@tracelog
def scan_live_quanta(self, **kwargs):
def scan_quanta(self, **kwargs):
stocks = kwargs['items']
frames = []
signalframes = []
Expand Down
1 change: 0 additions & 1 deletion nseta/scanner/scannerFactory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import enum
from nseta.scanner.intradayScanner import intradayScanner
from nseta.scanner.liveScanner import liveScanner
from nseta.scanner.quoteScanner import quoteScanner
Expand Down
10 changes: 7 additions & 3 deletions nseta/scanner/stockscanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ class scanner(baseStockScanner):
def __init__(self, indicator='all'):
super().__init__(indicator=indicator)

def get_func_name(self, scanner_type=ScannerType.Unknown):
scn = scanner.stockScanner(scanner_type=scanner_type, indicator=self.indicator)
return scn.get_func_name()
def get_instance(self, scanner_type=ScannerType.Unknown):
if scanner_type.name in self.instancedict:
return self.instancedict[scanner_type.name]
else:
instance = scanner.stockScanner(scanner_type=scanner_type, indicator=self.indicator)
self.instancedict[scanner_type.name] = instance
return instance

@staticmethod
def stockScanner(scanner_type=ScannerType.Unknown, indicator=None):
Expand Down
2 changes: 1 addition & 1 deletion nseta/scanner/swingScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def scan(self, option=None):
# TODO: Include get-quote results for OHLC of today before market closing hours for better accuracy

@tracelog
def scan_background(self, terminate_after_iter=0, wait_time=0):
def scan_background(self, scannerinstance, terminate_after_iter=0, wait_time=0):
default_logger().debug('Background running not supported yet. Stay tuned. Executing just once.')
self.background = False
self.scan(self.option)
Expand Down
6 changes: 1 addition & 5 deletions nseta/scanner/swingStockScanner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import pandas as pd
import talib as ta
import datetime
import sys

Expand All @@ -18,11 +17,8 @@ class swingStockScanner(baseStockScanner):
def __init__(self, indicator='all'):
super().__init__(indicator=indicator)

def get_func_name(self):
return self.scan_swing_quanta

@tracelog
def scan_swing_quanta(self, **kwargs):
def scan_quanta(self, **kwargs):
stocks = kwargs['items']
frames = []
signalframes = []
Expand Down
4 changes: 2 additions & 2 deletions nseta/scanner/volumeScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def scan(self, option=None):
self.sortAscending = False
super().scan(option=option)

def scan_background(self, terminate_after_iter=0, wait_time=resources.scanner().background_scan_frequency_intraday):
return super().scan_background(terminate_after_iter=terminate_after_iter, wait_time=wait_time)
def scan_background(self, scannerinstance, terminate_after_iter=0, wait_time=resources.scanner().background_scan_frequency_intraday):
return super().scan_background(scannerinstance, terminate_after_iter=terminate_after_iter, wait_time=wait_time)

def scan_results(self, df, signaldf, should_cache=True):
if self.option == 'momentum':
Expand Down
9 changes: 3 additions & 6 deletions nseta/scanner/volumeStockScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@ def __init__(self, indicator='all'):
super().__init__(indicator=indicator)
self._keys = ['symbol','previousClose', 'lastPrice', 'deliveryToTradedQuantity', 'BuySellDiffQty', 'totalTradedVolume', 'pChange']

def get_func_name(self):
return self.scan_volume_quanta

@property
def keys(self):
return self._keys

@tracelog
def scan_volume_quanta(self, **kwargs):
def scan_quanta(self, **kwargs):
stocks = kwargs['items']
frames = []
signalframes = []
Expand Down Expand Up @@ -148,7 +145,7 @@ def format_scan_volume_df(self, df, df_today, signalframes):
elif ltp >= r1:
df['Remarks'].iloc[n-1]='LTP >= R1'
df['S1-R3'].iloc[n-1] = r1
elif ltp < r1:
else:
df['Remarks'].iloc[n-1]='PP <= LTP < R1'
df['S1-R3'].iloc[n-1] = r1
else:
Expand All @@ -163,7 +160,7 @@ def format_scan_volume_df(self, df, df_today, signalframes):
elif ltp >= s3:
df['Remarks'].iloc[n-1]='LTP >= S3'
df['S1-R3'].iloc[n-1] = s3
elif ltp < s3:
else:
df['Remarks'].iloc[n-1]='LTP < S3'
df['S1-R3'].iloc[n-1] = s3
if current_datetime_in_ist_trading_time_range():
Expand Down
2 changes: 0 additions & 2 deletions nseta/strategy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
global __test_counter__
global __download_counter__
12 changes: 9 additions & 3 deletions nseta/strategy/strategyManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,15 @@ def multi_strategy(df, lower, upper, plot=False):
"multi": multi_strategy
}

__test_counter__ = 0
__download_counter__ = 0

class strategyManager:

def __init__(self, order_type=OrderType.Delivery):
self._strict = False
self._total_stocks_counter = 0
self._total_tests_counter = 0

@property
def total_stocks_counter(self):
Expand Down Expand Up @@ -101,7 +106,7 @@ def multithreadedScanner_callback(self, **kwargs):
if end is not None:
ed = datetime.strptime(end, "%Y-%m-%d").date()
frames = []
instance = scanner('all') if intraday else historicaldata()
instance = intradayStockScanner('all') if intraday else historicaldata()
for stock in stocks:
df_summary_dict = {'Symbol':['?'], 'RSI-PnL':[np.nan],'MACD-PnL':[np.nan], 'BBANDS-PnL':[np.nan], 'Reco-RSI':[np.nan], 'Reco-MACD':[np.nan], 'Reco-BBANDS':[np.nan]}
df_summary = pd.DataFrame(df_summary_dict)
Expand All @@ -112,7 +117,8 @@ def multithreadedScanner_callback(self, **kwargs):
if summary is not None and len(summary) > 0:
df_summary['Symbol'].iloc[0] = stock
df_summary['{}-PnL'.format(strategy.upper())].iloc[0] = summary['PnL'].iloc[0]
df_summary['Reco-{}'.format(strategy.upper())].iloc[0] = str(summary['Recommendation'].iloc[0])
reco = summary['Recommendation'].iloc[0]
df_summary['Reco-{}'.format(strategy.upper())].iloc[0] = '-' if reco == 'Unknown' else reco
except Exception as e:
default_logger().debug(e, exc_info=True)
default_logger().debug('Failed to test trading strategy for symbol: {}.'.format(stock))
Expand Down Expand Up @@ -191,7 +197,7 @@ def download_stock_data(self, **kwargs):
sd = datetime.strptime(start, "%Y-%m-%d").date()
if end is not None:
ed = datetime.strptime(end, "%Y-%m-%d").date()
instance = scanner('all') if intraday else historicaldata()
instance = intradayStockScanner('all') if intraday else historicaldata()
for stock in stocks:
try:
global __download_counter__
Expand Down
8 changes: 4 additions & 4 deletions tests/test_livecli.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_scan_intraday(self):
def test_scan_intraday_background(self):
s = scannerFactory.scanner(ScannerType.Intraday, ['HDFC'], 'emac', True)
scannerinstance = scanner(indicator='rsi')
result = s.scan_background(terminate_after_iter=2, wait_time=2)
result = s.scan_background(scannerinstance, terminate_after_iter=2, wait_time=2)
self.assertEqual(result , 2)

def test_scan_live(self):
Expand All @@ -53,7 +53,7 @@ def test_scan_live(self):
def test_scan_live_background(self):
s = scannerFactory.scanner(ScannerType.Live, ['HDFC'], 'emac', True)
scannerinstance = scanner(indicator='rsi')
result = s.scan_background(terminate_after_iter=2, wait_time=2)
result = s.scan_background(scannerinstance, terminate_after_iter=2, wait_time=2)
self.assertEqual(result , 2)

def test_scan_swing(self):
Expand All @@ -65,7 +65,7 @@ def test_scan_swing(self):
def test_scan_swing_background(self):
s = scannerFactory.scanner(ScannerType.Swing, ['HDFC'], 'emac', True)
scannerinstance = scanner(indicator='rsi')
result = s.scan_background(terminate_after_iter=2, wait_time=0)
result = s.scan_background(scannerinstance, terminate_after_iter=2, wait_time=0)
self.assertEqual(result , 0)
self.assertFalse(s.background)

Expand All @@ -84,7 +84,7 @@ def test_scan_volume_intraday(self):
def test_scan_volume_background(self):
s = scannerFactory.scanner(ScannerType.Volume, ['HDFC'], 'emac', True)
scannerinstance = scanner(indicator='rsi')
result = s.scan_background(terminate_after_iter=2, wait_time=2)
result = s.scan_background(scannerinstance, terminate_after_iter=2, wait_time=2)
self.assertEqual(result , 2)

def test_live_quote_inputs(self):
Expand Down
5 changes: 5 additions & 0 deletions tests/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ def test_debug_log(self):

def test_debug_log_filter(self):
log.setup_custom_logger('nseta', logging.DEBUG, False, filter='test_log.py')
default_logger().setLevel(logging.INFO)
self.assertEqual(default_logger().level, logging.INFO)
default_logger().level = logging.WARN
self.assertEqual(default_logger().level, logging.WARN)
default_logger().setLevel(logging.DEBUG)
default_logger().debug('test_debug_log_filter')
self.assertIn('test_debug_log_filter', self.capturedOutput.getvalue())
self.assertIn('test_log.py', self.capturedOutput.getvalue())
Expand Down
Loading

0 comments on commit 94f83d2

Please sign in to comment.