Created
April 2, 2013 19:40
-
-
Save treycordova/5295509 to your computer and use it in GitHub Desktop.
ArbitrageFinder produces potential arbitrage information from a 2-dimensional hash table. The algorithm employed is Bellman-Ford's Algorithm, which has an overall runtime of O(n^3).
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
(function() { | |
var currencies = { | |
// US Dollar | |
"USD": {"USD": 0, "GBP": 0.616056, "EUR": 0.733837, "CAD": 0.983195, "JPY": 83.3786, "CNY": 6.56997, "INR": 45.2, "BRL": 1.66691, "RUB": 29.1986}, | |
// British Pound | |
"GBP": {"USD": 1.62323, "GBP": 0, "EUR": 1.19119, "CAD": 1.59595, "JPY": 135.343, "CNY": 10.6646, "INR": 73.73, "BRL": 2.70578, "RUB": 47.396}, | |
// Euro | |
"EUR": {"USD": 1.3627, "GBP": 0.8395, "EUR": 0, "CAD": 1.3398, "JPY": 113.62, "CNY": 8.9529, "INR": 61.5941, "BRL": 2.2715, "RUB": 39.7889}, | |
// Canadian Dollar | |
"CAD": {"USD": 1.01709, "GBP": 0.626586, "EUR": 0.74638, "CAD": 0, "JPY": 84.8037, "CNY": 6.68227, "INR": 45.9726, "BRL": 1.6954, "RUB": 29.6977}, | |
// Japanese Yen | |
"JPY": {"USD": 0.0119935, "GBP": 0.00738866, "EUR": 0.00880126, "CAD": 0.0117919, "JPY": 0, "CNY": 0.0787968, "INR": 0.542106, "BRL": 0.0199921, "RUB": 0.350193}, | |
// Chinese Yuan | |
"CNY": {"USD": 0.152208, "GBP": 0.0937685, "EUR": 0.11696, "CAD": 0.14965, "JPY": 12.6909, "CNY": 0, "INR": 6.87979, "BRL": 0.253717, "RUB": 4.44425}, | |
// Indian Rupee | |
"INR": {"USD": 0.0221239, "GBP": 0.0136296, "EUR": 0.0162353, "CAD": 0.0217521, "JPY": 1.84466, "CNY": 0.145353, "INR": 0, "BRL": 0.0368785, "RUB": 0.645987}, | |
// Brazilian Real | |
"BRL": {"USD": 0.599912, "GBP": 0.36958, "EUR": 0.440238, "CAD": 0.589831, "JPY": 50.0199, "CNY": 3.94141, "INR": 27.116, "BRL": 0, "RUB": 17.5166}, | |
// Russian Ruble | |
"RUB": {"USD": 0.0342482, "GBP": 0.0210988, "EUR": 0.0251326, "CAD": 0.0336727, "JPY": 2.85557, "CNY": 0.22501, "INR": 1.54802, "BRL": 0.0570887, "RUB": 0} | |
}; | |
/** | |
* ArbitrageFinder produces potential arbitrage information from a 2-dimensional hash table. | |
* The algorithm employed is Bellman-Ford's Algorithm, which has an overall runtime of O(n^3). | |
* | |
**/ | |
var ArbitrageFinder = function() { | |
/** Private Variables **/ | |
var original_currencies = {}; | |
var distance = {}; | |
var predecessor = {}; | |
var cycles = {}; | |
/** private:findArbitrage employs the Bellman-Ford Algorithm to produce cyclic information **/ | |
var findArbitrage = function(currencies, justOne) { | |
// Boolean used as the determining return value | |
var arbitrage = false; | |
// The number of currencies | |
var size = 0; | |
// A helper variable to keep track of the main for-loop of this algorithm | |
var val = 0; | |
// Conversion to -log values for negative-cycle detection | |
for(currency in currencies) { | |
original_currencies[currency] = {}; | |
for(exchange in currencies[currency]) { | |
original_currencies[currency][exchange] = currencies[currency][exchange]; | |
currencies[currency][exchange] = - Math.log(currencies[currency][exchange]); | |
} | |
} | |
// Place a fake source called "ROOT" where every exchange is exactly 0 | |
currencies["ROOT"] = {}; | |
for(exchange in currencies.USD) { | |
currencies["ROOT"][exchange] = 0; | |
// Initialize all distances | |
distance[exchange] = Infinity; | |
// Initialize all predecessors | |
predecessor[exchange] = null; | |
// Keep track of the number of currencies | |
size++; | |
} | |
// Distance for root initialized to 0 | |
distance["ROOT"] = 0; | |
// The meat of our algorithm, taken directly from Bellman-Ford | |
for(var i = 0; i < size; ++i) { | |
for(currency in currencies) { | |
for(exchange in currencies[currency]) { | |
if( ( val = ( distance[currency] + currencies[currency][exchange] ) ) < distance[exchange]) { | |
distance[exchange] = val; | |
predecessor[exchange] = currency; | |
} | |
} | |
} | |
} | |
// Negative cycle detection and retention | |
for(currency in currencies) { | |
for(exchange in currencies[currency]) { | |
if(distance[exchange] > distance[currency] + currencies[currency][exchange]) { | |
// If we are just using hasArbitrage, we can return instantly | |
if(justOne) return true; | |
// Else, we save the fact and grab up the cycle | |
arbitrage = true; | |
cycles[exchange] = true; | |
} | |
} | |
} | |
return arbitrage; | |
}; | |
/** private:build_sequences takes cyclic information and outputs the path used to create that cycle **/ | |
var build_sequences = function(currencies, cycles) { | |
var p, visited, sequence, max; | |
for(cycle in cycles) { | |
p = cycle; | |
sequence = []; | |
visited = []; | |
while(p != undefined && !visited[p]) { | |
visited[p] = true; | |
sequence.unshift(p); | |
p = predecessor[p]; | |
} | |
sequence.push(sequence[0]); | |
val = 1; | |
for(var i = 0; i < sequence.length - 1; ++i) { | |
val = val * original_currencies[sequence[i]][sequence[i+1]]; | |
} | |
if(max == undefined || max[1] < val) max = [sequence, val]; | |
} | |
return max; | |
} | |
/** | |
* hasArbitrage takes a 2-dimensional (n x n) array of currencies and | |
* deduces whether of not an arbitrage exists | |
* | |
* @currencies: a 2-dimensional (n x n) array of currencies | |
* @return: A boolean value of true or false | |
**/ | |
this.hasArbitrage = function(currencies) { | |
return findArbitrage(currencies, true); | |
} | |
/** | |
* max returns the optimal arbitrage in a a 2-dimensional (n x n) array of currencies. | |
* The output is an array with the path and value. | |
* | |
* @currencies: a 2-dimensional (n x n) array of currencies | |
* @return: Array, [[path], val] | |
**/ | |
this.max = function(currencies) { | |
findArbitrage(currencies, false); | |
var max = build_sequences(currencies, cycles); | |
return max; | |
}; | |
return this; | |
}; | |
var abfinder = new ArbitrageFinder(); | |
console.log(abfinder.hasArbitrage(currencies)); | |
console.log(abfinder.max(currencies)); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment