// 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); var levels = {}; // Determine the bid/offer from input data using high/low fx.forEach(function(A) { levels[A] = {}; fx.forEach(function(B) { if (A == B) return; var first = rates[A][B], second = 1/rates[B][A]; levels[A][B] = { offer : Math.max(first,second), bid : Math.min(first,second) }; $("#prices").append('$$ '+frac(A,B)+'='+levels[A][B].bid+' / '+levels[A][B].offer+' $$'); }); }); // Go through all triangular combinations combinations(fx,3).forEach(function(c) { ['bid','offer'].forEach(function(side) { var result = 1, txtFx = [], txtPrice =[], msg; c.forEach(function(base,i) { var other = c[i+1] || c[0]; var price = levels[base][other][side]; result *= price; txtFx.push(frac(base+'^{\\text{'+side+'}}',other)); txtPrice.push(price); }); if (side == 'bid') msg = (result < 1) ? '(result < 1 = No Arbitrage)' : '(result > 1 = Arbitrage)'; else msg = (result > 1) ? '(result > 1 = No Arbitrage)' : '(result < 1 = Arbitrage)'; $("#triangular").append('$$ '+txtFx.join(' \\cdot ')+'='+txtPrice.join(' \\cdot ')+' = '+result+' \\text{'+msg+'}$$'); }); }); }