|
|
''' |
|
|
* Project : Screenipy |
|
|
* Author : Pranjal Joshi |
|
|
* Created : 28/04/2021 |
|
|
* Description : Class for handling networking for fetching stock codes and data |
|
|
''' |
|
|
|
|
|
import sys |
|
|
import urllib.request |
|
|
import csv |
|
|
import requests |
|
|
import random |
|
|
import os |
|
|
import datetime |
|
|
import yfinance as yf |
|
|
import pandas as pd |
|
|
from nsetools import Nse |
|
|
from classes.ColorText import colorText |
|
|
from classes.SuppressOutput import SuppressOutput |
|
|
from classes.Utility import isDocker |
|
|
|
|
|
nse = Nse() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StockDataEmptyException(Exception): |
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class tools: |
|
|
|
|
|
def __init__(self, configManager): |
|
|
self.configManager = configManager |
|
|
pass |
|
|
|
|
|
def getAllNiftyIndices(self) -> dict: |
|
|
return { |
|
|
"^NSEI": "NIFTY 50", |
|
|
"^NSMIDCP": "NIFTY NEXT 50", |
|
|
"^CNX100": "NIFTY 100", |
|
|
"^CNX200": "NIFTY 200", |
|
|
"^CNX500": "NIFTY 500", |
|
|
"^NSEMDCP50": "NIFTY MIDCAP 50", |
|
|
"NIFTY_MIDCAP_100.NS": "NIFTY MIDCAP 100", |
|
|
"^CNXSC": "NIFTY SMALLCAP 100", |
|
|
"^INDIAVIX": "INDIA VIX", |
|
|
"NIFTYMIDCAP150.NS": "NIFTY MIDCAP 150", |
|
|
"NIFTYSMLCAP50.NS": "NIFTY SMALLCAP 50", |
|
|
"NIFTYSMLCAP250.NS": "NIFTY SMALLCAP 250", |
|
|
"NIFTYMIDSML400.NS": "NIFTY MIDSMALLCAP 400", |
|
|
"NIFTY500_MULTICAP.NS": "NIFTY500 MULTICAP 50:25:25", |
|
|
"NIFTY_LARGEMID250.NS": "NIFTY LARGEMIDCAP 250", |
|
|
"NIFTY_MID_SELECT.NS": "NIFTY MIDCAP SELECT", |
|
|
"NIFTY_TOTAL_MKT.NS": "NIFTY TOTAL MARKET", |
|
|
"NIFTY_MICROCAP250.NS": "NIFTY MICROCAP 250", |
|
|
"^NSEBANK": "NIFTY BANK", |
|
|
"^CNXAUTO": "NIFTY AUTO", |
|
|
"NIFTY_FIN_SERVICE.NS": "NIFTY FINANCIAL SERVICES", |
|
|
"^CNXFMCG": "NIFTY FMCG", |
|
|
"^CNXIT": "NIFTY IT", |
|
|
"^CNXMEDIA": "NIFTY MEDIA", |
|
|
"^CNXMETAL": "NIFTY METAL", |
|
|
"^CNXPHARMA": "NIFTY PHARMA", |
|
|
"^CNXPSUBANK": "NIFTY PSU BANK", |
|
|
"^CNXREALTY": "NIFTY REALTY", |
|
|
"NIFTY_HEALTHCARE.NS": "NIFTY HEALTHCARE INDEX", |
|
|
"NIFTY_CONSR_DURBL.NS": "NIFTY CONSUMER DURABLES", |
|
|
"NIFTY_OIL_AND_GAS.NS": "NIFTY OIL & GAS", |
|
|
"NIFTYALPHA50.NS": "NIFTY ALPHA 50", |
|
|
"^CNXCMDT": "NIFTY COMMODITIES", |
|
|
"NIFTY_CPSE.NS": "NIFTY CPSE", |
|
|
"^CNXENERGY": "NIFTY ENERGY", |
|
|
"^CNXINFRA": "NIFTY INFRASTRUCTURE", |
|
|
"^CNXMNC": "NIFTY MNC", |
|
|
"^CNXPSE": "NIFTY PSE", |
|
|
"^CNXSERVICE": "NIFTY SERVICES SECTOR", |
|
|
"NIFTY100_ESG.NS": "NIFTY100 ESG SECTOR LEADERS", |
|
|
} |
|
|
|
|
|
def _getBacktestDate(self, backtest): |
|
|
try: |
|
|
end = backtest + datetime.timedelta(days=1) |
|
|
if "d" in self.configManager.period: |
|
|
delta = datetime.timedelta(days = self.configManager.getPeriodNumeric()) |
|
|
elif "wk" in self.configManager.period: |
|
|
delta = datetime.timedelta(days = self.configManager.getPeriodNumeric() * 7) |
|
|
elif "m" in self.configManager.period: |
|
|
delta = datetime.timedelta(minutes = self.configManager.getPeriodNumeric()) |
|
|
elif "h" in self.configManager.period: |
|
|
delta = datetime.timedelta(hours = self.configManager.getPeriodNumeric()) |
|
|
start = end - delta |
|
|
return [start, end] |
|
|
except: |
|
|
return [None, None] |
|
|
|
|
|
def _getDatesForBacktestReport(self, backtest): |
|
|
dateDict = {} |
|
|
try: |
|
|
today = datetime.date.today() |
|
|
dateDict['T+1d'] = backtest + datetime.timedelta(days=1) if backtest + datetime.timedelta(days=1) < today else None |
|
|
dateDict['T+1wk'] = backtest + datetime.timedelta(weeks=1) if backtest + datetime.timedelta(weeks=1) < today else None |
|
|
dateDict['T+1mo'] = backtest + datetime.timedelta(days=30) if backtest + datetime.timedelta(days=30) < today else None |
|
|
dateDict['T+6mo'] = backtest + datetime.timedelta(days=180) if backtest + datetime.timedelta(days=180) < today else None |
|
|
dateDict['T+1y'] = backtest + datetime.timedelta(days=365) if backtest + datetime.timedelta(days=365) < today else None |
|
|
for key, val in dateDict.copy().items(): |
|
|
if val is not None: |
|
|
if val.weekday() == 5: |
|
|
adjusted_date = val + datetime.timedelta(days=2) |
|
|
dateDict[key] = adjusted_date |
|
|
elif val.weekday() == 6: |
|
|
adjusted_date = val + datetime.timedelta(days=1) |
|
|
dateDict[key] = adjusted_date |
|
|
except: |
|
|
pass |
|
|
return dateDict |
|
|
|
|
|
def fetchCodes(self, tickerOption,proxyServer=None): |
|
|
listStockCodes = [] |
|
|
if tickerOption == 12: |
|
|
url = "https://archives.nseindia.com/content/equities/EQUITY_L.csv" |
|
|
return list(pd.read_csv(url)['SYMBOL'].values) |
|
|
if tickerOption == 15: |
|
|
return ["MMM", "ABT", "ABBV", "ABMD", "ACN", "ATVI", "ADBE", "AMD", "AAP", "AES", "AFL", "A", "APD", "AKAM", "ALK", "ALB", "ARE", "ALXN", "ALGN", "ALLE", "AGN", "ADS", "LNT", "ALL", "GOOGL", "GOOG", "MO", "AMZN", "AMCR", "AEE", "AAL", "AEP", "AXP", "AIG", "AMT", "AWK", "AMP", "ABC", "AME", "AMGN", "APH", "ADI", "ANSS", "ANTM", "AON", "AOS", "APA", "AIV", "AAPL", "AMAT", "APTV", "ADM", "ARNC", "ANET", "AJG", "AIZ", "ATO", "T", "ADSK", "ADP", "AZO", "AVB", "AVY", "BKR", "BLL", "BAC", "BK", "BAX", "BDX", "BRK.B", "BBY", "BIIB", "BLK", "BA", "BKNG", "BWA", "BXP", "BSX", "BMY", "AVGO", "BR", "BF.B", "CHRW", "COG", "CDNS", "CPB", "COF", "CPRI", "CAH", "KMX", "CCL", "CAT", "CBOE", "CBRE", "CDW", "CE", "CNC", "CNP", "CTL", "CERN", "CF", "SCHW", "CHTR", "CVX", "CMG", "CB", "CHD", "CI", "XEC", "CINF", "CTAS", "CSCO", "C", "CFG", "CTXS", "CLX", "CME", "CMS", "KO", "CTSH", "CL", "CMCSA", "CMA", "CAG", "CXO", "COP", "ED", "STZ", "COO", "CPRT", "GLW", "CTVA", "COST", "COTY", "CCI", "CSX", "CMI", "CVS", "DHI", "DHR", "DRI", "DVA", "DE", "DAL", "XRAY", "DVN", "FANG", "DLR", "DFS", "DISCA", "DISCK", "DISH", "DG", "DLTR", "D", "DOV", "DOW", "DTE", "DUK", "DRE", "DD", "DXC", "ETFC", "EMN", "ETN", "EBAY", "ECL", "EIX", "EW", "EA", "EMR", "ETR", "EOG", "EFX", "EQIX", "EQR", "ESS", "EL", "EVRG", "ES", "RE", "EXC", "EXPE", "EXPD", "EXR", "XOM", "FFIV", "FB", "FAST", "FRT", "FDX", "FIS", "FITB", "FE", "FRC", "FISV", "FLT", "FLIR", "FLS", "FMC", "F", "FTNT", "FTV", "FBHS", "FOXA", "FOX", "BEN", "FCX", "GPS", "GRMN", "IT", "GD", "GE", "GIS", "GM", "GPC", "GILD", "GL", "GPN", "GS", "GWW", "HRB", "HAL", "HBI", "HOG", "HIG", "HAS", "HCA", "PEAK", "HP", "HSIC", "HSY", "HES", "HPE", "HLT", "HFC", "HOLX", "HD", "HON", "HRL", "HST", "HPQ", "HUM", "HBAN", "HII", "IEX", "IDXX", "INFO", "ITW", "ILMN", "IR", "INTC", "ICE", "IBM", "INCY", "IP", "IPG", "IFF", "INTU", "ISRG", "IVZ", "IPGP", "IQV", "IRM", "JKHY", "J", "JBHT", "SJM", "JNJ", "JCI", "JPM", "JNPR", "KSU", "K", "KEY", "KEYS", "KMB", "KIM", "KMI", "KLAC", "KSS", "KHC", "KR", "LB", "LHX", "LH", "LRCX", "LW", "LVS", "LEG", "LDOS", "LEN", "LLY", "LNC", "LIN", "LYV", "LKQ", "LMT", "L", "LOW", "LYB", "MTB", "M", "MRO", "MPC", "MKTX", "MAR", "MMC", "MLM", "MAS", "MA", "MKC", "MXIM", "MCD", "MCK", "MDT", "MRK", "MET", "MTD", "MGM", "MCHP", "MU", "MSFT", "MAA", "MHK", "TAP", "MDLZ", "MNST", "MCO", "MS", "MOS", "MSI", "MSCI", "MYL", "NDAQ", "NOV", "NTAP", "NFLX", "NWL", "NEM", "NWSA", "NWS", "NEE", "NLSN", "NKE", "NI", "NBL", "JWN", "NSC", "NTRS", "NOC", "NLOK", "NCLH", "NRG", "NUE", "NVDA", "NVR", "ORLY", "OXY", "ODFL", "OMC", "OKE", "ORCL", "PCAR", "PKG", "PH", "PAYX", "PYPL", "PNR", "PBCT", "PEP", "PKI", "PRGO", "PFE", "PM", "PSX", "PNW", "PXD", "PNC", "PPG", "PPL", "PFG", "PG", "PGR", "PLD", "PRU", "PEG", "PSA", "PHM", "PVH", "QRVO", "PWR", "QCOM", "DGX", "RL", "RJF", "RTN", "O", "REG", "REGN", "RF", "RSG", "RMD", "RHI", "ROK", "ROL", "ROP", "ROST", "RCL", "SPGI", "CRM", "SBAC", "SLB", "STX", "SEE", "SRE", "NOW", "SHW", "SPG", "SWKS", "SLG", "SNA", "SO", "LUV", "SWK", "SBUX", "STT", "STE", "SYK", "SIVB", "SYF", "SNPS", "SYY", "TMUS", "TROW", "TTWO", "TPR", "TGT", "TEL", "FTI", "TFX", "TXN", "TXT", "TMO", "TIF", "TJX", "TSCO", "TDG", "TRV", "TFC", "TWTR", "TSN", "UDR", "ULTA", "USB", "UAA", "UA", "UNP", "UAL", "UNH", "UPS", "URI", "UTX", "UHS", "UNM", "VFC", "VLO", "VAR", "VTR", "VRSN", "VRSK", "VZ", "VRTX", "VIAC", "V", "VNO", "VMC", "WRB", "WAB", "WMT", "WBA", "DIS", "WM", "WAT", "WEC", "WCG", "WFC", "WELL", "WDC", "WU", "WRK", "WY", "WHR", "WMB", "WLTW", "WYNN", "XEL", "XRX", "XLNX", "XYL", "YUM", "ZBRA", "ZBH", "ZION", "ZTS"] |
|
|
if tickerOption == 16: |
|
|
return self.getAllNiftyIndices() |
|
|
tickerMapping = { |
|
|
1: "https://archives.nseindia.com/content/indices/ind_nifty50list.csv", |
|
|
2: "https://archives.nseindia.com/content/indices/ind_niftynext50list.csv", |
|
|
3: "https://archives.nseindia.com/content/indices/ind_nifty100list.csv", |
|
|
4: "https://archives.nseindia.com/content/indices/ind_nifty200list.csv", |
|
|
5: "https://archives.nseindia.com/content/indices/ind_nifty500list.csv", |
|
|
6: "https://archives.nseindia.com/content/indices/ind_niftysmallcap50list.csv", |
|
|
7: "https://archives.nseindia.com/content/indices/ind_niftysmallcap100list.csv", |
|
|
8: "https://archives.nseindia.com/content/indices/ind_niftysmallcap250list.csv", |
|
|
9: "https://archives.nseindia.com/content/indices/ind_niftymidcap50list.csv", |
|
|
10: "https://archives.nseindia.com/content/indices/ind_niftymidcap100list.csv", |
|
|
11: "https://archives.nseindia.com/content/indices/ind_niftymidcap150list.csv", |
|
|
14: "https://api.kite.trade/instruments" |
|
|
} |
|
|
|
|
|
url = tickerMapping.get(tickerOption) |
|
|
|
|
|
try: |
|
|
if proxyServer: |
|
|
res = requests.get(url,proxies={'https':proxyServer}) |
|
|
else: |
|
|
res = requests.get(url) |
|
|
|
|
|
cr = csv.reader(res.text.strip().split('\n')) |
|
|
|
|
|
if tickerOption == 14: |
|
|
cols = next(cr) |
|
|
df = pd.DataFrame(cr, columns=cols) |
|
|
listStockCodes = list(set(df[df['segment'] == 'NFO-FUT']["name"].to_list())) |
|
|
listStockCodes.sort() |
|
|
else: |
|
|
next(cr) |
|
|
for row in cr: |
|
|
listStockCodes.append(row[2]) |
|
|
except Exception as error: |
|
|
print(error) |
|
|
|
|
|
return listStockCodes |
|
|
|
|
|
|
|
|
def fetchStockCodes(self, tickerOption, proxyServer=None): |
|
|
listStockCodes = [] |
|
|
if tickerOption == 0: |
|
|
stockCode = None |
|
|
while stockCode == None or stockCode == "": |
|
|
stockCode = str(input(colorText.BOLD + colorText.BLUE + |
|
|
"[+] Enter Stock Code(s) for screening (Multiple codes should be seperated by ,): ")).upper() |
|
|
stockCode = stockCode.replace(" ", "") |
|
|
listStockCodes = stockCode.split(',') |
|
|
else: |
|
|
print(colorText.BOLD + |
|
|
"[+] Getting Stock Codes From NSE... ", end='') |
|
|
listStockCodes = self.fetchCodes(tickerOption,proxyServer=proxyServer) |
|
|
if type(listStockCodes) == dict: |
|
|
listStockCodes = list(listStockCodes.keys()) |
|
|
if len(listStockCodes) > 10: |
|
|
print(colorText.GREEN + ("=> Done! Fetched %d stock codes." % |
|
|
len(listStockCodes)) + colorText.END) |
|
|
if self.configManager.shuffleEnabled: |
|
|
random.shuffle(listStockCodes) |
|
|
print(colorText.BLUE + |
|
|
"[+] Stock shuffling is active." + colorText.END) |
|
|
else: |
|
|
print(colorText.FAIL + |
|
|
"[+] Stock shuffling is inactive." + colorText.END) |
|
|
if self.configManager.stageTwo: |
|
|
print( |
|
|
colorText.BLUE + "[+] Screening only for the stocks in Stage-2! Edit User Config to change this." + colorText.END) |
|
|
else: |
|
|
print( |
|
|
colorText.FAIL + "[+] Screening only for the stocks in all Stages! Edit User Config to change this." + colorText.END) |
|
|
|
|
|
else: |
|
|
input( |
|
|
colorText.FAIL + "=> Error getting stock codes from NSE! Press any key to exit!" + colorText.END) |
|
|
sys.exit("Exiting script..") |
|
|
|
|
|
return listStockCodes |
|
|
|
|
|
|
|
|
def fetchStockData(self, stockCode, period, duration, proxyServer, screenResultsCounter, screenCounter, totalSymbols, backtestDate=None, printCounter=False, tickerOption=None): |
|
|
dateDict = None |
|
|
with SuppressOutput(suppress_stdout=True, suppress_stderr=True): |
|
|
append_exchange = ".NS" |
|
|
if tickerOption == 15 or tickerOption == 16: |
|
|
append_exchange = "" |
|
|
data = yf.download( |
|
|
tickers=stockCode + append_exchange, |
|
|
period=period, |
|
|
interval=duration, |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10, |
|
|
start=self._getBacktestDate(backtest=backtestDate)[0], |
|
|
end=self._getBacktestDate(backtest=backtestDate)[1], |
|
|
auto_adjust=False |
|
|
) |
|
|
|
|
|
data = self.makeDataBackwardCompatible(data) |
|
|
|
|
|
if backtestDate != datetime.date.today(): |
|
|
dateDict = self._getDatesForBacktestReport(backtest=backtestDate) |
|
|
backtestData = yf.download( |
|
|
tickers=stockCode + append_exchange, |
|
|
interval='1d', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10, |
|
|
start=backtestDate - datetime.timedelta(days=1), |
|
|
end=backtestDate + datetime.timedelta(days=370) |
|
|
) |
|
|
for key, value in dateDict.copy().items(): |
|
|
if value is not None: |
|
|
try: |
|
|
dateDict[key] = backtestData.loc[pd.Timestamp(value)]['Close'] |
|
|
except KeyError: |
|
|
continue |
|
|
dateDict['T+52wkH'] = backtestData['High'].max() |
|
|
dateDict['T+52wkL'] = backtestData['Low'].min() |
|
|
if printCounter: |
|
|
sys.stdout.write("\r\033[K") |
|
|
try: |
|
|
print(colorText.BOLD + colorText.GREEN + ("[%d%%] Screened %d, Found %d. Fetching data & Analyzing %s..." % ( |
|
|
int((screenCounter.value/totalSymbols)*100), screenCounter.value, screenResultsCounter.value, stockCode)) + colorText.END, end='') |
|
|
except ZeroDivisionError: |
|
|
pass |
|
|
if len(data) == 0: |
|
|
print(colorText.BOLD + colorText.FAIL + |
|
|
"=> Failed to fetch!" + colorText.END, end='\r', flush=True) |
|
|
raise StockDataEmptyException |
|
|
return None |
|
|
print(colorText.BOLD + colorText.GREEN + "=> Done!" + |
|
|
colorText.END, end='\r', flush=True) |
|
|
return data, dateDict |
|
|
|
|
|
|
|
|
def fetchLatestNiftyDaily(self, proxyServer=None): |
|
|
data = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="^NSEI", |
|
|
period='5d', |
|
|
interval='1d', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
) |
|
|
gold = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="GC=F", |
|
|
period='5d', |
|
|
interval='1d', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
).add_prefix(prefix='gold_') |
|
|
crude = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="CL=F", |
|
|
period='5d', |
|
|
interval='1d', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
).add_prefix(prefix='crude_') |
|
|
data = self.makeDataBackwardCompatible(data) |
|
|
gold = self.makeDataBackwardCompatible(gold, column_prefix='gold_') |
|
|
crude = self.makeDataBackwardCompatible(crude, column_prefix='crude_') |
|
|
data = pd.concat([data, gold, crude], axis=1) |
|
|
return data |
|
|
|
|
|
|
|
|
def fetchFiveEmaData(self, proxyServer=None): |
|
|
nifty_sell = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="^NSEI", |
|
|
period='5d', |
|
|
interval='5m', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
) |
|
|
banknifty_sell = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="^NSEBANK", |
|
|
period='5d', |
|
|
interval='5m', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
) |
|
|
nifty_buy = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="^NSEI", |
|
|
period='5d', |
|
|
interval='15m', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
) |
|
|
banknifty_buy = yf.download( |
|
|
auto_adjust=False, |
|
|
tickers="^NSEBANK", |
|
|
period='5d', |
|
|
interval='15m', |
|
|
proxy=proxyServer, |
|
|
progress=False, |
|
|
timeout=10 |
|
|
) |
|
|
nifty_buy = self.makeDataBackwardCompatible(nifty_buy) |
|
|
banknifty_buy = self.makeDataBackwardCompatible(banknifty_buy) |
|
|
nifty_sell = self.makeDataBackwardCompatible(nifty_sell) |
|
|
banknifty_sell = self.makeDataBackwardCompatible(banknifty_sell) |
|
|
return nifty_buy, banknifty_buy, nifty_sell, banknifty_sell |
|
|
|
|
|
|
|
|
def fetchWatchlist(self): |
|
|
createTemplate = False |
|
|
data = pd.DataFrame() |
|
|
try: |
|
|
data = pd.read_excel('watchlist.xlsx') |
|
|
except FileNotFoundError: |
|
|
print(colorText.BOLD + colorText.FAIL + |
|
|
f'[+] watchlist.xlsx not found in f{os.getcwd()}' + colorText.END) |
|
|
createTemplate = True |
|
|
try: |
|
|
if not createTemplate: |
|
|
data = data['Stock Code'].values.tolist() |
|
|
except KeyError: |
|
|
print(colorText.BOLD + colorText.FAIL + |
|
|
'[+] Bad Watchlist Format: First Column (A1) should have Header named "Stock Code"' + colorText.END) |
|
|
createTemplate = True |
|
|
if createTemplate: |
|
|
if isDocker(): |
|
|
print(colorText.BOLD + colorText.FAIL + |
|
|
f'[+] This feature is not available with dockerized application. Try downloading .exe/.bin file to use this!' + colorText.END) |
|
|
return None |
|
|
sample = {'Stock Code': ['SBIN', 'INFY', 'TATAMOTORS', 'ITC']} |
|
|
sample_data = pd.DataFrame(sample, columns=['Stock Code']) |
|
|
sample_data.to_excel('watchlist_template.xlsx', |
|
|
index=False, header=True) |
|
|
print(colorText.BOLD + colorText.BLUE + |
|
|
f'[+] watchlist_template.xlsx created in {os.getcwd()} as a referance template.' + colorText.END) |
|
|
return None |
|
|
return data |
|
|
|
|
|
def makeDataBackwardCompatible(self, data:pd.DataFrame, column_prefix:str=None) -> pd.DataFrame: |
|
|
data = data.droplevel(level=1, axis=1) |
|
|
data = data.rename_axis(None, axis=1) |
|
|
column_prefix = '' if column_prefix is None else column_prefix |
|
|
data = data[ |
|
|
[ |
|
|
f'{column_prefix}Open', |
|
|
f'{column_prefix}High', |
|
|
f'{column_prefix}Low', |
|
|
f'{column_prefix}Close', |
|
|
f'{column_prefix}Adj Close', |
|
|
f'{column_prefix}Volume' |
|
|
] |
|
|
] |
|
|
return data |
|
|
|