Every day, 16 banks say how much it might cost them to borrow in various currencies, for various lengths of time. The four highest and four lowest figures are discarded, and the average of the remaining eight become that day’s Libor. In this toy model of how Libor works, you have total control over how one bank sets its rates, and some random partial influence on other banks, who will tend to follow you. Move your mouse along the axis to set your rate. Read the full story
Last active
October 9, 2015 08:23
-
-
Save tophtucker/77a322f02f13bf9b475d to your computer and use it in GitHub Desktop.
How LIBOR works
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title></title> | |
<link rel="stylesheet" type="text/css" href="main.css"/> | |
<body> | |
<p>Every day, 16 banks say how much it might cost them to borrow in various currencies, for various lengths of time. The four highest and four lowest figures are discarded, and the average of the remaining eight become that day’s Libor.</p> | |
<svg></svg> | |
<p>In this toy model of how Libor works, you have total control over how one bank sets its rates, and some random partial influence on other banks, who will tend to follow you. Move your mouse along the axis to set your rate.</p> | |
</body> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js" charset="utf-8"></script> | |
<script src="//cdn.rawgit.com/gka/d3-jetpack/master/d3-jetpack.js" charset="utf-8"></script> | |
<script src="main.js" charset="utf-8"></script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font: 12px sans-serif; | |
width: 960px; | |
margin: 2em auto; | |
} | |
svg { | |
font: 10px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #ccc; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
fill: #ccc; | |
} | |
.dot { | |
stroke: #000; | |
} | |
svg > g { | |
pointer-events: all; | |
cursor: ew-resize; | |
} | |
g.bank text { | |
text-anchor: middle; | |
} | |
line.libor-span { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
stroke-width: 3; | |
} | |
g.bank:not(.accepted) { | |
fill: #ccc; | |
} | |
g.libor-mark text { | |
text-anchor: middle; | |
} | |
g.bank.captured { | |
fill: red; | |
} | |
g.bank line.influence { | |
stroke: red; | |
shape-rendering: crispEdges; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var margin = {top: 20, right: 20, bottom: 30, left: 20}, | |
width = 960 - margin.left - margin.right, | |
height = 80 - margin.top - margin.bottom; | |
var svg = d3.select("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
svg.append('rect') | |
.attr('class', 'click-capture') | |
.style('visibility', 'hidden') | |
.attr('x', 0) | |
.attr('y', 0) | |
.attr('width', width) | |
.attr('height', height+margin.bottom); | |
/// | |
var mouse = false; | |
var percentage = d3.format(".0%"); | |
var percentage2 = d3.format(".2%"); | |
var numberOfBanks = 16, | |
liborLowPass = 4, | |
liborHighPass = 12; | |
var rRand = d3.random.normal(.05, .01), | |
drRand = d3.random.normal(0, .00005), | |
influenceRand = d3.random.logNormal(0,1); | |
var rates = d3.range(numberOfBanks).map(function(d, i) { | |
return { | |
"name": "Bank " + (i+1), | |
"r": rRand(), | |
"vr": drRand(), | |
"influence": influenceRand()/2000, | |
"captured": false | |
}; | |
}) | |
var x = d3.scale.linear() | |
.domain([0,.1]) | |
.range([0,width]) | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom") | |
.tickSize("10") | |
.tickFormat(percentage); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis) | |
.append("text") | |
.attr("class", "label") | |
.attr("x", width) | |
.attr("y", -6) | |
.style("text-anchor", "end") | |
.text("Rate"); | |
var bankG = svg.selectAll("g.bank") | |
.data(rates, ƒ('name')) | |
.enter() | |
.append("g.bank"); | |
bankG.append("circle") | |
.attr("cx", 0) | |
.attr("cy", 0) | |
.attr("r", 2); | |
bankG.append("text") | |
.attr("dy", "-.5em") | |
.text(ƒ('name')); | |
// bankG.append("line.influence") | |
// .attr("y1", 0) | |
// .attr("y2", 0) | |
// .attr("x1", 0) | |
// .attr("x2", 0); | |
var liborSpan = svg.append("line.libor-span") | |
.attr("y1", height) | |
.attr("y2", height); | |
var liborMark = svg.append("g.libor-mark"); | |
liborMark.append("path") | |
.attr("d", d3.svg.symbol().type("triangle-up")); | |
liborMark.append("text") | |
.attr("dy", "15px"); | |
d3.timer(function(t) { | |
rates.forEach(function(d,i) { | |
if(d.captured) return; | |
d.r += d.vr; | |
d.vr += drRand() - 0.2 * d.vr; | |
if(mouse) { | |
d.vr += d.influence * (x.invert(mouse[0]) - d.r); | |
} | |
}) | |
rates.sort(function(a,b) { | |
return a.r-b.r; | |
}); | |
var liborRates = rates.slice(liborLowPass,liborHighPass); | |
var liborExtent = d3.extent(liborRates, ƒ('r')); | |
var liborRate = liborRates.reduce(function(a, b) { return a + b.r; }, 0) / liborRates.length; | |
bankG | |
.attr("transform", function(d) { return "translate("+x(d.r)+"," + height/2 + ")"; }) | |
.classed("captured", ƒ('captured')) | |
.classed("accepted", function(d) { return d.r >= liborExtent[0] && d.r <= liborExtent[1]; }); | |
liborMark | |
.attr("transform", function(d) { return "translate(" + x(liborRate) + "," + (height+5) + ")"; }) | |
.select("text").text(percentage2(liborRate)); | |
liborSpan | |
.attr("x1", function(d) { return x(liborExtent[0]); }) | |
.attr("x2", function(d) { return x(liborExtent[1]); }) | |
// if(mouse) { | |
// bankG.select("line.influence").attr("x2", function(d) { | |
// return d.influence * (mouse[0] - x(d.r)); | |
// }); | |
// } else { | |
// bankG.select("line.influence").attr("x2", 0); | |
// } | |
}); | |
svg.on("mouseenter", function() { | |
mouse = d3.mouse(this); | |
rates.filter(function(d,i) { return d.name=="Bank 1"; })[0].captured = true; | |
}) | |
svg.on("mouseleave", function() { | |
mouse = false; | |
rates.filter(function(d,i) { return d.name=="Bank 1"; })[0].captured = false; | |
}) | |
svg.on("mousemove", function() { | |
mouse = d3.mouse(this); | |
rates.filter(function(d,i) { return d.name=="Bank 1"; })[0].r = x.invert(d3.mouse(this)[0]); | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment