public void ValidateArbitrationTradeOrderExecution(ArbitrationOpportunity arbitrationTrade) { bool tradeFailed = false; StringBuilder errorMessage = new StringBuilder("Arbitration trade " + CommonFunctions.StringManipulation.NullIntString(arbitrationTrade.Id) + " did not execute. "); //Note, btce is special. If orders are fulfilled immediately, it just returns zero, not the actual order id. So if the exchange is btce, //and the order id is 0, no need to do a check. //Check to see if both the buy and sell orders were executed; check for btce order fulfillment first, to keep an error getting thrown on the order fulfillment check because of a non-existent '0' order id. if (!(arbitrationTrade.SellExchange.GetType() == typeof(Btce) && arbitrationTrade.SellOrderId == "0") && !arbitrationTrade.SellExchange.IsOrderFulfilled(arbitrationTrade.SellOrderId)) { errorMessage.Append("Sell order did not get filled. "); tradeFailed = true; } if (!(arbitrationTrade.BuyExchange.GetType() == typeof(Btce) && arbitrationTrade.BuyOrderId == "0") && !arbitrationTrade.BuyExchange.IsOrderFulfilled(arbitrationTrade.BuyOrderId)) { errorMessage.Append("Buy order did not get filled. "); tradeFailed = true; } if (tradeFailed) { ExchangeBalanceInfo postArbitrationTradebalanceInfo = CalculateFiatAndBitcoinTotals(); string balanceString = ""; balanceString += "Balances after trade:" + Environment.NewLine + postArbitrationTradebalanceInfo.ToString() + Environment.NewLine; balanceString += "Differences: " + Environment.NewLine + BuildDifferenceString(_exchangeBalanceInfoBeforeArbitrationTrade, postArbitrationTradebalanceInfo); throw new ArbitrationTradeValidationException(errorMessage.ToString(), balanceString); } }
/// <summary> /// Given two ExchangeBalanceInfo objects, subtracts the pre trade balance from the post trade balance and builds a of the results. /// </summary> /// <param name="exchangeBalanceInfoBeforeArbitrationTrade">Balances of the exchanges before the arbitration trade.</param> /// <param name="postArbitrationTradebalanceInfo">Balances of the exchanges after the arbitration trade.</param> /// <returns></returns> private string BuildDifferenceString(ExchangeBalanceInfo exchangeBalanceInfoBeforeArbitrationTrade, ExchangeBalanceInfo postArbitrationTradebalanceInfo) { string returnString = ""; foreach (KeyValuePair <string, decimal[]> preExchangeBalanceDetailInfo in exchangeBalanceInfoBeforeArbitrationTrade.exchangeBalanceDictionary) { //Grab the balance info from the post balance object as well KeyValuePair <string, decimal[]> postExchangeBalanceDetailInfo = postArbitrationTradebalanceInfo.exchangeBalanceDictionary.First(x => x.Key == preExchangeBalanceDetailInfo.Key); if (returnString.Length > 0) { returnString += Environment.NewLine; } returnString += "\t\t" + preExchangeBalanceDetailInfo.Key + Environment.NewLine; returnString += "\t\t\tFiat: " + (postExchangeBalanceDetailInfo.Value[0] - preExchangeBalanceDetailInfo.Value[0]) + Environment.NewLine; returnString += "\t\t\tBtc: " + (postExchangeBalanceDetailInfo.Value[1] - preExchangeBalanceDetailInfo.Value[1]); } return(returnString); }
public string ValidateExchangeBalancesAfterTrade(ArbitrationOpportunity arbitrationTrade) { ExchangeBalanceInfo postArbitrationTradebalanceInfo = CalculateFiatAndBitcoinTotals(); decimal realizedProfit = postArbitrationTradebalanceInfo.TotalFiatBalance - _exchangeBalanceInfoBeforeArbitrationTrade.TotalFiatBalance; string errorMessage = ""; string balanceString = ""; balanceString += "\tBalances after trade:" + Environment.NewLine + postArbitrationTradebalanceInfo.ToString() + Environment.NewLine; balanceString += "\tDifferences: " + Environment.NewLine + BuildDifferenceString(_exchangeBalanceInfoBeforeArbitrationTrade, postArbitrationTradebalanceInfo); if (realizedProfit <= arbitrationTrade.Profit * 0.98m) { errorMessage = "Realized profit for arbitration trade " + arbitrationTrade.Id + " was more than 2% less than the expected profit. Expected profit = " + arbitrationTrade.Profit + ", realized profit = " + realizedProfit + "."; } else if (realizedProfit >= arbitrationTrade.Profit * 1.02m) { errorMessage = "Realized profit for arbitration trade " + arbitrationTrade.Id + " was more than 2% greater than the expected profit. Expected profit = " + arbitrationTrade.Profit + ", realized profit = " + realizedProfit + "."; } if (postArbitrationTradebalanceInfo.TotalBitcoinBalance <= _exchangeBalanceInfoBeforeArbitrationTrade.TotalBitcoinBalance * 0.98m) { errorMessage += "Bitcoin balance after arbitration trade " + arbitrationTrade.Id + " decreased by more than 2%. Bitcoin balance before trade = " + _exchangeBalanceInfoBeforeArbitrationTrade.TotalBitcoinBalance + ", bitcoin balance after trade = " + postArbitrationTradebalanceInfo.TotalBitcoinBalance + "."; } else if (postArbitrationTradebalanceInfo.TotalBitcoinBalance >= _exchangeBalanceInfoBeforeArbitrationTrade.TotalBitcoinBalance * 1.02m) { errorMessage += "Bitcoin balance after arbitration trade " + arbitrationTrade.Id + " increased by more than 2%. Bitcoin balance before trade = " + _exchangeBalanceInfoBeforeArbitrationTrade.TotalBitcoinBalance + ", bitcoin balance after trade = " + postArbitrationTradebalanceInfo.TotalBitcoinBalance + "."; } //If there is text in erroMessage, the trade did not validate if (!String.IsNullOrWhiteSpace(errorMessage)) { throw new ArbitrationTradeValidationException(errorMessage, balanceString); } return(balanceString); }
private ExchangeBalanceInfo CalculateFiatAndBitcoinTotals() { decimal totalFiat = 0.0m; decimal totalBitcoin = 0.0m; string balanceString = ""; ExchangeBalanceInfo returnInfo = new ExchangeBalanceInfo(); foreach (BaseExchange exchange in _exchangeList) { //Add to the running totals of the fiat and bitcoin balances totalFiat += exchange.AvailableFiat; totalBitcoin += exchange.AvailableBtc; //Add to the dictionary so the balances and be compared later returnInfo.exchangeBalanceDictionary.Add(exchange.Name, new [] { exchange.AvailableFiat, exchange.AvailableBtc }); } returnInfo.TotalBitcoinBalance = totalBitcoin; returnInfo.TotalFiatBalance = totalFiat; return(returnInfo); }
public void SetFiatAndBitcoinBalanceBeforeArbitrationTrade() { _exchangeBalanceInfoBeforeArbitrationTrade = CalculateFiatAndBitcoinTotals(); }