Skip to content

Instantly share code, notes, and snippets.

@ZJONSSON

ZJONSSON/arb.js

Last active Jan 1, 2016
Embed
What would you like to do?
Bitcoin Arbitrage - Priceonomics
// Get all possible states for a k length array
function states(k) {
if (k==1) return [0,1];
var ret = [];
states(k-1).forEach(function(d) {
ret.push([0].concat(d));
ret.push([1].concat(d));
});
return ret;
}
// Get all k-combinations from array
function combinations(arr, k){
if (k==1) return arr;
var ret = [];
arr.forEach(function(d,i) {
combinations(arr.slice(i+1, arr.length), k-1)
.forEach(function(sub) {
var next = [].concat(sub);
next.unshift(d);
ret.push( next );
});
});
return ret;
}
// Generate a LaTex fraction
function frac(a,b) {
if (!b || b == 1) return a;
return '\\frac{'+(a || 1)+'}{'+b+'}';
}
// Main calculation - callback to the JSONP request
function main(input) {
input = input.query.results.json;
// Build rates matrix
var rates = {};
Object.keys(input).forEach(function(key) {
var numerator = key.slice(0,3),
denominator = key.slice(4);
if (!rates[numerator]) rates[numerator] = {};
rates[numerator][denominator] = input[key];
});
// List FX rates
fx = Object.keys(rates);
// Go through all single-pair arbs
combinations(fx,2).forEach(function(d) {
var ret = rates[d[0]][d[1]]*rates[d[1]][d[0]],
first = frac(d[0],d[1])+' \\cdot '+frac(d[1],d[0]),
second = rates[d[0]][d[1]]+'\\cdot '+rates[d[1]][d[0]];
// If return is below 1 the arb is in the inverse
if (ret < 1) {
first = frac(1,first);
second = frac(1,second);
ret = 1 / ret;
}
$("#dual").append('$$'+first+' = '+second+' = '+ret+ '$$');
});
// Go through all triangular combinations
combinations(fx,3).forEach(function(c) {
var best = {};
// Go through all possible selections of currency pairs for those three currencies
states(3).forEach(function(states) {
var d = {result: 1, above: [], below: []};
states.forEach(function(state,i) {
var a = (state) ? c[i] : c[i+1] || c[0],
b = (state) ? c[i+1] || c[0] : c[i],
rate = rates[a][b];
if (state) d.above.push([a,b,rate]);
else d.below.push([a,b,rate]);
d.result *= state ? rate : 1/rate;
});
// If the result is below 1 the arb is in the inverse
if (d.result < 1) {
var tmp = d.below;
d.below = d.above;
d.above = tmp;
d.result = 1 / d.result;
}
// To eliminate duality-arb effect, we take the lowest triangular arb
if (!best.result || d.result < best.result) best = d;
});
$("#triangular").append('$$ '+frac(
best.above.map(function(d) { return frac(d[0],d[1]);}).join(' \\cdot '),
best.below.map(function(d) { return frac(d[0],d[1]);}).join(' \\cdot ')
)+' = '+ frac(
best.above.map(function(d) { return d[2];}).join(' \\cdot '),
best.below.map(function(d) { return d[2];}).join(' \\cdot ')
)+ ' = '+best.result +' $$'
);
});
}
<!DOCTYPE html>
<meta charset="utf-8">
<style>.MathJax_Display {text-align: left !important;}</style>
<body>
<h1>Bitcoin Arbitrage Exercise</h1>
This is my solution to the <a href="http://priceonomics.com/jobs/puzzle/">Bitcoin Arbitrage puzzle</a> posted earlier this year by <a href="http://priceonomics.com">Priceonomics</a>. A matrix of continuously-published currency rates is algorithmically skewed and the challenge is to uncover any arbitrage opportunities. Calculations are re-run every time this page is loaded/refreshed, using <a href="http://developer.yahoo.com/yql/">YQL</a> to fetch the latest rates and <a href="http://www.mathjax.org/">MathJax</a> to render the results. <br><br>
All spot market arbitrage can be decomposed into duality-arbitrage (different prices for the same thing) and triangular-arbitrage (relative prices between three assets not unity). Any higher order arbitrage relationships (i.e. involving more than three assets) are a combination of duality- and triangular-arbs.
<h2>Duality Arbitrage</h2>
Duality arbitrage occurs when the different prices are attached to the same currency pair.
<div id="dual"></div>
<h2>Triangular Arbitrage</h2>
A currency has no absolute value, only relative value against other assets/currencies. Triangular arbitrage occurs when the relative value of a currency towards two different assets does not match the relative value between those assets. For any triangular relationship in this exercise there are 8 combinations of currency pairs to choose from (i.e. the price of EURUSD differs from USDEUR). To avoid double-counting the duality issues identified above, we pick the triangular combination of rates that results in the minimum arbitrage possible (the rest is contaminated by duality-arb)
<div id="triangular"></div>
<hr>
(c) 2013 <a href="https://github.com/zjonsson">Ziggy Jonsson</a> - Licence <a href="http://opensource.org/licenses/MIT">MIT</a> - <a href="https://gist.github.com/ZJONSSON/8138007">(source)</a>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script src="arb.js"></script>
<script src="http://query.yahooapis.com/v1/public/yql?callback=main&format=json&q=select%20*%20from%20json%20where%20url=%22http://fx.priceonomics.com/v1/rates/%22"></script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment