Skip to content

Instantly share code, notes, and snippets.

@cesarvargas00
Last active November 3, 2020 23:08
Show Gist options
  • Save cesarvargas00/0a3d765cea51df8b04c37fee09690a3e to your computer and use it in GitHub Desktop.
Save cesarvargas00/0a3d765cea51df8b04c37fee09690a3e to your computer and use it in GitHub Desktop.
markowitz.js
function correlation(x, y) {
if (x.length !== y.length) return null
const xMean = x.reduce((acc, el) => el + acc, 0) / x.length
const yMean = y.reduce((acc, el) => el + acc, 0) / y.length
let numerator = 0,
xDSquaredSum = 0,
yDSquaredSum = 0
for (let i = 0; i < x.length; i++) {
const xd = x[i] - xMean
const yd = y[i] - yMean
numerator += xd * yd
xDSquaredSum += xd ** 2
yDSquaredSum += yd ** 2
}
return numerator / (xDSquaredSum * yDSquaredSum) ** 0.5
}
function covariancesFromCorrelations(correlations, stdevs) {
return Object.keys(correlations).reduce(
(acc, row) => ({
...acc,
[row]: Object.keys(correlations[row]).reduce(
(acc, col) => ({
...acc,
[col]: correlations[row][col] * stdevs[row] * stdevs[col],
}),
{}
),
}),
{}
)
}
// portfolio = [{symbol, closes, amount}]
function markowitz(portfolio) {
let assets = []
for (let i = 0; i < portfolio.length; i++) {
const returns = []
for (let j = 1; j < portfolio[i].closes.length; j++) {
returns.push(
Math.log(portfolio[i].closes[j] / portfolio[i].closes[j-1])
)
}
const n = returns.length
const mean = returns.reduce((acc, r) => r + acc, 0) / n
const variance = returns.reduce((acc, r) => (r - mean) ** 2 + acc, 0) / n
const stdev = variance ** 0.5
const close = portfolio[i].returns[portfolio[i].returns.length-1]
assets.push({ portfolio[i].symbol, returns, portfolio[i].amount, mean, variance, stdev, close })
}
const correlations = {}
for (let i = 0; i < assets.length; i++) {
for (let j = 0; j < assets.length; j++) {
if (typeof correlations[assets[i].symbol] === 'undefined') {
correlations[assets[i].symbol] = {}
}
correlations[assets[i].symbol][assets[j].symbol] = correlation(
assets[i].returns,
assets[j].returns
)
}
}
const stdevs = assets.reduce(
(acc, asset) => ({ ...acc, [asset.symbol]: asset.stdev }),
{}
)
const covariances = covariancesFromCorrelations(correlations, stdevs)
const total = assets.reduce(
(acc, { amount, close }) => acc + amount * close,
0
)
const w = assets.map(({ amount, close }) => (amount * close) / total)
const Ω = Object.keys(covariances).map(k =>
Object.keys(covariances[k]).map(l => covariances[k][l])
)
let r = 0
for (let i = 0; i < w.length; i++) {
let sum = 0
for (let j = 0; j < w.length; j++) {
sum += Ω[i][j] * w[j]
}
r += sum * w[i]
}
return r ** 0.5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment