Skip to content

Commit

Permalink
Docs / README update
Browse files Browse the repository at this point in the history
  • Loading branch information
ft-adm committed Jun 18, 2024
1 parent d590c66 commit b599580
Show file tree
Hide file tree
Showing 23 changed files with 173 additions and 131 deletions.
16 changes: 5 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,17 @@ for a walkthrough of the package's functionality and examples.

For a high-level introduction to the investment framework, see this `YouTube video <https://youtu.be/4ESigySdGf8>`_
and `Medium article <https://medium.com/@ft_anvo/entropy-pooling-and-cvar-portfolio-optimization-in-python-ffed736a8347>`_.
For an in-depth mathematical introduction to the investment framework, see
these `SSRN articles <https://ssrn.com/author=2738420>`_.
For a mathematical introduction to the investment framework, see these
`SSRN articles <https://ssrn.com/author=2738420>`_.

For a careful and pedagogical presentation of the investment framework,
see the `Portfolio Construction and Risk Management Book <https://igg.me/at/pcrm-book>`_
crowdfunding campaign.
For a pedagogical and deep presentation of the investment framework,
you can access the `Portfolio Construction and Risk Management Book <https://igg.me/at/pcrm-book>`_.

The package is intended for advanced users who are comfortable specifying
portfolio constraints and Entropy Pooling views using matrices and vectors.
This gives full flexibility in relation to working with these technologies.
Hence, input checking is intentionally kept to a minimum.

If you like this package, we invite you to show your support by giving it a
GitHub star. The greater the number of stars it receives, the more time and
energy we will invest in enhancing its functionality and providing additional
examples.

Fortitudo Technologies offers novel investment software as well as quantitative
and digitalization consultancy to the investment management industry. For more
information, please visit our `website <https://fortitudo.tech>`_.
Expand Down Expand Up @@ -72,6 +66,6 @@ Disclaimer

This package is completely separate from our proprietary solutions and therefore
not representative of the quality and functionality offered by the Investment Simulation
and Investment Analysis modules. If you are an institutional investor who wants to
and Investment Analysis modules. If you are an institutional investor and want to
experience how these methods can be used for sophisticated analysis in practice,
please request a demo by sending an email to [email protected].
Binary file modified docs/build/doctrees/documentation.doctree
Binary file not shown.
Binary file modified docs/build/doctrees/environment.pickle
Binary file not shown.
Binary file modified docs/build/doctrees/index.doctree
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/build/html/.buildinfo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 97eebfb36ce3d804e6eb83040da75dbe
config: 87a22906f6ffd59cc805aedeef7b96fe
tags: 645f666f9bcd5a90fca523b33c5a78b7
16 changes: 5 additions & 11 deletions docs/build/html/_sources/index.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,17 @@ for a walkthrough of the package's functionality and examples.

For a high-level introduction to the investment framework, see this `YouTube video <https://youtu.be/4ESigySdGf8>`_
and `Medium article <https://medium.com/@ft_anvo/entropy-pooling-and-cvar-portfolio-optimization-in-python-ffed736a8347>`_.
For an in-depth mathematical introduction to the investment framework, see
these `SSRN articles <https://ssrn.com/author=2738420>`_.
For a mathematical introduction to the investment framework, see these
`SSRN articles <https://ssrn.com/author=2738420>`_.

For a careful and pedagogical presentation of the investment framework,
see the `Portfolio Construction and Risk Management Book <https://igg.me/at/pcrm-book>`_
crowdfunding campaign.
For a pedagogical and deep presentation of the investment framework,
you can access the `Portfolio Construction and Risk Management Book <https://igg.me/at/pcrm-book>`_.

The package is intended for advanced users who are comfortable specifying
portfolio constraints and Entropy Pooling views using matrices and vectors.
This gives full flexibility in relation to working with these technologies.
Hence, input checking is intentionally kept to a minimum.

If you like this package, we invite you to show your support by giving it a
GitHub star. The greater the number of stars it receives, the more time and
energy we will invest in enhancing its functionality and providing additional
examples.

Fortitudo Technologies offers novel investment software as well as quantitative
and digitalization consultancy to the investment management industry. For more
information, please visit our `website <https://fortitudo.tech>`_.
Expand All @@ -34,7 +28,7 @@ Disclaimer

This package is completely separate from our proprietary solutions and therefore
not representative of the quality and functionality offered by the Investment Simulation
and Investment Analysis modules. If you are an institutional investor who wants to
and Investment Analysis modules. If you are an institutional investor and want to
experience how these methods can be used for sophisticated analysis in practice,
please request a demo by sending an email to [email protected].

Expand Down
2 changes: 1 addition & 1 deletion docs/build/html/_static/basic.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
Expand Down
2 changes: 1 addition & 1 deletion docs/build/html/_static/doctools.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* Base JavaScript utilities for all Sphinx HTML documentation.
*
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
Expand Down
4 changes: 2 additions & 2 deletions docs/build/html/_static/language_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
* This script contains the language-specific data used by searchtools.js,
* namely the list of stopwords, stemmer, scorer and splitter.
*
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/

var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"];


/* Non-minified version is copied as a separate JS file, is available */
/* Non-minified version is copied as a separate JS file, if available */

/**
* Porter Stemmer
Expand Down
165 changes: 105 additions & 60 deletions docs/build/html/_static/searchtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* Sphinx JavaScript utilities for the full-text search.
*
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
Expand Down Expand Up @@ -99,7 +99,7 @@ const _displayItem = (item, searchTerms, highlightTerms) => {
.then((data) => {
if (data)
listItem.appendChild(
Search.makeSearchSummary(data, searchTerms)
Search.makeSearchSummary(data, searchTerms, anchor)
);
// highlight search terms in the summary
if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
Expand All @@ -116,8 +116,8 @@ const _finishSearch = (resultCount) => {
);
else
Search.status.innerText = _(
`Search finished, found ${resultCount} page(s) matching the search query.`
);
"Search finished, found ${resultCount} page(s) matching the search query."
).replace('${resultCount}', resultCount);
};
const _displayNextItem = (
results,
Expand All @@ -137,6 +137,22 @@ const _displayNextItem = (
// search finished, update title and status message
else _finishSearch(resultCount);
};
// Helper function used by query() to order search results.
// Each input is an array of [docname, title, anchor, descr, score, filename].
// Order the results by score (in opposite order of appearance, since the
// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically.
const _orderResultsByScoreThenName = (a, b) => {
const leftScore = a[4];
const rightScore = b[4];
if (leftScore === rightScore) {
// same score: sort alphabetically
const leftTitle = a[1].toLowerCase();
const rightTitle = b[1].toLowerCase();
if (leftTitle === rightTitle) return 0;
return leftTitle > rightTitle ? -1 : 1; // inverted is intentional
}
return leftScore > rightScore ? 1 : -1;
};

/**
* Default splitQuery function. Can be overridden in ``sphinx.search`` with a
Expand All @@ -160,13 +176,26 @@ const Search = {
_queued_query: null,
_pulse_status: -1,

htmlToText: (htmlString) => {
htmlToText: (htmlString, anchor) => {
const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html');
htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() });
for (const removalQuery of [".headerlinks", "script", "style"]) {
htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() });
}
if (anchor) {
const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`);
if (anchorContent) return anchorContent.textContent;

console.warn(
`Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.`
);
}

// if anchor not specified or not found, fall back to main content
const docContent = htmlElement.querySelector('[role="main"]');
if (docContent !== undefined) return docContent.textContent;
if (docContent) return docContent.textContent;

console.warn(
"Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."
"Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template."
);
return "";
},
Expand Down Expand Up @@ -239,16 +268,7 @@ const Search = {
else Search.deferQuery(query);
},

/**
* execute search (requires search index to be loaded)
*/
query: (query) => {
const filenames = Search._index.filenames;
const docNames = Search._index.docnames;
const titles = Search._index.titles;
const allTitles = Search._index.alltitles;
const indexEntries = Search._index.indexentries;

_parseQuery: (query) => {
// stem the search terms and add them to the correct list
const stemmer = new Stemmer();
const searchTerms = new Set();
Expand Down Expand Up @@ -284,16 +304,32 @@ const Search = {
// console.info("required: ", [...searchTerms]);
// console.info("excluded: ", [...excludedTerms]);

// array of [docname, title, anchor, descr, score, filename]
let results = [];
return [query, searchTerms, excludedTerms, highlightTerms, objectTerms];
},

/**
* execute search (requires search index to be loaded)
*/
_performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => {
const filenames = Search._index.filenames;
const docNames = Search._index.docnames;
const titles = Search._index.titles;
const allTitles = Search._index.alltitles;
const indexEntries = Search._index.indexentries;

// Collect multiple result groups to be sorted separately and then ordered.
// Each is an array of [docname, title, anchor, descr, score, filename].
const normalResults = [];
const nonMainIndexResults = [];

_removeChildren(document.getElementById("search-progress"));

const queryLower = query.toLowerCase();
const queryLower = query.toLowerCase().trim();
for (const [title, foundTitles] of Object.entries(allTitles)) {
if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) {
if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) {
for (const [file, id] of foundTitles) {
let score = Math.round(100 * queryLower.length / title.length)
results.push([
normalResults.push([
docNames[file],
titles[file] !== title ? `${titles[file]} > ${title}` : title,
id !== null ? "#" + id : "",
Expand All @@ -308,46 +344,47 @@ const Search = {
// search for explicit entries in index directives
for (const [entry, foundEntries] of Object.entries(indexEntries)) {
if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) {
for (const [file, id] of foundEntries) {
let score = Math.round(100 * queryLower.length / entry.length)
results.push([
for (const [file, id, isMain] of foundEntries) {
const score = Math.round(100 * queryLower.length / entry.length);
const result = [
docNames[file],
titles[file],
id ? "#" + id : "",
null,
score,
filenames[file],
]);
];
if (isMain) {
normalResults.push(result);
} else {
nonMainIndexResults.push(result);
}
}
}
}

// lookup as object
objectTerms.forEach((term) =>
results.push(...Search.performObjectSearch(term, objectTerms))
normalResults.push(...Search.performObjectSearch(term, objectTerms))
);

// lookup as search terms in fulltext
results.push(...Search.performTermsSearch(searchTerms, excludedTerms));
normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms));

// let the scorer override scores with a custom scoring function
if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item)));

// now sort the results by score (in opposite order of appearance, since the
// display function below uses pop() to retrieve items) and then
// alphabetically
results.sort((a, b) => {
const leftScore = a[4];
const rightScore = b[4];
if (leftScore === rightScore) {
// same score: sort alphabetically
const leftTitle = a[1].toLowerCase();
const rightTitle = b[1].toLowerCase();
if (leftTitle === rightTitle) return 0;
return leftTitle > rightTitle ? -1 : 1; // inverted is intentional
}
return leftScore > rightScore ? 1 : -1;
});
if (Scorer.score) {
normalResults.forEach((item) => (item[4] = Scorer.score(item)));
nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item)));
}

// Sort each group of results by score and then alphabetically by name.
normalResults.sort(_orderResultsByScoreThenName);
nonMainIndexResults.sort(_orderResultsByScoreThenName);

// Combine the result groups in (reverse) order.
// Non-main index entries are typically arbitrary cross-references,
// so display them after other results.
let results = [...nonMainIndexResults, ...normalResults];

// remove duplicate search results
// note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept
Expand All @@ -361,7 +398,12 @@ const Search = {
return acc;
}, []);

results = results.reverse();
return results.reverse();
},

query: (query) => {
const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query);
const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms);

// for debugging
//Search.lastresults = results.slice(); // a copy
Expand Down Expand Up @@ -466,14 +508,18 @@ const Search = {
// add support for partial matches
if (word.length > 2) {
const escapedWord = _escapeRegExp(word);
Object.keys(terms).forEach((term) => {
if (term.match(escapedWord) && !terms[word])
arr.push({ files: terms[term], score: Scorer.partialTerm });
});
Object.keys(titleTerms).forEach((term) => {
if (term.match(escapedWord) && !titleTerms[word])
arr.push({ files: titleTerms[word], score: Scorer.partialTitle });
});
if (!terms.hasOwnProperty(word)) {
Object.keys(terms).forEach((term) => {
if (term.match(escapedWord))
arr.push({ files: terms[term], score: Scorer.partialTerm });
});
}
if (!titleTerms.hasOwnProperty(word)) {
Object.keys(titleTerms).forEach((term) => {
if (term.match(escapedWord))
arr.push({ files: titleTerms[term], score: Scorer.partialTitle });
});
}
}

// no match but word was a required one
Expand All @@ -496,9 +542,8 @@ const Search = {

// create the mapping
files.forEach((file) => {
if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1)
fileMap.get(file).push(word);
else fileMap.set(file, [word]);
if (!fileMap.has(file)) fileMap.set(file, [word]);
else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word);
});
});

Expand Down Expand Up @@ -549,8 +594,8 @@ const Search = {
* search summary for a given text. keywords is a list
* of stemmed words.
*/
makeSearchSummary: (htmlText, keywords) => {
const text = Search.htmlToText(htmlText);
makeSearchSummary: (htmlText, keywords, anchor) => {
const text = Search.htmlToText(htmlText, anchor);
if (text === "") return null;

const textLower = text.toLowerCase();
Expand Down
Loading

0 comments on commit b599580

Please sign in to comment.