// Given a dictionary of starting balances, create min/max values based on given percentages (upPct/downPct) public static BalanceMinMaxMap CreatePercentageUpDown(IDictionary <string, ZAccountBalance> balances, decimal upPct, decimal downPct) { var limits = new BalanceMinMaxMap(); foreach (var kv in balances) { var free = balances[kv.Key].Free; limits.Add(kv.Key, free - (downPct / 100 * free), free + (upPct / 100 * free)); } return(limits); }
// BINANCE ARBS #1 public static void TestBinanceArbs1() { // Create Prowl messaging client var msg1 = new Tools.Messaging.Prowl.ProwlClient(Crypto.ApiKeys["PROWL"].ApiKey, "BINANCE", "MACD"); var assetInfo = binance.GetAssetInfo(); //assetInfo.Select(xkv => xkv).OrderBy(xkv => xkv.Key).ToList().ForEach(xai => cout(xai.Value.ToDisplay())); // Create a BalanceMinMaxMap that we will pass to ArbZero to set our Min/Max currency balance limits var balances = binance.GetAccountBalances(); var limits = BalanceMinMaxMap.CreatePercentageUpDown(balances, 50, 50); // set limits to up or down 50% from current balances var args = new List <ArbZeroArgs>(); args.AddRange(GetArgs("BCC", 0.01M)); args.AddRange(GetArgs("LTC", 0.1M)); args.AddRange(GetArgs("NEO", 0.1M)); Task.Run(() => ArbOne(args, limits, true, 0.14M, 4001)); }
// BINANCE ARB #1 public static void ArbOne(List <ArbZeroArgs> args, BalanceMinMaxMap balanceLimits, bool enableLiveOrders, decimal targetPct = 0.2M, int?threadSleepMillis = null) { var rnd = new Random(); int sleepMillis = 0; if (threadSleepMillis == null) { sleepMillis = 5000 + rnd.Next(-2000, 2000); } else { sleepMillis = threadSleepMillis.Value; } cout("\nSLEEP_MILLIS = {0}\n", sleepMillis); var pairs = GetBinancePairs(); var assetInfo = binance.GetAssetInfo(); binance.EnableLiveOrders = enableLiveOrders; // turn on/off live orders const int MAX_ORDERS = 100; //100000; int norders = 0; const int MIN_PRIME_COUNT = 2; int nprime = 0; // THREAD LOOP STARTS HERE ZTicker t1, t2, t3; while (true) { // Get the balances in each currency (we will check these against our balanceLimits Min/Max values) var balances = binance.GetAccountBalances(); // Get all the tickers as a dictionary var bnd = binance.GetAllTickers().Result; var bxd = bittrex.GetAllTickers(); // Loop through each symbol set that was passed as ArbZeroArgs foreach (var aza in args) { var symbols = aza.symbols; var size = aza.size; t1 = bnd[symbols[0]]; t2 = bnd[symbols[1]]; t3 = bnd[symbols[2]]; var buy1 = t1.Ask; var buy2 = t2.Bid * t3.Ask; var buypct = (buy2 - buy1) / buy2 * 100; var sell1 = t1.Bid; var sell2 = t2.Ask * t3.Bid; var sellpct = (sell1 - sell2) / sell1 * 100; if (nprime >= MIN_PRIME_COUNT) { // Check tickers for BUY signal if (buypct >= targetPct) { if (norders < MAX_ORDERS) { var pair0 = pairs[symbols[0]]; var lbalance0 = balances[pair0.Left]; var rbalance0 = balances[pair0.Right]; var llimit0 = balanceLimits[pair0.Left]; var rlimit0 = balanceLimits[pair0.Right]; if (lbalance0.Free < llimit0.Max && rbalance0.Free > rlimit0.Min) { var pair1 = pairs[symbols[1]]; var lbalance1 = balances[pair1.Left]; var rbalance1 = balances[pair1.Right]; var llimit1 = balanceLimits[pair1.Left]; var rlimit1 = balanceLimits[pair1.Right]; if (lbalance1.Free > llimit1.Min && rbalance1.Free < rlimit1.Max) { var pair2 = pairs[symbols[2]]; var lbalance2 = balances[pair2.Left]; var rbalance2 = balances[pair2.Right]; var llimit2 = balanceLimits[pair2.Left]; var rlimit2 = balanceLimits[pair2.Right]; if (lbalance2.Free < llimit2.Max && rbalance2.Free > rlimit2.Min) { int places = binance.RoundSize(symbols[2]); var calculatedSize = Math.Round(size * t2.Bid, places); binance.SubmitLimitOrder(symbols[0], OrderSide.Buy, t1.Ask, size); binance.SubmitLimitOrder(symbols[1], OrderSide.Sell, t2.Bid, size); binance.SubmitLimitOrder(symbols[2], OrderSide.Buy, t3.Ask, calculatedSize); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[0], OrderSide.Buy, t1.Ask, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[1], OrderSide.Sell, t2.Bid, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[2], OrderSide.Buy, t3.Ask, calculatedSize); // Adjust the balances for these orders/trades (assume they will be filled) lbalance0.Free += size; rbalance2.Free -= calculatedSize; } else { cout("+++Ignoring BUY signal due to {0} limits", symbols[2]); } } else { cout("+++Ignoring BUY signal due to {0} limits", symbols[1]); } } else { cout("+++Ignoring BUY signal due to {0} limits", symbols[0]); } } ++norders; } // Check tickers for SELL signal if (sellpct >= targetPct) { if (norders < MAX_ORDERS) { var pair0 = pairs[symbols[0]]; var lbalance0 = balances[pair0.Left]; var rbalance0 = balances[pair0.Right]; var llimit0 = balanceLimits[pair0.Left]; var rlimit0 = balanceLimits[pair0.Right]; if (lbalance0.Free > llimit0.Min && rbalance0.Free < rlimit0.Max) { var pair1 = pairs[symbols[1]]; var lbalance1 = balances[pair1.Left]; var rbalance1 = balances[pair1.Right]; var llimit1 = balanceLimits[pair1.Left]; var rlimit1 = balanceLimits[pair1.Right]; if (lbalance1.Free < llimit1.Max && rbalance1.Free > rlimit1.Min) { var pair2 = pairs[symbols[2]]; var lbalance2 = balances[pair2.Left]; var rbalance2 = balances[pair2.Right]; var llimit2 = balanceLimits[pair2.Left]; var rlimit2 = balanceLimits[pair2.Right]; if (lbalance2.Free > llimit2.Min && rbalance2.Free < rlimit2.Max) { int places = binance.RoundSize(symbols[2]); var calculatedSize = Math.Round(size * t2.Ask, places); binance.SubmitLimitOrder(symbols[0], OrderSide.Sell, t1.Bid, size); binance.SubmitLimitOrder(symbols[1], OrderSide.Buy, t2.Ask, size); binance.SubmitLimitOrder(symbols[2], OrderSide.Sell, t3.Bid, calculatedSize); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[0], OrderSide.Sell, t1.Bid, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[1], OrderSide.Buy, t2.Ask, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[2], OrderSide.Sell, t3.Bid, calculatedSize); // Adjust the balances for these orders/trades (assume they will be filled) lbalance0.Free -= size; rbalance2.Free += calculatedSize; } else { cout("+++Ignoring SELL signal due to {0} limits", symbols[2]); } } else { cout("+++Ignoring SELL signal due to {0} limits", symbols[1]); } } else { cout("+++Ignoring SELL signal due to {0} limits", symbols[0]); } } ++norders; } } //cout("{0}\n{1}\n{2}", t1.ToDisplay(), t2.ToDisplay(), t3.ToDisplay()); var bsize1 = t1.AskSize; var bsize2 = Math.Min(t2.BidSize, t3.AskSize); string btext = (buy1 < buy2 ? "BUY" : "buy"); string bbtext = (buy1 < buy2 ? string.Format("BUY {0:#.000}%", buypct) : " "); var ssize1 = t1.BidSize; var ssize2 = Math.Min(t2.AskSize, t3.BidSize); string stext = (sell1 > sell2 ? "SELL" : "sell"); string sstext = (sell1 > sell2 ? string.Format("SELL {0:#.000}%", sellpct) : " "); cout("{0}: {1} x {2} < {3} x {4} {5}: {6} x {7} > {8} x {9} {10} {11}", btext, bsize1, buy1, buy2, bsize2, stext, ssize1, sell1, sell2, ssize2, bbtext, sstext); } ++nprime; Thread.Sleep(sleepMillis); } }
//var symbols = new string[] { "BCCUSDT", "BCCBTC", "BTCUSDT" }; //decimal size = 0.01M; //int? threadSleepMillis = (int?)5000; public static void ArbZero(List <ArbZeroArgs> args, BalanceMinMaxMap balanceLimits, bool enableLiveOrders, decimal targetPct = 0.2M, int?threadSleepMillis = null) { var rnd = new Random(); int sleepMillis = 0; if (threadSleepMillis == null) { sleepMillis = 5000 + rnd.Next(-2000, 2000); } else { sleepMillis = threadSleepMillis.Value; } cout("\nSLEEP_MILLIS = {0}\n", sleepMillis); var pairs = GetBinancePairs(); var assetInfo = binance.GetAssetInfo(); binance.EnableLiveOrders = enableLiveOrders; // turn on/off live orders const int MAX_ORDERS = 100; //100000; int norders = 0; const int MIN_PRIME_COUNT = 2; int nprime = 0; // THREAD LOOP STARTS HERE //DateTime startTime; //double elapsed; //List<double> millis = new List<double>(); ZTicker t1, t2, t3; while (true) { // Get the balances in each currency (we will check these against our balanceLimits Min/Max values) var balances = binance.GetAccountBalances(); // Get all the tickers as a dictionary var d = binance.GetAllTickers().Result; // Loop through each symbol set that was passed as ArbZeroArgs foreach (var aza in args) { var symbols = aza.symbols; var size = aza.size; t1 = d[symbols[0]]; t2 = d[symbols[1]]; t3 = d[symbols[2]]; // THIS WHOLE SECTION WAS TO SPEED TEST VARIOUS GET TICKER METHODS /*int calc = 2; * if (calc == 1) // use GetFastTicker * { * //startTime = DateTime.Now; * t1 = binance.GetBookTicker(symbols[0]); * t2 = binance.GetBookTicker(symbols[1]); * t3 = binance.GetBookTicker(symbols[2]); * //elapsed = DateTime.Now.Subtract(startTime).TotalMilliseconds; * //millis.Add(elapsed); * } * else if (calc == 2) // use GetAllTickers * { * //startTime = DateTime.Now; * var d = binance.GetAllTickers(); * t1 = d[symbols[0]]; * t2 = d[symbols[1]]; * t3 = d[symbols[2]]; * //elapsed = DateTime.Now.Subtract(startTime).TotalMilliseconds; * //millis.Add(elapsed); * } * else // standard GetTicker * { * //startTime = DateTime.Now; * t1 = binance.GetTicker(symbols[0]); * t2 = binance.GetTicker(symbols[1]); * t3 = binance.GetTicker(symbols[2]); * //elapsed = DateTime.Now.Subtract(startTime).TotalMilliseconds; * //millis.Add(elapsed); * }*/ //cout("elapsed: {0:0.000} ms avg:{1:0.000} std:{2:0.000}", elapsed, millis.Average(), GMath.Std(millis)); var buy1 = t1.Ask; var buy2 = t2.Bid * t3.Ask; var buypct = (buy2 - buy1) / buy2 * 100; var sell1 = t1.Bid; var sell2 = t2.Ask * t3.Bid; var sellpct = (sell1 - sell2) / sell1 * 100; if (nprime >= MIN_PRIME_COUNT) { // Check tickers for BUY signal if (buypct >= targetPct) { if (norders < MAX_ORDERS) { var pair0 = pairs[symbols[0]]; var lbalance0 = balances[pair0.Left]; var rbalance0 = balances[pair0.Right]; var llimit0 = balanceLimits[pair0.Left]; var rlimit0 = balanceLimits[pair0.Right]; if (lbalance0.Free < llimit0.Max && rbalance0.Free > rlimit0.Min) { var pair1 = pairs[symbols[1]]; var lbalance1 = balances[pair1.Left]; var rbalance1 = balances[pair1.Right]; var llimit1 = balanceLimits[pair1.Left]; var rlimit1 = balanceLimits[pair1.Right]; if (lbalance1.Free > llimit1.Min && rbalance1.Free < rlimit1.Max) { var pair2 = pairs[symbols[2]]; var lbalance2 = balances[pair2.Left]; var rbalance2 = balances[pair2.Right]; var llimit2 = balanceLimits[pair2.Left]; var rlimit2 = balanceLimits[pair2.Right]; if (lbalance2.Free < llimit2.Max && rbalance2.Free > rlimit2.Min) { int places = binance.RoundSize(symbols[2]); //int places = m_binanceRoundLotSize[assetInfo[symbols[2]].stepSize]; var calculatedSize = Math.Round(size * t2.Bid, places); binance.SubmitLimitOrder(symbols[0], OrderSide.Buy, t1.Ask, size); binance.SubmitLimitOrder(symbols[1], OrderSide.Sell, t2.Bid, size); binance.SubmitLimitOrder(symbols[2], OrderSide.Buy, t3.Ask, calculatedSize); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[0], OrderSide.Buy, t1.Ask, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[1], OrderSide.Sell, t2.Bid, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[2], OrderSide.Buy, t3.Ask, calculatedSize); // Adjust the balances for these orders/trades (assume they will be filled) lbalance0.Free += size; rbalance2.Free -= calculatedSize; } else { cout("+++Ignoring BUY signal due to {0} limits", symbols[2]); } } else { cout("+++Ignoring BUY signal due to {0} limits", symbols[1]); } } else { cout("+++Ignoring BUY signal due to {0} limits", symbols[0]); } } ++norders; } // Check tickers for SELL signal if (sellpct >= targetPct) { if (norders < MAX_ORDERS) { var pair0 = pairs[symbols[0]]; var lbalance0 = balances[pair0.Left]; var rbalance0 = balances[pair0.Right]; var llimit0 = balanceLimits[pair0.Left]; var rlimit0 = balanceLimits[pair0.Right]; if (lbalance0.Free > llimit0.Min && rbalance0.Free < rlimit0.Max) { var pair1 = pairs[symbols[1]]; var lbalance1 = balances[pair1.Left]; var rbalance1 = balances[pair1.Right]; var llimit1 = balanceLimits[pair1.Left]; var rlimit1 = balanceLimits[pair1.Right]; if (lbalance1.Free < llimit1.Max && rbalance1.Free > rlimit1.Min) { var pair2 = pairs[symbols[2]]; var lbalance2 = balances[pair2.Left]; var rbalance2 = balances[pair2.Right]; var llimit2 = balanceLimits[pair2.Left]; var rlimit2 = balanceLimits[pair2.Right]; if (lbalance2.Free > llimit2.Min && rbalance2.Free < rlimit2.Max) { int places = binance.RoundSize(symbols[2]); var calculatedSize = Math.Round(size * t2.Ask, places); binance.SubmitLimitOrder(symbols[0], OrderSide.Sell, t1.Bid, size); binance.SubmitLimitOrder(symbols[1], OrderSide.Buy, t2.Ask, size); binance.SubmitLimitOrder(symbols[2], OrderSide.Sell, t3.Bid, calculatedSize); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[0], OrderSide.Sell, t1.Bid, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[1], OrderSide.Buy, t2.Ask, size); cout("---Crypto::ArbZero=> '{0}' {1} {2} {3}", symbols[2], OrderSide.Sell, t3.Bid, calculatedSize); // Adjust the balances for these orders/trades (assume they will be filled) lbalance0.Free -= size; rbalance2.Free += calculatedSize; } else { cout("+++Ignoring SELL signal due to {0} limits", symbols[2]); } } else { cout("+++Ignoring SELL signal due to {0} limits", symbols[1]); } } else { cout("+++Ignoring SELL signal due to {0} limits", symbols[0]); } } ++norders; } } //cout("{0}\n{1}\n{2}", t1.ToDisplay(), t2.ToDisplay(), t3.ToDisplay()); var bsize1 = t1.AskSize; var bsize2 = Math.Min(t2.BidSize, t3.AskSize); string btext = (buy1 < buy2 ? "BUY" : "buy"); string bbtext = (buy1 < buy2 ? string.Format("BUY {0:#.000}%", buypct) : " "); var ssize1 = t1.BidSize; var ssize2 = Math.Min(t2.AskSize, t3.BidSize); string stext = (sell1 > sell2 ? "SELL" : "sell"); string sstext = (sell1 > sell2 ? string.Format("SELL {0:#.000}%", sellpct) : " "); cout("{0}: {1} x {2} < {3} x {4} {5}: {6} x {7} > {8} x {9} {10} {11}", btext, bsize1, buy1, buy2, bsize2, stext, ssize1, sell1, sell2, ssize2, bbtext, sstext); /*buy1 = t1.Bid; * buy2 = t2.Bid * t3.Ask; * bsize1 = t1.BidSize; * bsize2 = Math.Min(t2.BidSize, t3.AskSize); * btext = (buy1 < buy2 ? "BUY" : "buy"); * sell1 = t1.Ask; * sell2 = t2.Ask * t3.Bid; * ssize1 = t1.AskSize; * ssize2 = Math.Min(t2.AskSize, t3.BidSize); * stext = (sell1 > sell2 ? "SELL" : "sell"); * cout("{0}: {1} x {2} < {3} x {4} {5}: {6} x {7} > {8} x {9}\n", btext, bsize1, buy1, buy2, bsize2, stext, ssize1, sell1, sell2, ssize2); */ } ++nprime; Thread.Sleep(sleepMillis); } }