Trading simultaneously with multiple accounts, brokers, exchanges, or data feeds allows broker arbitrage, i.e. exploiting prices differences of the same asset between different market places. Arbitrage opportunities appear for instance when Forex liquidity providers deviate from each other, or when market makers do not precisely follow the market. There is no central exchange for currencies and CFDs, so their prices vary from broker to broker. If the price differences temporarily exceed trading costs, you can collect risk-free profits.
Zorro S can simultaneously trade with up to 12 brokers or price data feeds. It allows trading strategies to compare currency or CFD prices between broker A and broker B, and enter a long position with the cheaper broker and a short position with the other. Here's the step by step setup and a code example for taking advantage of Forex/CFD price differences. But be aware that brokers dislike broker arbitrage practices, and may close accounts when they learn that they were exploited in this way.
Name | Broker | Account | User | Pass | Assets | CCY | Real | NFA | Plugin |
BrokerA | AAA | 0 | 4009876 | n4qw4ert7 | AssetsArb | USD | 1 | 0 | Broker1.dll |
BrokerB | BBB | 0 | 3456789 | ab234qrz2 | AssetsArb | USD | 1 | 0 | Broker2.dll |
Name | Price | Spread | Roll | Roll | PIP | Cost | Margin | Market | Amount | Comm | Symbol |
EURUSD_A | 1.17311 | 0.00005 | 0 | 0 | 0.0001 | 0.1 | -0.01 | 0 | 1000 | 0.6 | BrokerA:EUR/USD |
EURUSD_B | 1.17299 | 0.00007 | 0 | 0 | 0.0001 | 0.1 | -0.01 | 0 | 1000 | 0.5 | BrokerB:EUR/USD |
// Simple broker arbitrage example //////////////////////////// function tick() { asset("EURUSD_A"); var SpreadA = Spread, PriceA = priceClose(), CommissionA = Commission*LotAmount/10000*PIP/PIPCost; // convert commission to price difference asset("EURUSD_B"); var SpreadB = Spread, PriceB = priceClose(), CommissionB = Commission*LotAmount/10000*PIP/PIPCost; var Threshold = 1.5*(SpreadA+SpreadB+CommissionA+CommissionB); // arbitrage threshold var Difference = PriceA - PriceB; asset("EURUSD_A"); if(NumOpenShort && Difference < 0) exitShort(); else if(NumOpenLong && Difference > 0) exitLong(); else if(!NumOpenShort && Difference > Threshold) // go short with the expensive asset enterShort(); else if(!NumOpenLong && Difference < -Threshold) // go long with the cheap asset enterLong(); asset("EURUSD_B"); if(NumOpenShort && Difference > 0) exitShort(); else if(NumOpenLong && Difference < 0) exitLong(); else if(!NumOpenShort && Difference < -Threshold) enterShort(); else if(!NumOpenLong && Difference > Threshold) enterLong(); } function run() { StartDate = EndDate = 2017; LookBack = 0; set(TICKS); History = "*.t1"; assetList("AssetsArb.csv"); asset("EURUSD_A"); asset("EURUSD_B"); }
// Generate a multi-broker asset list /////////////////////// #define LISTS "FXCM","Oanda" #define ASSETLIST "AssetsMulti" function main() { char OutName[NAMESIZE2]; // to store a temporary string strcpy(OutName,strf("History\\%s.csv",ASSETLIST)); file_delete(OutName); string Name, Source = 0; while(Name = of(LISTS)) { static char Dest[40000]; file_read(strf("History\\Assets%s.csv",Name),Dest,0); if(!*Dest) return quit("Source not found!"); string Pos = strchr(Dest,'\n'); // skip header line after first file if(!Source) Source = Dest; else Source = Pos+1; while(Pos) { Pos = strchr(Pos+1,','); if(!Pos) break; // append list name to asset name strcatf(Pos,strf("_%s",Name)); int i; for(i=0; i<11; i++) // find Symbol column Pos = strchr(Pos+1,','); // append list name as source to symbol strcatf(Pos+1,strf("%s:",Name)); Pos = strchr(Pos,'\n'); } file_append(OutName,Source,0); } }