mirror of
https://github.com/wilsonfreitas/awesome-quant.git
synced 2026-08-07 01:07:44 +00:00
deploy: 5a6f90cc85
This commit is contained in:
@@ -1,639 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="quarto-1.9.36">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<title>Contributor Covenant Code of Conduct – Awesome Quant</title>
|
||||
<style>
|
||||
/* Default styles provided by pandoc.
|
||||
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
|
||||
*/
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||||
div.column{flex: auto; overflow-x: auto;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
ul.task-list li input[type="checkbox"] {
|
||||
width: 0.8em;
|
||||
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script src="site_libs/quarto-nav/quarto-nav.js"></script>
|
||||
<script src="site_libs/quarto-nav/headroom.min.js"></script>
|
||||
<script src="site_libs/clipboard/clipboard.min.js"></script>
|
||||
<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
|
||||
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
||||
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
||||
<meta name="quarto:offset" content="./">
|
||||
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
|
||||
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
|
||||
<script src="site_libs/quarto-html/popper.min.js"></script>
|
||||
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
||||
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-845c23b38eaddc0f92fda52bfe77a8c8.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
||||
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="site_libs/bootstrap/bootstrap-dea667461a5c81afc9ba75ce94cd63f3.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<script id="quarto-search-options" type="application/json">{
|
||||
"location": "navbar",
|
||||
"copy-button": false,
|
||||
"collapse-after": 3,
|
||||
"panel-placement": "end",
|
||||
"type": "overlay",
|
||||
"limit": 50,
|
||||
"keyboard-shortcut": [
|
||||
"f",
|
||||
"/",
|
||||
"s"
|
||||
],
|
||||
"show-item-context": false,
|
||||
"language": {
|
||||
"search-no-results-text": "No results",
|
||||
"search-matching-documents-text": "matching documents",
|
||||
"search-copy-link-title": "Copy link to search",
|
||||
"search-hide-matches-text": "Hide additional matches",
|
||||
"search-more-match-text": "more match in this document",
|
||||
"search-more-matches-text": "more matches in this document",
|
||||
"search-clear-button-title": "Clear",
|
||||
"search-text-placeholder": "",
|
||||
"search-detached-cancel-button-title": "Cancel",
|
||||
"search-submit-button-title": "Submit",
|
||||
"search-label": "Search"
|
||||
}
|
||||
}</script>
|
||||
<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7994446359957143" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
|
||||
<body class="nav-fixed quarto-light">
|
||||
|
||||
<div id="quarto-search-results"></div>
|
||||
<header id="quarto-header" class="headroom fixed-top">
|
||||
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
||||
<div class="navbar-container container-fluid">
|
||||
<div class="navbar-brand-container mx-auto">
|
||||
<a class="navbar-brand" href="./index.html">
|
||||
<span class="navbar-title">Awesome Quant</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav navbar-nav-scroll me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./index.html">
|
||||
<span class="menu-text">Home</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./projects.html">
|
||||
<span class="menu-text">Projects</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="./CODE_OF_CONDUCT.html" aria-current="page">
|
||||
<span class="menu-text">Code of Conduct</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- /navcollapse -->
|
||||
<div class="quarto-navbar-tools">
|
||||
</div>
|
||||
</div> <!-- /container-fluid -->
|
||||
</nav>
|
||||
</header>
|
||||
<!-- content -->
|
||||
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
||||
<!-- sidebar -->
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
|
||||
<nav id="TOC" role="doc-toc" class="toc-active">
|
||||
<h2 id="toc-title">On this page</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#our-pledge" id="toc-our-pledge" class="nav-link active" data-scroll-target="#our-pledge">Our Pledge</a></li>
|
||||
<li><a href="#our-standards" id="toc-our-standards" class="nav-link" data-scroll-target="#our-standards">Our Standards</a></li>
|
||||
<li><a href="#enforcement-responsibilities" id="toc-enforcement-responsibilities" class="nav-link" data-scroll-target="#enforcement-responsibilities">Enforcement Responsibilities</a></li>
|
||||
<li><a href="#scope" id="toc-scope" class="nav-link" data-scroll-target="#scope">Scope</a></li>
|
||||
<li><a href="#enforcement" id="toc-enforcement" class="nav-link" data-scroll-target="#enforcement">Enforcement</a></li>
|
||||
<li><a href="#enforcement-guidelines" id="toc-enforcement-guidelines" class="nav-link" data-scroll-target="#enforcement-guidelines">Enforcement Guidelines</a>
|
||||
<ul class="collapse">
|
||||
<li><a href="#correction" id="toc-correction" class="nav-link" data-scroll-target="#correction">1. Correction</a></li>
|
||||
<li><a href="#warning" id="toc-warning" class="nav-link" data-scroll-target="#warning">2. Warning</a></li>
|
||||
<li><a href="#temporary-ban" id="toc-temporary-ban" class="nav-link" data-scroll-target="#temporary-ban">3. Temporary Ban</a></li>
|
||||
<li><a href="#permanent-ban" id="toc-permanent-ban" class="nav-link" data-scroll-target="#permanent-ban">4. Permanent Ban</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#attribution" id="toc-attribution" class="nav-link" data-scroll-target="#attribution">Attribution</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- main -->
|
||||
<main class="content" id="quarto-document-content">
|
||||
|
||||
<header id="title-block-header" class="quarto-title-block default">
|
||||
<div class="quarto-title">
|
||||
<h1 class="title">Contributor Covenant Code of Conduct</h1>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="quarto-title-meta">
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
<section id="our-pledge" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="our-pledge">Our Pledge</h2>
|
||||
<p>We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.</p>
|
||||
<p>We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.</p>
|
||||
</section>
|
||||
<section id="our-standards" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="our-standards">Our Standards</h2>
|
||||
<p>Examples of behavior that contributes to a positive environment for our community include:</p>
|
||||
<ul>
|
||||
<li>Demonstrating empathy and kindness toward other people</li>
|
||||
<li>Being respectful of differing opinions, viewpoints, and experiences</li>
|
||||
<li>Giving and gracefully accepting constructive feedback</li>
|
||||
<li>Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience</li>
|
||||
<li>Focusing on what is best not just for us as individuals, but for the overall community</li>
|
||||
</ul>
|
||||
<p>Examples of unacceptable behavior include:</p>
|
||||
<ul>
|
||||
<li>The use of sexualized language or imagery, and sexual attention or advances of any kind</li>
|
||||
<li>Trolling, insulting or derogatory comments, and personal or political attacks</li>
|
||||
<li>Public or private harassment</li>
|
||||
<li>Publishing others’ private information, such as a physical or email address, without their explicit permission</li>
|
||||
<li>Other conduct which could reasonably be considered inappropriate in a professional setting</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="enforcement-responsibilities" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="enforcement-responsibilities">Enforcement Responsibilities</h2>
|
||||
<p>Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.</p>
|
||||
<p>Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.</p>
|
||||
</section>
|
||||
<section id="scope" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="scope">Scope</h2>
|
||||
<p>This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.</p>
|
||||
</section>
|
||||
<section id="enforcement" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="enforcement">Enforcement</h2>
|
||||
<p>Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at awesom3quant@gmail.com. All complaints will be reviewed and investigated promptly and fairly.</p>
|
||||
<p>All community leaders are obligated to respect the privacy and security of the reporter of any incident.</p>
|
||||
</section>
|
||||
<section id="enforcement-guidelines" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="enforcement-guidelines">Enforcement Guidelines</h2>
|
||||
<p>Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:</p>
|
||||
<section id="correction" class="level3">
|
||||
<h3 class="anchored" data-anchor-id="correction">1. Correction</h3>
|
||||
<p><strong>Community Impact</strong>: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.</p>
|
||||
<p><strong>Consequence</strong>: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.</p>
|
||||
</section>
|
||||
<section id="warning" class="level3">
|
||||
<h3 class="anchored" data-anchor-id="warning">2. Warning</h3>
|
||||
<p><strong>Community Impact</strong>: A violation through a single incident or series of actions.</p>
|
||||
<p><strong>Consequence</strong>: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.</p>
|
||||
</section>
|
||||
<section id="temporary-ban" class="level3">
|
||||
<h3 class="anchored" data-anchor-id="temporary-ban">3. Temporary Ban</h3>
|
||||
<p><strong>Community Impact</strong>: A serious violation of community standards, including sustained inappropriate behavior.</p>
|
||||
<p><strong>Consequence</strong>: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.</p>
|
||||
</section>
|
||||
<section id="permanent-ban" class="level3">
|
||||
<h3 class="anchored" data-anchor-id="permanent-ban">4. Permanent Ban</h3>
|
||||
<p><strong>Community Impact</strong>: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.</p>
|
||||
<p><strong>Consequence</strong>: A permanent ban from any sort of public interaction within the community.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="attribution" class="level2">
|
||||
<h2 class="anchored" data-anchor-id="attribution">Attribution</h2>
|
||||
<p>This Code of Conduct is adapted from the <a href="https://www.contributor-covenant.org">Contributor Covenant</a>, version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.</p>
|
||||
<p>Community Impact Guidelines were inspired by <a href="https://github.com/mozilla/diversity">Mozilla’s code of conduct enforcement ladder</a>.</p>
|
||||
<p>For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</main> <!-- /main -->
|
||||
<script id="quarto-html-after-body" type="application/javascript">
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const outerScaffold = trigger.parentElement.cloneNode(true);
|
||||
const codeEl = outerScaffold.querySelector('code');
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
}
|
||||
}
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
const html = processXRef(null, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div> <!-- /content -->
|
||||
|
||||
|
||||
|
||||
|
||||
</body></html>
|
||||
-554
@@ -1,554 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="quarto-1.9.36">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<title>About – Awesome Quant</title>
|
||||
<style>
|
||||
/* Default styles provided by pandoc.
|
||||
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
|
||||
*/
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||||
div.column{flex: auto; overflow-x: auto;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
ul.task-list li input[type="checkbox"] {
|
||||
width: 0.8em;
|
||||
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script src="site_libs/quarto-nav/quarto-nav.js"></script>
|
||||
<script src="site_libs/quarto-nav/headroom.min.js"></script>
|
||||
<script src="site_libs/clipboard/clipboard.min.js"></script>
|
||||
<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
|
||||
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
||||
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
||||
<meta name="quarto:offset" content="./">
|
||||
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
|
||||
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
|
||||
<script src="site_libs/quarto-html/popper.min.js"></script>
|
||||
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
||||
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-845c23b38eaddc0f92fda52bfe77a8c8.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
||||
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="site_libs/bootstrap/bootstrap-dea667461a5c81afc9ba75ce94cd63f3.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||
<script id="quarto-search-options" type="application/json">{
|
||||
"location": "navbar",
|
||||
"copy-button": false,
|
||||
"collapse-after": 3,
|
||||
"panel-placement": "end",
|
||||
"type": "overlay",
|
||||
"limit": 50,
|
||||
"keyboard-shortcut": [
|
||||
"f",
|
||||
"/",
|
||||
"s"
|
||||
],
|
||||
"show-item-context": false,
|
||||
"language": {
|
||||
"search-no-results-text": "No results",
|
||||
"search-matching-documents-text": "matching documents",
|
||||
"search-copy-link-title": "Copy link to search",
|
||||
"search-hide-matches-text": "Hide additional matches",
|
||||
"search-more-match-text": "more match in this document",
|
||||
"search-more-matches-text": "more matches in this document",
|
||||
"search-clear-button-title": "Clear",
|
||||
"search-text-placeholder": "",
|
||||
"search-detached-cancel-button-title": "Cancel",
|
||||
"search-submit-button-title": "Submit",
|
||||
"search-label": "Search"
|
||||
}
|
||||
}</script>
|
||||
<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7994446359957143" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
|
||||
<body class="nav-fixed quarto-light">
|
||||
|
||||
<div id="quarto-search-results"></div>
|
||||
<header id="quarto-header" class="headroom fixed-top">
|
||||
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
||||
<div class="navbar-container container-fluid">
|
||||
<div class="navbar-brand-container mx-auto">
|
||||
<a class="navbar-brand" href="./index.html">
|
||||
<span class="navbar-title">Awesome Quant</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="quarto-search" class="" title="Search"></div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav navbar-nav-scroll me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./index.html">
|
||||
<span class="menu-text">Home</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./projects.html">
|
||||
<span class="menu-text">Projects</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./CODE_OF_CONDUCT.html">
|
||||
<span class="menu-text">Code of Conduct</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- /navcollapse -->
|
||||
<div class="quarto-navbar-tools">
|
||||
</div>
|
||||
</div> <!-- /container-fluid -->
|
||||
</nav>
|
||||
</header>
|
||||
<!-- content -->
|
||||
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
||||
<!-- sidebar -->
|
||||
<!-- margin-sidebar -->
|
||||
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar zindex-bottom">
|
||||
|
||||
</div>
|
||||
<!-- main -->
|
||||
<main class="content" id="quarto-document-content">
|
||||
|
||||
<header id="title-block-header" class="quarto-title-block default">
|
||||
<div class="quarto-title">
|
||||
<h1 class="title">About</h1>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="quarto-title-meta">
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
<p>About this site</p>
|
||||
|
||||
|
||||
|
||||
</main> <!-- /main -->
|
||||
<script id="quarto-html-after-body" type="application/javascript">
|
||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||
const icon = "";
|
||||
const anchorJS = new window.AnchorJS();
|
||||
anchorJS.options = {
|
||||
placement: 'right',
|
||||
icon: icon
|
||||
};
|
||||
anchorJS.add('.anchored');
|
||||
const isCodeAnnotation = (el) => {
|
||||
for (const clz of el.classList) {
|
||||
if (clz.startsWith('code-annotation-')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const onCopySuccess = function(e) {
|
||||
// button target
|
||||
const button = e.trigger;
|
||||
// don't keep focus
|
||||
button.blur();
|
||||
// flash "checked"
|
||||
button.classList.add('code-copy-button-checked');
|
||||
var currentTitle = button.getAttribute("title");
|
||||
button.setAttribute("title", "Copied!");
|
||||
let tooltip;
|
||||
if (window.bootstrap) {
|
||||
button.setAttribute("data-bs-toggle", "tooltip");
|
||||
button.setAttribute("data-bs-placement", "left");
|
||||
button.setAttribute("data-bs-title", "Copied!");
|
||||
tooltip = new bootstrap.Tooltip(button,
|
||||
{ trigger: "manual",
|
||||
customClass: "code-copy-button-tooltip",
|
||||
offset: [0, -8]});
|
||||
tooltip.show();
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (tooltip) {
|
||||
tooltip.hide();
|
||||
button.removeAttribute("data-bs-title");
|
||||
button.removeAttribute("data-bs-toggle");
|
||||
button.removeAttribute("data-bs-placement");
|
||||
}
|
||||
button.setAttribute("title", currentTitle);
|
||||
button.classList.remove('code-copy-button-checked');
|
||||
}, 1000);
|
||||
// clear code selection
|
||||
e.clearSelection();
|
||||
}
|
||||
const getTextToCopy = function(trigger) {
|
||||
const outerScaffold = trigger.parentElement.cloneNode(true);
|
||||
const codeEl = outerScaffold.querySelector('code');
|
||||
for (const childEl of codeEl.children) {
|
||||
if (isCodeAnnotation(childEl)) {
|
||||
childEl.remove();
|
||||
}
|
||||
}
|
||||
return codeEl.innerText;
|
||||
}
|
||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||
text: getTextToCopy
|
||||
});
|
||||
clipboard.on('success', onCopySuccess);
|
||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||
text: getTextToCopy,
|
||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||
});
|
||||
clipboardModal.on('success', onCopySuccess);
|
||||
}
|
||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||
var mailtoRegex = new RegExp(/^mailto:/);
|
||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||
var isInternal = (href) => {
|
||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||
}
|
||||
// Inspect non-navigation links and adorn them if external
|
||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||
for (var i=0; i<links.length; i++) {
|
||||
const link = links[i];
|
||||
if (!isInternal(link.href)) {
|
||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||
// links that we want to consider external
|
||||
if (link.dataset.originalHref !== undefined) {
|
||||
link.href = link.dataset.originalHref;
|
||||
}
|
||||
}
|
||||
}
|
||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
maxWidth: 500,
|
||||
delay: 100,
|
||||
arrow: false,
|
||||
appendTo: function(el) {
|
||||
return el.parentElement;
|
||||
},
|
||||
interactive: true,
|
||||
interactiveBorder: 10,
|
||||
theme: 'quarto',
|
||||
placement: 'bottom-start',
|
||||
};
|
||||
if (contentFn) {
|
||||
config.content = contentFn;
|
||||
}
|
||||
if (onTriggerFn) {
|
||||
config.onTrigger = onTriggerFn;
|
||||
}
|
||||
if (onUntriggerFn) {
|
||||
config.onUntrigger = onUntriggerFn;
|
||||
}
|
||||
window.tippy(el, config);
|
||||
}
|
||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||
for (var i=0; i<noterefs.length; i++) {
|
||||
const ref = noterefs[i];
|
||||
tippyHover(ref, function() {
|
||||
// use id or data attribute instead here
|
||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||
try { href = new URL(href).hash; } catch {}
|
||||
const id = href.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note) {
|
||||
return note.innerHTML;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||
const processXRef = (id, note) => {
|
||||
// Strip column container classes
|
||||
const stripColumnClz = (el) => {
|
||||
el.classList.remove("page-full", "page-columns");
|
||||
if (el.children) {
|
||||
for (const child of el.children) {
|
||||
stripColumnClz(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
stripColumnClz(note)
|
||||
if (id === null || id.startsWith('sec-')) {
|
||||
// Special case sections, only their first couple elements
|
||||
const container = document.createElement("div");
|
||||
if (note.children && note.children.length > 2) {
|
||||
container.appendChild(note.children[0].cloneNode(true));
|
||||
for (let i = 1; i < note.children.length; i++) {
|
||||
const child = note.children[i];
|
||||
if (child.tagName === "P" && child.innerText === "") {
|
||||
continue;
|
||||
} else {
|
||||
container.appendChild(child.cloneNode(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(container);
|
||||
}
|
||||
return container.innerHTML
|
||||
} else {
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
return note.innerHTML;
|
||||
}
|
||||
} else {
|
||||
// Remove any anchor links if they are present
|
||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||
if (anchorLink) {
|
||||
anchorLink.remove();
|
||||
}
|
||||
if (window.Quarto?.typesetMath) {
|
||||
window.Quarto.typesetMath(note);
|
||||
}
|
||||
if (note.classList.contains("callout")) {
|
||||
return note.outerHTML;
|
||||
} else {
|
||||
return note.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<xrefs.length; i++) {
|
||||
const xref = xrefs[i];
|
||||
tippyHover(xref, undefined, function(instance) {
|
||||
instance.disable();
|
||||
let url = xref.getAttribute('href');
|
||||
let hash = undefined;
|
||||
if (url.startsWith('#')) {
|
||||
hash = url;
|
||||
} else {
|
||||
try { hash = new URL(url).hash; } catch {}
|
||||
}
|
||||
if (hash) {
|
||||
const id = hash.replace(/^#\/?/, "");
|
||||
const note = window.document.getElementById(id);
|
||||
if (note !== null) {
|
||||
try {
|
||||
const html = processXRef(id, note.cloneNode(true));
|
||||
instance.setContent(html);
|
||||
} finally {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch this
|
||||
fetch(url.split('#')[0])
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.getElementById(id);
|
||||
if (note !== null) {
|
||||
const html = processXRef(id, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// See if we can fetch a full url (with no hash to target)
|
||||
// This is a special case and we should probably do some content thinning / targeting
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||
const note = htmlDoc.querySelector('main.content');
|
||||
if (note !== null) {
|
||||
// This should only happen for chapter cross references
|
||||
// (since there is no id in the URL)
|
||||
// remove the first header
|
||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||
note.children[0].remove();
|
||||
}
|
||||
const html = processXRef(null, note);
|
||||
instance.setContent(html);
|
||||
}
|
||||
}).finally(() => {
|
||||
instance.enable();
|
||||
instance.show();
|
||||
});
|
||||
}
|
||||
}, function(instance) {
|
||||
});
|
||||
}
|
||||
let selectedAnnoteEl;
|
||||
const selectorForAnnotation = ( cell, annotation) => {
|
||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||
return selector;
|
||||
}
|
||||
const selectCodeLines = (annoteEl) => {
|
||||
const doc = window.document;
|
||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||
const lineIds = lines.map((line) => {
|
||||
return targetCell + "-" + line;
|
||||
})
|
||||
let top = null;
|
||||
let height = null;
|
||||
let parent = null;
|
||||
if (lineIds.length > 0) {
|
||||
//compute the position of the single el (top and bottom and make a div)
|
||||
const el = window.document.getElementById(lineIds[0]);
|
||||
top = el.offsetTop;
|
||||
height = el.offsetHeight;
|
||||
parent = el.parentElement.parentElement;
|
||||
if (lineIds.length > 1) {
|
||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||
height = bottom - top;
|
||||
}
|
||||
if (top !== null && height !== null && parent !== null) {
|
||||
// cook up a div (if necessary) and position it
|
||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||
if (div === null) {
|
||||
div = window.document.createElement("div");
|
||||
div.setAttribute("id", "code-annotation-line-highlight");
|
||||
div.style.position = 'absolute';
|
||||
parent.appendChild(div);
|
||||
}
|
||||
div.style.top = top - 2 + "px";
|
||||
div.style.height = height + 4 + "px";
|
||||
div.style.left = 0;
|
||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||
if (gutterDiv === null) {
|
||||
gutterDiv = window.document.createElement("div");
|
||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||
gutterDiv.style.position = 'absolute';
|
||||
const codeCell = window.document.getElementById(targetCell);
|
||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||
gutter.appendChild(gutterDiv);
|
||||
}
|
||||
gutterDiv.style.top = top - 2 + "px";
|
||||
gutterDiv.style.height = height + 4 + "px";
|
||||
}
|
||||
selectedAnnoteEl = annoteEl;
|
||||
}
|
||||
};
|
||||
const unselectCodeLines = () => {
|
||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||
elementsIds.forEach((elId) => {
|
||||
const div = window.document.getElementById(elId);
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
selectedAnnoteEl = undefined;
|
||||
};
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
if (selectedAnnoteEl) {
|
||||
selectCodeLines(selectedAnnoteEl);
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
function throttle(fn, ms) {
|
||||
let throttle = false;
|
||||
let timer;
|
||||
return (...args) => {
|
||||
if(!throttle) { // first call gets through
|
||||
fn.apply(this, args);
|
||||
throttle = true;
|
||||
} else { // all the others get throttled
|
||||
if(timer) clearTimeout(timer); // cancel #2
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
timer = throttle = false;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Attach click handler to the DT
|
||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||
for (const annoteDlNode of annoteDls) {
|
||||
annoteDlNode.addEventListener('click', (event) => {
|
||||
const clickedEl = event.target;
|
||||
if (clickedEl !== selectedAnnoteEl) {
|
||||
unselectCodeLines();
|
||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||
if (activeEl) {
|
||||
activeEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
selectCodeLines(clickedEl);
|
||||
clickedEl.classList.add('code-annotation-active');
|
||||
} else {
|
||||
// Unselect the line
|
||||
unselectCodeLines();
|
||||
clickedEl.classList.remove('code-annotation-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
const findCites = (el) => {
|
||||
const parentEl = el.parentElement;
|
||||
if (parentEl) {
|
||||
const cites = parentEl.dataset.cites;
|
||||
if (cites) {
|
||||
return {
|
||||
el,
|
||||
cites: cites.split(' ')
|
||||
};
|
||||
} else {
|
||||
return findCites(el.parentElement)
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||
for (var i=0; i<bibliorefs.length; i++) {
|
||||
const ref = bibliorefs[i];
|
||||
const citeInfo = findCites(ref);
|
||||
if (citeInfo) {
|
||||
tippyHover(citeInfo.el, function() {
|
||||
var popup = window.document.createElement('div');
|
||||
citeInfo.cites.forEach(function(cite) {
|
||||
var citeDiv = window.document.createElement('div');
|
||||
citeDiv.classList.add('hanging-indent');
|
||||
citeDiv.classList.add('csl-entry');
|
||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||
if (biblioDiv) {
|
||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||
}
|
||||
popup.appendChild(citeDiv);
|
||||
});
|
||||
return popup.innerHTML;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div> <!-- /content -->
|
||||
|
||||
|
||||
|
||||
|
||||
</body></html>
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Parse README.md and generate a static HTML site for awesome-quant.
|
||||
|
||||
Can run in two modes:
|
||||
1. With projects.csv (produced by parse.py) — includes stars, last commit, etc.
|
||||
2. Without CSV — parses README.md directly for a quick local preview.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import html
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def slugify(text: str) -> str:
|
||||
"""Convert text to lowercase hyphen-separated slug."""
|
||||
text = text.lower().strip()
|
||||
text = re.sub(r"[&/]+", "-", text)
|
||||
text = re.sub(r"[^\w\s-]", "", text)
|
||||
text = re.sub(r"[\s_]+", "-", text)
|
||||
text = re.sub(r"-+", "-", text)
|
||||
return text.strip("-")
|
||||
|
||||
|
||||
def parse_readme(path: str) -> list[dict]:
|
||||
"""Parse README.md and return a list of project entries (no API data)."""
|
||||
entries = []
|
||||
current_language = ""
|
||||
current_category = ""
|
||||
|
||||
re_h2 = re.compile(r"^## (.+)$")
|
||||
re_h3 = re.compile(r"^### (.+)$")
|
||||
re_entry = re.compile(r"^\s*- \[(.+?)\]\((.+?)\) - (.+)$")
|
||||
re_github = re.compile(r"\[GitHub\]\((https://github\.com/[\w-]+/[-\w\.]+)\)")
|
||||
|
||||
skip_sections = {"Languages"}
|
||||
|
||||
# Strip markdown badge images before parsing
|
||||
re_badge = re.compile(r"\s*!\[[^\]]*\]\([^)]*\)\s*")
|
||||
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = re_badge.sub(" ", line).rstrip("\n")
|
||||
|
||||
m = re_h2.match(line)
|
||||
if m:
|
||||
current_language = m.group(1).strip()
|
||||
current_category = ""
|
||||
continue
|
||||
|
||||
m = re_h3.match(line)
|
||||
if m:
|
||||
current_category = m.group(1).strip()
|
||||
continue
|
||||
|
||||
if current_language in skip_sections:
|
||||
continue
|
||||
|
||||
m = re_entry.match(line)
|
||||
if m:
|
||||
name = m.group(1).strip()
|
||||
url = m.group(2).strip()
|
||||
desc = m.group(3).strip()
|
||||
|
||||
github_url = ""
|
||||
gh_match = re_github.search(desc)
|
||||
if gh_match:
|
||||
github_url = gh_match.group(1)
|
||||
desc = re_github.sub("", desc).rstrip(". ").rstrip() + "."
|
||||
elif "github.com" in url:
|
||||
github_url = url
|
||||
|
||||
repo = ""
|
||||
if github_url:
|
||||
repo_match = re.match(
|
||||
r"https://github\.com/([\w-]+/[-\w\.]+)", github_url
|
||||
)
|
||||
if repo_match:
|
||||
repo = repo_match.group(1)
|
||||
|
||||
is_cran = "cran.r-project.org" in url
|
||||
is_pypi = "pypi.org" in url or "pypi.python.org" in url
|
||||
is_commercial = current_language == "Commercial & Proprietary Services"
|
||||
category = current_category or current_language
|
||||
section_slug = slugify(category)
|
||||
|
||||
entries.append(
|
||||
{
|
||||
"project": name,
|
||||
"language": current_language,
|
||||
"category": category,
|
||||
"section_slug": section_slug,
|
||||
"url": url,
|
||||
"description": desc,
|
||||
"github": bool(github_url),
|
||||
"cran": is_cran,
|
||||
"pypi": is_pypi,
|
||||
"commercial": is_commercial,
|
||||
"github_url": github_url,
|
||||
"repo": repo,
|
||||
"stars": 0,
|
||||
"last_commit": "",
|
||||
}
|
||||
)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
def load_csv(path: str) -> list[dict]:
|
||||
"""Load projects from CSV produced by parse.py."""
|
||||
entries = []
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
# Normalize booleans
|
||||
for key in ("github", "cran", "pypi", "commercial"):
|
||||
row[key] = row.get(key, "").lower() in ("true", "1", "yes")
|
||||
# Normalize numbers
|
||||
row["stars"] = int(float(row.get("stars", 0) or 0))
|
||||
# Extract github_url and repo from CSV data
|
||||
repo = row.get("repo", "")
|
||||
row["github_url"] = f"https://github.com/{repo}" if repo else ""
|
||||
# Clean description: strip [GitHub](url) if present
|
||||
desc = row.get("description", "")
|
||||
desc = re.sub(
|
||||
r"\s*\[GitHub\]\(https://github\.com/[\w-]+/[-\w\.]+\)\s*",
|
||||
"",
|
||||
desc,
|
||||
)
|
||||
desc = desc.rstrip(". ").rstrip()
|
||||
if desc and not desc.endswith("."):
|
||||
desc += "."
|
||||
row["description"] = desc
|
||||
entries.append(row)
|
||||
return entries
|
||||
|
||||
|
||||
def format_stars(n: int) -> str:
|
||||
"""Format star count for display."""
|
||||
if n >= 1000:
|
||||
return f"{n / 1000:.1f}k".replace(".0k", "k")
|
||||
return str(n) if n > 0 else ""
|
||||
|
||||
|
||||
def build_tags_html(e: dict) -> str:
|
||||
"""Build tag pills for an entry."""
|
||||
esc = html.escape
|
||||
tags = []
|
||||
|
||||
# Language tag
|
||||
lang = e.get("language", "")
|
||||
if lang and lang != "Commercial & Proprietary Services" and lang != "Related Lists":
|
||||
lang_slug = slugify(lang)
|
||||
tags.append(
|
||||
f'<button class="tag tag-lang" data-filter-type="language" '
|
||||
f'data-filter-value="{esc(lang)}">{esc(lang_slug)}</button>'
|
||||
)
|
||||
|
||||
# Section tag
|
||||
section_slug = e.get("section_slug", "")
|
||||
category = e.get("category", "")
|
||||
if section_slug and section_slug != slugify(lang):
|
||||
tags.append(
|
||||
f'<button class="tag tag-section" data-filter-type="category" '
|
||||
f'data-filter-value="{esc(category)}">{esc(section_slug)}</button>'
|
||||
)
|
||||
|
||||
# Source tags
|
||||
if e.get("github"):
|
||||
tags.append(
|
||||
'<button class="tag tag-source tag-github" '
|
||||
'data-filter-type="source" data-filter-value="github">github</button>'
|
||||
)
|
||||
if e.get("cran"):
|
||||
tags.append(
|
||||
'<button class="tag tag-source tag-cran" '
|
||||
'data-filter-type="source" data-filter-value="cran">cran</button>'
|
||||
)
|
||||
if e.get("pypi"):
|
||||
tags.append(
|
||||
'<button class="tag tag-source tag-pypi" '
|
||||
'data-filter-type="source" data-filter-value="pypi">pypi</button>'
|
||||
)
|
||||
if e.get("commercial"):
|
||||
tags.append(
|
||||
'<button class="tag tag-source tag-commercial" '
|
||||
'data-filter-type="source" data-filter-value="commercial">commercial</button>'
|
||||
)
|
||||
|
||||
return "\n ".join(tags)
|
||||
|
||||
|
||||
def generate_html(entries: list[dict]) -> str:
|
||||
"""Generate the full HTML page from project entries."""
|
||||
languages = sorted(
|
||||
set(
|
||||
e["language"]
|
||||
for e in entries
|
||||
if e.get("language") and e["language"] != "Languages"
|
||||
)
|
||||
)
|
||||
|
||||
# Build table rows
|
||||
rows = []
|
||||
for i, e in enumerate(entries, 1):
|
||||
esc = html.escape
|
||||
name = esc(e["project"])
|
||||
url = esc(e["url"])
|
||||
desc = esc(e["description"])
|
||||
language = esc(e.get("language", ""))
|
||||
category = esc(e.get("category", ""))
|
||||
github_url = esc(e.get("github_url", ""))
|
||||
repo = esc(e.get("repo", ""))
|
||||
stars = int(e.get("stars", 0) or 0)
|
||||
last_commit = e.get("last_commit", "") or ""
|
||||
is_github = e.get("github", False)
|
||||
is_cran = e.get("cran", False)
|
||||
is_pypi = e.get("pypi", False)
|
||||
is_commercial = e.get("commercial", False)
|
||||
|
||||
# Stars display
|
||||
stars_html = (
|
||||
f'<span class="stars" title="{stars:,} stars">'
|
||||
f'<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>'
|
||||
f" {format_stars(stars)}</span>"
|
||||
if stars > 0
|
||||
else ""
|
||||
)
|
||||
|
||||
# Last update display
|
||||
last_update_html = (
|
||||
f'<span class="last-update" title="Last commit: {esc(last_commit)}">{esc(last_commit)}</span>'
|
||||
if last_commit and last_commit != "error"
|
||||
else ""
|
||||
)
|
||||
|
||||
# Source flags for data attributes
|
||||
sources = []
|
||||
if is_github:
|
||||
sources.append("github")
|
||||
if is_cran:
|
||||
sources.append("cran")
|
||||
if is_pypi:
|
||||
sources.append("pypi")
|
||||
if is_commercial:
|
||||
sources.append("commercial")
|
||||
sources_attr = esc(" ".join(sources))
|
||||
|
||||
tags_html = build_tags_html(e)
|
||||
|
||||
rows.append(
|
||||
f""" <tr class="row" data-language="{language}" data-category="{category}" data-sources="{sources_attr}" data-stars="{stars}">
|
||||
<td class="col-num">{i}</td>
|
||||
<td class="col-name">
|
||||
<a href="{url}" target="_blank" rel="noopener">{name}</a>
|
||||
<span class="mobile-category">{category}</span>
|
||||
</td>
|
||||
<td class="col-stars">{stars_html}</td>
|
||||
<td class="col-update">{last_update_html}</td>
|
||||
<td class="col-tags">
|
||||
{tags_html}
|
||||
</td>
|
||||
<td class="col-arrow"><span class="arrow">›</span></td>
|
||||
</tr>
|
||||
<tr class="expand-row" hidden>
|
||||
<td colspan="6">
|
||||
<div class="expand-content">
|
||||
<p class="expand-desc">{desc}</p>
|
||||
<div class="expand-links">
|
||||
<a href="{url}" target="_blank" rel="noopener">{url}</a>
|
||||
{f'<a href="{github_url}" target="_blank" rel="noopener">{github_url}</a>' if github_url and github_url != url else ''}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>"""
|
||||
)
|
||||
|
||||
total = len(entries)
|
||||
total_stars = sum(int(e.get("stars", 0) or 0) for e in entries)
|
||||
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Awesome Quant</title>
|
||||
<meta name="description" content="A curated list of insanely awesome libraries, packages and resources for Quants (Quantitative Finance).">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<a href="#content" class="sr-only">Skip to content</a>
|
||||
|
||||
<header class="hero">
|
||||
<div class="hero-inner">
|
||||
<nav class="nav">
|
||||
<span class="nav-brand">awesome-quant</span>
|
||||
<div class="nav-links">
|
||||
<a href="https://github.com/wilsonfreitas/awesome-quant/blob/master/CONTRIBUTING.md" class="nav-submit">Submit a Project</a>
|
||||
<a href="https://github.com/wilsonfreitas/awesome-quant">GitHub</a>
|
||||
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle dark mode">
|
||||
<svg class="icon-sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
||||
<svg class="icon-moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="hero-content">
|
||||
<h1>Awesome Quant</h1>
|
||||
<p class="hero-subtitle">A curated list of insanely awesome libraries, packages and resources for Quants.</p>
|
||||
<p class="hero-maintained">Maintained by <a href="https://github.com/wilsonfreitas">Wilson Freitas</a></p>
|
||||
<div class="hero-stats">
|
||||
<span class="stat"><strong>{total}</strong> projects</span>
|
||||
<span class="stat-sep"></span>
|
||||
<span class="stat"><strong>{len(languages)}</strong> languages</span>
|
||||
<span class="stat-sep"></span>
|
||||
<span class="stat"><strong>{format_stars(total_stars)}</strong> total stars</span>
|
||||
</div>
|
||||
<a href="#content" class="hero-cta">Browse the List</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="content">
|
||||
<section class="list-section">
|
||||
<div class="shell">
|
||||
<div class="controls">
|
||||
<div class="search-wrap">
|
||||
<svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
|
||||
<input type="search" id="search" class="search-input" placeholder="Search projects..." autocomplete="off" aria-label="Search projects">
|
||||
<kbd class="search-kbd">/</kbd>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar" id="filter-bar" style="display:none">
|
||||
<span class="filter-label">Filtered by:</span>
|
||||
<span class="filter-value" id="filter-value"></span>
|
||||
<button class="filter-clear" id="filter-clear">Clear filter</button>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="table" id="project-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-num">#</th>
|
||||
<th class="col-name" data-sort="name">Project <span class="sort-arrow"></span></th>
|
||||
<th class="col-stars" data-sort="stars">Stars <span class="sort-arrow"></span></th>
|
||||
<th class="col-update" data-sort="update">Last Update <span class="sort-arrow"></span></th>
|
||||
<th class="col-tags">Tags</th>
|
||||
<th class="col-arrow"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{chr(10).join(rows)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="no-results" id="no-results" hidden>
|
||||
<p>No projects match your search.</p>
|
||||
</div>
|
||||
|
||||
<div class="results-count" id="results-count"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-section">
|
||||
<div class="shell">
|
||||
<h2>Know a great project?</h2>
|
||||
<p>Contribute to the list by opening a pull request on GitHub.</p>
|
||||
<a href="https://github.com/wilsonfreitas/awesome-quant" class="btn" target="_blank" rel="noopener">Contribute on GitHub</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="shell">
|
||||
<span>Maintained by <a href="https://github.com/wilsonfreitas">Wilson Freitas</a></span>
|
||||
<span class="footer-sep">·</span>
|
||||
<a href="https://github.com/wilsonfreitas/awesome-quant">GitHub</a>
|
||||
<span class="footer-sep">·</span>
|
||||
<a href="https://awesome.re">awesome.re</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="static/main.js"></script>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
def main():
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
readme = root / "README.md"
|
||||
csv_path = root / "site" / "projects.csv"
|
||||
output = root / "site" / "index.html"
|
||||
|
||||
# Prefer CSV if it exists (has stars, last commit from API)
|
||||
if csv_path.exists():
|
||||
print(f"Loading from {csv_path}")
|
||||
entries = load_csv(str(csv_path))
|
||||
elif readme.exists():
|
||||
print(f"Parsing {readme} (no CSV — stars/dates will be empty)")
|
||||
entries = parse_readme(str(readme))
|
||||
else:
|
||||
print(f"ERROR: neither {csv_path} nor {readme} found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Loaded {len(entries)} projects")
|
||||
html_content = generate_html(entries)
|
||||
output.write_text(html_content, encoding="utf-8")
|
||||
print(f"Generated {output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+12764
-1331
File diff suppressed because it is too large
Load Diff
+496
@@ -0,0 +1,496 @@
|
||||
project,language,category,section,section_slug,last_commit,stars,url,description,github,cran,pypi,commercial,repo
|
||||
numpy,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-22,31639,https://www.numpy.org,NumPy is the fundamental package for scientific computing with Python. [GitHub](https://github.com/numpy/numpy),True,False,False,False,numpy/numpy
|
||||
scipy,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-21,14552,https://www.scipy.org,"SciPy (pronounced “Sigh Pie”) is a Python-based ecosystem of open-source software for mathematics, science, and engineering. [GitHub](https://github.com/scipy/scipy)",True,False,False,False,scipy/scipy
|
||||
pandas,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-22,48216,https://pandas.pydata.org,"pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language. [GitHub](https://github.com/pandas-dev/pandas)",True,False,False,False,pandas-dev/pandas
|
||||
polars,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-20,37826,https://docs.pola.rs/,Polars is a blazingly fast DataFrame library for manipulating structured data. [GitHub](https://github.com/pola-rs/polars),True,False,False,False,pola-rs/polars
|
||||
quantdsl,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2017-10-26,377,https://github.com/johnbywater/quantdsl,Domain specific language for quantitative analytics in finance and trading.,True,False,False,False,johnbywater/quantdsl
|
||||
statistics,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,,0,https://docs.python.org/3/library/statistics.html,Builtin Python library for all basic statistical calculations.,False,False,False,False,
|
||||
sympy,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-22,14501,https://www.sympy.org/,SymPy is a Python library for symbolic mathematics. [GitHub](https://github.com/sympy/sympy),True,False,False,False,sympy/sympy
|
||||
pymc3,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-04,9542,https://docs.pymc.io/,Probabilistic Programming in Python: Bayesian Modeling and Probabilistic Machine Learning with Theano. [GitHub](https://github.com/pymc-devs/pymc),True,False,False,False,pymc-devs/pymc
|
||||
modelx,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-02-16,122,https://docs.modelx.io/,Python reimagination of spreadsheets as formula-centric objects that are interoperable with pandas. [GitHub](https://github.com/fumitoh/modelx),True,False,False,False,fumitoh/modelx
|
||||
ArcticDB,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-20,2224,https://github.com/man-group/ArcticDB,High performance datastore for time series and tick data.,True,False,False,False,man-group/ArcticDB
|
||||
pmxt,Python,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-22,1140,https://github.com/pmxt-dev/pmxt,"The CCXT for prediction markets. A unified API for trading on Polymarket, Kalshi, and more.",True,False,False,False,pmxt-dev/pmxt
|
||||
OpenBB Terminal,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-22,63429,https://github.com/OpenBB-finance/OpenBBTerminal,Terminal for investment research for everyone.,True,False,False,False,OpenBB-finance/OpenBBTerminal
|
||||
Fincept Terminal,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-21,2858,https://github.com/Fincept-Corporation/FinceptTerminal,Advance Data Based A.I Terminal for all Types of Financial Asset Research.,True,False,False,False,Fincept-Corporation/FinceptTerminal
|
||||
PyQL,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-08-20,1261,https://github.com/enthought/pyql,QuantLib's Python port.,True,False,False,False,enthought/pyql
|
||||
pyfin,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2014-12-03,316,https://github.com/opendoor-labs/pyfin,Basic options pricing in Python. *ARCHIVED*,True,False,False,False,opendoor-labs/pyfin
|
||||
vollib,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-04-01,929,https://github.com/vollib/vollib,"vollib is a python library for calculating option prices, implied volatility and greeks.",True,False,False,False,vollib/vollib
|
||||
QuantPy,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2017-11-28,973,https://github.com/jsmidt/QuantPy,A framework for quantitative finance In python.,True,False,False,False,jsmidt/QuantPy
|
||||
Finance-Python,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2024-01-01,873,https://github.com/alpha-miner/Finance-Python,Python tools for Finance.,True,False,False,False,alpha-miner/Finance-Python
|
||||
ffn,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-21,2519,https://github.com/pmorissette/ffn,A financial function library for Python.,True,False,False,False,pmorissette/ffn
|
||||
pynance,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2021-02-03,440,https://github.com/GriffinAustin/pynance,Lightweight Python library for assembling and analyzing financial data.,True,False,False,False,GriffinAustin/pynance
|
||||
tia,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2017-06-05,430,https://github.com/bpsmith/tia,Toolkit for integration and analysis.,True,False,False,False,bpsmith/tia
|
||||
pysabr,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2022-04-21,592,https://github.com/ynouri/pysabr,SABR model Python implementation.,True,False,False,False,ynouri/pysabr
|
||||
FinancePy,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-11,2837,https://github.com/domokane/FinancePy,"A Python Finance Library that focuses on the pricing and risk-management of Financial Derivatives, including fixed-income, equity, FX and credit derivatives.",True,False,False,False,domokane/FinancePy
|
||||
gs-quant,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-19,10000,https://github.com/goldmansachs/gs-quant,Python toolkit for quantitative finance,True,False,False,False,goldmansachs/gs-quant
|
||||
willowtree,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2018-07-14,344,https://github.com/federicomariamassari/willowtree,Robust and flexible Python implementation of the willow tree lattice for derivatives pricing.,True,False,False,False,federicomariamassari/willowtree
|
||||
financial-engineering,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2017-11-20,500,https://github.com/federicomariamassari/financial-engineering,"Applications of Monte Carlo methods to financial engineering projects, in Python.",True,False,False,False,federicomariamassari/financial-engineering
|
||||
optlib,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2022-11-18,1347,https://github.com/dbrojas/optlib,A library for financial options pricing written in Python.,True,False,False,False,dbrojas/optlib
|
||||
tf-quant-finance,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-02-12,5266,https://github.com/google/tf-quant-finance,High-performance TensorFlow library for quantitative finance.,True,False,False,False,google/tf-quant-finance
|
||||
Q-Fin,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-04-07,582,https://github.com/RomanMichaelPaolucci/Q-Fin,A Python library for mathematical finance.,True,False,False,False,RomanMichaelPaolucci/Q-Fin
|
||||
Quantsbin,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2021-05-23,612,https://github.com/quantsbin/Quantsbin,"Tools for pricing and plotting of vanilla option prices, greeks and various other analysis around them.",True,False,False,False,quantsbin/Quantsbin
|
||||
finoptions,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2024-02-01,295,https://github.com/bbcho/finoptions-dev,Complete python implementation of R package fOptions with partial implementation of fExoticOptions for pricing various options.,True,False,False,False,bbcho/finoptions-dev
|
||||
pypme,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-01-16,13,https://github.com/ymyke/pypme,PME (Public Market Equivalent) calculation.,True,False,False,False,ymyke/pypme
|
||||
AbsBox,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-17,64,https://github.com/yellowbean/AbsBox,A Python based library to model cashflow for structured product like Asset-backed securities (ABS) and Mortgage-backed securities (MBS).,True,False,False,False,yellowbean/AbsBox
|
||||
Intrinsic-Value-Calculator,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-07-02,83,https://github.com/akashaero/Intrinsic-Value-Calculator,A Python tool for quick calculations of a stock's fair value using Discounted Cash Flow analysis.,True,False,False,False,akashaero/Intrinsic-Value-Calculator
|
||||
Kelly-Criterion,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2019-02-16,110,https://github.com/deltaray-io/kelly-criterion,Kelly Criterion implemented in Python to size portfolios based on J. L. Kelly Jr's formula.,True,False,False,False,deltaray-io/kelly-criterion
|
||||
rateslib,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-02-15,327,https://github.com/attack68/rateslib,"A fixed income library for pricing bonds and bond futures, and derivatives such as IRS, cross-currency and FX swaps.",True,False,False,False,attack68/rateslib
|
||||
fypy,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-02-27,139,https://github.com/jkirkby3/fypy,"Vanilla and exotic option pricing library to support quantitative R&D. Focus on pricing interesting/useful models and contracts (including and beyond Black-Scholes), as well as calibration of financial models to market data.",True,False,False,False,jkirkby3/fypy
|
||||
optionlab,Python,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-12-25,487,https://github.com/rgaveiga/optionlab,A Python library for evaluating option trading strategies.,True,False,False,False,rgaveiga/optionlab
|
||||
pandas_talib,Python,Indicators,Indicators,indicators,2018-05-30,781,https://github.com/femtotrader/pandas_talib,A Python Pandas implementation of technical analysis indicators.,True,False,False,False,femtotrader/pandas_talib
|
||||
finta,Python,Indicators,Indicators,indicators,2022-07-24,2246,https://github.com/peerchemist/finta,Common financial technical analysis indicators implemented in Pandas.,True,False,False,False,peerchemist/finta
|
||||
Tulipy,Python,Indicators,Indicators,indicators,2019-04-11,92,https://github.com/cirla/tulipy,Financial Technical Analysis Indicator Library (Python bindings for [tulipindicators](https://github.com/TulipCharts/tulipindicators)),True,False,False,False,cirla/tulipy
|
||||
lppls,Python,Indicators,Indicators,indicators,2026-02-15,450,https://github.com/Boulder-Investment-Technologies/lppls,A Python module for fitting the [Log-Periodic Power Law Singularity (LPPLS)](https://en.wikipedia.org/wiki/Didier_Sornette#The_JLS_and_LPPLS_models) model.,True,False,False,False,Boulder-Investment-Technologies/lppls
|
||||
talipp,Python,Indicators,Indicators,indicators,2025-09-09,526,https://github.com/nardew/talipp,Incremental technical analysis library for Python.,True,False,False,False,nardew/talipp
|
||||
streaming_indicators,Python,Indicators,Indicators,indicators,2025-04-27,146,https://github.com/mr-easy/streaming_indicators,A python library for computing technical analysis indicators on streaming data.,True,False,False,False,mr-easy/streaming_indicators
|
||||
the0,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,209,https://github.com/alexanderwanyoike/the0,"Self-hosted execution engine for algorithmic trading bots. Write strategies in Python, TypeScript, Rust, C++, C#, Scala, or Haskell and deploy with one command. Each bot runs in an isolated container with scheduled or streaming execution.",True,False,False,False,alexanderwanyoike/the0
|
||||
skfolio,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-14,1906,https://github.com/skfolio/skfolio,"Python library for portfolio optimization built on top of scikit-learn. It provides a unified interface and sklearn compatible tools to build, tune and cross-validate portfolio models.",True,False,False,False,skfolio/skfolio
|
||||
Investing algorithm framework,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-20,702,https://github.com/coding-kitties/investing-algorithm-framework,"Framework for developing, backtesting, and deploying automated trading algorithms.",True,False,False,False,coding-kitties/investing-algorithm-framework
|
||||
QSTrader,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-06-24,3328,https://github.com/mhallsmoore/qstrader,QSTrader backtesting simulation engine.,True,False,False,False,mhallsmoore/qstrader
|
||||
Blankly,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-12-30,2417,https://github.com/Blankly-Finance/Blankly,"Fully integrated backtesting, paper trading, and live deployment.",True,False,False,False,Blankly-Finance/Blankly
|
||||
TA-Lib,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-16,11803,https://github.com/mrjbq7/ta-lib,Python wrapper for TA-Lib (<http://ta-lib.org/>).,True,False,False,False,mrjbq7/ta-lib
|
||||
zipline,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2020-10-14,19533,https://github.com/quantopian/zipline,Pythonic algorithmic trading library.,True,False,False,False,quantopian/zipline
|
||||
zipline-reloaded,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-11-13,1687,https://github.com/stefan-jansen/zipline-reloaded,"Zipline, a Pythonic Algorithmic Trading Library.",True,False,False,False,stefan-jansen/zipline-reloaded
|
||||
QuantSoftware Toolkit,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2016-10-07,476,https://github.com/QuantSoftware/QuantSoftwareToolkit,Python-based open source software framework designed to support portfolio construction and management.,True,False,False,False,QuantSoftware/QuantSoftwareToolkit
|
||||
quantitative,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2019-03-03,66,https://github.com/jeffrey-liang/quantitative,"Quantitative finance, and backtesting library.",True,False,False,False,jeffrey-liang/quantitative
|
||||
analyzer,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2015-12-22,214,https://github.com/llazzaro/analyzer,Python framework for real-time financial and backtesting trading strategies.,True,False,False,False,llazzaro/analyzer
|
||||
bt,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-21,2830,https://github.com/pmorissette/bt,Flexible Backtesting for Python.,True,False,False,False,pmorissette/bt
|
||||
backtrader,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-04-19,20874,https://github.com/backtrader/backtrader,Python Backtesting library for trading strategies.,True,False,False,False,backtrader/backtrader
|
||||
pythalesians,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2016-09-23,63,https://github.com/thalesians/pythalesians,"Python library to backtest trading strategies, plot charts, seamlessly download market data, analyze market patterns etc.",True,False,False,False,thalesians/pythalesians
|
||||
pybacktest,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2019-09-09,817,https://github.com/ematvey/pybacktest,"Vectorized backtesting framework in Python / pandas, designed to make your backtesting easier.",True,False,False,False,ematvey/pybacktest
|
||||
pyalgotrade,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-03-05,4643,https://github.com/gbeced/pyalgotrade,Python Algorithmic Trading Library.,True,False,False,False,gbeced/pyalgotrade
|
||||
basana,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-12-29,820,https://github.com/gbeced/basana,"A Python async and event driven framework for algorithmic trading, with a focus on crypto currencies.",True,False,False,False,gbeced/basana
|
||||
ta,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-18,4915,https://github.com/bukosabino/ta,Technical Analysis Library using Pandas (Python),True,False,False,False,bukosabino/ta
|
||||
algobroker,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2016-03-31,97,https://github.com/joequant/algobroker,This is an execution engine for algo trading.,True,False,False,False,joequant/algobroker
|
||||
finmarketpy,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-03-10,3727,https://github.com/cuemacro/finmarketpy,Python library for backtesting trading strategies and analyzing financial markets.,True,False,False,False,cuemacro/finmarketpy
|
||||
binary-martingale,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2017-10-16,48,https://github.com/metaperl/binary-martingale,Computer program to automatically trade binary options martingale style.,True,False,False,False,metaperl/binary-martingale
|
||||
fooltrader,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2020-07-19,1182,https://github.com/foolcage/fooltrader,the project using big-data technology to provide an uniform way to analyze the whole market.,True,False,False,False,foolcage/fooltrader
|
||||
zvt,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-01,4033,https://github.com/zvtvz/zvt,"the project using sql, pandas to provide an uniform and extendable way to record data, computing factors, select securities, backtesting, realtime trading and it could show all of them in clearly charts in realtime.",True,False,False,False,zvtvz/zvt
|
||||
pylivetrader,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2022-04-11,681,https://github.com/alpacahq/pylivetrader,zipline-compatible live trading library.,True,False,False,False,alpacahq/pylivetrader
|
||||
pipeline-live,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2022-04-11,206,https://github.com/alpacahq/pipeline-live,zipline's pipeline capability with IEX for live trading.,True,False,False,False,alpacahq/pipeline-live
|
||||
zipline-extensions,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2018-09-17,18,https://github.com/quantrocket-llc/zipline-extensions,Zipline extensions and adapters for QuantRocket.,True,False,False,False,quantrocket-llc/zipline-extensions
|
||||
moonshot,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-08-14,256,https://github.com/quantrocket-llc/moonshot,Vectorized backtester and trading engine for QuantRocket based on Pandas.,True,False,False,False,quantrocket-llc/moonshot
|
||||
PyPortfolioOpt,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-10,5570,https://github.com/robertmartin8/PyPortfolioOpt,"Financial portfolio optimization in python, including classical efficient frontier and advanced methods.",True,False,False,False,robertmartin8/PyPortfolioOpt
|
||||
Eiten,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2020-09-21,3165,https://github.com/tradytics/eiten,"Eiten is an open source toolkit by Tradytics that implements various statistical and algorithmic investing strategies such as Eigen Portfolios, Minimum Variance Portfolios, Maximum Sharpe Ratio Portfolios, and Genetic Algorithms based Portfolios.",True,False,False,False,tradytics/eiten
|
||||
riskparity.py,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-05-27,318,https://github.com/dppalomar/riskparity.py,fast and scalable design of risk parity portfolios with TensorFlow 2.0,True,False,False,False,dppalomar/riskparity.py
|
||||
mlfinlab,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2021-12-01,4619,https://github.com/hudson-and-thames/mlfinlab,"Implementations regarding ""Advances in Financial Machine Learning"" by Marcos Lopez de Prado. (Feature Engineering, Financial Data Structures, Meta-Labeling)",True,False,False,False,hudson-and-thames/mlfinlab
|
||||
pyqstrat,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-11-05,371,https://github.com/abbass2/pyqstrat,"A fast, extensible, transparent python library for backtesting quantitative strategies.",True,False,False,False,abbass2/pyqstrat
|
||||
NowTrade,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2017-02-07,101,https://github.com/edouardpoitras/NowTrade,Python library for backtesting technical/mechanical strategies in the stock and currency markets.,True,False,False,False,edouardpoitras/NowTrade
|
||||
pinkfish,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-05-12,293,https://github.com/fja05680/pinkfish,A backtester and spreadsheet library for security analysis.,True,False,False,False,fja05680/pinkfish
|
||||
PRISM-INSIGHT,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-20,505,https://github.com/dragon1086/prism-insight,"AI-powered stock analysis system with 13 specialized agents, automated trading via KIS API, supporting Korean & US markets.",True,False,False,False,dragon1086/prism-insight
|
||||
FinClaw,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,15,https://github.com/NeuZhou/finclaw,"AI-powered financial intelligence engine with 8 master strategies across US, CN, and HK markets. Multi-agent architecture with +29.1% annual alpha. 227 tests.",True,False,False,False,NeuZhou/finclaw
|
||||
aat,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-02,780,https://github.com/timkpaine/aat,Async Algorithmic Trading Engine,True,False,False,False,timkpaine/aat
|
||||
Backtesting.py,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,,0,https://kernc.github.io/backtesting.py/,Backtest trading strategies in Python,False,False,False,False,
|
||||
catalyst,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2021-09-22,2556,https://github.com/enigmampc/catalyst,An Algorithmic Trading Library for Crypto-Assets in Python,True,False,False,False,enigmampc/catalyst
|
||||
quantstats,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-01-13,6871,https://github.com/ranaroussi/quantstats,"Portfolio analytics for quants, written in Python",True,False,False,False,ranaroussi/quantstats
|
||||
qtpylib,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2021-03-24,2256,https://github.com/ranaroussi/qtpylib,"QTPyLib, Pythonic Algorithmic Trading <http://qtpylib.io>",True,False,False,False,ranaroussi/qtpylib
|
||||
Quantdom,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2019-03-12,761,https://github.com/constverum/Quantdom,Python-based framework for backtesting trading strategies & analyzing financial markets [GUI :neckbeard:],True,False,False,False,constverum/Quantdom
|
||||
freqtrade,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,47917,https://github.com/freqtrade/freqtrade,"Free, open source crypto trading bot",True,False,False,False,freqtrade/freqtrade
|
||||
algorithmic-trading-with-python,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2021-06-01,3265,https://github.com/chrisconlan/algorithmic-trading-with-python,"Free `pandas` and `scikit-learn` resources for trading simulation, backtesting, and machine learning on financial data.",True,False,False,False,chrisconlan/algorithmic-trading-with-python
|
||||
DeepDow,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-01-24,1117,https://github.com/jankrepl/deepdow,Portfolio optimization with deep learning,True,False,False,False,jankrepl/deepdow
|
||||
Qlib,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-10,39187,https://github.com/microsoft/qlib,"An AI-oriented Quantitative Investment Platform by Microsoft. Full ML pipeline of data processing, model training, back-testing; and covers the entire chain of quantitative investment: alpha seeking, risk modeling, portfolio optimization, and order execution.",True,False,False,False,microsoft/qlib
|
||||
machine-learning-for-trading,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-03-05,16805,https://github.com/stefan-jansen/machine-learning-for-trading,Code and resources for Machine Learning for Algorithmic Trading,True,False,False,False,stefan-jansen/machine-learning-for-trading
|
||||
AlphaPy,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-08-24,1703,https://github.com/ScottfreeLLC/AlphaPy,"Automated Machine Learning [AutoML] with Python, scikit-learn, Keras, XGBoost, LightGBM, and CatBoost",True,False,False,False,ScottfreeLLC/AlphaPy
|
||||
jesse,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-21,7570,https://github.com/jesse-ai/jesse,An advanced crypto trading bot written in Python,True,False,False,False,jesse-ai/jesse
|
||||
rqalpha,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-11,6245,https://github.com/ricequant/rqalpha,"A extendable, replaceable Python algorithmic backtest && trading framework supporting multiple securities.",True,False,False,False,ricequant/rqalpha
|
||||
FinRL-Library,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-21,14253,https://github.com/AI4Finance-LLC/FinRL-Library,A Deep Reinforcement Learning Library for Automated Trading in Quantitative Finance. NeurIPS 2020.,True,False,False,False,AI4Finance-LLC/FinRL-Library
|
||||
bulbea,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2017-03-19,2264,https://github.com/achillesrasquinha/bulbea,Deep Learning based Python Library for Stock Market Prediction and Modelling.,True,False,False,False,achillesrasquinha/bulbea
|
||||
ib_nope,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2021-04-22,33,https://github.com/ajhpark/ib_nope,Automated trading system for NOPE strategy over IBKR TWS.,True,False,False,False,ajhpark/ib_nope
|
||||
OctoBot,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-17,5499,https://github.com/Drakkar-Software/OctoBot,"Open source cryptocurrency trading bot for high frequency, arbitrage, TA and social trading with an advanced web interface.",True,False,False,False,Drakkar-Software/OctoBot
|
||||
OpenFinClaw,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,120,https://github.com/cryptoSUN2049/openFinclaw,"AI-native hedge fund platform: natural language strategy generation, Rust backtesting engine, multi-market execution, and self-evolving strategy pipeline with community leaderboard.",True,False,False,False,cryptoSUN2049/openFinclaw
|
||||
bta-lib,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2020-03-11,492,https://github.com/mementum/bta-lib,Technical Analysis library in pandas for backtesting algotrading and quantitative analysis.,True,False,False,False,mementum/bta-lib
|
||||
Stock-Prediction-Models,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2021-01-05,9264,https://github.com/huseinzol05/Stock-Prediction-Models,Gathers machine learning and deep learning models for Stock forecasting including trading bots and simulations.,True,False,False,False,huseinzol05/Stock-Prediction-Models
|
||||
TuneTA,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-10-13,457,https://github.com/jmrichardson/tuneta,TuneTA optimizes technical indicators using a distance correlation measure to a user defined target feature such as next day return.,True,False,False,False,jmrichardson/tuneta
|
||||
AutoTrader,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-05-04,1236,https://github.com/kieran-mackle/AutoTrader,A Python-based development platform for automated trading systems - from backtesting to optimization to livetrading.,True,False,False,False,kieran-mackle/AutoTrader
|
||||
fast-trade,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-11,532,https://github.com/jrmeier/fast-trade,A library built with backtest portability and performance in mind for backtest trading strategies.,True,False,False,False,jrmeier/fast-trade
|
||||
qf-lib,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-05,902,https://github.com/quarkfin/qf-lib,QF-Lib is a Python library that provides high quality tools for quantitative finance.,True,False,False,False,quarkfin/qf-lib
|
||||
tda-api,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-06-16,1313,https://github.com/alexgolec/tda-api,"Gather data and trade equities, options, and ETFs via TDAmeritrade.",True,False,False,False,alexgolec/tda-api
|
||||
vectorbt,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-19,6949,https://github.com/polakowo/vectorbt,"Find your trading edge, using a powerful toolkit for backtesting, algorithmic trading, and research.",True,False,False,False,polakowo/vectorbt
|
||||
Lean,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-14,18007,https://github.com/QuantConnect/Lean,"Lean Algorithmic Trading Engine by QuantConnect (Python, C#).",True,False,False,False,QuantConnect/Lean
|
||||
fast-trade,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-11,532,https://github.com/jrmeier/fast-trade,Low code backtesting library utilizing pandas and technical analysis indicators.,True,False,False,False,jrmeier/fast-trade
|
||||
pysystemtrade,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-19,3233,https://github.com/robcarver17/pysystemtrade,"pysystemtrade is the open source version of Robert Carver's backtesting and trading engine that implements systems according to the framework outlined in his book ""Systematic Trading"", which is further developed on his [blog](https://qoppac.blogspot.com/).",True,False,False,False,robcarver17/pysystemtrade
|
||||
pytrendseries,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-21,163,https://github.com/rafa-rod/pytrendseries,"Detect trend in time series, drawdown, drawdown within a constant look-back window , maximum drawdown, time underwater.",True,False,False,False,rafa-rod/pytrendseries
|
||||
PyLOB,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-01-01,199,https://github.com/DrAshBooth/PyLOB,Fully functioning fast Limit Order Book written in Python.,True,False,False,False,DrAshBooth/PyLOB
|
||||
PyBroker,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-05,3240,https://github.com/edtechre/pybroker,Algorithmic Trading with Machine Learning.,True,False,False,False,edtechre/pybroker
|
||||
OctoBot Script,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-04,39,https://github.com/Drakkar-Software/OctoBot-Script,A quant framework to create cryptocurrencies strategies - from backtesting to optimization to livetrading.,True,False,False,False,Drakkar-Software/OctoBot-Script
|
||||
hftbacktest,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-12-23,3838,https://github.com/nkaz001/hftbacktest,"A high-frequency trading and market-making backtesting tool accounts for limit orders, queue positions, and latencies, utilizing full tick data for trades and order books.",True,False,False,False,nkaz001/hftbacktest
|
||||
vnpy,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-01-14,38185,https://github.com/vnpy/vnpy,VeighNa is a Python-based open source quantitative trading system development framework.,True,False,False,False,vnpy/vnpy
|
||||
Intelligent Trading Bot,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-02-28,1642,https://github.com/asavinov/intelligent-trading-bot,Automatically generating signals and trading based on machine learning and feature engineering,True,False,False,False,asavinov/intelligent-trading-bot
|
||||
fastquant,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2023-09-15,1746,https://github.com/enzoampil/fastquant,fastquant allows you to easily backtest investment strategies with as few as 3 lines of python code.,True,False,False,False,enzoampil/fastquant
|
||||
nautilus_trader,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,21357,https://github.com/nautechsystems/nautilus_trader,A high-performance algorithmic trading platform and event-driven backtester.,True,False,False,False,nautechsystems/nautilus_trader
|
||||
YABTE,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2024-05-11,6,https://github.com/bsdz/yabte,Yet Another (Python) BackTesting Engine.,True,False,False,False,bsdz/yabte
|
||||
Trading Strategy,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-21,207,https://github.com/tradingstrategy-ai/getting-started,"TradingStrategy.ai is a market data, backtesting, live trading and investor management framework for decentralised finance",True,False,False,False,tradingstrategy-ai/getting-started
|
||||
Hikyuu,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,3053,https://github.com/fasiondog/hikyuu,"A base on Python/C++ open source high-performance quant framework for faster analysis and backtesting, contains the complete trading system components for reuse and combination.",True,False,False,False,fasiondog/hikyuu
|
||||
rust_bt,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-01-05,58,https://github.com/jensnesten/rust_bt,"A high performance, low-latency backtesting engine for testing quantitative trading strategies on historical and live data in Rust.",True,False,False,False,jensnesten/rust_bt
|
||||
Gunbot Quant,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-08-19,42,https://github.com/GuntharDeNiro/gunbot-quant,"Toolkit for quantitative trading analysis. It integrates an advanced market screener, a multi-strategy, multi-asset backtesting engine. Use with built-in GUI or through CLI.",True,False,False,False,GuntharDeNiro/gunbot-quant
|
||||
StrateQueue,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-12-30,170,https://github.com/StrateQueue/StrateQueue,"An open‑source, broker‑agnostic Python library that lets you seamlessly deploy strategies from any major backtesting engine to live (or paper) trading with zero code changes and built‑in safety controls.",True,False,False,False,StrateQueue/StrateQueue
|
||||
PythonTradingFramework,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-22,27,https://github.com/JustinGuese/python_tradingbot_framework,"Python algorithmic trading bot framework for Kubernetes: backtesting, hyperparameter optimization, 150+ technical analysis indicators (RSI, MACD, Bollinger Bands, ADX), portfolio management, PostgreSQL integration, Helm deployment, CronJob scheduling. Minimal overhead, production-ready, Yahoo Finance data.",True,False,False,False,JustinGuese/python_tradingbot_framework
|
||||
QTradeX-AI-Agents,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-05-25,16,https://github.com/squidKid-deluxe/QTradeX-AI-Agents,Example strategies for the QTradeX platfrom.,True,False,False,False,squidKid-deluxe/QTradeX-AI-Agents
|
||||
QTradeX-Algo-Trading-SDK,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-01-13,60,https://github.com/squidKid-deluxe/QTradeX-Algo-Trading-SDK,"AI-powered SDK featuring algorithmic trading, backtesting, deployment on 100+ exchanges, and multiple optimization engines.",True,False,False,False,squidKid-deluxe/QTradeX-Algo-Trading-SDK
|
||||
antback,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2025-11-12,15,https://github.com/ts-kontakt/antback,"A lightweight, event-loop-style backtest engine that allows a function-driven imperative style using efficient stateful helper functions and data containers.",True,False,False,False,ts-kontakt/antback
|
||||
VARRD,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-09,10,https://github.com/augiemazza/varrd,"AI-powered trading edge discovery platform that validates trading ideas with event studies, statistical tests, and real market data. Web app, MCP server, CLI (`pip install varrd`), and Python SDK.",True,False,False,False,augiemazza/varrd
|
||||
polymarket-whales,Python,Trading & Backtesting,Trading & Backtesting,trading-backtesting,2026-03-20,28,https://github.com/al1enjesus/polymarket-whales,Real-time whale trade tracker for Polymarket — terminal alerts + Telegram notifications when large orders hit the book.,True,False,False,False,al1enjesus/polymarket-whales
|
||||
QuantLibRisks,Python,Risk Analysis,Risk Analysis,risk-analysis,2024-04-04,19,https://github.com/auto-differentiation/QuantLib-Risks-Py,Fast risks with QuantLib,True,False,False,False,auto-differentiation/QuantLib-Risks-Py
|
||||
XAD,Python,Risk Analysis,Risk Analysis,risk-analysis,2024-05-21,19,https://github.com/auto-differentiation/xad-py,Automatic Differentation (AAD) Library,True,False,False,False,auto-differentiation/xad-py
|
||||
pyfolio,Python,Risk Analysis,Risk Analysis,risk-analysis,2020-02-28,6265,https://github.com/quantopian/pyfolio,Portfolio and risk analytics in Python.,True,False,False,False,quantopian/pyfolio
|
||||
empyrical,Python,Risk Analysis,Risk Analysis,risk-analysis,2020-10-14,1474,https://github.com/quantopian/empyrical,Common financial risk and performance metrics.,True,False,False,False,quantopian/empyrical
|
||||
fecon235,Python,Risk Analysis,Risk Analysis,risk-analysis,2018-12-03,1255,https://github.com/rsvp/fecon235,"Computational tools for financial economics include: Gaussian Mixture model of leptokurtotic risk, adaptive Boltzmann portfolios.",True,False,False,False,rsvp/fecon235
|
||||
finance,Python,Risk Analysis,Risk Analysis,risk-analysis,2014-03-24,0,https://pypi.org/project/finance/,Financial Risk Calculations. Optimized for ease of use through class construction and operator overload.,False,False,True,False,
|
||||
qfrm,Python,Risk Analysis,Risk Analysis,risk-analysis,2015-12-12,0,https://pypi.org/project/qfrm/,"Quantitative Financial Risk Management: awesome OOP tools for measuring, managing and visualizing risk of financial instruments and portfolios. (Last updated: 2015-12-12)",False,False,True,False,
|
||||
visualize-wealth,Python,Risk Analysis,Risk Analysis,risk-analysis,2015-06-10,146,https://github.com/benjaminmgross/visualize-wealth,Portfolio construction and quantitative analysis.,True,False,False,False,benjaminmgross/visualize-wealth
|
||||
VisualPortfolio,Python,Risk Analysis,Risk Analysis,risk-analysis,2017-02-28,107,https://github.com/wegamekinglc/VisualPortfolio,This tool is used to visualize the performance of a portfolio.,True,False,False,False,wegamekinglc/VisualPortfolio
|
||||
universal-portfolios,Python,Risk Analysis,Risk Analysis,risk-analysis,2025-09-11,852,https://github.com/Marigold/universal-portfolios,Collection of algorithms for online portfolio selection.,True,False,False,False,Marigold/universal-portfolios
|
||||
FinQuant,Python,Risk Analysis,Risk Analysis,risk-analysis,2023-09-03,1731,https://github.com/fmilthaler/FinQuant,"A program for financial portfolio management, analysis and optimization.",True,False,False,False,fmilthaler/FinQuant
|
||||
Empyrial,Python,Risk Analysis,Risk Analysis,risk-analysis,2025-09-14,1053,https://github.com/ssantoshp/Empyrial,Portfolio's risk and performance analytics and returns predictions.,True,False,False,False,ssantoshp/Empyrial
|
||||
risktools,Python,Risk Analysis,Risk Analysis,risk-analysis,2024-12-07,38,https://github.com/bbcho/risktools-dev,Risk tools for use within the crude and crude products trading space with partial implementation of R's PerformanceAnalytics.,True,False,False,False,bbcho/risktools-dev
|
||||
Riskfolio-Lib,Python,Risk Analysis,Risk Analysis,risk-analysis,2026-03-08,3825,https://github.com/dcajasn/Riskfolio-Lib,Portfolio Optimization and Quantitative Strategic Asset Allocation in Python.,True,False,False,False,dcajasn/Riskfolio-Lib
|
||||
empyrical-reloaded,Python,Risk Analysis,Risk Analysis,risk-analysis,2025-07-29,101,https://github.com/stefan-jansen/empyrical-reloaded,Common financial risk and performance metrics. [empyrical](https://github.com/quantopian/empyrical) fork.,True,False,False,False,stefan-jansen/empyrical-reloaded
|
||||
pyfolio-reloaded,Python,Risk Analysis,Risk Analysis,risk-analysis,2025-06-02,579,https://github.com/stefan-jansen/pyfolio-reloaded,Portfolio and risk analytics in Python. [pyfolio](https://github.com/quantopian/pyfolio) fork.,True,False,False,False,stefan-jansen/pyfolio-reloaded
|
||||
fortitudo.tech,Python,Risk Analysis,Risk Analysis,risk-analysis,2026-02-19,289,https://github.com/fortitudo-tech/fortitudo.tech,Conditional Value-at-Risk (CVaR) portfolio optimization and Entropy Pooling views / stress-testing in Python.,True,False,False,False,fortitudo-tech/fortitudo.tech
|
||||
quantitative-finance-tools,Python,Risk Analysis,Risk Analysis,risk-analysis,2025-12-13,4,https://github.com/omichauhan-lgtm/quantitative-finance-tools,Library for portfolio optimization (MVO) and rigorous risk metrics (VaR/CVaR).,True,False,False,False,omichauhan-lgtm/quantitative-finance-tools
|
||||
curistat,Python,Risk Analysis,Risk Analysis,risk-analysis,,0,https://github.com/moxiespirit/MyClone/tree/main/volatility_platform,"Futures volatility forecasting platform for ES/NQ. Proprietary CVN rating (1-10), regime detection (CRC composite), 8 directional signals, economic event impact analytics. Includes MCP server for AI agent integration.",True,False,False,False,
|
||||
Prop Trader Compass,Python,Risk Analysis,Risk Analysis,risk-analysis,,0,https://otto-ships.github.io/prop-trader-compass/,Interactive risk and payout calculator for Futures and CFD traders; features one-time fee firm comparisons.,False,False,False,False,
|
||||
alphalens,Python,Factor Analysis,Factor Analysis,factor-analysis,2020-04-27,4188,https://github.com/quantopian/alphalens,Performance analysis of predictive alpha factors.,True,False,False,False,quantopian/alphalens
|
||||
alphalens-reloaded,Python,Factor Analysis,Factor Analysis,factor-analysis,2025-06-02,557,https://github.com/stefan-jansen/alphalens-reloaded,Performance analysis of predictive (alpha) stock factors.,True,False,False,False,stefan-jansen/alphalens-reloaded
|
||||
Spectre,Python,Factor Analysis,Factor Analysis,factor-analysis,2025-04-15,784,https://github.com/Heerozh/spectre,GPU-accelerated Factors analysis library and Backtester,True,False,False,False,Heerozh/spectre
|
||||
quant-lab-alpha,Python,Factor Analysis,Factor Analysis,factor-analysis,2026-03-15,27,https://github.com/husainm97/quant-lab-alpha,Open-source investment analytics platform bridging academic research and retail finance.,True,False,False,False,husainm97/quant-lab-alpha
|
||||
Asset News Sentiment Analyzer,Python,Sentiment Analysis,Sentiment Analysis,sentiment-analysis,2024-07-27,193,https://github.com/KVignesh122/AssetNewsSentimentAnalyzer,Sentiment analysis and report generation package for financial assets and securities utilizing GPT models.,True,False,False,False,KVignesh122/AssetNewsSentimentAnalyzer
|
||||
Social Stock Sentiment API,Python,Sentiment Analysis,Sentiment Analysis,sentiment-analysis,,0,https://api.adanos.org/docs,"REST API analyzing Reddit and X/Twitter for stock mentions and sentiment, providing buzz scores, trending stocks, and AI-generated trend explanations.",False,False,False,False,
|
||||
Jupyter Quant,Python,Quant Research Environment,Quant Research Environment,quant-research-environment,2024-06-14,19,https://github.com/gnzsnz/jupyter-quant,"A dockerized Jupyter quant research environment with preloaded tools for quant analysis, statsmodels, pymc, arch, py_vollib, zipline-reloaded, PyPortfolioOpt, etc.",True,False,False,False,gnzsnz/jupyter-quant
|
||||
ARCH,Python,Time Series,Time Series,time-series,2026-03-09,1496,https://github.com/bashtage/arch,ARCH models in Python.,True,False,False,False,bashtage/arch
|
||||
statsmodels,Python,Time Series,Time Series,time-series,2026-03-19,11311,http://statsmodels.sourceforge.net,"Python module that allows users to explore data, estimate statistical models, and perform statistical tests. [GitHub](https://github.com/statsmodels/statsmodels)",True,False,False,False,statsmodels/statsmodels
|
||||
dynts,Python,Time Series,Time Series,time-series,2016-11-02,87,https://github.com/quantmind/dynts,Python package for timeseries analysis and manipulation.,True,False,False,False,quantmind/dynts
|
||||
PyFlux,Python,Time Series,Time Series,time-series,2018-12-16,2141,https://github.com/RJT1990/pyflux,Python library for timeseries modelling and inference (frequentist and Bayesian) on models.,True,False,False,False,RJT1990/pyflux
|
||||
tsfresh,Python,Time Series,Time Series,time-series,2025-11-15,9154,https://github.com/blue-yonder/tsfresh,Automatic extraction of relevant features from time series.,True,False,False,False,blue-yonder/tsfresh
|
||||
Facebook Prophet,Python,Time Series,Time Series,time-series,2026-02-02,20088,https://github.com/facebook/prophet,Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth.,True,False,False,False,facebook/prophet
|
||||
tsmoothie,Python,Time Series,Time Series,time-series,2023-11-23,769,https://github.com/cerlymarco/tsmoothie,A python library for time-series smoothing and outlier detection in a vectorized way.,True,False,False,False,cerlymarco/tsmoothie
|
||||
pmdarima,Python,Time Series,Time Series,time-series,2025-11-17,1717,https://github.com/alkaline-ml/pmdarima,"A statistical library designed to fill the void in Python's time series analysis capabilities, including the equivalent of R's auto.arima function.",True,False,False,False,alkaline-ml/pmdarima
|
||||
gluon-ts,Python,Time Series,Time Series,time-series,2026-03-17,5146,https://github.com/awslabs/gluon-ts,vProbabilistic time series modeling in Python.,True,False,False,False,awslabs/gluon-ts
|
||||
functime,Python,Time Series,Time Series,time-series,2024-06-15,1168,https://github.com/functime-org/functime,Time-series machine learning at scale. Built with Polars for embarrassingly parallel feature extraction and forecasts on panel data.,True,False,False,False,functime-org/functime
|
||||
exchange_calendars,Python,Calendars,Calendars,calendars,2026-01-19,607,https://github.com/gerrymanoim/exchange_calendars,Stock Exchange Trading Calendars.,True,False,False,False,gerrymanoim/exchange_calendars
|
||||
bizdays,Python,Calendars,Calendars,calendars,2026-03-08,89,https://github.com/wilsonfreitas/python-bizdays,Business days calculations and utilities.,True,False,False,False,wilsonfreitas/python-bizdays
|
||||
pandas_market_calendars,Python,Calendars,Calendars,calendars,2026-03-12,958,https://github.com/rsheftel/pandas_market_calendars,Exchange calendars to use with pandas for trading applications.,True,False,False,False,rsheftel/pandas_market_calendars
|
||||
Polymarket Scanner API,Python,Data Sources,Data Sources,data-sources,2026-03-14,1,https://github.com/vesper-astrena/polymarket-scanner-api,"Real-time arbitrage detection API for Polymarket prediction markets, scanning 12,000+ markets for mispricings.",True,False,False,False,vesper-astrena/polymarket-scanner-api
|
||||
yfinance,Python,Data Sources,Data Sources,data-sources,2026-03-19,22269,https://github.com/ranaroussi/yfinance,Yahoo! Finance market data downloader (+faster Pandas Datareader),True,False,False,False,ranaroussi/yfinance
|
||||
defeatbeta-api,Python,Data Sources,Data Sources,data-sources,2026-03-19,520,https://github.com/defeat-beta/defeatbeta-api,An open-source alternative to Yahoo Finance's market data APIs with higher reliability.,True,False,False,False,defeat-beta/defeatbeta-api
|
||||
findatapy,Python,Data Sources,Data Sources,data-sources,2026-03-20,2008,https://github.com/cuemacro/findatapy,"Python library to download market data via Bloomberg, Quandl, Yahoo etc.",True,False,False,False,cuemacro/findatapy
|
||||
googlefinance,Python,Data Sources,Data Sources,data-sources,2018-09-23,818,https://github.com/hongtaocai/googlefinance,Python module to get real-time stock data from Google Finance API.,True,False,False,False,hongtaocai/googlefinance
|
||||
yahoo-finance,Python,Data Sources,Data Sources,data-sources,2021-12-15,1430,https://github.com/lukaszbanasiak/yahoo-finance,Python module to get stock data from Yahoo! Finance.,True,False,False,False,lukaszbanasiak/yahoo-finance
|
||||
pandas-datareader,Python,Data Sources,Data Sources,data-sources,2025-04-03,3169,https://github.com/pydata/pandas-datareader,"Python module to get data from various sources (Google Finance, Yahoo Finance, FRED, OECD, Fama/French, World Bank, Eurostat...) into Pandas datastructures such as DataFrame, Panel with a caching mechanism.",True,False,False,False,pydata/pandas-datareader
|
||||
pandas-finance,Python,Data Sources,Data Sources,data-sources,2025-03-07,160,https://github.com/davidastephens/pandas-finance,High level API for access to and analysis of financial data.,True,False,False,False,davidastephens/pandas-finance
|
||||
pyhoofinance,Python,Data Sources,Data Sources,data-sources,2016-10-07,9,https://github.com/innes213/pyhoofinance,Rapidly queries Yahoo Finance for multiple tickers and returns typed data for analysis.,True,False,False,False,innes213/pyhoofinance
|
||||
yfinanceapi,Python,Data Sources,Data Sources,data-sources,2020-05-26,9,https://github.com/Karthik005/yfinanceapi,Finance API for Python.,True,False,False,False,Karthik005/yfinanceapi
|
||||
yql-finance,Python,Data Sources,Data Sources,data-sources,2015-08-29,16,https://github.com/slawek87/yql-finance,"yql-finance is simple and fast. API returns stock closing prices for current period of time and current stock ticker (i.e. APPL, GOOGL).",True,False,False,False,slawek87/yql-finance
|
||||
ystockquote,Python,Data Sources,Data Sources,data-sources,2017-03-10,537,https://github.com/cgoldberg/ystockquote,Retrieve stock quote data from Yahoo Finance.,True,False,False,False,cgoldberg/ystockquote
|
||||
wallstreet,Python,Data Sources,Data Sources,data-sources,2024-03-09,1625,https://github.com/mcdallas/wallstreet,Real time stock and option data.,True,False,False,False,mcdallas/wallstreet
|
||||
stock_extractor,Python,Data Sources,Data Sources,data-sources,2016-09-10,51,https://github.com/ZachLiuGIS/stock_extractor,General Purpose Stock Extractors from Online Resources.,True,False,False,False,ZachLiuGIS/stock_extractor
|
||||
Stockex,Python,Data Sources,Data Sources,data-sources,2021-09-15,33,https://github.com/cttn/Stockex,Python wrapper for Yahoo! Finance API.,True,False,False,False,cttn/Stockex
|
||||
SwapAPI,Python,Data Sources,Data Sources,data-sources,2026-03-17,0,https://swapapi.dev,Free DEX aggregator API returning executable swap calldata across 46 EVM chains. No API key required. [GitHub](https://github.com/swap-api/swap-api),True,False,False,False,swap-api/swap-api
|
||||
finsymbols,Python,Data Sources,Data Sources,data-sources,2017-07-23,123,https://github.com/skillachie/finsymbols,"Obtains stock symbols and relating information for SP500, AMEX, NYSE, and NASDAQ.",True,False,False,False,skillachie/finsymbols
|
||||
FRB,Python,Data Sources,Data Sources,data-sources,2018-12-22,180,https://github.com/avelkoski/FRB,Python Client for FRED® API.,True,False,False,False,avelkoski/FRB
|
||||
inquisitor,Python,Data Sources,Data Sources,data-sources,2019-10-10,56,https://github.com/econdb/inquisitor,Python Interface to Econdb.com API.,True,False,False,False,econdb/inquisitor
|
||||
yfi,Python,Data Sources,Data Sources,data-sources,2016-02-12,2,https://github.com/nickelkr/yfi,Yahoo! YQL library.,True,False,False,False,nickelkr/yfi
|
||||
chinesestockapi,Python,Data Sources,Data Sources,data-sources,2015-03-21,0,https://pypi.org/project/chinesestockapi/,Python API to get Chinese stock price. (Last updated: 2015-03-21),False,False,True,False,
|
||||
exchange,Python,Data Sources,Data Sources,data-sources,2015-07-07,18,https://github.com/akarat/exchange,Get current exchange rate.,True,False,False,False,akarat/exchange
|
||||
ticks,Python,Data Sources,Data Sources,data-sources,2016-01-08,16,https://github.com/jamescnowell/ticks,Simple command line tool to get stock ticker data.,True,False,False,False,jamescnowell/ticks
|
||||
pybbg,Python,Data Sources,Data Sources,data-sources,2015-01-20,53,https://github.com/bpsmith/pybbg,Python interface to Bloomberg COM APIs.,True,False,False,False,bpsmith/pybbg
|
||||
ccy,Python,Data Sources,Data Sources,data-sources,2025-12-28,95,https://github.com/lsbardel/ccy,Python module for currencies.,True,False,False,False,lsbardel/ccy
|
||||
tushare,Python,Data Sources,Data Sources,data-sources,2024-08-27,0,https://pypi.org/project/tushare/,A utility for crawling historical and Real-time Quotes data of China stocks. (Last updated: 2024-08-27),False,False,True,False,
|
||||
edinet-mcp,Python,Data Sources,Data Sources,data-sources,2026-03-02,4,https://github.com/ajtgjmdjp/edinet-mcp,"Parse Japanese XBRL financial statements from EDINET with 161 normalized labels, 26 financial metrics, and multi-company screening.",True,False,False,False,ajtgjmdjp/edinet-mcp
|
||||
estat-mcp,Python,Data Sources,Data Sources,data-sources,2026-03-02,0,https://github.com/ajtgjmdjp/estat-mcp,"Access Japanese government statistics (e-Stat) covering population, GDP, CPI, labor, and trade data with MCP integration and Polars export.",True,False,False,False,ajtgjmdjp/estat-mcp
|
||||
tdnet-disclosure-mcp,Python,Data Sources,Data Sources,data-sources,2026-03-02,1,https://github.com/ajtgjmdjp/tdnet-disclosure-mcp,"Access Japanese timely disclosures (TDNet) via MCP. Retrieve earnings, dividends, forecasts, buybacks, and other filings for 4,000+ listed companies. No API key required.",True,False,False,False,ajtgjmdjp/tdnet-disclosure-mcp
|
||||
cn_stock_src,Python,Data Sources,Data Sources,data-sources,2016-02-29,34,https://github.com/jealous/cn_stock_src,Utility for retrieving basic China stock data from different sources.,True,False,False,False,jealous/cn_stock_src
|
||||
coinmarketcap,Python,Data Sources,Data Sources,data-sources,2023-05-23,435,https://github.com/barnumbirr/coinmarketcap,Python API for coinmarketcap.,True,False,False,False,barnumbirr/coinmarketcap
|
||||
coinpulse,Python,Data Sources,Data Sources,data-sources,2026-01-09,1,https://github.com/soutone/coinpulse-python,"Python SDK for cryptocurrency portfolio tracking with real-time prices, P/L calculations, and price alerts. Free tier available.",True,False,False,False,soutone/coinpulse-python
|
||||
after-hours,Python,Data Sources,Data Sources,data-sources,2020-06-22,38,https://github.com/datawrestler/after-hours,Obtain pre market and after hours stock prices for a given symbol.,True,False,False,False,datawrestler/after-hours
|
||||
bronto-python,Python,Data Sources,Data Sources,data-sources,2015-02-27,0,https://pypi.org/project/bronto-python/,Bronto API Integration for Python. [GitHub](https://github.com/Scotts-Marketplace/bronto-python),True,False,True,False,Scotts-Marketplace/bronto-python
|
||||
pytdx,Python,Data Sources,Data Sources,data-sources,2020-04-15,1506,https://github.com/rainx/pytdx,Python Interface for retrieving chinese stock realtime quote data from TongDaXin Nodes.,True,False,False,False,rainx/pytdx
|
||||
pdblp,Python,Data Sources,Data Sources,data-sources,2024-12-14,255,https://github.com/matthewgilbert/pdblp,A simple interface to integrate pandas and the Bloomberg Open API.,True,False,False,False,matthewgilbert/pdblp
|
||||
tiingo,Python,Data Sources,Data Sources,data-sources,2025-06-22,303,https://github.com/hydrosquall/tiingo-python,"Python interface for daily composite prices/OHLC/Volume + Real-time News Feeds, powered by the Tiingo Data Platform.",True,False,False,False,hydrosquall/tiingo-python
|
||||
iexfinance,Python,Data Sources,Data Sources,data-sources,2021-01-02,650,https://github.com/addisonlynch/iexfinance,Python Interface for retrieving real-time and historical prices and equities data from The Investor's Exchange.,True,False,False,False,addisonlynch/iexfinance
|
||||
pyEX,Python,Data Sources,Data Sources,data-sources,2024-02-05,409,https://github.com/timkpaine/pyEX,"Python interface to IEX with emphasis on pandas, support for streaming data, premium data, points data (economic, rates, commodities), and technical indicators.",True,False,False,False,timkpaine/pyEX
|
||||
alpaca-trade-api,Python,Data Sources,Data Sources,data-sources,2024-01-12,1861,https://github.com/alpacahq/alpaca-trade-api-python,Python interface for retrieving real-time and historical prices from Alpaca API as well as trade execution.,True,False,False,False,alpacahq/alpaca-trade-api-python
|
||||
metatrader5,Python,Data Sources,Data Sources,data-sources,2026-02-20,0,https://pypi.org/project/MetaTrader5/,API Connector to MetaTrader 5 Terminal. (Last updated: 2026-02-20),False,False,True,False,
|
||||
akshare,Python,Data Sources,Data Sources,data-sources,2026-03-22,17581,https://github.com/jindaxiang/akshare,"AkShare is an elegant and simple financial data interface library for Python, built for human beings! <https://akshare.readthedocs.io>",True,False,False,False,jindaxiang/akshare
|
||||
yahooquery,Python,Data Sources,Data Sources,data-sources,2025-05-15,900,https://github.com/dpguthrie/yahooquery,Python interface for retrieving data through unofficial Yahoo Finance API.,True,False,False,False,dpguthrie/yahooquery
|
||||
investpy,Python,Data Sources,Data Sources,data-sources,2022-10-02,1811,https://github.com/alvarobartt/investpy,Financial Data Extraction from Investing.com with Python! <https://investpy.readthedocs.io/>,True,False,False,False,alvarobartt/investpy
|
||||
yliveticker,Python,Data Sources,Data Sources,data-sources,2021-04-29,163,https://github.com/yahoofinancelive/yliveticker,Live stream of market data from Yahoo Finance websocket.,True,False,False,False,yahoofinancelive/yliveticker
|
||||
bbgbridge,Python,Data Sources,Data Sources,data-sources,2020-01-07,2,https://github.com/ran404/bbgbridge,Easy to use Bloomberg Desktop API wrapper for Python.,True,False,False,False,ran404/bbgbridge
|
||||
polygon.io,Python,Data Sources,Data Sources,data-sources,2026-03-05,1361,https://github.com/polygon-io/client-python,A python library for Polygon.io financial data APIs.,True,False,False,False,polygon-io/client-python
|
||||
alpha_vantage,Python,Data Sources,Data Sources,data-sources,2026-03-03,4743,https://github.com/RomelTorres/alpha_vantage,A python wrapper for Alpha Vantage API for financial data.,True,False,False,False,RomelTorres/alpha_vantage
|
||||
oilpriceapi,Python,Data Sources,Data Sources,data-sources,2026-03-18,0,https://github.com/OilpriceAPI/python-sdk,"Python SDK for real-time oil and commodity prices (WTI, Brent, Urals, natural gas, coal) with OpenBB integration.",True,False,False,False,OilpriceAPI/python-sdk
|
||||
FinanceDataReader,Python,Data Sources,Data Sources,data-sources,2026-03-11,1442,https://github.com/FinanceData/FinanceDataReader,"Open Source Financial data reader for U.S, Korean, Japanese, Chinese, Vietnamese Stocks",True,False,False,False,FinanceData/FinanceDataReader
|
||||
pystlouisfed,Python,Data Sources,Data Sources,data-sources,2024-01-09,21,https://github.com/TomasKoutek/pystlouisfed,"Python client for Federal Reserve Bank of St. Louis API - FRED, ALFRED, GeoFRED and FRASER.",True,False,False,False,TomasKoutek/pystlouisfed
|
||||
python-bcb,Python,Data Sources,Data Sources,data-sources,2026-02-27,109,https://github.com/wilsonfreitas/python-bcb,Python interface to Brazilian Central Bank web services.,True,False,False,False,wilsonfreitas/python-bcb
|
||||
swiss-finance-data,Python,Data Sources,Data Sources,data-sources,2026-03-11,0,https://github.com/EMen11/swiss-finance-data,"Python package for Swiss financial data (SNB Policy Rate, SARON, CHF FX rates, CPI, SMI equities, Confederation bond yields) from official SNB sources.",True,False,False,False,EMen11/swiss-finance-data
|
||||
market-prices,Python,Data Sources,Data Sources,data-sources,2026-02-05,95,https://github.com/maread99/market_prices,Create meaningful OHLCV datasets from knowledge of [exchange-calendars](https://github.com/gerrymanoim/exchange_calendars) (works out-the-box with data from Yahoo Finance).,True,False,False,False,maread99/market_prices
|
||||
tardis-python,Python,Data Sources,Data Sources,data-sources,2026-02-26,140,https://github.com/tardis-dev/tardis-python,Python interface for Tardis.dev high frequency crypto market data,True,False,False,False,tardis-dev/tardis-python
|
||||
lake-api,Python,Data Sources,Data Sources,data-sources,2025-11-02,63,https://github.com/crypto-lake/lake-api,Python interface for Crypto Lake high frequency crypto market data,True,False,False,False,crypto-lake/lake-api
|
||||
tessa,Python,Data Sources,Data Sources,data-sources,2026-01-16,53,https://github.com/ymyke/tessa,"simple, hassle-free access to price information of financial assets (currently based on yfinance and pycoingecko), including search and a symbol class.",True,False,False,False,ymyke/tessa
|
||||
pandaSDMX,Python,Data Sources,Data Sources,data-sources,2023-02-25,133,https://github.com/dr-leo/pandaSDMX,"Python package that implements SDMX 2.1 (ISO 17369:2013), a format for exchange of statistical data and metadata used by national statistical agencies, central banks, and international organisations.",True,False,False,False,dr-leo/pandaSDMX
|
||||
cif,Python,Data Sources,Data Sources,data-sources,2022-06-18,64,https://github.com/LenkaV/CIF,"Python package that include few composite indicators, which summarize multidimensional relationships between individual economic indicators.",True,False,False,False,LenkaV/CIF
|
||||
finagg,Python,Data Sources,Data Sources,data-sources,2026-03-22,525,https://github.com/theOGognf/finagg,"finagg is a Python package that provides implementations of popular and free financial APIs, tools for aggregating historical data from those APIs into SQL databases, and tools for transforming aggregated data into features useful for analysis and AI/ML.",True,False,False,False,theOGognf/finagg
|
||||
FinanceDatabase,Python,Data Sources,Data Sources,data-sources,2026-03-22,7249,https://github.com/JerBouma/FinanceDatabase,"This is a database of 300.000+ symbols containing Equities, ETFs, Funds, Indices, Currencies, Cryptocurrencies and Money Markets.",True,False,False,False,JerBouma/FinanceDatabase
|
||||
Trading Strategy,Python,Data Sources,Data Sources,data-sources,,0,https://github.com/tradingstrategy-ai/trading-strategy/,download price data for decentralised exchanges and lending protocols (DeFi),True,False,False,False,
|
||||
datamule-python,Python,Data Sources,Data Sources,data-sources,2026-03-19,519,https://github.com/john-friedman/datamule-python,A package to work with SEC data. Incorporates datamule endpoints.,True,False,False,False,john-friedman/datamule-python
|
||||
fsynth,Python,Data Sources,Data Sources,data-sources,2025-12-27,4,https://github.com/welcra/fsynth,Python library for high-fidelity unlimited synthetic financial data generation using Heston Stochastic Volatility and Merton Jump Diffusion.,True,False,False,False,welcra/fsynth
|
||||
fedfred,Python,Data Sources,Data Sources,data-sources,,0,https://nikhilxsunder.github.io/fedfred/,"FRED & GeoFRED Economic data API with preprocessed dataframe output in pandas/geopandas, polars/polars_st, and dask dataframes/geodataframes.",False,False,False,False,
|
||||
edgar-sec,Python,Data Sources,Data Sources,data-sources,,0,https://nikhilxsunder.github.io/edgar-sec/,EDGAR Financial data API with preprocessed dataclass outputs.,False,False,False,False,
|
||||
edgartools,Python,Data Sources,Data Sources,data-sources,2026-03-20,1879,https://github.com/dgunning/edgartools,"AI-native SEC EDGAR library with XBRL financials, clean text extraction, 17+ typed forms, and pandas DataFrames.",True,False,False,False,dgunning/edgartools
|
||||
FXMacroData,Python,Data Sources,Data Sources,data-sources,2026-01-17,3,https://fxmacrodata.com/,Real-time forex macroeconomic API for all major currency pairs sourced from central bank announcements. [GitHub](https://github.com/fxmacrodata/fxmacrodata),True,False,False,False,fxmacrodata/fxmacrodata
|
||||
wallstreet,Python,Data Sources,Data Sources,data-sources,2024-03-09,1625,https://github.com/mcdallas/wallstreet,Real time stock and option data.,True,False,False,False,mcdallas/wallstreet
|
||||
xlwings,Python,Excel Integration,Excel Integration,excel-integration,2026-03-22,3325,https://www.xlwings.org/,Make Excel fly with Python. [GitHub](https://github.com/xlwings/xlwings),True,False,False,False,xlwings/xlwings
|
||||
openpyxl,Python,Excel Integration,Excel Integration,excel-integration,,0,https://openpyxl.readthedocs.io/en/latest/,Read/Write Excel 2007 xlsx/xlsm files.,False,False,False,False,
|
||||
xlrd,Python,Excel Integration,Excel Integration,excel-integration,2025-06-14,2203,https://github.com/python-excel/xlrd,Library for developers to extract data from Microsoft Excel spreadsheet files.,True,False,False,False,python-excel/xlrd
|
||||
xlsxwriter,Python,Excel Integration,Excel Integration,excel-integration,2026-03-22,3923,https://xlsxwriter.readthedocs.io/,Write files in the Excel 2007+ XLSX file format. [GitHub](https://github.com/jmcnamara/XlsxWriter),True,False,False,False,jmcnamara/XlsxWriter
|
||||
xlwt,Python,Excel Integration,Excel Integration,excel-integration,2018-09-16,1046,https://github.com/python-excel/xlwt,"Library to create spreadsheet files compatible with MS Excel 97/2000/XP/2003 XLS files, on any platform.",True,False,False,False,python-excel/xlwt
|
||||
xlloop,Python,Excel Integration,Excel Integration,excel-integration,2018-03-10,110,http://xlloop.sourceforge.net,XLLoop is an open source framework for implementing Excel user-defined functions (UDFs) on a centralised server (a function server). [GitHub](https://github.com/poidasmith/xlloop),True,False,False,False,poidasmith/xlloop
|
||||
expy,Python,Excel Integration,Excel Integration,excel-integration,,0,http://www.bnikolic.co.uk/expy/expy.html,"The ExPy add-in allows easy use of Python directly from within an Microsoft Excel spreadsheet, both to execute arbitrary code and to define new Excel functions.",False,False,False,False,
|
||||
pyxll,Python,Excel Integration,Excel Integration,excel-integration,,0,https://www.pyxll.com,PyXLL is an Excel add-in that enables you to extend Excel using nothing but Python code.,False,False,False,False,
|
||||
D-Tale,Python,Visualization,Visualization,visualization,2026-03-03,5078,https://github.com/man-group/dtale,Visualizer for pandas dataframes and xarray datasets.,True,False,False,False,man-group/dtale
|
||||
mplfinance,Python,Visualization,Visualization,visualization,2024-04-02,4323,https://github.com/matplotlib/mplfinance,"matplotlib utilities for the visualization, and visual analysis, of financial data.",True,False,False,False,matplotlib/mplfinance
|
||||
finplot,Python,Visualization,Visualization,visualization,2026-02-27,1128,https://github.com/highfestiva/finplot,Performant and effortless finance plotting for Python.,True,False,False,False,highfestiva/finplot
|
||||
finvizfinance,Python,Visualization,Visualization,visualization,2026-01-03,1273,https://github.com/lit26/finvizfinance,Finviz analysis python library.,True,False,False,False,lit26/finvizfinance
|
||||
market-analy,Python,Visualization,Visualization,visualization,2026-03-05,75,https://github.com/maread99/market_analy,Analysis and interactive charting using [market-prices](https://github.com/maread99/market_prices) and bqplot.,True,False,False,False,maread99/market_analy
|
||||
QuantInvestStrats,Python,Visualization,Visualization,visualization,2026-03-22,521,https://github.com/ArturSepp/QuantInvestStrats,"Quantitative Investment Strategies (QIS) package implements Python analytics for visualisation of financial data, performance reporting, analysis of quantitative strategies.",True,False,False,False,ArturSepp/QuantInvestStrats
|
||||
xts,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-02-27,222,https://github.com/joshuaulrich/xts,"eXtensible Time Series: Provide for uniform handling of R's different time-based data classes by extending zoo, maximizing native format information preservation and allowing for user level customization and extension, while simplifying cross-class interoperability.",True,False,False,False,joshuaulrich/xts
|
||||
data.table,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-03-15,3870,https://github.com/Rdatatable/data.table,"Extension of data.frame: Fast aggregation of large data (e.g. 100GB in RAM), fast ordered joins, fast add/modify/delete of columns by group using no copies at all, list columns and a fast file reader (fread). Offers a natural and flexible syntax, for faster development.",True,False,False,False,Rdatatable/data.table
|
||||
sparseEigen,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2018-12-22,12,https://github.com/dppalomar/sparseEigen,Sparse principal component analysis.,True,False,False,False,dppalomar/sparseEigen
|
||||
TSdbi,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,,0,http://tsdbi.r-forge.r-project.org/,Provides a common interface to time series databases.,False,False,False,False,
|
||||
tseries,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2026-02-18,0,https://cran.r-project.org/web/packages/tseries/index.html,Time Series Analysis and Computational Finance.,False,True,False,False,
|
||||
zoo,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2025-12-15,0,https://cran.r-project.org/web/packages/zoo/index.html,S3 Infrastructure for Regular and Irregular Time Series (Z's Ordered Observations).,False,True,False,False,
|
||||
tis,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2021-09-28,0,https://cran.r-project.org/web/packages/tis/index.html,"Functions and S3 classes for time indexes and time indexed series, which are compatible with FAME frequencies.",False,True,False,False,
|
||||
tfplot,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,,0,https://cran.r-project.org/web/packages/tfplot/index.html,Utilities for simple manipulation and quick plotting of time series data.,False,True,False,False,
|
||||
tframe,R,Numerical Libraries & Data Structures,Numerical Libraries & Data Structures,numerical-libraries-data-structures,2019-05-30,0,https://cran.r-project.org/web/packages/tframe/index.html,A kernel of functions for programming time series methods in a way that is relatively independently of the representation of time.,False,True,False,False,
|
||||
IBrokers,R,Data Sources,Data Sources,data-sources,2022-11-16,0,https://cran.r-project.org/web/packages/IBrokers/index.html,Provides native R access to Interactive Brokers Trader Workstation API.,False,True,False,False,
|
||||
Rblpapi,R,Data Sources,Data Sources,data-sources,2026-01-10,175,https://github.com/Rblp/Rblpapi,An R Interface to 'Bloomberg' is provided via the 'Blp API'.,True,False,False,False,Rblp/Rblpapi
|
||||
Rbitcoin,R,Data Sources,Data Sources,data-sources,2016-10-25,57,https://github.com/jangorecki/Rbitcoin,"Unified markets API interface (bitstamp, kraken, btce, bitmarket).",True,False,False,False,jangorecki/Rbitcoin
|
||||
GetTDData,R,Data Sources,Data Sources,data-sources,2025-05-19,26,https://github.com/msperlin/GetTDData,Downloads and aggregates data for Brazilian government issued bonds directly from the website of Tesouro Direto.,True,False,False,False,msperlin/GetTDData
|
||||
GetHFData,R,Data Sources,Data Sources,data-sources,2020-06-30,41,https://github.com/msperlin/GetHFData,Downloads and aggregates high frequency trading data for Brazilian instruments directly from Bovespa ftp site.,True,False,False,False,msperlin/GetHFData
|
||||
td,R,Data Sources,Data Sources,data-sources,2026-02-12,18,https://github.com/eddelbuettel/td,Interfaces the 'twelvedata' API for stocks and (digital and standard) currencies.,True,False,False,False,eddelbuettel/td
|
||||
rbcb,R,Data Sources,Data Sources,data-sources,2024-01-23,99,https://github.com/wilsonfreitas/rbcb,R interface to Brazilian Central Bank web services.,True,False,False,False,wilsonfreitas/rbcb
|
||||
rb3,R,Data Sources,Data Sources,data-sources,2025-11-01,91,https://github.com/ropensci/rb3,A bunch of downloaders and parsers for data delivered from B3.,True,False,False,False,ropensci/rb3
|
||||
simfinapi,R,Data Sources,Data Sources,data-sources,2025-08-13,21,https://github.com/matthiasgomolka/simfinapi,Makes 'SimFin' data (<https://simfin.com/>) easily accessible in R.,True,False,False,False,matthiasgomolka/simfinapi
|
||||
tidyfinance,R,Data Sources,Data Sources,data-sources,2026-03-16,20,https://github.com/tidy-finance/r-tidyfinance,"Tidy Finance helper functions to download financial data and process the raw data into a structured Format (tidy data), including",True,False,False,False,tidy-finance/r-tidyfinance
|
||||
RQuantLib,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-09,131,https://github.com/eddelbuettel/rquantlib,RQuantLib connects GNU R with QuantLib.,True,False,False,False,eddelbuettel/rquantlib
|
||||
quantmod,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-08-07,884,https://cran.r-project.org/web/packages/quantmod/index.html,Quantitative Financial Modelling Framework. [GitHub](https://github.com/joshuaulrich/quantmod),True,True,False,False,joshuaulrich/quantmod
|
||||
Rmetrics,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://www.rmetrics.org,The premier open source software solution for teaching and training quantitative finance.,False,False,False,False,
|
||||
fAsianOptions,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://cran.r-project.org/web/packages/fAsianOptions/index.html,EBM and Asian Option Valuation.,False,True,False,False,
|
||||
fAssets,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-04-24,0,https://cran.r-project.org/web/packages/fAssets/index.html,Analysing and Modelling Financial Assets.,False,True,False,False,
|
||||
fBasics,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-12-07,0,https://cran.r-project.org/web/packages/fBasics/index.html,Markets and Basic Statistics.,False,True,False,False,
|
||||
fBonds,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2017-11-15,0,https://cran.r-project.org/web/packages/fBonds/index.html,Bonds and Interest Rate Models.,False,True,False,False,
|
||||
fExoticOptions,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://cran.r-project.org/web/packages/fExoticOptions/index.html,Exotic Option Valuation.,False,True,False,False,
|
||||
fOptions,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://cran.r-project.org/web/packages/fOptions/index.html,Pricing and Evaluating Basic Options.,False,True,False,False,
|
||||
fPortfolio,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-04-25,0,https://cran.r-project.org/web/packages/fPortfolio/index.html,Portfolio Selection and Optimization.,False,True,False,False,
|
||||
portfolio,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2024-08-19,17,https://github.com/dgerlanc/portfolio,Analysing equity portfolios.,True,False,False,False,dgerlanc/portfolio
|
||||
sparseIndexTracking,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-05-28,59,https://github.com/dppalomar/sparseIndexTracking,Portfolio design to track an index.,True,False,False,False,dppalomar/sparseIndexTracking
|
||||
covFactorModel,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2019-03-25,38,https://github.com/dppalomar/covFactorModel,Covariance matrix estimation via factor models.,True,False,False,False,dppalomar/covFactorModel
|
||||
riskParityPortfolio,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2022-11-15,121,https://github.com/dppalomar/riskParityPortfolio,Blazingly fast design of risk parity portfolios.,True,False,False,False,dppalomar/riskParityPortfolio
|
||||
sde,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-12-22,0,https://cran.r-project.org/web/packages/sde/index.html,Simulation and Inference for Stochastic Differential Equations.,False,True,False,False,
|
||||
YieldCurve,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2022-10-02,0,https://cran.r-project.org/web/packages/YieldCurve/index.html,Modelling and estimation of the yield curve.,False,True,False,False,
|
||||
SmithWilsonYieldCurve,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2024-07-12,0,https://cran.r-project.org/web/packages/SmithWilsonYieldCurve/index.html,Constructs a yield curve by the Smith-Wilson method from a table of LIBOR and SWAP rates.,False,True,False,False,
|
||||
ycinterextra,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://cran.r-project.org/web/packages/ycinterextra/index.html,Yield curve or zero-coupon prices interpolation and extrapolation.,False,True,False,False,
|
||||
AmericanCallOpt,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://cran.r-project.org/web/packages/AmericanCallOpt/index.html,This package includes pricing function for selected American call options with underlying assets that generate payouts.,False,True,False,False,
|
||||
VarSwapPrice,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,,0,https://cran.r-project.org/web/packages/VarSwapPrice/index.html,Pricing a variance swap on an equity index.,False,True,False,False,
|
||||
RND,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2017-01-11,0,https://cran.r-project.org/web/packages/RND/index.html,Risk Neutral Density Extraction Package.,False,True,False,False,
|
||||
LSMonteCarlo,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2013-09-23,0,https://cran.r-project.org/web/packages/LSMonteCarlo/index.html,American options pricing with Least Squares Monte Carlo method.,False,True,False,False,
|
||||
OptHedging,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2013-10-11,0,https://cran.r-project.org/web/packages/OptHedging/index.html,Estimation of value and hedging strategy of call and put options.,False,True,False,False,
|
||||
tvm,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-08-30,0,https://cran.r-project.org/web/packages/tvm/index.html,Time Value of Money Functions.,False,True,False,False,
|
||||
OptionPricing,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2023-09-16,0,https://cran.r-project.org/web/packages/OptionPricing/index.html,Option Pricing with Efficient Simulation Algorithms.,False,True,False,False,
|
||||
credule,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2015-08-05,7,https://github.com/blenezet/credule,Credit Default Swap Functions.,True,False,False,False,blenezet/credule
|
||||
derivmkts,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-02-12,35,https://cran.r-project.org/web/packages/derivmkts/index.html,Functions and R Code to Accompany Derivatives Markets. [GitHub](https://github.com/rmcd1024/derivmkts),True,True,False,False,rmcd1024/derivmkts
|
||||
FinCal,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-10-30,24,https://github.com/felixfan/FinCal,"Package for time value of money calculation, time series analysis and computational finance.",True,False,False,False,felixfan/FinCal
|
||||
r-quant,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2014-02-19,34,https://github.com/artyyouth/r-quant,R code for quantitative analysis in finance.,True,False,False,False,artyyouth/r-quant
|
||||
options.studies,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2015-12-17,6,https://github.com/taylorizing/options.studies,options trading studies functions for use with options.data package and shiny.,True,False,False,False,taylorizing/options.studies
|
||||
PortfolioAnalytics,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2026-03-19,98,https://github.com/braverock/PortfolioAnalytics,"Portfolio Analysis, Including Numerical Methods for Optimizationof Portfolios.",True,False,False,False,braverock/PortfolioAnalytics
|
||||
fmbasics,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2019-12-03,12,https://github.com/imanuelcostigan/fmbasics,Financial Market Building Blocks.,True,False,False,False,imanuelcostigan/fmbasics
|
||||
R-fixedincome,R,Financial Instruments and Pricing,Financial Instruments and Pricing,financial-instruments-and-pricing,2025-05-10,64,https://github.com/wilsonfreitas/R-fixedincome,Fixed income tools for R.,True,False,False,False,wilsonfreitas/R-fixedincome
|
||||
backtest,R,Trading,Trading,trading,2015-09-17,0,https://cran.r-project.org/web/packages/backtest/index.html,Exploring Portfolio-Based Conjectures About Financial Instruments.,False,True,False,False,
|
||||
pa,R,Trading,Trading,trading,2023-08-21,0,https://cran.r-project.org/web/packages/pa/index.html,Performance Attribution for Equity Portfolios.,False,True,False,False,
|
||||
TTR,R,Trading,Trading,trading,2026-02-28,342,https://github.com/joshuaulrich/TTR,Technical Trading Rules.,True,False,False,False,joshuaulrich/TTR
|
||||
QuantTools,R,Trading,Trading,trading,,0,https://quanttools.bitbucket.io/_site/index.html,Enhanced Quantitative Trading Modelling.,False,False,False,False,
|
||||
blotter,R,Trading,Trading,trading,2024-12-13,118,https://github.com/braverock/blotter,"Transaction infrastructure for defining instruments, transactions, portfolios and accounts for trading systems and simulation. Provides portfolio support for multi-asset class and multi-currency portfolios. Actively maintained and developed.",True,False,False,False,braverock/blotter
|
||||
quantstrat,R,Backtesting,Backtesting,backtesting,2023-09-14,301,https://github.com/braverock/quantstrat,Transaction-oriented infrastructure for constructing trading systems and simulation. Provides support for multi-asset class and multi-currency portfolios for backtesting and other financial research.,True,False,False,False,braverock/quantstrat
|
||||
PerformanceAnalytics,R,Risk Analysis,Risk Analysis,risk-analysis,2026-03-05,235,https://github.com/braverock/PerformanceAnalytics,Econometric tools for performance and risk analysis.,True,False,False,False,braverock/PerformanceAnalytics
|
||||
FactorAnalytics,R,Factor Analysis,Factor Analysis,factor-analysis,2024-12-12,85,https://github.com/braverock/FactorAnalytics,"The FactorAnalytics package contains fitting and analysis methods for the three main types of factor models used in conjunction with portfolio construction, optimization and risk management, namely fundamental factor models, time series factor models and statistical factor models.",True,False,False,False,braverock/FactorAnalytics
|
||||
Expected Returns,R,Factor Analysis,Factor Analysis,factor-analysis,2025-08-12,56,https://github.com/JustinMShea/ExpectedReturns,"Solutions for enhancing portfolio diversification and replications of seminal papers with R, most of which are discussed in one of the best investment references of the recent decade, Expected Returns: An Investors Guide to Harvesting Market Rewards by Antti Ilmanen.",True,False,False,False,JustinMShea/ExpectedReturns
|
||||
tseries,R,Time Series,Time Series,time-series,2026-02-18,0,https://cran.r-project.org/web/packages/tseries/index.html,Time Series Analysis and Computational Finance.,False,True,False,False,
|
||||
fGarch,R,Time Series,Time Series,time-series,2025-12-12,0,https://cran.r-project.org/web/packages/fGarch/index.html,Rmetrics - Autoregressive Conditional Heteroskedastic Modelling.,False,True,False,False,
|
||||
timeSeries,R,Time Series,Time Series,time-series,2025-12-12,0,https://cran.r-project.org/web/packages/timeSeries/index.html,Rmetrics - Financial Time Series Objects.,False,True,False,False,
|
||||
rugarch,R,Time Series,Time Series,time-series,2026-03-13,31,https://github.com/alexiosg/rugarch,Univariate GARCH Models.,True,False,False,False,alexiosg/rugarch
|
||||
rmgarch,R,Time Series,Time Series,time-series,2025-08-31,17,https://github.com/alexiosg/rmgarch,Multivariate GARCH Models.,True,False,False,False,alexiosg/rmgarch
|
||||
tidypredict,R,Time Series,Time Series,time-series,2021-09-28,3,https://github.com/edgararuiz/tidypredict,Run predictions inside the database <https://tidypredict.netlify.com/>.,True,False,False,False,edgararuiz/tidypredict
|
||||
tidyquant,R,Time Series,Time Series,time-series,2026-03-16,900,https://github.com/business-science/tidyquant,Bringing financial analysis to the tidyverse.,True,False,False,False,business-science/tidyquant
|
||||
timetk,R,Time Series,Time Series,time-series,2025-08-29,639,https://github.com/business-science/timetk,A toolkit for working with time series in R.,True,False,False,False,business-science/timetk
|
||||
tibbletime,R,Time Series,Time Series,time-series,2024-12-03,177,https://github.com/business-science/tibbletime,"Built on top of the tidyverse, tibbletime is an extension that allows for the creation of time aware tibbles through the setting of a time index.",True,False,False,False,business-science/tibbletime
|
||||
matrixprofile,R,Time Series,Time Series,time-series,2022-11-25,387,https://github.com/matrix-profile-foundation/matrixprofile,Time series data mining library built on top of the novel Matrix Profile data structure and algorithms.,True,False,False,False,matrix-profile-foundation/matrixprofile
|
||||
garchmodels,R,Time Series,Time Series,time-series,2022-08-11,35,https://github.com/AlbertoAlmuinha/garchmodels,A parsnip backend for GARCH models.,True,False,False,False,AlbertoAlmuinha/garchmodels
|
||||
timeDate,R,Calendars,Calendars,calendars,2026-01-28,0,https://cran.r-project.org/web/packages/timeDate/index.html,Chronological and Calendar Objects,False,True,False,False,
|
||||
bizdays,R,Calendars,Calendars,calendars,2025-01-08,57,https://github.com/wilsonfreitas/R-bizdays,Business days calculations and utilities,True,False,False,False,wilsonfreitas/R-bizdays
|
||||
RunMat,Matlab,Alternatives,Alternatives,alternatives,2026-03-20,194,https://runmat.org,"High performance, Open Source, MATLAB syntax runtime. [GitHub](https://github.com/runmat-org/runmat)",True,False,False,False,runmat-org/runmat
|
||||
QUANTAXIS,Matlab,FrameWorks,FrameWorks,frameworks,2026-02-28,10134,https://github.com/yutiansut/quantaxis,Integrated Quantitative Toolbox with Matlab.,True,False,False,False,yutiansut/quantaxis
|
||||
PROJ_Option_Pricing_Matlab,Matlab,FrameWorks,FrameWorks,frameworks,2024-11-19,208,https://github.com/jkirkby3/PROJ_Option_Pricing_Matlab,"Quant Option Pricing - Exotic/Vanilla: Barrier, Asian, European, American, Parisian, Lookback, Cliquet, Variance Swap, Swing, Forward Starting, Step, Fader",True,False,False,False,jkirkby3/PROJ_Option_Pricing_Matlab
|
||||
CcyConv.jl,Julia,,,julia,2025-10-14,25,https://github.com/bhftbootcamp/CcyConv.jl,Currency conversion library for Julia,True,False,False,False,bhftbootcamp/CcyConv.jl
|
||||
CryptoExchangeAPIs.jl,Julia,,,julia,2025-11-27,30,https://github.com/bhftbootcamp/CryptoExchangeAPIs.jl,A Julia library for cryptocurrency exchange APIs,True,False,False,False,bhftbootcamp/CryptoExchangeAPIs.jl
|
||||
Fastback.jl,Julia,,,julia,2026-03-01,19,https://github.com/rbeeli/Fastback.jl,Blazing fast Julia backtester.,True,False,False,False,rbeeli/Fastback.jl
|
||||
Lucky.jl,Julia,,,julia,2026-03-09,26,https://github.com/oliviermilla/Lucky.jl,"Modular, asynchronous trading engine in pure Julia.",True,False,False,False,oliviermilla/Lucky.jl
|
||||
QuantLib.jl,Julia,,,julia,2020-02-18,143,https://github.com/pazzo83/QuantLib.jl,Quantlib implementation in pure Julia.,True,False,False,False,pazzo83/QuantLib.jl
|
||||
Ito.jl,Julia,,,julia,2017-03-21,39,https://github.com/aviks/Ito.jl,A Julia package for quantitative finance.,True,False,False,False,aviks/Ito.jl
|
||||
LightweightCharts.jl,Julia,,,julia,2026-01-20,48,https://github.com/bhftbootcamp/LightweightCharts.jl,Julia wrapper for Lightweight Charts™ by TradingView.,True,False,False,False,bhftbootcamp/LightweightCharts.jl
|
||||
TALib.jl,Julia,,,julia,2017-08-22,52,https://github.com/femtotrader/TALib.jl,A Julia wrapper for TA-Lib.,True,False,False,False,femtotrader/TALib.jl
|
||||
Miletus.jl,Julia,,,julia,2023-12-07,90,https://github.com/JuliaComputing/Miletus.jl,"A financial contract definition, modeling language, and valuation framework.",True,False,False,False,JuliaComputing/Miletus.jl
|
||||
Temporal.jl,Julia,,,julia,2021-12-28,101,https://github.com/dysonance/Temporal.jl,Flexible and efficient time series class & methods.,True,False,False,False,dysonance/Temporal.jl
|
||||
Indicators.jl,Julia,,,julia,2022-12-06,227,https://github.com/dysonance/Indicators.jl,Financial market technical analysis & indicators on top of Temporal.,True,False,False,False,dysonance/Indicators.jl
|
||||
Strategems.jl,Julia,,,julia,2021-04-06,167,https://github.com/dysonance/Strategems.jl,Quantitative systematic trading strategy development and backtesting.,True,False,False,False,dysonance/Strategems.jl
|
||||
TimeSeries.jl,Julia,,,julia,2026-01-26,368,https://github.com/JuliaStats/TimeSeries.jl,Time series toolkit for Julia.,True,False,False,False,JuliaStats/TimeSeries.jl
|
||||
TechnicalIndicatorCharts.jl,Julia,,,julia,2026-03-09,6,https://github.com/g-gundam/TechnicalIndicatorCharts.jl,Visualize OnlineTechnicalIndicators.jl using LightweightCharts.jl.,True,False,False,False,g-gundam/TechnicalIndicatorCharts.jl
|
||||
MarketTechnicals.jl,Julia,,,julia,2021-07-12,130,https://github.com/JuliaQuant/MarketTechnicals.jl,Technical analysis of financial time series on top of TimeSeries.,True,False,False,False,JuliaQuant/MarketTechnicals.jl
|
||||
MarketData.jl,Julia,,,julia,2025-11-10,163,https://github.com/JuliaQuant/MarketData.jl,Time series market data.,True,False,False,False,JuliaQuant/MarketData.jl
|
||||
OnlineTechnicalIndicators.jl,Julia,,,julia,2026-01-06,33,https://github.com/femtotrader/OnlineTechnicalIndicators.jl,Julia Technical Analysis Indicators via online algorithms.,True,False,False,False,femtotrader/OnlineTechnicalIndicators.jl
|
||||
OnlinePortfolioAnalytics.jl,Julia,,,julia,2026-01-06,13,https://github.com/femtotrader/OnlinePortfolioAnalytics.jl,A Julia quantitative portfolio analytics (risk / performance) via online algorithms.,True,False,False,False,femtotrader/OnlinePortfolioAnalytics.jl
|
||||
OnlineResamplers.jl,Julia,,,julia,2026-01-06,2,https://github.com/femtotrader/OnlineResamplers.jl,High-performance Julia package for real-time resampling of financial market data.,True,False,False,False,femtotrader/OnlineResamplers.jl
|
||||
RiskPerf.jl,Julia,,,julia,2026-02-02,15,https://github.com/rbeeli/RiskPerf.jl,Quantitative risk and performance analysis package for financial time series powered by the Julia language.,True,False,False,False,rbeeli/RiskPerf.jl
|
||||
TimeFrames.jl,Julia,,,julia,2026-03-09,4,https://github.com/femtotrader/TimeFrames.jl,A Julia library that defines TimeFrame (essentially for resampling TimeSeries).,True,False,False,False,femtotrader/TimeFrames.jl
|
||||
DataFrames.jl,Julia,,,julia,2026-03-17,1819,https://github.com/JuliaData/DataFrames.jl,In-memory tabular data in Julia,True,False,False,False,JuliaData/DataFrames.jl
|
||||
TSFrames.jl,Julia,,,julia,2024-06-18,100,https://github.com/xKDR/TSFrames.jl,Handle timeseries data on top of the powerful and mature DataFrames.jl,True,False,False,False,xKDR/TSFrames.jl
|
||||
TimeArrays.jl,Julia,,,julia,2025-10-15,38,https://github.com/bhftbootcamp/TimeArrays.jl,Time series handling for Julia,True,False,False,False,bhftbootcamp/TimeArrays.jl
|
||||
Strata,Java,,,java,2026-03-11,929,http://strata.opengamma.io/,Modern open-source analytics and market risk library designed and written in Java. [GitHub](https://github.com/OpenGamma/Strata),True,False,False,False,OpenGamma/Strata
|
||||
JQuantLib,Java,,,java,2016-02-26,152,https://github.com/frgomes/jquantlib,"JQuantLib is a free, open-source, comprehensive framework for quantitative finance, written in 100% Java.",True,False,False,False,frgomes/jquantlib
|
||||
finmath.net,Java,,,java,2026-02-20,558,http://finmath.net,Java library with algorithms and methodologies related to mathematical finance. [GitHub](https://github.com/finmath/finmath-lib),True,False,False,False,finmath/finmath-lib
|
||||
quantcomponents,Java,,,java,2015-10-07,169,https://github.com/lsgro/quantcomponents,Free Java components for Quantitative Finance and Algorithmic Trading.,True,False,False,False,lsgro/quantcomponents
|
||||
DRIP,Java,,,java,,0,https://lakshmidrip.github.io/DRIP,"Fixed Income, Asset Allocation, Transaction Cost Analysis, XVA Metrics Libraries.",False,False,False,False,
|
||||
ta4j,Java,,,java,2026-03-15,2395,https://github.com/ta4j/ta4j,A Java library for technical analysis.,True,False,False,False,ta4j/ta4j
|
||||
finance.js,JavaScript,,,javascript,2018-10-11,1266,https://github.com/ebradyjobory/finance.js,A JavaScript library for common financial calculations.,True,False,False,False,ebradyjobory/finance.js
|
||||
portfolio-allocation,JavaScript,,,javascript,2022-08-11,187,https://github.com/lequant40/portfolio_allocation_js,"PortfolioAllocation is a JavaScript library designed to help constructing financial portfolios made of several assets: bonds, commodities, cryptocurrencies, currencies, exchange traded funds (ETFs), mutual funds, stocks...",True,False,False,False,lequant40/portfolio_allocation_js
|
||||
Ghostfolio,JavaScript,,,javascript,2026-03-22,7980,https://github.com/ghostfolio/ghostfolio,"Wealth management software to keep track of financial assets like stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions.",True,False,False,False,ghostfolio/ghostfolio
|
||||
IndicatorTS,JavaScript,,,javascript,2025-02-26,429,https://github.com/cinar/indicatorts,"Indicator is a TypeScript module providing various stock technical analysis indicators, strategies, and a backtest framework for trading.",True,False,False,False,cinar/indicatorts
|
||||
chart-patterns,JavaScript,,,javascript,error,0,https://github.com/focus1691/chart-patterns,"Technical analysis library for Market Profile, Volume Profile, Stacked Imbalances and High Volume Node indicators.",True,False,False,False,focus1691/chart-patterns
|
||||
orderflow,JavaScript,,,javascript,2025-03-31,65,https://github.com/focus1691/orderflow,Orderflow trade aggregator for building Footprint Candles from exchange websocket data.,True,False,False,False,focus1691/orderflow
|
||||
ccxt,JavaScript,,,javascript,2026-03-22,41466,https://github.com/ccxt/ccxt,A JavaScript / Python / PHP cryptocurrency trading API with support for more than 100 bitcoin/altcoin exchanges.,True,False,False,False,ccxt/ccxt
|
||||
SimpleFunctions,JavaScript,,,javascript,2026-03-21,1,https://github.com/spfunctions/simplefunctions-cli,"Prediction market intelligence CLI for Kalshi and Polymarket. Causal thesis models, edge detection, 24/7 orderbook monitoring, what-if scenarios, and trade execution. MCP server for AI agent integration.",True,False,False,False,spfunctions/simplefunctions-cli
|
||||
PENDAX,JavaScript,,,javascript,2024-05-09,48,https://github.com/CompendiumFi/PENDAX-SDK,"Javascript SDK for Trading/Data API and Websockets for FTX, FTXUS, OKX, Bybit, & More.",True,False,False,False,CompendiumFi/PENDAX-SDK
|
||||
PreReason,JavaScript,,,javascript,2026-03-22,0,https://github.com/PreReason/mcp,"Pre-analyzed Bitcoin and macro market briefings for AI agents. 17 contexts with trend signals, confidence scores, and regime classification via REST API and MCP.",True,False,False,False,PreReason/mcp
|
||||
pmxt,JavaScript,,,javascript,2026-03-22,1140,https://github.com/pmxt-dev/pmxt,"The CCXT for prediction markets. A unified API for trading on Polymarket, Kalshi, and more.",True,False,False,False,pmxt-dev/pmxt
|
||||
pmxt,JavaScript,,,javascript,2026-03-22,1140,https://github.com/qoery-com/pmxt,A unified API for accessing prediction market data across multiple exchanges. CCXT for prediction markets.,True,False,False,False,qoery-com/pmxt
|
||||
rebalance,JavaScript,,,javascript,2026-03-01,2,https://github.com/cjroth/rebalance,"Interactive portfolio rebalancing tool that imports brokerage CSV data, sets target allocations, and generates trade instructions.",True,False,False,False,cjroth/rebalance
|
||||
QUANTAXIS_Webkit,JavaScript,Data Visualization,Data Visualization,data-visualization,2017-07-30,37,https://github.com/yutiansut/QUANTAXIS_Webkit,An awesome visualization center based on quantaxis.,True,False,False,False,yutiansut/QUANTAXIS_Webkit
|
||||
quantfin,Haskell,,,haskell,2019-04-06,139,https://github.com/boundedvariation/quantfin,quant finance in pure haskell.,True,False,False,False,boundedvariation/quantfin
|
||||
Haxcel,Haskell,,,haskell,2022-09-13,37,https://github.com/MarcusRainbow/Haxcel,Excel Addin for Haskell.,True,False,False,False,MarcusRainbow/Haxcel
|
||||
Ffinar,Haskell,,,haskell,2021-11-26,5,https://github.com/MarcusRainbow/Ffinar,A financial maths library in Haskell.,True,False,False,False,MarcusRainbow/Ffinar
|
||||
QuantScale,Scala,,,scala,2014-01-14,50,https://github.com/choucrifahed/quantscale,Scala Quantitative Finance Library.,True,False,False,False,choucrifahed/quantscale
|
||||
Scala Quant,Scala,,,scala,2017-05-06,10,https://github.com/frankcash/Scala-Quant,Scala library for working with stock data from IFTTT recipes or Google Finance.,True,False,False,False,frankcash/Scala-Quant
|
||||
Jiji,Ruby,,,ruby,2019-01-22,249,https://github.com/unageanu/jiji2,Open Source Forex algorithmic trading framework using OANDA REST API.,True,False,False,False,unageanu/jiji2
|
||||
Tai,Elixir/Erlang,,,elixir-erlang,2024-12-06,493,https://github.com/fremantle-capital/tai,"Open Source composable, real time, market data and trade execution toolkit.",True,False,False,False,fremantle-capital/tai
|
||||
Workbench,Elixir/Erlang,,,elixir-erlang,2022-06-06,121,https://github.com/fremantle-industries/workbench,From Idea to Execution - Manage your trading operation across a globally distributed cluster,True,False,False,False,fremantle-industries/workbench
|
||||
Prop,Elixir/Erlang,,,elixir-erlang,2022-06-06,55,https://github.com/fremantle-industries/prop,"An open and opinionated trading platform using productive & familiar open source libraries and tools for strategy research, execution and operation.",True,False,False,False,fremantle-industries/prop
|
||||
Kelp,Golang,,,golang,2021-11-26,1122,https://github.com/stellar/kelp,Kelp is an open-source Golang algorithmic cryptocurrency trading bot that runs on centralized exchanges and Stellar DEX (command-line usage and desktop GUI).,True,False,False,False,stellar/kelp
|
||||
marketstore,Golang,,,golang,error,0,https://github.com/alpacahq/marketstore,DataFrame Server for Financial Timeseries Data.,True,False,False,False,alpacahq/marketstore
|
||||
IndicatorGo,Golang,,,golang,2026-03-02,828,https://github.com/cinar/indicator,"IndicatorGo is a Golang module providing various stock technical analysis indicators, strategies, and a backtest framework for trading.",True,False,False,False,cinar/indicator
|
||||
QuantLib,CPP,,,cpp,2026-03-17,6890,https://github.com/lballabio/QuantLib,The QuantLib project is aimed at providing a comprehensive software framework for quantitative finance.,True,False,False,False,lballabio/QuantLib
|
||||
QuantLibRisks,CPP,,,cpp,2026-02-06,38,https://github.com/auto-differentiation/QuantLib-Risks-Cpp,Fast risks with QuantLib in C++,True,False,False,False,auto-differentiation/QuantLib-Risks-Cpp
|
||||
XAD,CPP,,,cpp,2026-02-06,411,https://github.com/auto-differentiation/xad,Automatic Differentation (AAD) Library,True,False,False,False,auto-differentiation/xad
|
||||
TradeFrame,CPP,,,cpp,2026-03-05,651,https://github.com/rburkholder/trade-frame,C++ 17 based framework/library (with sample applications) for testing options based automated trading ideas using DTN IQ real time data feed and Interactive Brokers (TWS API) for trade execution. Comes with built-in [Option Greeks/IV](https://github.com/rburkholder/trade-frame/tree/master/lib/TFOptions) calculation library.,True,False,False,False,rburkholder/trade-frame
|
||||
Hikyuu,CPP,,,cpp,2026-03-22,3053,https://github.com/fasiondog/hikyuu,"A base on Python/C++ open source high-performance quant framework for faster analysis and backtesting, contains the complete trading system components for reuse and combination. You can use python or c++ freely.",True,False,False,False,fasiondog/hikyuu
|
||||
OrderMatchingEngine,CPP,,,cpp,2026-01-11,128,https://github.com/PIYUSH-KUMAR1809/order-matching-engine,"A production-grade, lock-free, high-frequency trading matching engine achieving 150M+ orders/sec.",True,False,False,False,PIYUSH-KUMAR1809/order-matching-engine
|
||||
PandoraTrader,CPP,,,cpp,2025-07-29,1363,https://github.com/pegasusTrader/PandoraTrader,"A C++ CTP trading framework, with very clear logic",True,False,False,False,pegasusTrader/PandoraTrader
|
||||
NexusFix,CPP,,,cpp,2026-03-22,11,https://github.com/SilverstreamsAI/NexusFix,"C++23 FIX protocol engine with zero-copy parsing and SIMD acceleration, 3x faster than QuickFIX.",True,False,False,False,SilverstreamsAI/NexusFix
|
||||
QuantLib,Frameworks,,,frameworks,2026-03-17,6890,https://github.com/lballabio/QuantLib,The QuantLib project is aimed at providing a comprehensive software framework for quantitative finance.,True,False,False,False,lballabio/QuantLib
|
||||
JQuantLib,Frameworks,,,frameworks,2016-02-26,152,https://github.com/frgomes/jquantlib,Java port.,True,False,False,False,frgomes/jquantlib
|
||||
RQuantLib,Frameworks,,,frameworks,2026-03-09,131,https://github.com/eddelbuettel/rquantlib,R port.,True,False,False,False,eddelbuettel/rquantlib
|
||||
QuantLibAddin,Frameworks,,,frameworks,,0,https://www.quantlib.org/quantlibaddin/,Excel support.,False,False,False,False,
|
||||
QuantLibXL,Frameworks,,,frameworks,,0,https://www.quantlib.org/quantlibxl/,Excel support.,False,False,False,False,
|
||||
QLNet,Frameworks,,,frameworks,2026-03-10,422,https://github.com/amaggiulli/qlnet,.Net port.,True,False,False,False,amaggiulli/qlnet
|
||||
PyQL,Frameworks,,,frameworks,2025-08-20,1261,https://github.com/enthought/pyql,Python port.,True,False,False,False,enthought/pyql
|
||||
QuantLib.jl,Frameworks,,,frameworks,2020-02-18,143,https://github.com/pazzo83/QuantLib.jl,Julia port.,True,False,False,False,pazzo83/QuantLib.jl
|
||||
QuantLib-Python Documentation,Frameworks,,,frameworks,,0,https://quantlib-python-docs.readthedocs.io/,Documentation for the Python bindings for the QuantLib library,False,False,False,False,
|
||||
TA-Lib,Frameworks,,,frameworks,2025-10-19,1505,https://ta-lib.org,perform technical analysis of financial market data. [GitHub](https://github.com/TA-Lib/ta-lib),True,False,False,False,TA-Lib/ta-lib
|
||||
QuantConnect,CSharp,,,csharp,2026-03-14,18007,https://github.com/QuantConnect/Lean,Lean Engine is an open-source fully managed C# algorithmic trading engine built for desktop and cloud usage.,True,False,False,False,QuantConnect/Lean
|
||||
StockSharp,CSharp,,,csharp,2026-03-21,9302,https://github.com/StockSharp/StockSharp,"Algorithmic trading and quantitative trading open source platform to develop trading robots (stock markets, forex, crypto, bitcoins, and options).",True,False,False,False,StockSharp/StockSharp
|
||||
TDAmeritrade.DotNetCore,CSharp,,,csharp,2023-03-10,56,https://github.com/NVentimiglia/TDAmeritrade.DotNetCore,"Free, open-source .NET Client for the TD Ameritrade Trading Platform. Helps developers integrate TD Ameritrade API into custom trading solutions.",True,False,False,False,NVentimiglia/TDAmeritrade.DotNetCore
|
||||
QuantMath,Rust,,,rust,2020-05-28,402,https://github.com/MarcusRainbow/QuantMath,Financial maths library for risk-neutral pricing and risk,True,False,False,False,MarcusRainbow/QuantMath
|
||||
Barter,Rust,,,rust,2026-03-05,2022,https://github.com/barter-rs/barter-rs,Open-source Rust framework for building event-driven live-trading & backtesting systems,True,False,False,False,barter-rs/barter-rs
|
||||
LFEST,Rust,,,rust,2026-02-05,77,https://github.com/MathisWellmann/lfest-rs,Simulated perpetual futures exchange to trade your strategy against.,True,False,False,False,MathisWellmann/lfest-rs
|
||||
TradeAggregation,Rust,,,rust,2026-02-05,115,https://github.com/MathisWellmann/trade_aggregation-rs,Aggregate trades into user-defined candles using information driven rules.,True,False,False,False,MathisWellmann/trade_aggregation-rs
|
||||
OpenFinClaw,Rust,,,rust,2026-03-22,120,https://github.com/cryptoSUN2049/openFinclaw,"AI-native one-person hedge fund platform with Rust trading engine. Natural language → strategy → backtest → execution in 60s. Multi-market (US/HK/CN/Crypto), self-evolving strategy pipeline. Built on OpenClaw (68K+ stars).",True,False,False,False,cryptoSUN2049/openFinclaw
|
||||
SlidingFeatures,Rust,,,rust,2026-02-18,72,https://github.com/MathisWellmann/sliding_features-rs,Chainable tree-like sliding windows for signal processing and technical analysis.,True,False,False,False,MathisWellmann/sliding_features-rs
|
||||
RustQuant,Rust,,,rust,2026-01-14,1683,https://github.com/avhz/RustQuant,Quantitative finance library written in Rust.,True,False,False,False,avhz/RustQuant
|
||||
fin-primitives,Rust,,,rust,2026-03-21,4,https://github.com/Mattbusel/fin-primitives,"Financial market primitives in Rust: Price/Quantity/Symbol newtypes, BTreeMap order book, OHLCV aggregation, SMA/EMA/RSI indicators, position ledger with PnL, and composable risk monitor.",True,False,False,False,Mattbusel/fin-primitives
|
||||
fin-stream,Rust,,,rust,2026-03-21,2,https://github.com/Mattbusel/fin-stream,"Real-time market data streaming in Rust: lock-free SPSC ring buffer, 100K+ ticks/second ingestion, multi-timeframe OHLCV construction, and Lorentz transforms on financial time series.",True,False,False,False,Mattbusel/fin-stream
|
||||
Special-Relativity-in-Financial-Modeling,Rust,,,rust,2026-03-19,4,https://github.com/Mattbusel/Special-Relativity-in-Financial-Modeling,"C++20 implementation of special-relativistic geometry applied to OHLCV data: Lorentz factors, spacetime intervals, Christoffel symbols, and geodesic deviation signals from live market data. DOI: 10.5281/zenodo.18639919",True,False,False,False,Mattbusel/Special-Relativity-in-Financial-Modeling
|
||||
finalytics,Rust,,,rust,2026-02-17,67,https://github.com/Nnamdi-sys/finalytics,A rust library for financial data analysis.,True,False,False,False,Nnamdi-sys/finalytics
|
||||
RunMat,Rust,,,rust,2026-03-20,194,https://github.com/runmat-org/runmat,Rust runtime for MATLAB-syntax array math with automatic CPU/GPU execution and fused kernels for quant simulations.,True,False,False,False,runmat-org/runmat
|
||||
Auto-Differentiation Website,"Reproducing Works, Training & Books",,,reproducing-works-training-books,,0,https://auto-differentiation.github.io/,Background and resources on Automatic Differentiation (AD) / Adjoint Algorithmic Differentitation (AAD).,False,False,False,False,
|
||||
Derman Papers,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2017-10-21,507,https://github.com/MarcosCarreira/DermanPapers,Notebooks that replicate original quantitative finance papers from Emanuel Derman.,True,False,False,False,MarcosCarreira/DermanPapers
|
||||
volatility-trading,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-10-21,1881,https://github.com/jasonstrimpel/volatility-trading,A complete set of volatility estimators based on Euan Sinclair's Volatility Trading.,True,False,False,False,jasonstrimpel/volatility-trading
|
||||
quant,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2015-07-14,407,https://github.com/paulperry/quant,"Quantitative Finance and Algorithmic Trading exhaust; mostly ipython notebooks based on Quantopian, Zipline, or Pandas.",True,False,False,False,paulperry/quant
|
||||
fecon235,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2018-12-03,1255,https://github.com/rsvp/fecon235,Open source project for software tools in financial economics. Many jupyter notebook to verify theoretical ideas and practical methods interactively.,True,False,False,False,rsvp/fecon235
|
||||
Quantitative-Notebooks,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2020-07-02,1315,https://github.com/LongOnly/Quantitative-Notebooks,"Educational notebooks on quantitative finance, algorithmic trading, financial modelling and investment strategy",True,False,False,False,LongOnly/Quantitative-Notebooks
|
||||
QuantEcon,"Reproducing Works, Training & Books",,,reproducing-works-training-books,,0,https://quantecon.org/,"Lecture series on economics, finance, econometrics and data science; QuantEcon.py, QuantEcon.jl, notebooks",False,False,False,False,
|
||||
FinanceHub,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2021-05-25,782,https://github.com/Finance-Hub/FinanceHub,Resources for Quantitative Finance,True,False,False,False,Finance-Hub/FinanceHub
|
||||
Python_Option_Pricing,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-05-13,828,https://github.com/dedwards25/Python_Option_Pricing,"An library to price financial options written in Python. Includes: Black Scholes, Black 76, Implied Volatility, American, European, Asian, Spread Options.",True,False,False,False,dedwards25/Python_Option_Pricing
|
||||
python-training,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2023-11-27,12862,https://github.com/jpmorganchase/python-training,J.P. Morgan's Python training for business analysts and traders.,True,False,False,False,jpmorganchase/python-training
|
||||
Stock_Analysis_For_Quant,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-05-04,1985,https://github.com/LastAncientOne/Stock_Analysis_For_Quant,"Different Types of Stock Analysis in Excel, Matlab, Power BI, Python, R, and Tableau.",True,False,False,False,LastAncientOne/Stock_Analysis_For_Quant
|
||||
algorithmic-trading-with-python,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2021-06-01,3265,https://github.com/chrisconlan/algorithmic-trading-with-python,Source code for Algorithmic Trading with Python (2020) by Chris Conlan.,True,False,False,False,chrisconlan/algorithmic-trading-with-python
|
||||
MEDIUM_NoteBook,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-09-22,2138,https://github.com/cerlymarco/MEDIUM_NoteBook,Repository containing notebooks of [cerlymarco](https://github.com/cerlymarco)'s posts on Medium.,True,False,False,False,cerlymarco/MEDIUM_NoteBook
|
||||
QuantFinance,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-09-02,605,https://github.com/PythonCharmers/QuantFinance,Training materials in quantitative finance.,True,False,False,False,PythonCharmers/QuantFinance
|
||||
IPythonScripts,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2026-02-28,175,https://github.com/mgroncki/IPythonScripts,"Tutorials about Quantitative Finance in Python and QuantLib: Pricing, xVAs, Hedging, Portfolio Optimisation, Machine Learning and Deep Learning.",True,False,False,False,mgroncki/IPythonScripts
|
||||
Computational-Finance-Course,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-03-01,491,https://github.com/LechGrzelak/Computational-Finance-Course,Materials for the course of Computational Finance.,True,False,False,False,LechGrzelak/Computational-Finance-Course
|
||||
Machine-Learning-for-Asset-Managers,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-01-29,615,https://github.com/emoen/Machine-Learning-for-Asset-Managers,"Implementation of code snippets, exercises and application to live data from Machine Learning for Asset Managers (Elements in Quantitative Finance) written by Prof. Marcos López de Prado.",True,False,False,False,emoen/Machine-Learning-for-Asset-Managers
|
||||
Python-for-Finance-Cookbook,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2026-03-02,785,https://github.com/PacktPublishing/Python-for-Finance-Cookbook,"Python for Finance Cookbook, published by Packt.",True,False,False,False,PacktPublishing/Python-for-Finance-Cookbook
|
||||
modelos_vol_derivativos,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2023-08-19,59,https://github.com/ysaporito/modelos_vol_derivativos,"""Modelos de Volatilidade para Derivativos"" book's Jupyter notebooks",True,False,False,False,ysaporito/modelos_vol_derivativos
|
||||
NMOF,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-10-27,38,https://github.com/enricoschumann/NMOF,"Functions, examples and data from the first and the second edition of ""Numerical Methods and Optimization in Finance"" by M. Gilli, D. Maringer and E. Schumann (2019, ISBN:978-0128150658).",True,False,False,False,enricoschumann/NMOF
|
||||
py4fi2nd,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-06-06,2148,https://github.com/yhilpisch/py4fi2nd,"Jupyter Notebooks and code for Python for Finance (2nd ed., O'Reilly) by Yves Hilpisch.",True,False,False,False,yhilpisch/py4fi2nd
|
||||
aiif,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2023-10-09,385,https://github.com/yhilpisch/aiif,Jupyter Notebooks and code for the book Artificial Intelligence in Finance (O'Reilly) by Yves Hilpisch.,True,False,False,False,yhilpisch/aiif
|
||||
py4at,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2023-10-09,826,https://github.com/yhilpisch/py4at,Jupyter Notebooks and code for the book Python for Algorithmic Trading (O'Reilly) by Yves Hilpisch.,True,False,False,False,yhilpisch/py4at
|
||||
dawp,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2021-02-22,633,https://github.com/yhilpisch/dawp,Jupyter Notebooks and code for Derivatives Analytics with Python (Wiley Finance) by Yves Hilpisch.,True,False,False,False,yhilpisch/dawp
|
||||
dx,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-04-05,767,https://github.com/yhilpisch/dx,DX Analytics | Financial and Derivatives Analytics with Python.,True,False,False,False,yhilpisch/dx
|
||||
QuantFinanceBook,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-04-14,858,https://github.com/LechGrzelak/QuantFinanceBook,Quantitative Finance book.,True,False,False,False,LechGrzelak/QuantFinanceBook
|
||||
rough_bergomi,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2018-09-17,141,https://github.com/ryanmccrickerd/rough_bergomi,A Python implementation of the rough Bergomi model.,True,False,False,False,ryanmccrickerd/rough_bergomi
|
||||
frh-fx,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2018-05-24,13,https://github.com/ryanmccrickerd/frh-fx,A python implementation of the fast-reversion Heston model of Mechkov for FX purposes.,True,False,False,False,ryanmccrickerd/frh-fx
|
||||
Value Investing Studies,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2021-10-26,92,https://github.com/euclidjda/value-investing-studies,A collection of data analysis studies that examine the performance and characteristics of value investing over long periods of time.,True,False,False,False,euclidjda/value-investing-studies
|
||||
Machine Learning Asset Management,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2021-12-17,1734,https://github.com/firmai/machine-learning-asset-management,Machine Learning in Asset Management (by @firmai).,True,False,False,False,firmai/machine-learning-asset-management
|
||||
Deep Learning Machine Learning Stock,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-03-01,1723,https://github.com/LastAncientOne/Deep-Learning-Machine-Learning-Stock,Deep Learning and Machine Learning stocks represent a promising long-term or short-term opportunity for investors and traders.,True,False,False,False,LastAncientOne/Deep-Learning-Machine-Learning-Stock
|
||||
Technical Analysis and Feature Engineering,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-02-16,198,https://github.com/jo-cho/Technical_Analysis_and_Feature_Engineering,Feature Engineering and Feature Importance of Machine Learning in Financial Market.,True,False,False,False,jo-cho/Technical_Analysis_and_Feature_Engineering
|
||||
Differential Machine Learning and Axes that matter by Brian Huge and Antoine Savine,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2022-10-05,148,https://github.com/differential-machine-learning/notebooks,"Implement, demonstrate, reproduce and extend the results of the Risk articles 'Differential Machine Learning' (2020) and 'PCA with a Difference' (2021) by Huge and Savine, and cover implementation details left out from the papers.",True,False,False,False,differential-machine-learning/notebooks
|
||||
systematictradingexamples,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2020-07-22,461,https://github.com/robcarver17/systematictradingexamples,Examples of code related to book [Systematic Trading](www.systematictrading.org) and [blog](http://qoppac.blogspot.com),True,False,False,False,robcarver17/systematictradingexamples
|
||||
pysystemtrade_examples,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2018-02-21,259,https://github.com/robcarver17/pysystemtrade_examples,Examples using pysystemtrade for Robert Carver's [blog](http://qoppac.blogspot.com).,True,False,False,False,robcarver17/pysystemtrade_examples
|
||||
ML_Finance_Codes,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2020-06-13,2526,https://github.com/mfrdixon/ML_Finance_Codes,Machine Learning in Finance: From Theory to Practice Book,True,False,False,False,mfrdixon/ML_Finance_Codes
|
||||
Hands-On Machine Learning for Algorithmic Trading,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2023-01-18,1815,https://github.com/packtpublishing/hands-on-machine-learning-for-algorithmic-trading,"Hands-On Machine Learning for Algorithmic Trading, published by Packt",True,False,False,False,packtpublishing/hands-on-machine-learning-for-algorithmic-trading
|
||||
financialnoob-misc,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-08-26,28,https://github.com/financialnoob/misc,Codes from @financialnoob's posts,True,False,False,False,financialnoob/misc
|
||||
MesoSim Options Trading Strategy Library,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-04-06,20,https://github.com/deltaray-io/strategy-library,Free and public Options Trading strategy library for MesoSim. ,True,False,False,False,deltaray-io/strategy-library
|
||||
Quant-Finance-With-Python-Code,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2026-01-15,168,https://github.com/lingyixu/Quant-Finance-With-Python-Code,Repo for code examples in Quantitative Finance with Python by Chris Kelliher,True,False,False,False,lingyixu/Quant-Finance-With-Python-Code
|
||||
QuantFinanceTraining,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-02-20,40,https://github.com/JoaoJungblut/QuantFinanceTraining,"This repository contains codes that were executed during my training in the CQF (Certificate in Quantitative Finance). The codes are organized by class, facilitating navigation and reference.",True,False,False,False,JoaoJungblut/QuantFinanceTraining
|
||||
Statistical-Learning-based-Portfolio-Optimization,"Reproducing Works, Training & Books",,,reproducing-works-training-books,error,0,https://github.com/YannickKae/Statistical-Learning-based-Portfolio-Optimization,"This R Shiny App utilizes the Hierarchical Equal Risk Contribution (HERC) approach, a modern portfolio optimization method developed by Raffinot (2018).",True,False,False,False,YannickKae/Statistical-Learning-based-Portfolio-Optimization
|
||||
book_irds3,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2022-10-29,114,https://github.com/attack68/book_irds3,Code repository for Pricing and Trading Interest Rate Derivatives.,True,False,False,False,attack68/book_irds3
|
||||
Autoencoder-Asset-Pricing-Models,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-08-17,140,https://github.com/RichardS0268/Autoencoder-Asset-Pricing-Models,"Reimplementation of Autoencoder Asset Pricing Models ([GKX, 2019](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3335536)).",True,False,False,False,RichardS0268/Autoencoder-Asset-Pricing-Models
|
||||
Finance,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-05-12,3709,https://github.com/shashankvemuri/Finance,"150+ quantitative finance Python programs to help you gather, manipulate, and analyze stock market data.",True,False,False,False,shashankvemuri/Finance
|
||||
101_formulaic_alphas,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2022-07-11,45,https://github.com/ram-ki/101_formulaic_alphas,Implementation of [101 formulaic alphas](https://arxiv.org/ftp/arxiv/papers/1601/1601.00991.pdf) using qstrader.,True,False,False,False,ram-ki/101_formulaic_alphas
|
||||
Tidy Finance,"Reproducing Works, Training & Books",,,reproducing-works-training-books,,0,https://www.tidy-finance.org/,"An opinionated approach to empirical research in financial economics - a fully transparent, open-source code base in multiple programming languages (Python and R) to enable the reproducible implementation of financial research projects for students and practitioners.",False,False,False,False,
|
||||
RoughVolatilityWorkshop,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-09-06,71,https://github.com/jgatheral/RoughVolatilityWorkshop,2024 QuantMind's Rough Volatility Workshop lectures.,True,False,False,False,jgatheral/RoughVolatilityWorkshop
|
||||
AFML,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2024-09-05,810,https://github.com/boyboi86/AFML,All the answers for exercises from Advances in Financial Machine Learning by Dr Marco Lopez de Parodo.,True,False,False,False,boyboi86/AFML
|
||||
AlgoTradingLib,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2026-02-10,28,https://github.com/usdaud/algotradinglib.github.io,"A catalog of algorithmic trading libraries, frameworks, strategies, and educational materials.",True,False,False,False,usdaud/algotradinglib.github.io
|
||||
Portfolio Optimization Book,"Reproducing Works, Training & Books",,,reproducing-works-training-books,2025-02-17,25,https://portfoliooptimizationbook.com/,Prof. Daniel Palomar's Portfolio Optimization Book. [GitHub](https://github.com/dppalomar/pob),True,False,False,False,dppalomar/pob
|
||||
Chartscout,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://chartscout.io,Real-time cryptocurrency chart pattern detection with automated alerts across multiple exchanges.,False,False,False,True,
|
||||
DayTradingBench,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://daytradingbench.com,Live autonomous benchmark that evaluates LLM trading performance on DAX and Nasdaq indices using identical strategies and real-time market data. API access available.,False,False,False,True,
|
||||
CoinTester,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://cointester.io,"No-code crypto backtesting platform with 100+ indicators, AI sentiment signals, and 5+ years of historical data across 1,000+ trading pairs.",False,False,False,True,
|
||||
goMacro.ai,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://gomacro.ai,"AI-powered economic calendar with institutional-grade insights, bull/bear/base case scenario planning for NFP, CPI, PPI and other macro data releases.",False,False,False,True,
|
||||
StockAInsights,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://stockainsights.com,"AI-extracted financial statements API covering SEC filings including foreign filers (20-F, 6-K, 40-F), normalized quarterly and annual data from 2014+.",False,False,False,True,
|
||||
brapi.dev,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://brapi.dev/,"Brazilian stock market data API for B3/Bovespa quotes, historical OHLCV, dividends, and fundamentals.",False,False,False,True,
|
||||
13F Insight,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://13finsight.com/,"Track institutional investor 13F holdings with AI-powered analysis, position change alerts, and filing summaries.",False,False,False,True,
|
||||
Earnings Feed,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://earningsfeed.com/api,"Real-time SEC filings, insider trades, and institutional holdings API.",False,False,False,True,
|
||||
Financial Data,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://financialdata.net/,Stock Market and Financial Data API.,False,False,False,True,
|
||||
Frostbyte,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://agent-gateway-kappa.vercel.app,"Real-time crypto prices for 500+ tokens via REST API with free tier, DeFi swap routing and portfolio tracking.",False,False,False,True,
|
||||
SaxoOpenAPI,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://www.developer.saxo/,Saxo Bank financial data API.,False,False,False,True,
|
||||
RTPR,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://rtpr.io,"Real-time press release API delivering news from Business Wire, PR Newswire, and GlobeNewswire with sub-500ms latency. REST and WebSocket APIs for financial applications. Python and Node.js SDKs available.",False,False,False,True,
|
||||
Nasdaq Data Link,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://data.nasdaq.com/tools/full-list,"Financial data API with support for R, Python, Excel, Ruby, and many other languages (formerly Quandl).",False,False,False,True,
|
||||
Parsec,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://parsecfinance.com,Prediction market API with Python SDK for normalized data and execution across 5 prediction market exchanges. Free tier: 10K requests/month.,False,False,False,True,
|
||||
Portfolio Optimizer,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://portfoliooptimizer.io/,Portfolio Optimizer is a Web API for portfolio analysis and optimization.,False,False,False,True,
|
||||
Reddit WallstreetBets API,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://dashboard.nbshare.io/apps/reddit/api/,Provides daily top 50 stocks from reddit (subreddit) Wallstreetbets and their sentiments via the API.,False,False,False,True,
|
||||
System R,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://agents.systemr.ai,"AI-native risk intelligence API for trading agents. Position sizing, risk validation, and system health in one call.",False,False,False,True,
|
||||
Telonex,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://telonex.io,"Tick-level prediction market data (trades, quotes, orderbooks, on-chain fills) via REST API and Python SDK.",False,False,False,True,
|
||||
ValueRay,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://www.valueray.com/api,"Technical, quantitative and sentiment data for stocks and ETFs with risk metrics, peer percentiles and market regime signals. Optimized for AI/LLM agents.",False,False,False,True,
|
||||
VertData,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://vertdata.com,"Institutional-grade financial intelligence platform. Track 43K+ congressional trades (STOCK Act), SEC insider Form 4 filings, 25 superinvestor 13F portfolios, CFTC futures positioning, ARK ETF holdings, and short interest — all scored by AI for signal strength.",False,False,False,True,
|
||||
KeepRule,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://keeprule.com/,"Curated library of decision-making principles and investment wisdom from masters like Buffett and Munger, featuring mental models for better investment thinking.",False,False,False,True,
|
||||
ML-Quant,Commercial & Proprietary Services,,,commercial-proprietary-services,,0,https://www.ml-quant.com/,"Top Quant resources like ArXiv (sanity), SSRN, RePec, Journals, Podcasts, Videos, and Blogs.",False,False,False,True,
|
||||
awesome-sec-filings,Related Lists,,,related-lists,2026-02-14,9,https://github.com/vibeyclaw/awesome-sec-filings,"A curated list of tools, data sources, libraries, and resources for working with SEC filings (13F, 10-K, 10-Q, 8-K).",True,False,False,False,vibeyclaw/awesome-sec-filings
|
||||
CONVEXFI,Related Lists,,,related-lists,,0,https://github.com/convexfi,Official GitHub organization for the convex research group at the Hong Kong University of Science and Technology (HKUST).,True,False,False,False,
|
||||
|
-575
File diff suppressed because one or more lines are too long
-205
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-2106
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Vendored
-7
File diff suppressed because one or more lines are too long
Vendored
-7
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,75 +0,0 @@
|
||||
/* Adjust margins outwards, so column contents line up with the edges of the
|
||||
parent of container-fluid. */
|
||||
.container-fluid.crosstalk-bscols {
|
||||
margin-left: -30px;
|
||||
margin-right: -30px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* But don't adjust the margins outwards if we're directly under the body,
|
||||
i.e. we were the top-level of something at the console. */
|
||||
body > .container-fluid.crosstalk-bscols {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column {
|
||||
display: inline-block;
|
||||
padding-right: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@media only screen and (max-width:480px) {
|
||||
.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column {
|
||||
display: block;
|
||||
padding-right: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */
|
||||
.crosstalk-input {
|
||||
margin-bottom: 15px; /* a la .form-group */
|
||||
.control-label {
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
margin: 4px 0 0;
|
||||
margin-top: 1px;
|
||||
line-height: normal;
|
||||
}
|
||||
.checkbox {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.checkbox > label{
|
||||
padding-left: 20px;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
}
|
||||
.checkbox input[type="checkbox"],
|
||||
.checkbox-inline input[type="checkbox"] {
|
||||
position: absolute;
|
||||
margin-top: 2px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
.checkbox + .checkbox {
|
||||
margin-top: -5px;
|
||||
}
|
||||
.checkbox-inline {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding-left: 20px;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
.checkbox-inline + .checkbox-inline {
|
||||
margin-top: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
.dt-crosstalk-fade {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
html body div.DTS div.dataTables_scrollBody {
|
||||
background: none;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fix https://github.com/rstudio/DT/issues/563
|
||||
If the `table.display` is set to "block" (e.g., pkgdown), the browser will display
|
||||
datatable objects strangely. The search panel and the page buttons will still be
|
||||
in full-width but the table body will be "compact" and shorter.
|
||||
In therory, having this attributes will affect `dom="t"`
|
||||
with `display: block` users. But in reality, there should be no one.
|
||||
We may remove the below lines in the future if the upstream agree to have this there.
|
||||
See https://github.com/DataTables/DataTablesSrc/issues/160
|
||||
*/
|
||||
|
||||
table.dataTable {
|
||||
display: table;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
When DTOutput(fill = TRUE), it receives a .html-fill-item class (via htmltools::bindFillRole()), which effectively amounts to `flex: 1 1 auto`. That's mostly fine, but the case where `fillContainer=TRUE`+`height:auto`+`flex-basis:auto` and the container (e.g., a bslib::card()) doesn't have a defined height is a bit problematic since the table wants to fit the parent but the parent wants to fit the table, which results pretty small table height (maybe because there is a minimum height somewhere?). It seems better in this case to impose a 400px height default for the table, which we can do by setting `flex-basis` to 400px (the table is still allowed to grow/shrink when the container has an opinionated height).
|
||||
*/
|
||||
|
||||
.html-fill-container > .html-fill-item.datatables {
|
||||
flex-basis: 400px;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Selected rows/cells */
|
||||
table.dataTable tr.selected td, table.dataTable td.selected {
|
||||
background-color: #b0bed9 !important;
|
||||
}
|
||||
/* In case of scrollX/Y or FixedHeader */
|
||||
.dataTables_scrollBody .dataTables_sizing {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* The datatables' theme CSS file doesn't define
|
||||
the color but with white background. It leads to an issue that
|
||||
when the HTML's body color is set to 'white', the user can't
|
||||
see the text since the background is white. One case happens in the
|
||||
RStudio's IDE when inline viewing the DT table inside an Rmd file,
|
||||
if the IDE theme is set to "Cobalt".
|
||||
|
||||
See https://github.com/rstudio/DT/issues/447 for more info
|
||||
|
||||
This fixes should have little side-effects because all the other elements
|
||||
of the default theme use the #333 font color.
|
||||
|
||||
TODO: The upstream may use relative colors for both the table background
|
||||
and the color. It means the table can display well without this patch
|
||||
then. At that time, we need to remove the below CSS attributes.
|
||||
*/
|
||||
div.datatables {
|
||||
color: #333;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,21 +0,0 @@
|
||||
@layer htmltools {
|
||||
.html-fill-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* Prevent the container from expanding vertically or horizontally beyond its
|
||||
parent's constraints. */
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
.html-fill-container > .html-fill-item {
|
||||
/* Fill items can grow and shrink freely within
|
||||
available vertical space in fillable container */
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
.html-fill-container > :not(.html-fill-item) {
|
||||
/* Prevent shrinking or growing of non-fill items */
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -1,901 +0,0 @@
|
||||
(function() {
|
||||
// If window.HTMLWidgets is already defined, then use it; otherwise create a
|
||||
// new object. This allows preceding code to set options that affect the
|
||||
// initialization process (though none currently exist).
|
||||
window.HTMLWidgets = window.HTMLWidgets || {};
|
||||
|
||||
// See if we're running in a viewer pane. If not, we're in a web browser.
|
||||
var viewerMode = window.HTMLWidgets.viewerMode =
|
||||
/\bviewer_pane=1\b/.test(window.location);
|
||||
|
||||
// See if we're running in Shiny mode. If not, it's a static document.
|
||||
// Note that static widgets can appear in both Shiny and static modes, but
|
||||
// obviously, Shiny widgets can only appear in Shiny apps/documents.
|
||||
var shinyMode = window.HTMLWidgets.shinyMode =
|
||||
typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings;
|
||||
|
||||
// We can't count on jQuery being available, so we implement our own
|
||||
// version if necessary.
|
||||
function querySelectorAll(scope, selector) {
|
||||
if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) {
|
||||
return scope.find(selector);
|
||||
}
|
||||
if (scope.querySelectorAll) {
|
||||
return scope.querySelectorAll(selector);
|
||||
}
|
||||
}
|
||||
|
||||
function asArray(value) {
|
||||
if (value === null)
|
||||
return [];
|
||||
if ($.isArray(value))
|
||||
return value;
|
||||
return [value];
|
||||
}
|
||||
|
||||
// Implement jQuery's extend
|
||||
function extend(target /*, ... */) {
|
||||
if (arguments.length == 1) {
|
||||
return target;
|
||||
}
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = arguments[i];
|
||||
for (var prop in source) {
|
||||
if (source.hasOwnProperty(prop)) {
|
||||
target[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
// IE8 doesn't support Array.forEach.
|
||||
function forEach(values, callback, thisArg) {
|
||||
if (values.forEach) {
|
||||
values.forEach(callback, thisArg);
|
||||
} else {
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
callback.call(thisArg, values[i], i, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces the specified method with the return value of funcSource.
|
||||
//
|
||||
// Note that funcSource should not BE the new method, it should be a function
|
||||
// that RETURNS the new method. funcSource receives a single argument that is
|
||||
// the overridden method, it can be called from the new method. The overridden
|
||||
// method can be called like a regular function, it has the target permanently
|
||||
// bound to it so "this" will work correctly.
|
||||
function overrideMethod(target, methodName, funcSource) {
|
||||
var superFunc = target[methodName] || function() {};
|
||||
var superFuncBound = function() {
|
||||
return superFunc.apply(target, arguments);
|
||||
};
|
||||
target[methodName] = funcSource(superFuncBound);
|
||||
}
|
||||
|
||||
// Add a method to delegator that, when invoked, calls
|
||||
// delegatee.methodName. If there is no such method on
|
||||
// the delegatee, but there was one on delegator before
|
||||
// delegateMethod was called, then the original version
|
||||
// is invoked instead.
|
||||
// For example:
|
||||
//
|
||||
// var a = {
|
||||
// method1: function() { console.log('a1'); }
|
||||
// method2: function() { console.log('a2'); }
|
||||
// };
|
||||
// var b = {
|
||||
// method1: function() { console.log('b1'); }
|
||||
// };
|
||||
// delegateMethod(a, b, "method1");
|
||||
// delegateMethod(a, b, "method2");
|
||||
// a.method1();
|
||||
// a.method2();
|
||||
//
|
||||
// The output would be "b1", "a2".
|
||||
function delegateMethod(delegator, delegatee, methodName) {
|
||||
var inherited = delegator[methodName];
|
||||
delegator[methodName] = function() {
|
||||
var target = delegatee;
|
||||
var method = delegatee[methodName];
|
||||
|
||||
// The method doesn't exist on the delegatee. Instead,
|
||||
// call the method on the delegator, if it exists.
|
||||
if (!method) {
|
||||
target = delegator;
|
||||
method = inherited;
|
||||
}
|
||||
|
||||
if (method) {
|
||||
return method.apply(target, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Implement a vague facsimilie of jQuery's data method
|
||||
function elementData(el, name, value) {
|
||||
if (arguments.length == 2) {
|
||||
return el["htmlwidget_data_" + name];
|
||||
} else if (arguments.length == 3) {
|
||||
el["htmlwidget_data_" + name] = value;
|
||||
return el;
|
||||
} else {
|
||||
throw new Error("Wrong number of arguments for elementData: " +
|
||||
arguments.length);
|
||||
}
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
}
|
||||
|
||||
function hasClass(el, className) {
|
||||
var re = new RegExp("\\b" + escapeRegExp(className) + "\\b");
|
||||
return re.test(el.className);
|
||||
}
|
||||
|
||||
// elements - array (or array-like object) of HTML elements
|
||||
// className - class name to test for
|
||||
// include - if true, only return elements with given className;
|
||||
// if false, only return elements *without* given className
|
||||
function filterByClass(elements, className, include) {
|
||||
var results = [];
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (hasClass(elements[i], className) == include)
|
||||
results.push(elements[i]);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function on(obj, eventName, func) {
|
||||
if (obj.addEventListener) {
|
||||
obj.addEventListener(eventName, func, false);
|
||||
} else if (obj.attachEvent) {
|
||||
obj.attachEvent(eventName, func);
|
||||
}
|
||||
}
|
||||
|
||||
function off(obj, eventName, func) {
|
||||
if (obj.removeEventListener)
|
||||
obj.removeEventListener(eventName, func, false);
|
||||
else if (obj.detachEvent) {
|
||||
obj.detachEvent(eventName, func);
|
||||
}
|
||||
}
|
||||
|
||||
// Translate array of values to top/right/bottom/left, as usual with
|
||||
// the "padding" CSS property
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/padding
|
||||
function unpackPadding(value) {
|
||||
if (typeof(value) === "number")
|
||||
value = [value];
|
||||
if (value.length === 1) {
|
||||
return {top: value[0], right: value[0], bottom: value[0], left: value[0]};
|
||||
}
|
||||
if (value.length === 2) {
|
||||
return {top: value[0], right: value[1], bottom: value[0], left: value[1]};
|
||||
}
|
||||
if (value.length === 3) {
|
||||
return {top: value[0], right: value[1], bottom: value[2], left: value[1]};
|
||||
}
|
||||
if (value.length === 4) {
|
||||
return {top: value[0], right: value[1], bottom: value[2], left: value[3]};
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an unpacked padding object to a CSS value
|
||||
function paddingToCss(paddingObj) {
|
||||
return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px";
|
||||
}
|
||||
|
||||
// Makes a number suitable for CSS
|
||||
function px(x) {
|
||||
if (typeof(x) === "number")
|
||||
return x + "px";
|
||||
else
|
||||
return x;
|
||||
}
|
||||
|
||||
// Retrieves runtime widget sizing information for an element.
|
||||
// The return value is either null, or an object with fill, padding,
|
||||
// defaultWidth, defaultHeight fields.
|
||||
function sizingPolicy(el) {
|
||||
var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']");
|
||||
if (!sizingEl)
|
||||
return null;
|
||||
var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}");
|
||||
if (viewerMode) {
|
||||
return sp.viewer;
|
||||
} else {
|
||||
return sp.browser;
|
||||
}
|
||||
}
|
||||
|
||||
// @param tasks Array of strings (or falsy value, in which case no-op).
|
||||
// Each element must be a valid JavaScript expression that yields a
|
||||
// function. Or, can be an array of objects with "code" and "data"
|
||||
// properties; in this case, the "code" property should be a string
|
||||
// of JS that's an expr that yields a function, and "data" should be
|
||||
// an object that will be added as an additional argument when that
|
||||
// function is called.
|
||||
// @param target The object that will be "this" for each function
|
||||
// execution.
|
||||
// @param args Array of arguments to be passed to the functions. (The
|
||||
// same arguments will be passed to all functions.)
|
||||
function evalAndRun(tasks, target, args) {
|
||||
if (tasks) {
|
||||
forEach(tasks, function(task) {
|
||||
var theseArgs = args;
|
||||
if (typeof(task) === "object") {
|
||||
theseArgs = theseArgs.concat([task.data]);
|
||||
task = task.code;
|
||||
}
|
||||
var taskFunc = tryEval(task);
|
||||
if (typeof(taskFunc) !== "function") {
|
||||
throw new Error("Task must be a function! Source:\n" + task);
|
||||
}
|
||||
taskFunc.apply(target, theseArgs);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt eval() both with and without enclosing in parentheses.
|
||||
// Note that enclosing coerces a function declaration into
|
||||
// an expression that eval() can parse
|
||||
// (otherwise, a SyntaxError is thrown)
|
||||
function tryEval(code) {
|
||||
var result = null;
|
||||
try {
|
||||
result = eval("(" + code + ")");
|
||||
} catch(error) {
|
||||
if (!(error instanceof SyntaxError)) {
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
result = eval(code);
|
||||
} catch(e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
throw error;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function initSizing(el) {
|
||||
var sizing = sizingPolicy(el);
|
||||
if (!sizing)
|
||||
return;
|
||||
|
||||
var cel = document.getElementById("htmlwidget_container");
|
||||
if (!cel)
|
||||
return;
|
||||
|
||||
if (typeof(sizing.padding) !== "undefined") {
|
||||
document.body.style.margin = "0";
|
||||
document.body.style.padding = paddingToCss(unpackPadding(sizing.padding));
|
||||
}
|
||||
|
||||
if (sizing.fill) {
|
||||
document.body.style.overflow = "hidden";
|
||||
document.body.style.width = "100%";
|
||||
document.body.style.height = "100%";
|
||||
document.documentElement.style.width = "100%";
|
||||
document.documentElement.style.height = "100%";
|
||||
cel.style.position = "absolute";
|
||||
var pad = unpackPadding(sizing.padding);
|
||||
cel.style.top = pad.top + "px";
|
||||
cel.style.right = pad.right + "px";
|
||||
cel.style.bottom = pad.bottom + "px";
|
||||
cel.style.left = pad.left + "px";
|
||||
el.style.width = "100%";
|
||||
el.style.height = "100%";
|
||||
|
||||
return {
|
||||
getWidth: function() { return cel.getBoundingClientRect().width; },
|
||||
getHeight: function() { return cel.getBoundingClientRect().height; }
|
||||
};
|
||||
|
||||
} else {
|
||||
el.style.width = px(sizing.width);
|
||||
el.style.height = px(sizing.height);
|
||||
|
||||
return {
|
||||
getWidth: function() { return cel.getBoundingClientRect().width; },
|
||||
getHeight: function() { return cel.getBoundingClientRect().height; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Default implementations for methods
|
||||
var defaults = {
|
||||
find: function(scope) {
|
||||
return querySelectorAll(scope, "." + this.name);
|
||||
},
|
||||
renderError: function(el, err) {
|
||||
var $el = $(el);
|
||||
|
||||
this.clearError(el);
|
||||
|
||||
// Add all these error classes, as Shiny does
|
||||
var errClass = "shiny-output-error";
|
||||
if (err.type !== null) {
|
||||
// use the classes of the error condition as CSS class names
|
||||
errClass = errClass + " " + $.map(asArray(err.type), function(type) {
|
||||
return errClass + "-" + type;
|
||||
}).join(" ");
|
||||
}
|
||||
errClass = errClass + " htmlwidgets-error";
|
||||
|
||||
// Is el inline or block? If inline or inline-block, just display:none it
|
||||
// and add an inline error.
|
||||
var display = $el.css("display");
|
||||
$el.data("restore-display-mode", display);
|
||||
|
||||
if (display === "inline" || display === "inline-block") {
|
||||
$el.hide();
|
||||
if (err.message !== "") {
|
||||
var errorSpan = $("<span>").addClass(errClass);
|
||||
errorSpan.text(err.message);
|
||||
$el.after(errorSpan);
|
||||
}
|
||||
} else if (display === "block") {
|
||||
// If block, add an error just after the el, set visibility:none on the
|
||||
// el, and position the error to be on top of the el.
|
||||
// Mark it with a unique ID and CSS class so we can remove it later.
|
||||
$el.css("visibility", "hidden");
|
||||
if (err.message !== "") {
|
||||
var errorDiv = $("<div>").addClass(errClass).css("position", "absolute")
|
||||
.css("top", el.offsetTop)
|
||||
.css("left", el.offsetLeft)
|
||||
// setting width can push out the page size, forcing otherwise
|
||||
// unnecessary scrollbars to appear and making it impossible for
|
||||
// the element to shrink; so use max-width instead
|
||||
.css("maxWidth", el.offsetWidth)
|
||||
.css("height", el.offsetHeight);
|
||||
errorDiv.text(err.message);
|
||||
$el.after(errorDiv);
|
||||
|
||||
// Really dumb way to keep the size/position of the error in sync with
|
||||
// the parent element as the window is resized or whatever.
|
||||
var intId = setInterval(function() {
|
||||
if (!errorDiv[0].parentElement) {
|
||||
clearInterval(intId);
|
||||
return;
|
||||
}
|
||||
errorDiv
|
||||
.css("top", el.offsetTop)
|
||||
.css("left", el.offsetLeft)
|
||||
.css("maxWidth", el.offsetWidth)
|
||||
.css("height", el.offsetHeight);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
},
|
||||
clearError: function(el) {
|
||||
var $el = $(el);
|
||||
var display = $el.data("restore-display-mode");
|
||||
$el.data("restore-display-mode", null);
|
||||
|
||||
if (display === "inline" || display === "inline-block") {
|
||||
if (display)
|
||||
$el.css("display", display);
|
||||
$(el.nextSibling).filter(".htmlwidgets-error").remove();
|
||||
} else if (display === "block"){
|
||||
$el.css("visibility", "inherit");
|
||||
$(el.nextSibling).filter(".htmlwidgets-error").remove();
|
||||
}
|
||||
},
|
||||
sizing: {}
|
||||
};
|
||||
|
||||
// Called by widget bindings to register a new type of widget. The definition
|
||||
// object can contain the following properties:
|
||||
// - name (required) - A string indicating the binding name, which will be
|
||||
// used by default as the CSS classname to look for.
|
||||
// - initialize (optional) - A function(el) that will be called once per
|
||||
// widget element; if a value is returned, it will be passed as the third
|
||||
// value to renderValue.
|
||||
// - renderValue (required) - A function(el, data, initValue) that will be
|
||||
// called with data. Static contexts will cause this to be called once per
|
||||
// element; Shiny apps will cause this to be called multiple times per
|
||||
// element, as the data changes.
|
||||
window.HTMLWidgets.widget = function(definition) {
|
||||
if (!definition.name) {
|
||||
throw new Error("Widget must have a name");
|
||||
}
|
||||
if (!definition.type) {
|
||||
throw new Error("Widget must have a type");
|
||||
}
|
||||
// Currently we only support output widgets
|
||||
if (definition.type !== "output") {
|
||||
throw new Error("Unrecognized widget type '" + definition.type + "'");
|
||||
}
|
||||
// TODO: Verify that .name is a valid CSS classname
|
||||
|
||||
// Support new-style instance-bound definitions. Old-style class-bound
|
||||
// definitions have one widget "object" per widget per type/class of
|
||||
// widget; the renderValue and resize methods on such widget objects
|
||||
// take el and instance arguments, because the widget object can't
|
||||
// store them. New-style instance-bound definitions have one widget
|
||||
// object per widget instance; the definition that's passed in doesn't
|
||||
// provide renderValue or resize methods at all, just the single method
|
||||
// factory(el, width, height)
|
||||
// which returns an object that has renderValue(x) and resize(w, h).
|
||||
// This enables a far more natural programming style for the widget
|
||||
// author, who can store per-instance state using either OO-style
|
||||
// instance fields or functional-style closure variables (I guess this
|
||||
// is in contrast to what can only be called C-style pseudo-OO which is
|
||||
// what we required before).
|
||||
if (definition.factory) {
|
||||
definition = createLegacyDefinitionAdapter(definition);
|
||||
}
|
||||
|
||||
if (!definition.renderValue) {
|
||||
throw new Error("Widget must have a renderValue function");
|
||||
}
|
||||
|
||||
// For static rendering (non-Shiny), use a simple widget registration
|
||||
// scheme. We also use this scheme for Shiny apps/documents that also
|
||||
// contain static widgets.
|
||||
window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
|
||||
// Merge defaults into the definition; don't mutate the original definition.
|
||||
var staticBinding = extend({}, defaults, definition);
|
||||
overrideMethod(staticBinding, "find", function(superfunc) {
|
||||
return function(scope) {
|
||||
var results = superfunc(scope);
|
||||
// Filter out Shiny outputs, we only want the static kind
|
||||
return filterByClass(results, "html-widget-output", false);
|
||||
};
|
||||
});
|
||||
window.HTMLWidgets.widgets.push(staticBinding);
|
||||
|
||||
if (shinyMode) {
|
||||
// Shiny is running. Register the definition with an output binding.
|
||||
// The definition itself will not be the output binding, instead
|
||||
// we will make an output binding object that delegates to the
|
||||
// definition. This is because we foolishly used the same method
|
||||
// name (renderValue) for htmlwidgets definition and Shiny bindings
|
||||
// but they actually have quite different semantics (the Shiny
|
||||
// bindings receive data that includes lots of metadata that it
|
||||
// strips off before calling htmlwidgets renderValue). We can't
|
||||
// just ignore the difference because in some widgets it's helpful
|
||||
// to call this.renderValue() from inside of resize(), and if
|
||||
// we're not delegating, then that call will go to the Shiny
|
||||
// version instead of the htmlwidgets version.
|
||||
|
||||
// Merge defaults with definition, without mutating either.
|
||||
var bindingDef = extend({}, defaults, definition);
|
||||
|
||||
// This object will be our actual Shiny binding.
|
||||
var shinyBinding = new Shiny.OutputBinding();
|
||||
|
||||
// With a few exceptions, we'll want to simply use the bindingDef's
|
||||
// version of methods if they are available, otherwise fall back to
|
||||
// Shiny's defaults. NOTE: If Shiny's output bindings gain additional
|
||||
// methods in the future, and we want them to be overrideable by
|
||||
// HTMLWidget binding definitions, then we'll need to add them to this
|
||||
// list.
|
||||
delegateMethod(shinyBinding, bindingDef, "getId");
|
||||
delegateMethod(shinyBinding, bindingDef, "onValueChange");
|
||||
delegateMethod(shinyBinding, bindingDef, "onValueError");
|
||||
delegateMethod(shinyBinding, bindingDef, "renderError");
|
||||
delegateMethod(shinyBinding, bindingDef, "clearError");
|
||||
delegateMethod(shinyBinding, bindingDef, "showProgress");
|
||||
|
||||
// The find, renderValue, and resize are handled differently, because we
|
||||
// want to actually decorate the behavior of the bindingDef methods.
|
||||
|
||||
shinyBinding.find = function(scope) {
|
||||
var results = bindingDef.find(scope);
|
||||
|
||||
// Only return elements that are Shiny outputs, not static ones
|
||||
var dynamicResults = results.filter(".html-widget-output");
|
||||
|
||||
// It's possible that whatever caused Shiny to think there might be
|
||||
// new dynamic outputs, also caused there to be new static outputs.
|
||||
// Since there might be lots of different htmlwidgets bindings, we
|
||||
// schedule execution for later--no need to staticRender multiple
|
||||
// times.
|
||||
if (results.length !== dynamicResults.length)
|
||||
scheduleStaticRender();
|
||||
|
||||
return dynamicResults;
|
||||
};
|
||||
|
||||
// Wrap renderValue to handle initialization, which unfortunately isn't
|
||||
// supported natively by Shiny at the time of this writing.
|
||||
|
||||
shinyBinding.renderValue = function(el, data) {
|
||||
Shiny.renderDependencies(data.deps);
|
||||
// Resolve strings marked as javascript literals to objects
|
||||
if (!(data.evals instanceof Array)) data.evals = [data.evals];
|
||||
for (var i = 0; data.evals && i < data.evals.length; i++) {
|
||||
window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
|
||||
}
|
||||
if (!bindingDef.renderOnNullValue) {
|
||||
if (data.x === null) {
|
||||
el.style.visibility = "hidden";
|
||||
return;
|
||||
} else {
|
||||
el.style.visibility = "inherit";
|
||||
}
|
||||
}
|
||||
if (!elementData(el, "initialized")) {
|
||||
initSizing(el);
|
||||
|
||||
elementData(el, "initialized", true);
|
||||
if (bindingDef.initialize) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
var result = bindingDef.initialize(el, rect.width, rect.height);
|
||||
elementData(el, "init_result", result);
|
||||
}
|
||||
}
|
||||
bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
|
||||
evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
|
||||
};
|
||||
|
||||
// Only override resize if bindingDef implements it
|
||||
if (bindingDef.resize) {
|
||||
shinyBinding.resize = function(el, width, height) {
|
||||
// Shiny can call resize before initialize/renderValue have been
|
||||
// called, which doesn't make sense for widgets.
|
||||
if (elementData(el, "initialized")) {
|
||||
bindingDef.resize(el, width, height, elementData(el, "init_result"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Shiny.outputBindings.register(shinyBinding, bindingDef.name);
|
||||
}
|
||||
};
|
||||
|
||||
var scheduleStaticRenderTimerId = null;
|
||||
function scheduleStaticRender() {
|
||||
if (!scheduleStaticRenderTimerId) {
|
||||
scheduleStaticRenderTimerId = setTimeout(function() {
|
||||
scheduleStaticRenderTimerId = null;
|
||||
window.HTMLWidgets.staticRender();
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Render static widgets after the document finishes loading
|
||||
// Statically render all elements that are of this widget's class
|
||||
window.HTMLWidgets.staticRender = function() {
|
||||
var bindings = window.HTMLWidgets.widgets || [];
|
||||
forEach(bindings, function(binding) {
|
||||
var matches = binding.find(document.documentElement);
|
||||
forEach(matches, function(el) {
|
||||
var sizeObj = initSizing(el, binding);
|
||||
|
||||
var getSize = function(el) {
|
||||
if (sizeObj) {
|
||||
return {w: sizeObj.getWidth(), h: sizeObj.getHeight()}
|
||||
} else {
|
||||
var rect = el.getBoundingClientRect();
|
||||
return {w: rect.width, h: rect.height}
|
||||
}
|
||||
};
|
||||
|
||||
if (hasClass(el, "html-widget-static-bound"))
|
||||
return;
|
||||
el.className = el.className + " html-widget-static-bound";
|
||||
|
||||
var initResult;
|
||||
if (binding.initialize) {
|
||||
var size = getSize(el);
|
||||
initResult = binding.initialize(el, size.w, size.h);
|
||||
elementData(el, "init_result", initResult);
|
||||
}
|
||||
|
||||
if (binding.resize) {
|
||||
var lastSize = getSize(el);
|
||||
var resizeHandler = function(e) {
|
||||
var size = getSize(el);
|
||||
if (size.w === 0 && size.h === 0)
|
||||
return;
|
||||
if (size.w === lastSize.w && size.h === lastSize.h)
|
||||
return;
|
||||
lastSize = size;
|
||||
binding.resize(el, size.w, size.h, initResult);
|
||||
};
|
||||
|
||||
on(window, "resize", resizeHandler);
|
||||
|
||||
// This is needed for cases where we're running in a Shiny
|
||||
// app, but the widget itself is not a Shiny output, but
|
||||
// rather a simple static widget. One example of this is
|
||||
// an rmarkdown document that has runtime:shiny and widget
|
||||
// that isn't in a render function. Shiny only knows to
|
||||
// call resize handlers for Shiny outputs, not for static
|
||||
// widgets, so we do it ourselves.
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on(
|
||||
"shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
|
||||
resizeHandler
|
||||
);
|
||||
window.jQuery(document).on(
|
||||
"hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
|
||||
resizeHandler
|
||||
);
|
||||
}
|
||||
|
||||
// This is needed for the specific case of ioslides, which
|
||||
// flips slides between display:none and display:block.
|
||||
// Ideally we would not have to have ioslide-specific code
|
||||
// here, but rather have ioslides raise a generic event,
|
||||
// but the rmarkdown package just went to CRAN so the
|
||||
// window to getting that fixed may be long.
|
||||
if (window.addEventListener) {
|
||||
// It's OK to limit this to window.addEventListener
|
||||
// browsers because ioslides itself only supports
|
||||
// such browsers.
|
||||
on(document, "slideenter", resizeHandler);
|
||||
on(document, "slideleave", resizeHandler);
|
||||
}
|
||||
}
|
||||
|
||||
var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
|
||||
if (scriptData) {
|
||||
var data = JSON.parse(scriptData.textContent || scriptData.text);
|
||||
// Resolve strings marked as javascript literals to objects
|
||||
if (!(data.evals instanceof Array)) data.evals = [data.evals];
|
||||
for (var k = 0; data.evals && k < data.evals.length; k++) {
|
||||
window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
|
||||
}
|
||||
binding.renderValue(el, data.x, initResult);
|
||||
evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
invokePostRenderHandlers();
|
||||
}
|
||||
|
||||
|
||||
function has_jQuery3() {
|
||||
if (!window.jQuery) {
|
||||
return false;
|
||||
}
|
||||
var $version = window.jQuery.fn.jquery;
|
||||
var $major_version = parseInt($version.split(".")[0]);
|
||||
return $major_version >= 3;
|
||||
}
|
||||
|
||||
/*
|
||||
/ Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
|
||||
/ on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
|
||||
/ really means $(setTimeout(fn)).
|
||||
/ https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
|
||||
/
|
||||
/ Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
|
||||
/ one tick later than it did before, which means staticRender() is
|
||||
/ called renderValue() earlier than (advanced) widget authors might be expecting.
|
||||
/ https://github.com/rstudio/shiny/issues/2630
|
||||
/
|
||||
/ For a concrete example, leaflet has some methods (e.g., updateBounds)
|
||||
/ which reference Shiny methods registered in initShiny (e.g., setInputValue).
|
||||
/ Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
|
||||
/ delay execution of those methods (until Shiny methods are ready)
|
||||
/ https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
|
||||
/
|
||||
/ Ideally widget authors wouldn't need to use this setTimeout() hack that
|
||||
/ leaflet uses to call Shiny methods on a staticRender(). In the long run,
|
||||
/ the logic initShiny should be broken up so that method registration happens
|
||||
/ right away, but binding happens later.
|
||||
*/
|
||||
function maybeStaticRenderLater() {
|
||||
if (shinyMode && has_jQuery3()) {
|
||||
window.jQuery(window.HTMLWidgets.staticRender);
|
||||
} else {
|
||||
window.HTMLWidgets.staticRender();
|
||||
}
|
||||
}
|
||||
|
||||
if (document.addEventListener) {
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
|
||||
maybeStaticRenderLater();
|
||||
}, false);
|
||||
} else if (document.attachEvent) {
|
||||
document.attachEvent("onreadystatechange", function() {
|
||||
if (document.readyState === "complete") {
|
||||
document.detachEvent("onreadystatechange", arguments.callee);
|
||||
maybeStaticRenderLater();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
|
||||
// If no key, default to the first item
|
||||
if (typeof(key) === "undefined")
|
||||
key = 1;
|
||||
|
||||
var link = document.getElementById(depname + "-" + key + "-attachment");
|
||||
if (!link) {
|
||||
throw new Error("Attachment " + depname + "/" + key + " not found in document");
|
||||
}
|
||||
return link.getAttribute("href");
|
||||
};
|
||||
|
||||
window.HTMLWidgets.dataframeToD3 = function(df) {
|
||||
var names = [];
|
||||
var length;
|
||||
for (var name in df) {
|
||||
if (df.hasOwnProperty(name))
|
||||
names.push(name);
|
||||
if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
|
||||
throw new Error("All fields must be arrays");
|
||||
} else if (typeof(length) !== "undefined" && length !== df[name].length) {
|
||||
throw new Error("All fields must be arrays of the same length");
|
||||
}
|
||||
length = df[name].length;
|
||||
}
|
||||
var results = [];
|
||||
var item;
|
||||
for (var row = 0; row < length; row++) {
|
||||
item = {};
|
||||
for (var col = 0; col < names.length; col++) {
|
||||
item[names[col]] = df[names[col]][row];
|
||||
}
|
||||
results.push(item);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
window.HTMLWidgets.transposeArray2D = function(array) {
|
||||
if (array.length === 0) return array;
|
||||
var newArray = array[0].map(function(col, i) {
|
||||
return array.map(function(row) {
|
||||
return row[i]
|
||||
})
|
||||
});
|
||||
return newArray;
|
||||
};
|
||||
// Split value at splitChar, but allow splitChar to be escaped
|
||||
// using escapeChar. Any other characters escaped by escapeChar
|
||||
// will be included as usual (including escapeChar itself).
|
||||
function splitWithEscape(value, splitChar, escapeChar) {
|
||||
var results = [];
|
||||
var escapeMode = false;
|
||||
var currentResult = "";
|
||||
for (var pos = 0; pos < value.length; pos++) {
|
||||
if (!escapeMode) {
|
||||
if (value[pos] === splitChar) {
|
||||
results.push(currentResult);
|
||||
currentResult = "";
|
||||
} else if (value[pos] === escapeChar) {
|
||||
escapeMode = true;
|
||||
} else {
|
||||
currentResult += value[pos];
|
||||
}
|
||||
} else {
|
||||
currentResult += value[pos];
|
||||
escapeMode = false;
|
||||
}
|
||||
}
|
||||
if (currentResult !== "") {
|
||||
results.push(currentResult);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
// Function authored by Yihui/JJ Allaire
|
||||
window.HTMLWidgets.evaluateStringMember = function(o, member) {
|
||||
var parts = splitWithEscape(member, '.', '\\');
|
||||
for (var i = 0, l = parts.length; i < l; i++) {
|
||||
var part = parts[i];
|
||||
// part may be a character or 'numeric' member name
|
||||
if (o !== null && typeof o === "object" && part in o) {
|
||||
if (i == (l - 1)) { // if we are at the end of the line then evalulate
|
||||
if (typeof o[part] === "string")
|
||||
o[part] = tryEval(o[part]);
|
||||
} else { // otherwise continue to next embedded object
|
||||
o = o[part];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Retrieve the HTMLWidget instance (i.e. the return value of an
|
||||
// HTMLWidget binding's initialize() or factory() function)
|
||||
// associated with an element, or null if none.
|
||||
window.HTMLWidgets.getInstance = function(el) {
|
||||
return elementData(el, "init_result");
|
||||
};
|
||||
|
||||
// Finds the first element in the scope that matches the selector,
|
||||
// and returns the HTMLWidget instance (i.e. the return value of
|
||||
// an HTMLWidget binding's initialize() or factory() function)
|
||||
// associated with that element, if any. If no element matches the
|
||||
// selector, or the first matching element has no HTMLWidget
|
||||
// instance associated with it, then null is returned.
|
||||
//
|
||||
// The scope argument is optional, and defaults to window.document.
|
||||
window.HTMLWidgets.find = function(scope, selector) {
|
||||
if (arguments.length == 1) {
|
||||
selector = scope;
|
||||
scope = document;
|
||||
}
|
||||
|
||||
var el = scope.querySelector(selector);
|
||||
if (el === null) {
|
||||
return null;
|
||||
} else {
|
||||
return window.HTMLWidgets.getInstance(el);
|
||||
}
|
||||
};
|
||||
|
||||
// Finds all elements in the scope that match the selector, and
|
||||
// returns the HTMLWidget instances (i.e. the return values of
|
||||
// an HTMLWidget binding's initialize() or factory() function)
|
||||
// associated with the elements, in an array. If elements that
|
||||
// match the selector don't have an associated HTMLWidget
|
||||
// instance, the returned array will contain nulls.
|
||||
//
|
||||
// The scope argument is optional, and defaults to window.document.
|
||||
window.HTMLWidgets.findAll = function(scope, selector) {
|
||||
if (arguments.length == 1) {
|
||||
selector = scope;
|
||||
scope = document;
|
||||
}
|
||||
|
||||
var nodes = scope.querySelectorAll(selector);
|
||||
var results = [];
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
results.push(window.HTMLWidgets.getInstance(nodes[i]));
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
var postRenderHandlers = [];
|
||||
function invokePostRenderHandlers() {
|
||||
while (postRenderHandlers.length) {
|
||||
var handler = postRenderHandlers.shift();
|
||||
if (handler) {
|
||||
handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register the given callback function to be invoked after the
|
||||
// next time static widgets are rendered.
|
||||
window.HTMLWidgets.addPostRenderHandler = function(callback) {
|
||||
postRenderHandlers.push(callback);
|
||||
};
|
||||
|
||||
// Takes a new-style instance-bound definition, and returns an
|
||||
// old-style class-bound definition. This saves us from having
|
||||
// to rewrite all the logic in this file to accomodate both
|
||||
// types of definitions.
|
||||
function createLegacyDefinitionAdapter(defn) {
|
||||
var result = {
|
||||
name: defn.name,
|
||||
type: defn.type,
|
||||
initialize: function(el, width, height) {
|
||||
return defn.factory(el, width, height);
|
||||
},
|
||||
renderValue: function(el, x, instance) {
|
||||
return instance.renderValue(x);
|
||||
},
|
||||
resize: function(el, width, height, instance) {
|
||||
return instance.resize(width, height);
|
||||
}
|
||||
};
|
||||
|
||||
if (defn.find)
|
||||
result.find = defn.find;
|
||||
if (defn.renderError)
|
||||
result.renderError = defn.renderError;
|
||||
if (defn.clearError)
|
||||
result.clearError = defn.clearError;
|
||||
|
||||
return result;
|
||||
}
|
||||
})();
|
||||
-10881
File diff suppressed because it is too large
Load Diff
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-9
File diff suppressed because one or more lines are too long
Vendored
-6
File diff suppressed because one or more lines are too long
-236
@@ -1,236 +0,0 @@
|
||||
/* quarto syntax highlight colors */
|
||||
:root {
|
||||
--quarto-hl-ot-color: #003B4F;
|
||||
--quarto-hl-at-color: #657422;
|
||||
--quarto-hl-ss-color: #20794D;
|
||||
--quarto-hl-an-color: #5E5E5E;
|
||||
--quarto-hl-fu-color: #4758AB;
|
||||
--quarto-hl-st-color: #20794D;
|
||||
--quarto-hl-cf-color: #003B4F;
|
||||
--quarto-hl-op-color: #5E5E5E;
|
||||
--quarto-hl-er-color: #AD0000;
|
||||
--quarto-hl-bn-color: #AD0000;
|
||||
--quarto-hl-al-color: #AD0000;
|
||||
--quarto-hl-va-color: #111111;
|
||||
--quarto-hl-bu-color: inherit;
|
||||
--quarto-hl-ex-color: inherit;
|
||||
--quarto-hl-pp-color: #AD0000;
|
||||
--quarto-hl-in-color: #5E5E5E;
|
||||
--quarto-hl-vs-color: #20794D;
|
||||
--quarto-hl-wa-color: #5E5E5E;
|
||||
--quarto-hl-do-color: #5E5E5E;
|
||||
--quarto-hl-im-color: #00769E;
|
||||
--quarto-hl-ch-color: #20794D;
|
||||
--quarto-hl-dt-color: #AD0000;
|
||||
--quarto-hl-fl-color: #AD0000;
|
||||
--quarto-hl-co-color: #5E5E5E;
|
||||
--quarto-hl-cv-color: #5E5E5E;
|
||||
--quarto-hl-cn-color: #8f5902;
|
||||
--quarto-hl-sc-color: #5E5E5E;
|
||||
--quarto-hl-dv-color: #AD0000;
|
||||
--quarto-hl-kw-color: #003B4F;
|
||||
}
|
||||
|
||||
/* other quarto variables */
|
||||
:root {
|
||||
--quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
/* syntax highlight based on Pandoc's rules */
|
||||
pre > code.sourceCode > span {
|
||||
color: #003B4F;
|
||||
}
|
||||
|
||||
code.sourceCode > span {
|
||||
color: #003B4F;
|
||||
}
|
||||
|
||||
div.sourceCode,
|
||||
div.sourceCode pre.sourceCode {
|
||||
color: #003B4F;
|
||||
}
|
||||
|
||||
/* Normal */
|
||||
code span {
|
||||
color: #003B4F;
|
||||
}
|
||||
|
||||
/* Alert */
|
||||
code span.al {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Annotation */
|
||||
code span.an {
|
||||
color: #5E5E5E;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Attribute */
|
||||
code span.at {
|
||||
color: #657422;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* BaseN */
|
||||
code span.bn {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* BuiltIn */
|
||||
code span.bu {
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* ControlFlow */
|
||||
code span.cf {
|
||||
color: #003B4F;
|
||||
font-weight: bold;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Char */
|
||||
code span.ch {
|
||||
color: #20794D;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Constant */
|
||||
code span.cn {
|
||||
color: #8f5902;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Comment */
|
||||
code span.co {
|
||||
color: #5E5E5E;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* CommentVar */
|
||||
code span.cv {
|
||||
color: #5E5E5E;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Documentation */
|
||||
code span.do {
|
||||
color: #5E5E5E;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* DataType */
|
||||
code span.dt {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* DecVal */
|
||||
code span.dv {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Error */
|
||||
code span.er {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Extension */
|
||||
code span.ex {
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Float */
|
||||
code span.fl {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Function */
|
||||
code span.fu {
|
||||
color: #4758AB;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Import */
|
||||
code span.im {
|
||||
color: #00769E;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Information */
|
||||
code span.in {
|
||||
color: #5E5E5E;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Keyword */
|
||||
code span.kw {
|
||||
color: #003B4F;
|
||||
font-weight: bold;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Operator */
|
||||
code span.op {
|
||||
color: #5E5E5E;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Other */
|
||||
code span.ot {
|
||||
color: #003B4F;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Preprocessor */
|
||||
code span.pp {
|
||||
color: #AD0000;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* SpecialChar */
|
||||
code span.sc {
|
||||
color: #5E5E5E;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* SpecialString */
|
||||
code span.ss {
|
||||
color: #20794D;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* String */
|
||||
code span.st {
|
||||
color: #20794D;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Variable */
|
||||
code span.va {
|
||||
color: #111111;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* VerbatimString */
|
||||
code span.vs {
|
||||
color: #20794D;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Warning */
|
||||
code span.wa {
|
||||
color: #5E5E5E;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.prevent-inlining {
|
||||
content: "</";
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=ac89f0bb514bba72461919f78549e31c.css.map */
|
||||
@@ -1,845 +0,0 @@
|
||||
import * as tabsets from "./tabsets/tabsets.js";
|
||||
|
||||
const sectionChanged = new CustomEvent("quarto-sectionChanged", {
|
||||
detail: {},
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
composed: false,
|
||||
});
|
||||
|
||||
const layoutMarginEls = () => {
|
||||
// Find any conflicting margin elements and add margins to the
|
||||
// top to prevent overlap
|
||||
const marginChildren = window.document.querySelectorAll(
|
||||
".column-margin.column-container > *, .margin-caption, .aside"
|
||||
);
|
||||
|
||||
let lastBottom = 0;
|
||||
for (const marginChild of marginChildren) {
|
||||
if (marginChild.offsetParent !== null) {
|
||||
// clear the top margin so we recompute it
|
||||
marginChild.style.marginTop = null;
|
||||
const top = marginChild.getBoundingClientRect().top + window.scrollY;
|
||||
if (top < lastBottom) {
|
||||
const marginChildStyle = window.getComputedStyle(marginChild);
|
||||
const marginBottom = parseFloat(marginChildStyle["marginBottom"]);
|
||||
const margin = lastBottom - top + marginBottom;
|
||||
marginChild.style.marginTop = `${margin}px`;
|
||||
}
|
||||
const styles = window.getComputedStyle(marginChild);
|
||||
const marginTop = parseFloat(styles["marginTop"]);
|
||||
lastBottom = top + marginChild.getBoundingClientRect().height + marginTop;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.document.addEventListener("DOMContentLoaded", function (_event) {
|
||||
// Recompute the position of margin elements anytime the body size changes
|
||||
if (window.ResizeObserver) {
|
||||
const resizeObserver = new window.ResizeObserver(
|
||||
throttle(() => {
|
||||
layoutMarginEls();
|
||||
if (
|
||||
window.document.body.getBoundingClientRect().width < 990 &&
|
||||
isReaderMode()
|
||||
) {
|
||||
quartoToggleReader();
|
||||
}
|
||||
}, 50)
|
||||
);
|
||||
resizeObserver.observe(window.document.body);
|
||||
}
|
||||
|
||||
const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]');
|
||||
const sidebarEl = window.document.getElementById("quarto-sidebar");
|
||||
const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left");
|
||||
const marginSidebarEl = window.document.getElementById(
|
||||
"quarto-margin-sidebar"
|
||||
);
|
||||
// function to determine whether the element has a previous sibling that is active
|
||||
const prevSiblingIsActiveLink = (el) => {
|
||||
const sibling = el.previousElementSibling;
|
||||
if (sibling && sibling.tagName === "A") {
|
||||
return sibling.classList.contains("active");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// dispatch for htmlwidgets
|
||||
// they use slideenter event to trigger resize
|
||||
function fireSlideEnter() {
|
||||
const event = window.document.createEvent("Event");
|
||||
event.initEvent("slideenter", true, true);
|
||||
window.document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]');
|
||||
tabs.forEach((tab) => {
|
||||
tab.addEventListener("shown.bs.tab", fireSlideEnter);
|
||||
});
|
||||
|
||||
// dispatch for shiny
|
||||
// they use BS shown and hidden events to trigger rendering
|
||||
function distpatchShinyEvents(previous, current) {
|
||||
if (window.jQuery) {
|
||||
if (previous) {
|
||||
window.jQuery(previous).trigger("hidden");
|
||||
}
|
||||
if (current) {
|
||||
window.jQuery(current).trigger("shown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tabby.js listener: Trigger event for htmlwidget and shiny
|
||||
document.addEventListener(
|
||||
"tabby",
|
||||
function (event) {
|
||||
fireSlideEnter();
|
||||
distpatchShinyEvents(event.detail.previousTab, event.detail.tab);
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Track scrolling and mark TOC links as active
|
||||
// get table of contents and sidebar (bail if we don't have at least one)
|
||||
const tocLinks = tocEl
|
||||
? [...tocEl.querySelectorAll("a[data-scroll-target]")]
|
||||
: [];
|
||||
const makeActive = (link) => tocLinks[link].classList.add("active");
|
||||
const removeActive = (link) => tocLinks[link].classList.remove("active");
|
||||
const removeAllActive = () =>
|
||||
[...Array(tocLinks.length).keys()].forEach((link) => removeActive(link));
|
||||
|
||||
// activate the anchor for a section associated with this TOC entry
|
||||
tocLinks.forEach((link) => {
|
||||
link.addEventListener("click", () => {
|
||||
if (link.href.indexOf("#") !== -1) {
|
||||
const anchor = link.href.split("#")[1];
|
||||
const heading = window.document.querySelector(
|
||||
`[data-anchor-id="${anchor}"]`
|
||||
);
|
||||
if (heading) {
|
||||
// Add the class
|
||||
heading.classList.add("reveal-anchorjs-link");
|
||||
|
||||
// function to show the anchor
|
||||
const handleMouseout = () => {
|
||||
heading.classList.remove("reveal-anchorjs-link");
|
||||
heading.removeEventListener("mouseout", handleMouseout);
|
||||
};
|
||||
|
||||
// add a function to clear the anchor when the user mouses out of it
|
||||
heading.addEventListener("mouseout", handleMouseout);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const sections = tocLinks.map((link) => {
|
||||
const target = link.getAttribute("data-scroll-target");
|
||||
if (target.startsWith("#")) {
|
||||
return window.document.getElementById(decodeURI(`${target.slice(1)}`));
|
||||
} else {
|
||||
return window.document.querySelector(decodeURI(`${target}`));
|
||||
}
|
||||
});
|
||||
|
||||
const sectionMargin = 200;
|
||||
let currentActive = 0;
|
||||
// track whether we've initialized state the first time
|
||||
let init = false;
|
||||
|
||||
const updateActiveLink = () => {
|
||||
// The index from bottom to top (e.g. reversed list)
|
||||
let sectionIndex = -1;
|
||||
if (
|
||||
window.innerHeight + window.pageYOffset >=
|
||||
window.document.body.offsetHeight
|
||||
) {
|
||||
// This is the no-scroll case where last section should be the active one
|
||||
sectionIndex = 0;
|
||||
} else {
|
||||
// This finds the last section visible on screen that should be made active
|
||||
sectionIndex = [...sections].reverse().findIndex((section) => {
|
||||
if (section) {
|
||||
return window.pageYOffset >= section.offsetTop - sectionMargin;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (sectionIndex > -1) {
|
||||
const current = sections.length - sectionIndex - 1;
|
||||
if (current !== currentActive) {
|
||||
removeAllActive();
|
||||
currentActive = current;
|
||||
makeActive(current);
|
||||
if (init) {
|
||||
window.dispatchEvent(sectionChanged);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const inHiddenRegion = (top, bottom, hiddenRegions) => {
|
||||
for (const region of hiddenRegions) {
|
||||
if (top <= region.bottom && bottom >= region.top) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const categorySelector = "header.quarto-title-block .quarto-category";
|
||||
const activateCategories = (href) => {
|
||||
// Find any categories
|
||||
// Surround them with a link pointing back to:
|
||||
// #category=Authoring
|
||||
try {
|
||||
const categoryEls = window.document.querySelectorAll(categorySelector);
|
||||
for (const categoryEl of categoryEls) {
|
||||
const categoryText = categoryEl.textContent;
|
||||
if (categoryText) {
|
||||
const link = `${href}#category=${encodeURIComponent(categoryText)}`;
|
||||
const linkEl = window.document.createElement("a");
|
||||
linkEl.setAttribute("href", link);
|
||||
for (const child of categoryEl.childNodes) {
|
||||
linkEl.append(child);
|
||||
}
|
||||
categoryEl.appendChild(linkEl);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors
|
||||
}
|
||||
};
|
||||
function hasTitleCategories() {
|
||||
return window.document.querySelector(categorySelector) !== null;
|
||||
}
|
||||
|
||||
function offsetRelativeUrl(url) {
|
||||
const offset = getMeta("quarto:offset");
|
||||
return offset ? offset + url : url;
|
||||
}
|
||||
|
||||
function offsetAbsoluteUrl(url) {
|
||||
const offset = getMeta("quarto:offset");
|
||||
const baseUrl = new URL(offset, window.location);
|
||||
|
||||
const projRelativeUrl = url.replace(baseUrl, "");
|
||||
if (projRelativeUrl.startsWith("/")) {
|
||||
return projRelativeUrl;
|
||||
} else {
|
||||
return "/" + projRelativeUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// read a meta tag value
|
||||
function getMeta(metaName) {
|
||||
const metas = window.document.getElementsByTagName("meta");
|
||||
for (let i = 0; i < metas.length; i++) {
|
||||
if (metas[i].getAttribute("name") === metaName) {
|
||||
return metas[i].getAttribute("content");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
async function findAndActivateCategories() {
|
||||
// Categories search with listing only use path without query
|
||||
const currentPagePath = offsetAbsoluteUrl(
|
||||
window.location.origin + window.location.pathname
|
||||
);
|
||||
const response = await fetch(offsetRelativeUrl("listings.json"));
|
||||
if (response.status == 200) {
|
||||
return response.json().then(function (listingPaths) {
|
||||
const listingHrefs = [];
|
||||
for (const listingPath of listingPaths) {
|
||||
const pathWithoutLeadingSlash = listingPath.listing.substring(1);
|
||||
for (const item of listingPath.items) {
|
||||
const encodedItem = encodeURI(item);
|
||||
if (
|
||||
encodedItem === currentPagePath ||
|
||||
encodedItem === currentPagePath + "index.html"
|
||||
) {
|
||||
// Resolve this path against the offset to be sure
|
||||
// we already are using the correct path to the listing
|
||||
// (this adjusts the listing urls to be rooted against
|
||||
// whatever root the page is actually running against)
|
||||
const relative = offsetRelativeUrl(pathWithoutLeadingSlash);
|
||||
const baseUrl = window.location;
|
||||
const resolvedPath = new URL(relative, baseUrl);
|
||||
listingHrefs.push(resolvedPath.pathname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the tree for a nearby linting and use that if we find one
|
||||
const nearestListing = findNearestParentListing(
|
||||
offsetAbsoluteUrl(window.location.pathname),
|
||||
listingHrefs
|
||||
);
|
||||
if (nearestListing) {
|
||||
activateCategories(nearestListing);
|
||||
} else {
|
||||
// See if the referrer is a listing page for this item
|
||||
const referredRelativePath = offsetAbsoluteUrl(document.referrer);
|
||||
const referrerListing = listingHrefs.find((listingHref) => {
|
||||
const isListingReferrer =
|
||||
listingHref === referredRelativePath ||
|
||||
listingHref === referredRelativePath + "index.html";
|
||||
return isListingReferrer;
|
||||
});
|
||||
|
||||
if (referrerListing) {
|
||||
// Try to use the referrer if possible
|
||||
activateCategories(referrerListing);
|
||||
} else if (listingHrefs.length > 0) {
|
||||
// Otherwise, just fall back to the first listing
|
||||
activateCategories(listingHrefs[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (hasTitleCategories()) {
|
||||
findAndActivateCategories();
|
||||
}
|
||||
|
||||
const findNearestParentListing = (href, listingHrefs) => {
|
||||
if (!href || !listingHrefs) {
|
||||
return undefined;
|
||||
}
|
||||
// Look up the tree for a nearby linting and use that if we find one
|
||||
const relativeParts = href.substring(1).split("/");
|
||||
while (relativeParts.length > 0) {
|
||||
const path = relativeParts.join("/");
|
||||
for (const listingHref of listingHrefs) {
|
||||
if (listingHref.startsWith(path)) {
|
||||
return listingHref;
|
||||
}
|
||||
}
|
||||
relativeParts.pop();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const manageSidebarVisiblity = (el, placeholderDescriptor) => {
|
||||
let isVisible = true;
|
||||
let elRect;
|
||||
|
||||
return (hiddenRegions) => {
|
||||
if (el === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the last element of the TOC
|
||||
const lastChildEl = el.lastElementChild;
|
||||
|
||||
if (lastChildEl) {
|
||||
// Converts the sidebar to a menu
|
||||
const convertToMenu = () => {
|
||||
for (const child of el.children) {
|
||||
child.style.opacity = 0;
|
||||
child.style.overflow = "hidden";
|
||||
child.style.pointerEvents = "none";
|
||||
}
|
||||
|
||||
nexttick(() => {
|
||||
const toggleContainer = window.document.createElement("div");
|
||||
toggleContainer.style.width = "100%";
|
||||
toggleContainer.classList.add("zindex-over-content");
|
||||
toggleContainer.classList.add("quarto-sidebar-toggle");
|
||||
toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom
|
||||
toggleContainer.id = placeholderDescriptor.id;
|
||||
toggleContainer.style.position = "fixed";
|
||||
|
||||
const toggleIcon = window.document.createElement("i");
|
||||
toggleIcon.classList.add("quarto-sidebar-toggle-icon");
|
||||
toggleIcon.classList.add("bi");
|
||||
toggleIcon.classList.add("bi-caret-down-fill");
|
||||
|
||||
const toggleTitle = window.document.createElement("div");
|
||||
const titleEl = window.document.body.querySelector(
|
||||
placeholderDescriptor.titleSelector
|
||||
);
|
||||
if (titleEl) {
|
||||
toggleTitle.append(
|
||||
titleEl.textContent || titleEl.innerText,
|
||||
toggleIcon
|
||||
);
|
||||
}
|
||||
toggleTitle.classList.add("zindex-over-content");
|
||||
toggleTitle.classList.add("quarto-sidebar-toggle-title");
|
||||
toggleContainer.append(toggleTitle);
|
||||
|
||||
const toggleContents = window.document.createElement("div");
|
||||
toggleContents.classList = el.classList;
|
||||
toggleContents.classList.add("zindex-over-content");
|
||||
toggleContents.classList.add("quarto-sidebar-toggle-contents");
|
||||
for (const child of el.children) {
|
||||
if (child.id === "toc-title") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const clone = child.cloneNode(true);
|
||||
clone.style.opacity = 1;
|
||||
clone.style.pointerEvents = null;
|
||||
clone.style.display = null;
|
||||
toggleContents.append(clone);
|
||||
}
|
||||
toggleContents.style.height = "0px";
|
||||
const positionToggle = () => {
|
||||
// position the element (top left of parent, same width as parent)
|
||||
if (!elRect) {
|
||||
elRect = el.getBoundingClientRect();
|
||||
}
|
||||
toggleContainer.style.left = `${elRect.left}px`;
|
||||
toggleContainer.style.top = `${elRect.top}px`;
|
||||
toggleContainer.style.width = `${elRect.width}px`;
|
||||
};
|
||||
positionToggle();
|
||||
|
||||
toggleContainer.append(toggleContents);
|
||||
el.parentElement.prepend(toggleContainer);
|
||||
|
||||
// Process clicks
|
||||
let tocShowing = false;
|
||||
// Allow the caller to control whether this is dismissed
|
||||
// when it is clicked (e.g. sidebar navigation supports
|
||||
// opening and closing the nav tree, so don't dismiss on click)
|
||||
const clickEl = placeholderDescriptor.dismissOnClick
|
||||
? toggleContainer
|
||||
: toggleTitle;
|
||||
|
||||
const closeToggle = () => {
|
||||
if (tocShowing) {
|
||||
toggleContainer.classList.remove("expanded");
|
||||
toggleContents.style.height = "0px";
|
||||
tocShowing = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Get rid of any expanded toggle if the user scrolls
|
||||
window.document.addEventListener(
|
||||
"scroll",
|
||||
throttle(() => {
|
||||
closeToggle();
|
||||
}, 50)
|
||||
);
|
||||
|
||||
// Handle positioning of the toggle
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
elRect = undefined;
|
||||
positionToggle();
|
||||
}, 50)
|
||||
);
|
||||
|
||||
window.addEventListener("quarto-hrChanged", () => {
|
||||
elRect = undefined;
|
||||
});
|
||||
|
||||
// Process the click
|
||||
clickEl.onclick = () => {
|
||||
if (!tocShowing) {
|
||||
toggleContainer.classList.add("expanded");
|
||||
toggleContents.style.height = null;
|
||||
tocShowing = true;
|
||||
} else {
|
||||
closeToggle();
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// Converts a sidebar from a menu back to a sidebar
|
||||
const convertToSidebar = () => {
|
||||
for (const child of el.children) {
|
||||
child.style.opacity = 1;
|
||||
child.style.overflow = null;
|
||||
child.style.pointerEvents = null;
|
||||
}
|
||||
|
||||
const placeholderEl = window.document.getElementById(
|
||||
placeholderDescriptor.id
|
||||
);
|
||||
if (placeholderEl) {
|
||||
placeholderEl.remove();
|
||||
}
|
||||
|
||||
el.classList.remove("rollup");
|
||||
};
|
||||
|
||||
if (isReaderMode()) {
|
||||
convertToMenu();
|
||||
isVisible = false;
|
||||
} else {
|
||||
// Find the top and bottom o the element that is being managed
|
||||
const elTop = el.offsetTop;
|
||||
const elBottom =
|
||||
elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight;
|
||||
|
||||
if (!isVisible) {
|
||||
// If the element is current not visible reveal if there are
|
||||
// no conflicts with overlay regions
|
||||
if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) {
|
||||
convertToSidebar();
|
||||
isVisible = true;
|
||||
}
|
||||
} else {
|
||||
// If the element is visible, hide it if it conflicts with overlay regions
|
||||
// and insert a placeholder toggle (or if we're in reader mode)
|
||||
if (inHiddenRegion(elTop, elBottom, hiddenRegions)) {
|
||||
convertToMenu();
|
||||
isVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]');
|
||||
for (const tabEl of tabEls) {
|
||||
const id = tabEl.getAttribute("data-bs-target");
|
||||
if (id) {
|
||||
const columnEl = document.querySelector(
|
||||
`${id} .column-margin, .tabset-margin-content`
|
||||
);
|
||||
if (columnEl)
|
||||
tabEl.addEventListener("shown.bs.tab", function (event) {
|
||||
const el = event.srcElement;
|
||||
if (el) {
|
||||
const visibleCls = `${el.id}-margin-content`;
|
||||
// walk up until we find a parent tabset
|
||||
let panelTabsetEl = el.parentElement;
|
||||
while (panelTabsetEl) {
|
||||
if (panelTabsetEl.classList.contains("panel-tabset")) {
|
||||
break;
|
||||
}
|
||||
panelTabsetEl = panelTabsetEl.parentElement;
|
||||
}
|
||||
|
||||
if (panelTabsetEl) {
|
||||
const prevSib = panelTabsetEl.previousElementSibling;
|
||||
if (
|
||||
prevSib &&
|
||||
prevSib.classList.contains("tabset-margin-container")
|
||||
) {
|
||||
const childNodes = prevSib.querySelectorAll(
|
||||
".tabset-margin-content"
|
||||
);
|
||||
for (const childEl of childNodes) {
|
||||
if (childEl.classList.contains(visibleCls)) {
|
||||
childEl.classList.remove("collapse");
|
||||
} else {
|
||||
childEl.classList.add("collapse");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layoutMarginEls();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Manage the visibility of the toc and the sidebar
|
||||
const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, {
|
||||
id: "quarto-toc-toggle",
|
||||
titleSelector: "#toc-title",
|
||||
dismissOnClick: true,
|
||||
});
|
||||
const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, {
|
||||
id: "quarto-sidebarnav-toggle",
|
||||
titleSelector: ".title",
|
||||
dismissOnClick: false,
|
||||
});
|
||||
let tocLeftScrollVisibility;
|
||||
if (leftTocEl) {
|
||||
tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, {
|
||||
id: "quarto-lefttoc-toggle",
|
||||
titleSelector: "#toc-title",
|
||||
dismissOnClick: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Find the first element that uses formatting in special columns
|
||||
const conflictingEls = window.document.body.querySelectorAll(
|
||||
'[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]'
|
||||
);
|
||||
|
||||
// Filter all the possibly conflicting elements into ones
|
||||
// the do conflict on the left or ride side
|
||||
const arrConflictingEls = Array.from(conflictingEls);
|
||||
const leftSideConflictEls = arrConflictingEls.filter((el) => {
|
||||
if (el.tagName === "ASIDE") {
|
||||
return false;
|
||||
}
|
||||
return Array.from(el.classList).find((className) => {
|
||||
return (
|
||||
className !== "column-body" &&
|
||||
className.startsWith("column-") &&
|
||||
!className.endsWith("right") &&
|
||||
!className.endsWith("container") &&
|
||||
className !== "column-margin"
|
||||
);
|
||||
});
|
||||
});
|
||||
const rightSideConflictEls = arrConflictingEls.filter((el) => {
|
||||
if (el.tagName === "ASIDE") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const hasMarginCaption = Array.from(el.classList).find((className) => {
|
||||
return className == "margin-caption";
|
||||
});
|
||||
if (hasMarginCaption) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Array.from(el.classList).find((className) => {
|
||||
return (
|
||||
className !== "column-body" &&
|
||||
!className.endsWith("container") &&
|
||||
className.startsWith("column-") &&
|
||||
!className.endsWith("left")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const kOverlapPaddingSize = 10;
|
||||
function toRegions(els) {
|
||||
return els.map((el) => {
|
||||
const boundRect = el.getBoundingClientRect();
|
||||
const top =
|
||||
boundRect.top +
|
||||
document.documentElement.scrollTop -
|
||||
kOverlapPaddingSize;
|
||||
return {
|
||||
top,
|
||||
bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
let hasObserved = false;
|
||||
const visibleItemObserver = (els) => {
|
||||
let visibleElements = [...els];
|
||||
const intersectionObserver = new IntersectionObserver(
|
||||
(entries, _observer) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
if (visibleElements.indexOf(entry.target) === -1) {
|
||||
visibleElements.push(entry.target);
|
||||
}
|
||||
} else {
|
||||
visibleElements = visibleElements.filter((visibleEntry) => {
|
||||
return visibleEntry !== entry;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasObserved) {
|
||||
hideOverlappedSidebars();
|
||||
}
|
||||
hasObserved = true;
|
||||
},
|
||||
{}
|
||||
);
|
||||
els.forEach((el) => {
|
||||
intersectionObserver.observe(el);
|
||||
});
|
||||
|
||||
return {
|
||||
getVisibleEntries: () => {
|
||||
return visibleElements;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const rightElementObserver = visibleItemObserver(rightSideConflictEls);
|
||||
const leftElementObserver = visibleItemObserver(leftSideConflictEls);
|
||||
|
||||
const hideOverlappedSidebars = () => {
|
||||
marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries()));
|
||||
sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries()));
|
||||
if (tocLeftScrollVisibility) {
|
||||
tocLeftScrollVisibility(
|
||||
toRegions(leftElementObserver.getVisibleEntries())
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.quartoToggleReader = () => {
|
||||
// Applies a slow class (or removes it)
|
||||
// to update the transition speed
|
||||
const slowTransition = (slow) => {
|
||||
const manageTransition = (id, slow) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) {
|
||||
if (slow) {
|
||||
el.classList.add("slow");
|
||||
} else {
|
||||
el.classList.remove("slow");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
manageTransition("TOC", slow);
|
||||
manageTransition("quarto-sidebar", slow);
|
||||
};
|
||||
const readerMode = !isReaderMode();
|
||||
setReaderModeValue(readerMode);
|
||||
|
||||
// If we're entering reader mode, slow the transition
|
||||
if (readerMode) {
|
||||
slowTransition(readerMode);
|
||||
}
|
||||
highlightReaderToggle(readerMode);
|
||||
hideOverlappedSidebars();
|
||||
|
||||
// If we're exiting reader mode, restore the non-slow transition
|
||||
if (!readerMode) {
|
||||
slowTransition(!readerMode);
|
||||
}
|
||||
};
|
||||
|
||||
const highlightReaderToggle = (readerMode) => {
|
||||
const els = document.querySelectorAll(".quarto-reader-toggle");
|
||||
if (els) {
|
||||
els.forEach((el) => {
|
||||
if (readerMode) {
|
||||
el.classList.add("reader");
|
||||
} else {
|
||||
el.classList.remove("reader");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const setReaderModeValue = (val) => {
|
||||
if (window.location.protocol !== "file:") {
|
||||
window.localStorage.setItem("quarto-reader-mode", val);
|
||||
} else {
|
||||
localReaderMode = val;
|
||||
}
|
||||
};
|
||||
|
||||
const isReaderMode = () => {
|
||||
if (window.location.protocol !== "file:") {
|
||||
return window.localStorage.getItem("quarto-reader-mode") === "true";
|
||||
} else {
|
||||
return localReaderMode;
|
||||
}
|
||||
};
|
||||
let localReaderMode = null;
|
||||
|
||||
const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded");
|
||||
const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1;
|
||||
|
||||
// Walk the TOC and collapse/expand nodes
|
||||
// Nodes are expanded if:
|
||||
// - they are top level
|
||||
// - they have children that are 'active' links
|
||||
// - they are directly below an link that is 'active'
|
||||
const walk = (el, depth) => {
|
||||
// Tick depth when we enter a UL
|
||||
if (el.tagName === "UL") {
|
||||
depth = depth + 1;
|
||||
}
|
||||
|
||||
// It this is active link
|
||||
let isActiveNode = false;
|
||||
if (el.tagName === "A" && el.classList.contains("active")) {
|
||||
isActiveNode = true;
|
||||
}
|
||||
|
||||
// See if there is an active child to this element
|
||||
let hasActiveChild = false;
|
||||
for (const child of el.children) {
|
||||
hasActiveChild = walk(child, depth) || hasActiveChild;
|
||||
}
|
||||
|
||||
// Process the collapse state if this is an UL
|
||||
if (el.tagName === "UL") {
|
||||
if (tocOpenDepth === -1 && depth > 1) {
|
||||
// toc-expand: false
|
||||
el.classList.add("collapse");
|
||||
} else if (
|
||||
depth <= tocOpenDepth ||
|
||||
hasActiveChild ||
|
||||
prevSiblingIsActiveLink(el)
|
||||
) {
|
||||
el.classList.remove("collapse");
|
||||
} else {
|
||||
el.classList.add("collapse");
|
||||
}
|
||||
|
||||
// untick depth when we leave a UL
|
||||
depth = depth - 1;
|
||||
}
|
||||
return hasActiveChild || isActiveNode;
|
||||
};
|
||||
|
||||
// walk the TOC and expand / collapse any items that should be shown
|
||||
if (tocEl) {
|
||||
updateActiveLink();
|
||||
walk(tocEl, 0);
|
||||
}
|
||||
|
||||
// Throttle the scroll event and walk peridiocally
|
||||
window.document.addEventListener(
|
||||
"scroll",
|
||||
throttle(() => {
|
||||
if (tocEl) {
|
||||
updateActiveLink();
|
||||
walk(tocEl, 0);
|
||||
}
|
||||
if (!isReaderMode()) {
|
||||
hideOverlappedSidebars();
|
||||
}
|
||||
}, 5)
|
||||
);
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
if (tocEl) {
|
||||
updateActiveLink();
|
||||
walk(tocEl, 0);
|
||||
}
|
||||
if (!isReaderMode()) {
|
||||
hideOverlappedSidebars();
|
||||
}
|
||||
}, 10)
|
||||
);
|
||||
hideOverlappedSidebars();
|
||||
highlightReaderToggle(isReaderMode());
|
||||
});
|
||||
|
||||
tabsets.init();
|
||||
|
||||
function throttle(func, wait) {
|
||||
let waiting = false;
|
||||
return function () {
|
||||
if (!waiting) {
|
||||
func.apply(this, arguments);
|
||||
waiting = true;
|
||||
setTimeout(function () {
|
||||
waiting = false;
|
||||
}, wait);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function nexttick(func) {
|
||||
return setTimeout(func, 0);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
// grouped tabsets
|
||||
|
||||
export function init() {
|
||||
window.addEventListener("pageshow", (_event) => {
|
||||
function getTabSettings() {
|
||||
const data = localStorage.getItem("quarto-persistent-tabsets-data");
|
||||
if (!data) {
|
||||
localStorage.setItem("quarto-persistent-tabsets-data", "{}");
|
||||
return {};
|
||||
}
|
||||
if (data) {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
function setTabSettings(data) {
|
||||
localStorage.setItem(
|
||||
"quarto-persistent-tabsets-data",
|
||||
JSON.stringify(data)
|
||||
);
|
||||
}
|
||||
|
||||
function setTabState(groupName, groupValue) {
|
||||
const data = getTabSettings();
|
||||
data[groupName] = groupValue;
|
||||
setTabSettings(data);
|
||||
}
|
||||
|
||||
function toggleTab(tab, active) {
|
||||
const tabPanelId = tab.getAttribute("aria-controls");
|
||||
const tabPanel = document.getElementById(tabPanelId);
|
||||
if (active) {
|
||||
tab.classList.add("active");
|
||||
tabPanel.classList.add("active");
|
||||
} else {
|
||||
tab.classList.remove("active");
|
||||
tabPanel.classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAll(selectedGroup, selectorsToSync) {
|
||||
for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) {
|
||||
const active = selectedGroup === thisGroup;
|
||||
for (const tab of tabs) {
|
||||
toggleTab(tab, active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findSelectorsToSyncByLanguage() {
|
||||
const result = {};
|
||||
const tabs = Array.from(
|
||||
document.querySelectorAll(`div[data-group] a[id^='tabset-']`)
|
||||
);
|
||||
for (const item of tabs) {
|
||||
const div = item.parentElement.parentElement.parentElement;
|
||||
const group = div.getAttribute("data-group");
|
||||
if (!result[group]) {
|
||||
result[group] = {};
|
||||
}
|
||||
const selectorsToSync = result[group];
|
||||
const value = item.innerHTML;
|
||||
if (!selectorsToSync[value]) {
|
||||
selectorsToSync[value] = [];
|
||||
}
|
||||
selectorsToSync[value].push(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function setupSelectorSync() {
|
||||
const selectorsToSync = findSelectorsToSyncByLanguage();
|
||||
Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => {
|
||||
Object.entries(tabSetsByValue).forEach(([value, items]) => {
|
||||
items.forEach((item) => {
|
||||
item.addEventListener("click", (_event) => {
|
||||
setTabState(group, value);
|
||||
toggleAll(value, selectorsToSync[group]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return selectorsToSync;
|
||||
}
|
||||
|
||||
const selectorsToSync = setupSelectorSync();
|
||||
for (const [group, selectedName] of Object.entries(getTabSettings())) {
|
||||
const selectors = selectorsToSync[group];
|
||||
// it's possible that stale state gives us empty selections, so we explicitly check here.
|
||||
if (selectors) {
|
||||
toggleAll(selectedName, selectors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}
|
||||
-2
File diff suppressed because one or more lines are too long
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
/*!
|
||||
* headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it
|
||||
* Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=l<t?"down":"up",a.distance=Math.abs(t-l),a.isOutOfBounds=t<0||o<t+n,a.top=t<=s.offset[a.direction],a.bottom=o<=t+n,a.toleranceExceeded=a.distance>s.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s});
|
||||
@@ -1,325 +0,0 @@
|
||||
const headroomChanged = new CustomEvent("quarto-hrChanged", {
|
||||
detail: {},
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
composed: false,
|
||||
});
|
||||
|
||||
const announceDismiss = () => {
|
||||
const annEl = window.document.getElementById("quarto-announcement");
|
||||
if (annEl) {
|
||||
annEl.remove();
|
||||
|
||||
const annId = annEl.getAttribute("data-announcement-id");
|
||||
window.localStorage.setItem(`quarto-announce-${annId}`, "true");
|
||||
}
|
||||
};
|
||||
|
||||
const announceRegister = () => {
|
||||
const annEl = window.document.getElementById("quarto-announcement");
|
||||
if (annEl) {
|
||||
const annId = annEl.getAttribute("data-announcement-id");
|
||||
const isDismissed =
|
||||
window.localStorage.getItem(`quarto-announce-${annId}`) || false;
|
||||
if (isDismissed) {
|
||||
announceDismiss();
|
||||
return;
|
||||
} else {
|
||||
annEl.classList.remove("hidden");
|
||||
}
|
||||
|
||||
const actionEl = annEl.querySelector(".quarto-announcement-action");
|
||||
if (actionEl) {
|
||||
actionEl.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
// Hide the bar immediately
|
||||
announceDismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.document.addEventListener("DOMContentLoaded", function () {
|
||||
let init = false;
|
||||
|
||||
announceRegister();
|
||||
|
||||
// Manage the back to top button, if one is present.
|
||||
let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const scrollDownBuffer = 5;
|
||||
const scrollUpBuffer = 35;
|
||||
const btn = document.getElementById("quarto-back-to-top");
|
||||
const hideBackToTop = () => {
|
||||
btn.style.display = "none";
|
||||
};
|
||||
const showBackToTop = () => {
|
||||
btn.style.display = "inline-block";
|
||||
};
|
||||
if (btn) {
|
||||
window.document.addEventListener(
|
||||
"scroll",
|
||||
function () {
|
||||
const currentScrollTop =
|
||||
window.pageYOffset || document.documentElement.scrollTop;
|
||||
|
||||
// Shows and hides the button 'intelligently' as the user scrolls
|
||||
if (currentScrollTop - scrollDownBuffer > lastScrollTop) {
|
||||
hideBackToTop();
|
||||
lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop;
|
||||
} else if (currentScrollTop < lastScrollTop - scrollUpBuffer) {
|
||||
showBackToTop();
|
||||
lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop;
|
||||
}
|
||||
|
||||
// Show the button at the bottom, hides it at the top
|
||||
if (currentScrollTop <= 0) {
|
||||
hideBackToTop();
|
||||
} else if (
|
||||
window.innerHeight + currentScrollTop >=
|
||||
document.body.offsetHeight
|
||||
) {
|
||||
showBackToTop();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
function throttle(func, wait) {
|
||||
var timeout;
|
||||
return function () {
|
||||
const context = this;
|
||||
const args = arguments;
|
||||
const later = function () {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
func.apply(context, args);
|
||||
};
|
||||
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(later, wait);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function headerOffset() {
|
||||
// Set an offset if there is are fixed top navbar
|
||||
const headerEl = window.document.querySelector("header.fixed-top");
|
||||
if (headerEl) {
|
||||
return headerEl.clientHeight;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function footerOffset() {
|
||||
const footerEl = window.document.querySelector("footer.footer");
|
||||
if (footerEl) {
|
||||
return footerEl.clientHeight;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function dashboardOffset() {
|
||||
const dashboardNavEl = window.document.getElementById(
|
||||
"quarto-dashboard-header"
|
||||
);
|
||||
if (dashboardNavEl !== null) {
|
||||
return dashboardNavEl.clientHeight;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function updateDocumentOffsetWithoutAnimation() {
|
||||
updateDocumentOffset(false);
|
||||
}
|
||||
|
||||
function updateDocumentOffset(animated) {
|
||||
// set body offset
|
||||
const topOffset = headerOffset();
|
||||
const bodyOffset = topOffset + footerOffset() + dashboardOffset();
|
||||
const bodyEl = window.document.body;
|
||||
bodyEl.setAttribute("data-bs-offset", topOffset);
|
||||
bodyEl.style.paddingTop = topOffset + "px";
|
||||
|
||||
// deal with sidebar offsets
|
||||
const sidebars = window.document.querySelectorAll(
|
||||
".sidebar, .headroom-target"
|
||||
);
|
||||
sidebars.forEach((sidebar) => {
|
||||
if (!animated) {
|
||||
sidebar.classList.add("notransition");
|
||||
// Remove the no transition class after the animation has time to complete
|
||||
setTimeout(function () {
|
||||
sidebar.classList.remove("notransition");
|
||||
}, 201);
|
||||
}
|
||||
|
||||
if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) {
|
||||
sidebar.style.top = "0";
|
||||
sidebar.style.maxHeight = "100vh";
|
||||
} else {
|
||||
sidebar.style.top = topOffset + "px";
|
||||
sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)";
|
||||
}
|
||||
});
|
||||
|
||||
// allow space for footer
|
||||
const mainContainer = window.document.querySelector(".quarto-container");
|
||||
if (mainContainer) {
|
||||
mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)";
|
||||
}
|
||||
|
||||
// link offset
|
||||
let linkStyle = window.document.querySelector("#quarto-target-style");
|
||||
if (!linkStyle) {
|
||||
linkStyle = window.document.createElement("style");
|
||||
linkStyle.setAttribute("id", "quarto-target-style");
|
||||
window.document.head.appendChild(linkStyle);
|
||||
}
|
||||
while (linkStyle.firstChild) {
|
||||
linkStyle.removeChild(linkStyle.firstChild);
|
||||
}
|
||||
if (topOffset > 0) {
|
||||
linkStyle.appendChild(
|
||||
window.document.createTextNode(`
|
||||
section:target::before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: ${topOffset}px;
|
||||
margin: -${topOffset}px 0 0;
|
||||
}`)
|
||||
);
|
||||
}
|
||||
if (init) {
|
||||
window.dispatchEvent(headroomChanged);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
|
||||
// initialize headroom
|
||||
var header = window.document.querySelector("#quarto-header");
|
||||
if (header && window.Headroom) {
|
||||
const headroom = new window.Headroom(header, {
|
||||
tolerance: 5,
|
||||
onPin: function () {
|
||||
const sidebars = window.document.querySelectorAll(
|
||||
".sidebar, .headroom-target"
|
||||
);
|
||||
sidebars.forEach((sidebar) => {
|
||||
sidebar.classList.remove("sidebar-unpinned");
|
||||
});
|
||||
updateDocumentOffset();
|
||||
},
|
||||
onUnpin: function () {
|
||||
const sidebars = window.document.querySelectorAll(
|
||||
".sidebar, .headroom-target"
|
||||
);
|
||||
sidebars.forEach((sidebar) => {
|
||||
sidebar.classList.add("sidebar-unpinned");
|
||||
});
|
||||
updateDocumentOffset();
|
||||
},
|
||||
});
|
||||
headroom.init();
|
||||
|
||||
let frozen = false;
|
||||
window.quartoToggleHeadroom = function () {
|
||||
if (frozen) {
|
||||
headroom.unfreeze();
|
||||
frozen = false;
|
||||
} else {
|
||||
headroom.freeze();
|
||||
frozen = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.addEventListener(
|
||||
"hashchange",
|
||||
function (e) {
|
||||
if (
|
||||
getComputedStyle(document.documentElement).scrollBehavior !== "smooth"
|
||||
) {
|
||||
window.scrollTo(0, window.pageYOffset - headerOffset());
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Observe size changed for the header
|
||||
const headerEl = window.document.querySelector("header.fixed-top");
|
||||
if (headerEl && window.ResizeObserver) {
|
||||
const observer = new window.ResizeObserver(() => {
|
||||
setTimeout(updateDocumentOffsetWithoutAnimation, 0);
|
||||
});
|
||||
observer.observe(headerEl, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
});
|
||||
} else {
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(updateDocumentOffsetWithoutAnimation, 50)
|
||||
);
|
||||
}
|
||||
setTimeout(updateDocumentOffsetWithoutAnimation, 250);
|
||||
|
||||
// fixup index.html links if we aren't on the filesystem
|
||||
if (window.location.protocol !== "file:") {
|
||||
const links = window.document.querySelectorAll("a");
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
if (links[i].href) {
|
||||
links[i].dataset.originalHref = links[i].href;
|
||||
links[i].href = links[i].href.replace(/\/index\.html/, "/");
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup any sharing links that require urls
|
||||
// Append url to any sharing urls
|
||||
const sharingLinks = window.document.querySelectorAll(
|
||||
"a.sidebar-tools-main-item, a.quarto-navigation-tool, a.quarto-navbar-tools, a.quarto-navbar-tools-item"
|
||||
);
|
||||
for (let i = 0; i < sharingLinks.length; i++) {
|
||||
const sharingLink = sharingLinks[i];
|
||||
const href = sharingLink.getAttribute("href");
|
||||
if (href) {
|
||||
sharingLink.setAttribute(
|
||||
"href",
|
||||
href.replace("|url|", window.location.href)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll the active navigation item into view, if necessary
|
||||
const navSidebar = window.document.querySelector("nav#quarto-sidebar");
|
||||
if (navSidebar) {
|
||||
// Find the active item
|
||||
const activeItem = navSidebar.querySelector("li.sidebar-item a.active");
|
||||
if (activeItem) {
|
||||
// Wait for the scroll height and height to resolve by observing size changes on the
|
||||
// nav element that is scrollable
|
||||
const resizeObserver = new ResizeObserver((_entries) => {
|
||||
// The bottom of the element
|
||||
const elBottom = activeItem.offsetTop;
|
||||
const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight;
|
||||
|
||||
// The element height and scroll height are the same, then we are still loading
|
||||
if (viewBottom !== navSidebar.scrollHeight) {
|
||||
// Determine if the item isn't visible and scroll to it
|
||||
if (elBottom >= viewBottom) {
|
||||
navSidebar.scrollTop = elBottom;
|
||||
}
|
||||
|
||||
// stop observing now since we've completed the scroll
|
||||
resizeObserver.unobserve(navSidebar);
|
||||
}
|
||||
});
|
||||
resizeObserver.observe(navSidebar);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
Vendored
-9
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+318
@@ -0,0 +1,318 @@
|
||||
/* awesome-quant – search, filter, sort, expand */
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
const $ = (sel, ctx = document) => ctx.querySelector(sel);
|
||||
const $$ = (sel, ctx = document) => [...ctx.querySelectorAll(sel)];
|
||||
|
||||
const searchInput = $("#search");
|
||||
const filterBar = $("#filter-bar");
|
||||
const filterValue = $("#filter-value");
|
||||
const filterClear = $("#filter-clear");
|
||||
const noResults = $("#no-results");
|
||||
const resultsCount = $("#results-count");
|
||||
const tableBody = $("tbody", $("#project-table"));
|
||||
const sortHeaders = $$("th[data-sort]");
|
||||
|
||||
let activeFilter = { type: "", value: "" };
|
||||
let currentSort = { key: "", dir: "" };
|
||||
|
||||
// ===== Theme =====
|
||||
const themeToggle = $(".theme-toggle");
|
||||
|
||||
function getPreferredTheme() {
|
||||
const stored = localStorage.getItem("theme");
|
||||
if (stored) return stored;
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
}
|
||||
|
||||
function applyTheme(theme) {
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
|
||||
applyTheme(getPreferredTheme());
|
||||
|
||||
themeToggle.addEventListener("click", () => {
|
||||
const current = document.documentElement.getAttribute("data-theme");
|
||||
applyTheme(current === "dark" ? "light" : "dark");
|
||||
});
|
||||
|
||||
// ===== Helpers =====
|
||||
function getRows() {
|
||||
return $$(".row", tableBody);
|
||||
}
|
||||
|
||||
function getExpandRow(row) {
|
||||
return row.nextElementSibling;
|
||||
}
|
||||
|
||||
function collapseAll() {
|
||||
for (const row of getRows()) {
|
||||
row.classList.remove("expanded");
|
||||
const expand = getExpandRow(row);
|
||||
if (expand) expand.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Search & Filter =====
|
||||
let searchTimeout;
|
||||
|
||||
function applyFilters() {
|
||||
const query = searchInput.value.trim().toLowerCase();
|
||||
let visible = 0;
|
||||
|
||||
collapseAll();
|
||||
|
||||
for (const row of getRows()) {
|
||||
const expand = getExpandRow(row);
|
||||
const text = (
|
||||
row.textContent +
|
||||
" " +
|
||||
(expand ? expand.textContent : "")
|
||||
).toLowerCase();
|
||||
const language = row.dataset.language || "";
|
||||
const category = row.dataset.category || "";
|
||||
const sources = row.dataset.sources || "";
|
||||
|
||||
let show = true;
|
||||
|
||||
// Search
|
||||
if (query && !text.includes(query)) show = false;
|
||||
|
||||
// Tag filter
|
||||
if (show && activeFilter.value) {
|
||||
const ft = activeFilter.type;
|
||||
const fv = activeFilter.value;
|
||||
if (ft === "language" && language !== fv) show = false;
|
||||
if (ft === "category" && category !== fv) show = false;
|
||||
if (ft === "source" && !sources.split(" ").includes(fv)) show = false;
|
||||
}
|
||||
|
||||
row.hidden = !show;
|
||||
if (expand) expand.hidden = true;
|
||||
|
||||
if (show) {
|
||||
visible++;
|
||||
const numCell = $(".col-num", row);
|
||||
if (numCell) numCell.textContent = visible;
|
||||
}
|
||||
}
|
||||
|
||||
noResults.hidden = visible > 0;
|
||||
resultsCount.textContent =
|
||||
query || activeFilter.value
|
||||
? `Showing ${visible} project${visible !== 1 ? "s" : ""}`
|
||||
: "";
|
||||
|
||||
// Sync filter bar
|
||||
if (activeFilter.value) {
|
||||
filterValue.textContent = activeFilter.value;
|
||||
filterBar.style.display = "flex";
|
||||
} else {
|
||||
filterBar.style.display = "none";
|
||||
}
|
||||
|
||||
syncURL();
|
||||
}
|
||||
|
||||
searchInput.addEventListener("input", () => {
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(applyFilters, 120);
|
||||
});
|
||||
|
||||
filterClear.addEventListener("click", () => {
|
||||
activeFilter = { type: "", value: "" };
|
||||
applyFilters();
|
||||
});
|
||||
|
||||
// ===== Tag Click =====
|
||||
tableBody.addEventListener("click", (e) => {
|
||||
const tag = e.target.closest(".tag");
|
||||
if (tag) {
|
||||
e.stopPropagation();
|
||||
const type = tag.dataset.filterType;
|
||||
const value = tag.dataset.filterValue;
|
||||
|
||||
// Toggle off if same filter
|
||||
if (activeFilter.type === type && activeFilter.value === value) {
|
||||
activeFilter = { type: "", value: "" };
|
||||
} else {
|
||||
activeFilter = { type, value };
|
||||
}
|
||||
applyFilters();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Row Expand =====
|
||||
tableBody.addEventListener("click", (e) => {
|
||||
if (e.target.closest(".tag") || e.target.closest("a")) return;
|
||||
const row = e.target.closest(".row");
|
||||
if (!row) return;
|
||||
|
||||
const expand = getExpandRow(row);
|
||||
if (!expand) return;
|
||||
|
||||
const isExpanded = row.classList.contains("expanded");
|
||||
|
||||
for (const r of getRows()) {
|
||||
if (r !== row) {
|
||||
r.classList.remove("expanded");
|
||||
const ex = getExpandRow(r);
|
||||
if (ex) ex.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isExpanded) {
|
||||
row.classList.remove("expanded");
|
||||
expand.hidden = true;
|
||||
} else {
|
||||
row.classList.add("expanded");
|
||||
expand.hidden = false;
|
||||
}
|
||||
});
|
||||
|
||||
tableBody.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
const row = e.target.closest(".row");
|
||||
if (row) {
|
||||
e.preventDefault();
|
||||
row.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Sort =====
|
||||
function getSortValue(row, key) {
|
||||
if (key === "name") {
|
||||
return ($(".col-name a", row)?.textContent || "").toLowerCase();
|
||||
}
|
||||
if (key === "stars") {
|
||||
return parseInt(row.dataset.stars || "0", 10);
|
||||
}
|
||||
if (key === "update") {
|
||||
return ($(".last-update", row)?.textContent || "").trim();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function doSort(key, dir) {
|
||||
const rows = getRows();
|
||||
const pairs = rows.map((r) => [r, getExpandRow(r)]);
|
||||
|
||||
if (!dir) {
|
||||
pairs.sort((a, b) => {
|
||||
const ai = parseInt(a[0].dataset.originalIndex || "0");
|
||||
const bi = parseInt(b[0].dataset.originalIndex || "0");
|
||||
return ai - bi;
|
||||
});
|
||||
} else {
|
||||
pairs.sort((a, b) => {
|
||||
const va = getSortValue(a[0], key);
|
||||
const vb = getSortValue(b[0], key);
|
||||
let cmp;
|
||||
if (typeof va === "number" && typeof vb === "number") {
|
||||
cmp = va - vb;
|
||||
} else {
|
||||
cmp = String(va).localeCompare(String(vb));
|
||||
}
|
||||
return dir === "asc" ? cmp : -cmp;
|
||||
});
|
||||
}
|
||||
|
||||
for (const [row, expand] of pairs) {
|
||||
tableBody.appendChild(row);
|
||||
if (expand) tableBody.appendChild(expand);
|
||||
}
|
||||
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
for (const th of sortHeaders) {
|
||||
th.addEventListener("click", () => {
|
||||
const key = th.dataset.sort;
|
||||
|
||||
let nextDir;
|
||||
if (currentSort.key !== key) {
|
||||
nextDir = key === "name" ? "asc" : "desc";
|
||||
} else if (currentSort.dir === "asc") {
|
||||
nextDir = "desc";
|
||||
} else if (currentSort.dir === "desc") {
|
||||
nextDir = key === "name" ? "" : "asc";
|
||||
} else {
|
||||
nextDir = key === "name" ? "asc" : "desc";
|
||||
}
|
||||
|
||||
for (const h of sortHeaders) {
|
||||
h.classList.remove("asc", "desc");
|
||||
}
|
||||
|
||||
if (nextDir) {
|
||||
th.classList.add(nextDir);
|
||||
}
|
||||
|
||||
currentSort = { key: nextDir ? key : "", dir: nextDir };
|
||||
doSort(key, nextDir);
|
||||
});
|
||||
}
|
||||
|
||||
// Store original indices
|
||||
getRows().forEach((r, i) => (r.dataset.originalIndex = i));
|
||||
|
||||
// ===== Keyboard Shortcuts =====
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "/" && !e.ctrlKey && !e.metaKey) {
|
||||
const active = document.activeElement;
|
||||
if (
|
||||
active &&
|
||||
(active.tagName === "INPUT" ||
|
||||
active.tagName === "SELECT" ||
|
||||
active.tagName === "TEXTAREA")
|
||||
)
|
||||
return;
|
||||
e.preventDefault();
|
||||
searchInput.focus();
|
||||
}
|
||||
|
||||
if (e.key === "Escape") {
|
||||
if (document.activeElement === searchInput) {
|
||||
if (searchInput.value) {
|
||||
searchInput.value = "";
|
||||
applyFilters();
|
||||
} else {
|
||||
searchInput.blur();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ===== URL State =====
|
||||
function syncURL() {
|
||||
const params = new URLSearchParams();
|
||||
if (searchInput.value) params.set("q", searchInput.value);
|
||||
if (activeFilter.value) {
|
||||
params.set("filter_type", activeFilter.type);
|
||||
params.set("filter", activeFilter.value);
|
||||
}
|
||||
const qs = params.toString();
|
||||
const url = qs ? `?${qs}` : location.pathname;
|
||||
history.replaceState(null, "", url);
|
||||
}
|
||||
|
||||
function restoreURL() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
if (params.has("q")) searchInput.value = params.get("q");
|
||||
if (params.has("filter")) {
|
||||
activeFilter = {
|
||||
type: params.get("filter_type") || "category",
|
||||
value: params.get("filter"),
|
||||
};
|
||||
}
|
||||
if (params.toString()) applyFilters();
|
||||
}
|
||||
|
||||
restoreURL();
|
||||
})();
|
||||
@@ -0,0 +1,860 @@
|
||||
/* ===== Reset & Base ===== */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:root {
|
||||
--font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
--shell-max: 72rem;
|
||||
--radius: 8px;
|
||||
--radius-pill: 999px;
|
||||
--transition: 0.2s ease;
|
||||
|
||||
/* Light mode (default) */
|
||||
--bg-page: #ffffff;
|
||||
--bg-surface: #f8fafc;
|
||||
--bg-surface-hover: #f1f5f9;
|
||||
--bg-hero: #0f172a;
|
||||
--bg-hero-accent: #1e293b;
|
||||
--ink: #0f172a;
|
||||
--ink-secondary: #475569;
|
||||
--ink-tertiary: #94a3b8;
|
||||
--ink-hero: #f1f5f9;
|
||||
--ink-hero-secondary: #94a3b8;
|
||||
--border: #e2e8f0;
|
||||
--border-light: #f1f5f9;
|
||||
--accent: #2563eb;
|
||||
--accent-hover: #1d4ed8;
|
||||
--accent-subtle: #eff6ff;
|
||||
--tag-group-bg: #f0f9ff;
|
||||
--tag-group-ink: #0369a1;
|
||||
--tag-group-border: #bae6fd;
|
||||
--tag-cat-bg: #f5f3ff;
|
||||
--tag-cat-ink: #6d28d9;
|
||||
--tag-cat-border: #ddd6fe;
|
||||
--badge-bg: #fef3c7;
|
||||
--badge-ink: #92400e;
|
||||
--expand-bg: #f8fafc;
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--bg-page: #0f172a;
|
||||
--bg-surface: #1e293b;
|
||||
--bg-surface-hover: #334155;
|
||||
--bg-hero: #020617;
|
||||
--bg-hero-accent: #0f172a;
|
||||
--ink: #f1f5f9;
|
||||
--ink-secondary: #94a3b8;
|
||||
--ink-tertiary: #64748b;
|
||||
--border: #334155;
|
||||
--border-light: #1e293b;
|
||||
--accent: #60a5fa;
|
||||
--accent-hover: #93c5fd;
|
||||
--accent-subtle: rgba(96, 165, 250, 0.1);
|
||||
--tag-group-bg: rgba(14, 165, 233, 0.12);
|
||||
--tag-group-ink: #7dd3fc;
|
||||
--tag-group-border: rgba(14, 165, 233, 0.25);
|
||||
--tag-cat-bg: rgba(139, 92, 246, 0.12);
|
||||
--tag-cat-ink: #c4b5fd;
|
||||
--tag-cat-border: rgba(139, 92, 246, 0.25);
|
||||
--badge-bg: rgba(251, 191, 36, 0.15);
|
||||
--badge-ink: #fcd34d;
|
||||
--expand-bg: #1e293b;
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font);
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
color: var(--ink);
|
||||
background: var(--bg-page);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
transition: color var(--transition);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--accent-hover);
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.shell {
|
||||
max-width: var(--shell-max);
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
}
|
||||
|
||||
/* ===== Hero ===== */
|
||||
.hero {
|
||||
background: var(--bg-hero);
|
||||
color: var(--ink-hero);
|
||||
min-height: 80vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 50% 40%, rgba(37, 99, 235, 0.12) 0%, transparent 70%),
|
||||
radial-gradient(ellipse 50% 80% at 80% 60%, rgba(99, 102, 241, 0.08) 0%, transparent 60%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h40v40H0z' fill='none'/%3E%3Cpath d='M0 40L40 0' stroke='%23ffffff' stroke-opacity='0.03' stroke-width='1'/%3E%3C/svg%3E");
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
width: 100%;
|
||||
max-width: var(--shell-max);
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1.5rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.nav-brand {
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
letter-spacing: -0.01em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: var(--ink-hero-secondary);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
transition: color var(--transition);
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--ink-hero);
|
||||
}
|
||||
|
||||
.nav-submit {
|
||||
background: var(--accent);
|
||||
color: #fff !important;
|
||||
padding: 0.375rem 0.875rem;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
transition: background var(--transition), opacity var(--transition);
|
||||
}
|
||||
|
||||
.nav-submit:hover {
|
||||
background: var(--accent-hover);
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
color: var(--ink-hero-secondary);
|
||||
padding: 0.375rem;
|
||||
border-radius: var(--radius);
|
||||
transition: color var(--transition), background var(--transition);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
color: var(--ink-hero);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.icon-moon { display: none; }
|
||||
[data-theme="dark"] .icon-sun { display: none; }
|
||||
[data-theme="dark"] .icon-moon { display: block; }
|
||||
|
||||
.hero-content {
|
||||
max-width: 40rem;
|
||||
}
|
||||
|
||||
.hero-content h1 {
|
||||
font-size: clamp(2.75rem, 6vw, 4.5rem);
|
||||
font-weight: 700;
|
||||
line-height: 1.05;
|
||||
letter-spacing: -0.03em;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: clamp(1.05rem, 2vw, 1.25rem);
|
||||
color: var(--ink-hero-secondary);
|
||||
line-height: 1.5;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.hero-maintained {
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink-hero-secondary);
|
||||
opacity: 0.7;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.hero-maintained a {
|
||||
color: var(--ink-hero);
|
||||
font-weight: 500;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hero-maintained a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.hero-stats {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 2.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink-hero-secondary);
|
||||
}
|
||||
|
||||
.hero-stats strong {
|
||||
color: var(--ink-hero);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stat-sep {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
background: var(--ink-hero-secondary);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.hero-cta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.75rem;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
border-radius: var(--radius-pill);
|
||||
transition: background var(--transition), transform var(--transition);
|
||||
}
|
||||
|
||||
.hero-cta:hover {
|
||||
background: var(--accent-hover);
|
||||
color: #fff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* ===== Controls ===== */
|
||||
.list-section {
|
||||
padding: 3rem 0 2rem;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-wrap {
|
||||
flex: 1;
|
||||
min-width: 240px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
left: 0.875rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--ink-tertiary);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding: 0.625rem 2.5rem 0.625rem 2.5rem;
|
||||
font-family: var(--font);
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--bg-surface);
|
||||
color: var(--ink);
|
||||
outline: none;
|
||||
transition: border-color var(--transition), box-shadow var(--transition);
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 3px var(--accent-subtle);
|
||||
}
|
||||
|
||||
.search-input::placeholder {
|
||||
color: var(--ink-tertiary);
|
||||
}
|
||||
|
||||
.search-kbd {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-family: var(--font);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
color: var(--ink-tertiary);
|
||||
background: var(--bg-page);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
padding: 0.1rem 0.4rem;
|
||||
line-height: 1.4;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.filter-controls select {
|
||||
padding: 0.625rem 2rem 0.625rem 0.875rem;
|
||||
font-family: var(--font);
|
||||
font-size: 0.875rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--bg-surface);
|
||||
color: var(--ink);
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2394a3b8' fill='none' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: border-color var(--transition);
|
||||
}
|
||||
|
||||
.filter-controls select:focus {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* ===== Filter Bar ===== */
|
||||
.filter-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--accent-subtle);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
color: var(--ink-secondary);
|
||||
}
|
||||
|
||||
.filter-value {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.filter-clear {
|
||||
margin-left: auto;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: var(--ink-secondary);
|
||||
padding: 0.2rem 0.6rem;
|
||||
border-radius: var(--radius-pill);
|
||||
transition: background var(--transition), color var(--transition);
|
||||
}
|
||||
|
||||
.filter-clear:hover {
|
||||
background: var(--bg-surface-hover);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
/* ===== Table ===== */
|
||||
.table-wrap {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.table thead {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background: var(--bg-surface);
|
||||
color: var(--ink-secondary);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.table th[data-sort] {
|
||||
cursor: pointer;
|
||||
transition: color var(--transition);
|
||||
}
|
||||
|
||||
.table th[data-sort]:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.sort-arrow::after {
|
||||
content: "";
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.table th[data-sort].asc .sort-arrow::after {
|
||||
content: " \2191";
|
||||
}
|
||||
|
||||
.table th[data-sort].desc .sort-arrow::after {
|
||||
content: " \2193";
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: 0.625rem 1rem;
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
vertical-align: middle;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Column widths */
|
||||
.col-num {
|
||||
width: 3rem;
|
||||
text-align: center;
|
||||
color: var(--ink-tertiary);
|
||||
font-size: 0.8rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.col-name {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.col-name a {
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
transition: color var(--transition);
|
||||
}
|
||||
|
||||
.col-name a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.mobile-category {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-stars {
|
||||
width: 6rem;
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stars {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: var(--ink-secondary);
|
||||
}
|
||||
|
||||
.stars svg {
|
||||
color: #eab308;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .stars svg {
|
||||
color: #facc15;
|
||||
}
|
||||
|
||||
.col-update {
|
||||
width: 7.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.last-update {
|
||||
font-size: 0.8rem;
|
||||
color: var(--ink-tertiary);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.col-tags {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.col-arrow {
|
||||
width: 2.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
color: var(--ink-tertiary);
|
||||
font-size: 1.1rem;
|
||||
transition: transform var(--transition);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Row interaction */
|
||||
.row {
|
||||
cursor: pointer;
|
||||
transition: background var(--transition);
|
||||
}
|
||||
|
||||
.row:hover {
|
||||
background: var(--bg-surface-hover);
|
||||
}
|
||||
|
||||
.row.expanded .arrow {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* Expand row */
|
||||
.expand-row td {
|
||||
padding: 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.expand-content {
|
||||
padding: 1rem 1rem 1rem 4rem;
|
||||
background: var(--expand-bg);
|
||||
animation: expand-in 0.15s ease;
|
||||
}
|
||||
|
||||
@keyframes expand-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.expand-desc {
|
||||
color: var(--ink-secondary);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.expand-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.expand-links a {
|
||||
color: var(--ink-tertiary);
|
||||
transition: color var(--transition);
|
||||
}
|
||||
|
||||
.expand-links a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* Tags */
|
||||
.tag {
|
||||
display: inline-block;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
padding: 0.15rem 0.6rem;
|
||||
border-radius: var(--radius-pill);
|
||||
margin: 0.125rem 0.125rem;
|
||||
transition: opacity var(--transition), transform var(--transition);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.tag:hover {
|
||||
opacity: 0.8;
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
.tag-lang {
|
||||
background: var(--tag-group-bg);
|
||||
color: var(--tag-group-ink);
|
||||
border: 1px solid var(--tag-group-border);
|
||||
}
|
||||
|
||||
.tag-section {
|
||||
background: var(--tag-cat-bg);
|
||||
color: var(--tag-cat-ink);
|
||||
border: 1px solid var(--tag-cat-border);
|
||||
}
|
||||
|
||||
.tag-source {
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.tag-github {
|
||||
background: rgba(36, 41, 47, 0.08);
|
||||
color: #24292f;
|
||||
border: 1px solid rgba(36, 41, 47, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .tag-github {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: #e6edf3;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.tag-cran {
|
||||
background: rgba(39, 109, 195, 0.08);
|
||||
color: #276dc3;
|
||||
border: 1px solid rgba(39, 109, 195, 0.25);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .tag-cran {
|
||||
background: rgba(75, 143, 219, 0.12);
|
||||
color: #6aaef0;
|
||||
border: 1px solid rgba(75, 143, 219, 0.25);
|
||||
}
|
||||
|
||||
.tag-pypi {
|
||||
background: rgba(0, 110, 165, 0.08);
|
||||
color: #006ea5;
|
||||
border: 1px solid rgba(0, 110, 165, 0.25);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .tag-pypi {
|
||||
background: rgba(0, 150, 214, 0.12);
|
||||
color: #41b6e6;
|
||||
border: 1px solid rgba(0, 150, 214, 0.25);
|
||||
}
|
||||
|
||||
.tag-commercial {
|
||||
background: var(--badge-bg);
|
||||
color: var(--badge-ink);
|
||||
border: 1px solid rgba(146, 64, 14, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .tag-commercial {
|
||||
border-color: rgba(252, 211, 77, 0.25);
|
||||
}
|
||||
|
||||
/* ===== Results ===== */
|
||||
.no-results {
|
||||
text-align: center;
|
||||
padding: 3rem 1rem;
|
||||
color: var(--ink-tertiary);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.results-count {
|
||||
padding: 0.75rem 0;
|
||||
font-size: 0.8rem;
|
||||
color: var(--ink-tertiary);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* ===== CTA Section ===== */
|
||||
.cta-section {
|
||||
text-align: center;
|
||||
padding: 4rem 0;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.cta-section h2 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.cta-section p {
|
||||
color: var(--ink-secondary);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.625rem 1.5rem;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
border-radius: var(--radius-pill);
|
||||
transition: background var(--transition), transform var(--transition);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: var(--accent-hover);
|
||||
color: #fff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* ===== Footer ===== */
|
||||
.footer {
|
||||
padding: 2rem 0;
|
||||
border-top: 1px solid var(--border);
|
||||
font-size: 0.8rem;
|
||||
color: var(--ink-tertiary);
|
||||
}
|
||||
|
||||
.footer .shell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: var(--ink-secondary);
|
||||
}
|
||||
|
||||
.footer a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.footer-sep {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* ===== Responsive ===== */
|
||||
@media (max-width: 1100px) {
|
||||
.col-update {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.tag-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tag-source {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.hero {
|
||||
min-height: auto;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.nav {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.hero-content h1 {
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
|
||||
.hero-stats {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.col-num {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-stars {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-tags {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-category {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
color: var(--ink-tertiary);
|
||||
font-weight: 400;
|
||||
margin-top: 0.125rem;
|
||||
}
|
||||
|
||||
.expand-content {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.controls {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.search-wrap {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user