//+------------------------------------------------------------------+ //| currencyArbitrage_demo.mq5 | //| Copyright © 2018, Amr Ali | //| https://www.mql5.com/en/users/amrali | //+------------------------------------------------------------------+ #property copyright "Copyright © 2018, Amr Ali" #property link "https://www.mql5.com/en/users/amrali" #property version "1.000" #property description "Currency arbitrage demo using my fast 'circular k-permutations' algorithm." #property description " " #property description "Minimum arbitrage rate:" #property description " " #property description "for profitable trading, you need to input values > 1.0 (e.g., 1.00008)" #property description "in the script window to overcome spreads and commission fees." #property description " " #property description "for testing only, please provide values < 1.0 (e.g., 0.99966 or less)" #property description "in the script window to display more arbitrage opportunities" #property strict #property script_show_inputs #include // you could also try ring sizes 4 and 5 input int InpRingSize=3; // RingSize // for profitable trading, you need to input values > 1.0 (e.g., 1.00008) // in the script window to overcome spread and commission fees. // for testing only, you may need to input values < 1.0 (e.g., 0.99966 or less) // in the script window to display more arbitrage opportunities input double InpArbitrageThreshold=0.99966; // Minimum arbitrage rate //+------------------------------------------------------------------+ // Arbitrage is simultaneously buying and selling the same asset at // different prices to get immediate profit. // Arbitrage is the practice of buying an asset and selling it for // a higher price in another market or area to take advantage of a // difference in price. (buy low and sell high) // Execution risk // Triangular aribitrage oppotunities last for few milliseconds, therefore // this type of arbitrage is only profitable for institutional traders. // Profits from a triangular arbitrage strategy are small but consistent // to those who are quickest to spot and act on the imbalance. Because // this type of "risk free" tri arb is extremely time sensitive, even a // small delay in order placement is enough to nullify any potential profit. // Fees // unfortunately, you have to pay fees every time you change money, and // these would more than wipe out your profit. // For further reading: // https://apiaryfund.com/forum/triangular-arbitrage-basics // https://www.kreslik.com/forums/viewtopic.php?t=307 // http://forum.vamist.ro/blog/2/entry-6-evolution-and-principles-of-the-intercross-arbitrage/ //+-----------------------------------------------------------+ // How to use exchange rates with arbitrage // EUR/USD exchange rate is 1.1898 / 1.1899 // so, you sell 1 EUR @1.1898 USD (Bid price) // so, you buy 1 EUR @1.1899 USD (Ask price) // Convert EUR->USD // = SELL euros // USD units you get = EUR units x Bid // Convert 1 unit left to right (sell pair): multiply x low rate (MODE_BID) // Convert EUR<-USD // = BUY euros // EUR units you get = USD units x 1 / Ask // Convert 1 unit right to left (buy pair): divide / high rate (MODE_ASK) //+-----------------------------------------------------------+ #define V 8 // Priority ranking of major currencies in forex currency pairs. // For example, EUR always comes first in all the 7 euro pairs. // USD comes last in 4 usd pairs, and comes first in other 3 pairs. string arrCcy[V] = {"EUR", "GBP", "AUD", "NZD", "USD", "CAD", "CHF", "JPY"}; int mapping[V] = { 0, 1, 2, 3, 4, 5, 6, 7 }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // My fast algorithm for k-angular currency arbitrage: void currencyArbitrageProblem(double &graph[][V],int k) { // number of arbitrage opportunities found int counter=0; // array to receive circular permutations one by one int ring[]; // choose "k out of n currencies" CombinationsIteratorcomboIt(mapping,k,ring); // For each unordered combination of "k out of n currencies": // 1) Consider the first currency as the starting and ending point. // 2) Generate all (k-1)! permutations of remaining currencies. do { // fix the first currency of k, permute next k-1 currencies. PermutationsIteratorperm(ring,1,k-1); do { // store current Path weight(arbitrage rate) double current_pathweight=1; // compute current path weight int s = ring[0]; int c = s; for(int i=1; iInpArbitrageThreshold) { // print the arbitrage path that visits every currency // exactly once and returns back to the starting point. printf("#%i: arbitrage opportunity %s = %.5f",++counter,RingToString(ring,"/"),current_pathweight); // decode the arbitrage path // https://algs4.cs.princeton.edu/44sp/Arbitrage.java.html int st=ring[0]; int from=st; int to=-1; current_pathweight=1; double stake=1000.00; for(int i=1; i 0) return (symbol_name); /** Get symbol name from all. */ symbol_name=getSymbol(pSymb,false); /** If symbol exists, add symbol to MarketWatch. */ if(StringLen(symbol_name)>0) { SymbolSelect(symbol_name,true); printf("adding symbol %s to MarketWatch.",symbol_name); /** * There is a time lag before being updated. * As a workaround, sleep for 1 second. */ // Sleep(1000); double bid=0.0; uint timeOut = 3000, start = GetTickCount(); bool success = false; do { success=SymbolInfoDouble(symbol_name,SYMBOL_BID,bid); } while((!success || bid==0.0) && (GetTickCount()-start)<=timeOut && !IsStopped()); // return fully qualified symbol name return (symbol_name); } // cannot get fully qualified name, so return passed symbol name, unchanged. return (pSymb); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string getSymbol(string pSymb,bool MarketWatch) { // case-insensitive search StringToUpper(pSymb); string symbol; for(int i=0,max=SymbolsTotal(MarketWatch); i-1) { return (SymbolName(i, MarketWatch)); } } return (NULL); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // driver program to test above function void OnStart() { if(InpRingSize<2) { Alert("Error: Incorrect parameters!"); return; } if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { Alert("Error: Terminal is not connected to a trade server!"); return; } // start stopwatch to benchmark ulong s_time=GetMicrosecondCount(); // matrix representation of exchange rates graph double graph[V][V]; ArrayInitialize(graph,1); for(int i=0; iusd graph[j][i] = 1.0 / vask; // eur<-usd } } int n = ArraySize(arrCcy); int k = InpRingSize; currencyArbitrageProblem(graph,k); // count of circular k-permutations = nPk / k printf("Done! examined all the %I64i possible arbitrage rings with %i currencies taken from %i. (%i microseconds)",nPk(n,k)/k,k,n,(GetMicrosecondCount()-s_time)); } //+------------------------------------------------------------------+