Last active
May 1, 2018 19:19
-
-
Save Beliavsky/16acfafe60b3fb1c5e1f41298497c79d to your computer and use it in GitHub Desktop.
Closed-End Fund quotes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 05/01/2018 10:31 AM display quotes for all CEFs --> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta charset="utf-8"> | |
<title>Closed-End Funds</title> | |
<link rel="icon" href="https://d3v3cbxkdlyonc.cloudfront.net/stocks/favicon.ico"> | |
<meta name="description" content="A free, lightweight, blazing-fast page to get stock quotes using the IEX API"> | |
<style> | |
body { | |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", | |
"Oxygen", "Ubuntu", "Helvetica Neue", Arial, sans-serif; | |
} | |
table { font-family: Courier, monospace; } | |
.stocks-container { | |
margin-bottom: 1.5em; | |
width: 100%; | |
max-width: 600px; | |
} | |
.stocks-container a { text-decoration: none; } | |
table { | |
border-collapse: collapse; | |
width: 100%; | |
font-size: 1.1em ; | |
} | |
.stock-symbol { | |
width: 12%; | |
padding: 2px 4px 2px 0px; | |
} | |
.stock-price, .stock-change, .stock-change-pct, .stock-mkt-cap { | |
width: 22%; | |
text-align: right; | |
padding: 2px 4px; | |
} | |
@media (max-width: 576px) { | |
table { margin-bottom: 3em; } | |
.stock-mkt-cap { display: none; } | |
.stock-symbol { width: 16%; } | |
.stock-price, .stock-change, .stock-change-pct { width: 28%; } | |
td.stock-symbol, td.stock-price, td.stock-change, td.stock-change-pct { | |
padding-top: 1em; | |
padding-bottom: 1em; | |
} | |
} | |
summary:hover { cursor: pointer; } | |
summary::-webkit-details-marker { display: none; } | |
</style> | |
</head> | |
<body> | |
<div class="stocks-container"></div> | |
<p class="attribution"> | |
Data provided subject to <a href="https://iextrading.com/api-exhibit-a/" target="_blank">IEX Exhibit A</a>. | |
</p> | |
<p class="updated-timestamp"></p> | |
<p>Customize <a href="https://github.com/toddwschneider/stocks" target="_blank">on GitHub</p> | |
<script> | |
'use strict'; | |
// categories below are from CEF Connect 2018-05-01 | |
const PORTFOLIOS = [ | |
{'name': 'ETFs', 'symbols': ['SPY', 'TLT', 'MUB']}, | |
{'name': 'Non-US/Other-Asia Equity', 'symbols': ['APB', 'APF', 'CAF', 'CHN', 'GCH', 'GRR', 'IAE', 'IF', 'IFN', 'IIF', 'JEQ', 'JOF', 'KF', 'SGF', 'TDF', 'TWN']}, | |
{'name': 'Non-US/Other-Emerging Market Equity', 'symbols': ['ABE', 'CEE', 'EMF', 'IHD', 'MSF']}, | |
{'name': 'Non-US/Other-Emerging Market Income', 'symbols': ['BGIO', 'EDD', 'EDF', 'EDI', 'EMD', 'JEMD', 'MSD', 'TEI']}, | |
{'name': 'Non-US/Other-Global Equity', 'symbols': ['BST', 'GDL', 'GGT', 'GGZ', 'GLQ', 'IDE', 'INF', 'RGT']}, | |
{'name': 'Non-US/Other-Global Equity Dividend', 'symbols': ['AGD', 'AOD', 'EOD', 'HEQ', 'IID']}, | |
{'name': 'Non-US/Other-Global Growth & Income', 'symbols': ['CGO', 'CHW', 'DEX', 'EGIF', 'FEO', 'GLO', 'GLV', 'JDD', 'LCM', 'LGI', 'LOR', 'SCD', 'ZF']}, | |
{'name': 'Non-US/Other-Global Income', 'symbols': ['BWG', 'EHI', 'FAM', 'FAX', 'FCO', 'GIM', 'JGH', 'KMM', 'KST', 'MCR', 'MIN', 'MMT', 'PPT', 'RCS']}, | |
{'name': 'Non-US/Other-Latin American Equity', 'symbols': ['CH', 'CUBA', 'LAQ', 'LDF', 'MXE', 'MXF']}, | |
{'name': 'Non-US/Other-Other Non-US Equity', 'symbols': ['EEA', 'FDEU', 'GF', 'IAF', 'IRL', 'ISL', 'SWZ']}, | |
{'name': 'Non-US/Other-undefined', 'symbols': ['VCF']}, | |
{'name': 'Tax-Free Income-Arizona', 'symbols': ['MZA', 'NAZ']}, | |
{'name': 'Tax-Free Income-California', 'symbols': ['AKP', 'BFZ', 'BJZ', 'CCA', 'CEV', 'EIA', 'EVM', 'MCA', 'MUC', 'MYC', 'NAC', 'NBW', 'NCA', 'NCB', 'NKX', 'NXC', 'PCK', 'PCQ', 'PZC', 'VCV']}, | |
{'name': 'Tax-Free Income-Connecticut', 'symbols': ['NTC']}, | |
{'name': 'Tax-Free Income-Florida', 'symbols': ['BFO']}, | |
{'name': 'Tax-Free Income-Georgia', 'symbols': ['NKG']}, | |
{'name': 'Tax-Free Income-High Yield', 'symbols': ['CMU', 'CXE', 'MAV', 'MFM', 'MHI', 'NMZ']}, | |
{'name': 'Tax-Free Income-Maryland', 'symbols': ['BZM', 'NMY']}, | |
{'name': 'Tax-Free Income-Massachusetts', 'symbols': ['MAB', 'MHE', 'MMV', 'NMT']}, | |
{'name': 'Tax-Free Income-Michigan', 'symbols': ['EMI', 'MIW', 'MIY', 'NUM']}, | |
{'name': 'Tax-Free Income-Minnesota', 'symbols': ['NMS', 'VMM']}, | |
{'name': 'Tax-Free Income-Missouri', 'symbols': ['NOM']}, | |
{'name': 'Tax-Free Income-National', 'symbols': ['AFB', 'BAF', 'BBF', 'BBK', 'BFK', 'BKK', 'BKN', 'BLE', 'BPK', 'BSD', 'BTA', 'BTT', 'BYM', 'CXH', 'DMB', 'DMF', 'DSM', 'DTF', 'EIM', 'EIV', 'EOT', 'ETX', 'EVN', 'FMN', 'IIM', 'IQI', 'KSM', 'KTF', 'LEO', 'MEN', 'MFL', 'MFT', 'MHD', 'MHF', 'MMD', 'MMU', 'MNP', 'MQT', 'MQY', 'MTT', 'MUA', 'MUE', 'MUH', 'MUI', 'MUS', 'MVF', 'MVT', 'MYD', 'MYF', 'MYI', 'MZF', 'NAD', 'NBH', 'NEA', 'NEV', 'NHA', 'NID', 'NIM', 'NIQ', 'NMI', 'NUV', 'NUW', 'NVG', 'NXP', 'NXQ', 'NXR', 'NZF', 'OIA', 'PMF', 'PML', 'PMM', 'PMO', 'PMX', 'SBI', 'VFL', 'VGM', 'VKI', 'VKQ', 'VMO']}, | |
{'name': 'Tax-Free Income-New Jersey', 'symbols': ['BLJ', 'BNJ', 'EMJ', 'EVJ', 'MUJ', 'MYJ', 'NJV', 'NXJ']}, | |
{'name': 'Tax-Free Income-New York', 'symbols': ['BFY', 'BLH', 'BNY', 'BQH', 'BSE', 'ENX', 'EVY', 'MHN', 'MNE', 'MYN', 'NAN', 'NBO', 'NNY', 'NRK', 'NXN', 'NYH', 'NYV', 'PNF', 'PNI', 'PYN', 'VTN']}, | |
{'name': 'Tax-Free Income-North Carolina', 'symbols': ['NNC']}, | |
{'name': 'Tax-Free Income-Ohio', 'symbols': ['EIO', 'EVO', 'NUO']}, | |
{'name': 'Tax-Free Income-Pennsylvania', 'symbols': ['EIP', 'EVP', 'MPA', 'NPN', 'NQP', 'VPV']}, | |
{'name': 'Tax-Free Income-Texas', 'symbols': ['NTX']}, | |
{'name': 'Tax-Free Income-Virginia', 'symbols': ['BHV', 'NPV']}, | |
{'name': 'Taxable Income-Convertible', 'symbols': ['AGC', 'AVK', 'BCV', 'ECF']}, | |
{'name': 'Taxable Income-Government', 'symbols': ['EXD', 'WIA', 'WIW']}, | |
{'name': 'Taxable Income-High Yield', 'symbols': ['AIF', 'AWF', 'BGH', 'CIF', 'CIK', 'DHF', 'DHY', 'EAD', 'EHT', 'FHY', 'FSD', 'GHY', 'HIO', 'HIX', 'HNW', 'HYB', 'HYI', 'HYT', 'ISD', 'IVH', 'JCO', 'JHA', 'JHB', 'JHD', 'JHY', 'KIO', 'MCI', 'MPV', 'NHS', 'PCF', 'PHT', 'VLT']}, | |
{'name': 'Taxable Income-Investment Grade', 'symbols': ['BTZ', 'DUC', 'GDO', 'GGM', 'ICB', 'IGI', 'INSI', 'JHI', 'JHS', 'PAI', 'PCN', 'PIM', 'PTY', 'VBF', 'WEA']}, | |
{'name': 'Taxable Income-Limited Duration', 'symbols': ['BLW', 'ERC', 'EVG', 'EVV', 'FTF']}, | |
{'name': 'Taxable Income-Mortgage Bond', 'symbols': ['BKT', 'DMO', 'EGF', 'FMY', 'IHIT', 'IHTA', 'JLS', 'JMM', 'JMT', 'PCM', 'RA']}, | |
{'name': 'Taxable Income-Multi-Sector', 'symbols': ['ACV', 'BHK', 'BIT', 'CBH', 'CCD', 'CHI', 'CHY', 'DBL', 'DCF', 'DSL', 'FT', 'GFY', 'MGF', 'NCV', 'NCZ', 'OPP', 'PCI', 'PDI', 'PFL', 'PFN', 'PGP', 'PHK', 'PKO', 'TSI', 'VGI']}, | |
{'name': 'Taxable Income-Municipal', 'symbols': ['BBN', 'GBAB', 'NBB', 'NBD']}, | |
{'name': 'Taxable Income-Preferreds', 'symbols': ['DFP', 'FFC', 'FLC', 'FPF', 'HPF', 'HPI', 'HPS', 'JPC', 'JPI', 'JPS', 'JPT', 'LDP', 'PDT', 'PFD', 'PFO', 'PSF']}, | |
{'name': 'Taxable Income-Senior Loan', 'symbols': ['ACP', 'AFT', 'ARDC', 'BGB', 'BGT', 'BGX', 'BSL', 'DSU', 'ECC', 'EFF', 'EFL', 'EFR', 'EFT', 'EVF', 'FCT', 'FIV', 'FRA', 'HFRO', 'JFR', 'JQC', 'JRO', 'JSD', 'NSL', 'OXLC', 'PHD', 'PPR', 'TLI', 'TSLF', 'VTA', 'VVR', 'XFLT']}, | |
{'name': 'US Equity-Commodities', 'symbols': ['CEF', 'PHYS', 'PSLV', 'SPPP']}, | |
{'name': 'US Equity-Covered Call', 'symbols': ['BDJ', 'BGY', 'BOE', 'BXMX', 'CII', 'DIAX', 'EOI', 'EOS', 'ETB', 'ETJ', 'ETV', 'ETW', 'ETY', 'EXG', 'FFA', 'GNT', 'GPM', 'IGA', 'IGD', 'INB', 'IRR', 'MCN', 'MSP', 'NFJ', 'QQQX', 'SPXX', 'STK']}, | |
{'name': 'US Equity-Dividend Equity', 'symbols': ['FOF', 'HIE']}, | |
{'name': 'US Equity-Energy/Resources', 'symbols': ['ASA', 'BCX', 'BGR', 'FIF', 'GGN', 'PEO', 'SZC', 'TTP']}, | |
{'name': 'US Equity-Equity Tax-Advantaged', 'symbols': ['ETG', 'ETO', 'EVT', 'GDV', 'HTD', 'HTY', 'JTA', 'JTD']}, | |
{'name': 'US Equity-Finance', 'symbols': ['BTO', 'FGB']}, | |
{'name': 'US Equity-General Equity', 'symbols': ['ADX', 'ASG', 'BIF', 'CET', 'CLM', 'CRF', 'FUND', 'FXBY', 'GAB', 'GAM', 'GRF', 'JCE', 'RMT', 'RVT', 'SOR', 'SPE', 'TY', 'USA']}, | |
{'name': 'US Equity-Growth & Income', 'symbols': ['CSQ', 'DDF', 'DNI', 'DNP', 'GCV', 'GGO', 'GOF', 'MFV', 'NHF', 'NIE', 'RCG', 'RIV', 'TPZ', 'ZTR']}, | |
{'name': 'US Equity-Health/Biotech', 'symbols': ['BME', 'GRX', 'HQH', 'HQL', 'THQ', 'THW']}, | |
{'name': 'US Equity-MLP', 'symbols': ['CBA', 'CEM', 'CEN', 'CTR', 'DSE', 'EMO', 'FEI', 'FEN', 'FMO', 'FPL', 'GER', 'GMZ', 'JMF', 'JMLP', 'KED', 'KMF', 'KYE', 'KYN', 'MIE', 'NDP', 'NML', 'NTG', 'SMM', 'SRF', 'SRV', 'TYG']}, | |
{'name': 'US Equity-Real Estate (Global)', 'symbols': ['AWP', 'IGR', 'JRI']}, | |
{'name': 'US Equity-Real Estate (US)', 'symbols': ['JRS', 'NRO', 'PGZ', 'RFI', 'RIF', 'RNP', 'RQI']}, | |
{'name': 'US Equity-Utilities', 'symbols': ['BUI', 'DPG', 'ERH', 'GLU', 'GUT', 'MFD', 'MGU', 'UTF', 'UTG']} | |
]; | |
const REFRESH_SECONDS = 10; | |
const BATCH_SIZE = 100; | |
const BASE_URL = 'https://api.iextrading.com/1.0/stock/market/batch'; | |
let symbols = []; | |
let containerDiv = document.querySelector('.stocks-container'); | |
let updatedDiv = document.querySelector('.updated-timestamp'); | |
PORTFOLIOS.forEach((p, i) => addPortfolio(p, i === 0)); | |
symbols = symbols.filter((s, i) => symbols.indexOf(s) === i); | |
updateData('addTitle'); | |
setInterval(updateData, REFRESH_SECONDS * 1000); | |
function addPortfolio(portfolio, includeHeader) { | |
let tableHeaderHtml = ''; | |
if (includeHeader) { | |
tableHeaderHtml = ` | |
<thead> | |
<tr> | |
<th></th> | |
<th class="stock-price">Last</th> | |
<th class="stock-change">Change</th> | |
<th class="stock-change-pct">Change%</th> | |
<th class="stock-mkt-cap">Mkt Cap</th> | |
</tr> | |
</thead> | |
` | |
} | |
let tableBodyHtml = portfolio.symbols.map(symbol => { | |
symbol = symbol.toUpperCase(); | |
symbols.push(symbol); | |
let html = ` | |
<tr data-symbol="${symbol}"> | |
<td class="stock-symbol"><a href="${symbolUrl(symbol)}" target="_blank">${symbol}</a></td> | |
<td class="stock-price"></td> | |
<td class="stock-change"></td> | |
<td class="stock-change-pct"></td> | |
<td class="stock-mkt-cap"></td> | |
</tr> | |
` | |
return html; | |
}).join(''); | |
let portfolioDiv = document.createElement('div'); | |
portfolioDiv.innerHTML = ` | |
<details open> | |
<summary><h2>${portfolio.name}</h2></summary> | |
<table>${tableHeaderHtml}<tbody>${tableBodyHtml}</tbody></table> | |
</details> | |
`; | |
containerDiv.appendChild(portfolioDiv); | |
} | |
function updateData(addTitle) { | |
let numberOfBatches = Math.ceil(symbols.length / BATCH_SIZE); | |
for (let i = 0; i < numberOfBatches; i++) { | |
let symbolsBatch = symbols.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE); | |
updateDataForBatch(symbolsBatch, addTitle); | |
} | |
updatedDiv.innerHTML = `Data updated at ${(new Date()).toLocaleString()}`; | |
} | |
function updateDataForBatch(symbols, addTitle) { | |
let filters = ['latestPrice', 'change', 'changePercent', 'marketCap']; | |
if (addTitle) filters.push('companyName'); | |
let url = `${BASE_URL}?types=quote&symbols=${symbols.join(',')}&filter=${filters.join(',')}`; | |
fetch(url).then(response => response.json()).then(json => { | |
symbols.forEach(symbol => { | |
let data = json[symbol]; | |
if (typeof(data) === 'undefined') return; | |
let formattedPrice = formatQuote(data.quote.latestPrice); | |
let formattedChange = data.quote.change.toLocaleString('en', {'minimumFractionDigits': 2}); | |
let formattedChangePercent = (data.quote.changePercent * 100).toFixed(1) + '%'; | |
let formattedMarketCap = formatMarketCap(data.quote.marketCap); | |
let rgbColor = data.quote.changePercent > 0 ? '0,255,0' : '255,0,0'; | |
let rgbOpacity = Math.min(Math.abs(data.quote.changePercent) * 20, 1); | |
document.querySelectorAll(`[data-symbol="${symbol}"] .stock-price`).forEach(e => { | |
e.innerHTML = formattedPrice; | |
e.setAttribute('style', `background-color: rgba(${rgbColor}, ${rgbOpacity})`); | |
}); | |
document.querySelectorAll(`[data-symbol="${symbol}"] .stock-change`).forEach(e => { | |
e.innerHTML = formattedChange; | |
e.setAttribute('style', `background-color: rgba(${rgbColor}, ${rgbOpacity})`); | |
}); | |
document.querySelectorAll(`[data-symbol="${symbol}"] .stock-change-pct`).forEach(e => { | |
e.innerHTML = formattedChangePercent; | |
e.setAttribute('style', `background-color: rgba(${rgbColor}, ${rgbOpacity})`); | |
}); | |
document.querySelectorAll(`[data-symbol="${symbol}"] .stock-mkt-cap`).forEach(e => { | |
e.innerHTML = formattedMarketCap; | |
e.setAttribute('style', `background-color: rgba(${rgbColor}, ${rgbOpacity})`); | |
}); | |
if (addTitle) { | |
document.querySelectorAll(`[data-symbol="${symbol}"] .stock-symbol a`).forEach(e => { | |
e.setAttribute('title', data.quote.companyName); | |
}); | |
} | |
}); | |
}); | |
} | |
function symbolUrl(symbol) { | |
return `https://iextrading.com/apps/stocks/#/${symbol}`; | |
} | |
function formatQuote(value) { | |
let options = { | |
'minimumFractionDigits': 2, | |
'style': 'currency', | |
'currency': 'USD' | |
}; | |
return value.toLocaleString('en', options); | |
} | |
function formatMarketCap(marketCap) { | |
let value, suffix; | |
if (marketCap >= 1e12) { | |
value = marketCap / 1e12; | |
suffix = 'T'; | |
} else if (marketCap >= 1e9) { | |
value = marketCap / 1e9; | |
suffix = 'B'; | |
} else { | |
value = marketCap / 1e6; | |
suffix = 'M'; | |
} | |
let digits = value < 10 ? 1 : 0; | |
return '$' + value.toFixed(digits) + suffix; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment