/// <summary> /// Checks order that are in waiting state, and changes it to placed state if is needed (Here transaction confirmations are verified)) /// </summary> /// <param name="aWaitingOrders">Orders with waiting state</param> /// <param name="aCurrencyItem">Order currency item</param> /// <param name="aCurrencyTransactions">Pandora's currency transactions</param> /// <param name="aListExchangeCoinMarket">Markets to look for</param> private void VerifyWaitingOrders(IEnumerable <UserTradeOrder> aWaitingOrders, ICurrencyIdentity aCurrencyItem, IEnumerable <TransactionRecord> aCurrencyTransactions) { long lCurrencyBlockHeight; int lExchangeminConf; ScanForCancelledOrders(aWaitingOrders); if (!aWaitingOrders.Any() || !aCurrencyTransactions.Any() || (lExchangeminConf = FExchanger.GetConfirmations(aCurrencyItem)) < 0 || (lCurrencyBlockHeight = FPandorasWalletConnection.GetBlockHeight(aCurrencyItem.Id)) <= 0) { return; } var lConfirmedTxs = aCurrencyTransactions.Where(lTx => lTx.Block != 0 && (lCurrencyBlockHeight - lTx.Block) > lExchangeminConf); foreach (var lTx in lConfirmedTxs) { UserTradeOrder lItem = aWaitingOrders.Where(lOrder => lOrder.CoinTxID == lTx.TxId).FirstOrDefault(); if (lItem == null) { continue; } if (lItem.Status == OrderStatus.Waiting && lItem.Market != null) { TryToPlaceOrder(lItem); } } }
public bool RefundOrder(UserTradeOrder aOrder, string aAddress, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder.Status == OrderStatus.Withdrawn) { return(false); } PoloniexClientOptions lPoloniexClientOptions = new PoloniexClientOptions() { Proxy = PandoraProxy.GetApiProxy(), ApiCredentials = new ApiCredentials(FUserCredentials.Item1, FUserCredentials.Item2) }; using (PoloniexClient lClient = aUseProxy ? new PoloniexClient(lPoloniexClientOptions) : new PoloniexClient()) { var lResponse = lClient.Withdraw(aOrder.Market.SellingCurrencyInfo.Ticker, aOrder.SentQuantity, aAddress); if (!lResponse.Success) { throw new Exception("Failed to refund order. Error message:" + lResponse.Error.Message); } if (!string.IsNullOrEmpty(lResponse.Data.error)) { throw new Exception($"Failed to refund order. Error message: {lResponse.Data.error}"); } } return(true); }
/// <summary> /// Tries to form a transaction that meets the order requeriments and then sends it to the exchange user address. Also does amount verification /// </summary> /// <param name="aOrder">Order to fulfill</param> /// <param name="aMarket">Order's market</param> /// <param name="aCurrencyID">Selected currency id</param> private async void TryToTransferMoneyToExchange(UserTradeOrder aOrder) { const string lAlreadyProcessingFlag = "Processing"; try { if (aOrder.CoinTxID == lAlreadyProcessingFlag) { return; } FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Info, string.Format("Stop price reached, trying to send coins to exchange.", FExchanger.GetConfirmations(aOrder.Market.SellingCurrencyInfo))); string lExchangeAddress = FExchanger.GetDepositAddress(aOrder.Market); decimal lAmount = aOrder.Market.MarketDirection == MarketDirection.Sell ? aOrder.SentQuantity : aOrder.SentQuantity + (aOrder.SentQuantity * (decimal)0.025); aOrder.CoinTxID = lAlreadyProcessingFlag; string lTxID = await Task.Run(() => OnTransferCoinsNeeded?.Invoke(lAmount, lExchangeAddress, aOrder.Market.SellingCurrencyInfo.Id, aOrder.CoinSendingTxFee)); if (string.IsNullOrEmpty(lTxID)) { throw new Exception("Unable to broadcast transaction."); } aOrder.CoinTxID = lTxID; FExchangeOrderManager.UpdateOrder(aOrder, OrderStatus.Waiting); FExchangeOrderManager.WriteTransactionLogEntry(aOrder); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Info, string.Format("Number of confirmations needed: {0} confirmations", FExchanger.GetConfirmations(aOrder.Market.SellingCurrencyInfo))); } catch (Exception ex) { FExchangeOrderManager.UpdateOrder(aOrder, OrderStatus.Interrupted); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.FatalError, string.Format("Failed to send transaction. Details: {0}.", ex.Message)); } }
public bool RefundOrder(UserTradeOrder aOrder, string aAddress, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder.Status == OrderStatus.Withdrawn) { return(false); } BitfinexClientOptions lBittrexClientOptions = new BitfinexClientOptions() { Proxy = PandoraProxy.GetApiProxy(), ApiCredentials = new ApiCredentials(FUserCredentials.Item1, FUserCredentials.Item2) }; using (BitfinexClient lClient = aUseProxy ? new BitfinexClient(lBittrexClientOptions) : new BitfinexClient()) { var lResponse = lClient.WithdrawAsync(aOrder.Market.SellingCurrencyInfo.Name.ToLowerInvariant(), WithdrawWallet.Exchange, aOrder.SentQuantity, aAddress).Result; if (!lResponse.Success) { throw new Exception("Failed to withdraw. Error message:" + lResponse.Error.Message); } } return(true); }
public void CancelOrder(UserTradeOrder aOrder, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder == null) { throw new ArgumentNullException(nameof(aOrder), "Invalid argument: " + nameof(aOrder)); } PoloniexClientOptions lPoloniexClientOptions = new PoloniexClientOptions() { Proxy = PandoraProxy.GetApiProxy(), ApiCredentials = new ApiCredentials(FUserCredentials.Item1, FUserCredentials.Item2) }; using (PoloniexClient lClient = aUseProxy ? new PoloniexClient(lPoloniexClientOptions) : new PoloniexClient()) { var lResponse = lClient.CancelOrder(Convert.ToInt64(aOrder.ID)); if (!lResponse.Success || !Convert.ToBoolean(lResponse.Data.success)) { throw new Exception($"Failed to cancel order in exchange. Message: {lResponse.Data?.message ?? lResponse.Error.Message}"); } } }
public void CancelOrder(UserTradeOrder aOrder, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder == null) { throw new ArgumentNullException(nameof(aOrder), "Invalid argument: " + nameof(aOrder)); } BittrexClientOptions lBittrexClientOptions = new BittrexClientOptions() { Proxy = PandoraProxy.GetApiProxy(), ApiCredentials = new ApiCredentials(FUserCredentials.Item1, FUserCredentials.Item2) }; using (BittrexClient lClient = aUseProxy ? new BittrexClient(lBittrexClientOptions) : new BittrexClient()) { var lResponse = lClient.CancelOrderAsync(aOrder.ID).Result; if (!lResponse.Success) { throw new Exception("Failed to cancel order in exchange. Message: " + lResponse.Error.Message); } } }
public int?WriteOrder(UserTradeOrder aMarketTransaction) { if (!Initialized && !FReadOnly) { throw new Exception("Save manager not initialized"); } using (SQLiteConnection lConnection = new SQLiteConnection(FConnectionString)) { SQLiteTransaction lTransaction; lConnection.Open(); lTransaction = lConnection.BeginTransaction(); try { SQLiteCommand lCommand1 = new SQLiteCommand("INSERT OR REPLACE INTO ExchangeTx (ID, Market, Quantity, OpenTime, Rate, Stop, Completed, Cancelled, Status, CoinTXID, CurrencyId, CurrencyTicker, Name, ProfileID) VALUES (@Id, @Market, @Quantity, @Opentime, @Rate, @Stop, @Completed, @Cancelled, @Status, @CoinTxID, @CurrencyId, @CurrencyTicker, @Name, @ProfileID); " + "SELECT InternalID FROM ExchangeTx where CoinTXID = @CoinTxID;", lConnection); lCommand1.Parameters.Add(new SQLiteParameter("@Id", aMarketTransaction.ID)); lCommand1.Parameters.Add(new SQLiteParameter("@Market", aMarketTransaction.Market.MarketID)); lCommand1.Parameters.Add(new SQLiteParameter("@Quantity", aMarketTransaction.SentQuantity)); lCommand1.Parameters.Add(new SQLiteParameter("@Opentime", aMarketTransaction.OpenTime)); lCommand1.Parameters.Add(new SQLiteParameter("@Rate", aMarketTransaction.Rate)); lCommand1.Parameters.Add(new SQLiteParameter("@Stop", aMarketTransaction.StopPrice)); lCommand1.Parameters.Add(new SQLiteParameter("@Completed", aMarketTransaction.Completed)); lCommand1.Parameters.Add(new SQLiteParameter("@Cancelled", aMarketTransaction.Cancelled)); lCommand1.Parameters.Add(new SQLiteParameter("@Status", aMarketTransaction.Status)); lCommand1.Parameters.Add(new SQLiteParameter("@CurrencyId", aMarketTransaction.Market.SellingCurrencyInfo.Id)); lCommand1.Parameters.Add(new SQLiteParameter("@CurrencyTicker", aMarketTransaction.Market.SellingCurrencyInfo.Ticker)); lCommand1.Parameters.Add(new SQLiteParameter("@CoinTxID", aMarketTransaction.CoinTxID)); lCommand1.Parameters.Add(new SQLiteParameter("@Name", aMarketTransaction.Name)); lCommand1.Parameters.Add(new SQLiteParameter("@ProfileID", aMarketTransaction.ProfileID)); var lScalarResult = lCommand1.ExecuteScalar()?.ToString(); if (lScalarResult == null) { throw new Exception("Failed to retrieve order id. Operation failed when writing order"); } var lId = int.Parse(lScalarResult); SQLiteCommand lCommand2 = new SQLiteCommand("INSERT OR REPLACE INTO Relationship_ExchangeID_OrderID (InternalOrderID, ExchangeID) Values (@InternalID, @ExchangeID)", lConnection); lCommand2.Parameters.Add(new SQLiteParameter("@InternalID", lId)); lCommand2.Parameters.Add(new SQLiteParameter("@ExchangeID", aMarketTransaction.Market.ExchangeID)); lCommand2.ExecuteNonQuery(); lTransaction.Commit(); return(lId); } catch (Exception ex) { lTransaction.Rollback(); Universal.Log.Write(Universal.LogLevel.Error, $"Error writing exchange order from db. Exception details: {ex}"); return(null); } finally { lConnection.Close(); } } }
private void RefundOrder(UserTradeOrder aOrderToWithdraw, OrderStatus?aOriginalStatus = null) { if (aOriginalStatus.HasValue && aOriginalStatus.Value == OrderStatus.Waiting) { FExchangeOrderManager.WriteTransactionLogEntry(aOrderToWithdraw, OrderMessage.OrderMessageLevel.Info, $"Waiting for transaction {aOrderToWithdraw.CoinTxID} to be confirmed at exchange to try withdraw coins."); FWaitingToRefund.TryAdd(aOrderToWithdraw.InternalID, aOrderToWithdraw); } else { TryRefundOrder(aOrderToWithdraw); } }
public UserTradeOrder SaveNewOrder(UserTradeOrder aNewOrder) { var lInternalID = FSaveManager.WriteOrder(aNewOrder); if (!lInternalID.HasValue) { throw new Exception("Failed to write new order in disk"); } aNewOrder.InternalID = lInternalID.Value; SetOrderInCache(aNewOrder); return(aNewOrder); }
private void TryCancelOrder(UserTradeOrder aOrder) { try { FExchanger.CancelOrder(aOrder); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Error, $"Order id: {aOrder.ID} successfully cancelled at exchange."); } catch (Exception ex) { Universal.Log.Write(Universal.LogLevel.Error, string.Format("Order: {0}. Exception: {1}", aOrder.InternalID, ex.ToString())); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Error, $"Error on cancel remote order: {ex.Message}."); } }
public void UpdateOrder(UserTradeOrder aNewOrder, OrderStatus aStatus) { if (aNewOrder.Market == null) { return; } FOrders.AddOrUpdate(aNewOrder.InternalID, aNewOrder, (key, lOldValue) => aNewOrder); if (!FSaveManager.UpdateOrder(aNewOrder, aStatus)) { throw new Exception("Failed to write new transaction into disk"); } aNewOrder.Status = aStatus; OnOrderStatusChanged?.BeginInvoke(aNewOrder.InternalID, aStatus, aNewOrder.Market.SellingCurrencyInfo.Id, null, null); }
public bool UpdateOrder(UserTradeOrder aMarketTransaction, OrderStatus aStatus) { if (!Initialized && !FReadOnly) { throw new Exception("Save manager not initialized"); } using (SQLiteConnection lConnection = new SQLiteConnection(FConnectionString)) { lConnection.Open(); var lTransaction = lConnection.BeginTransaction(); SQLiteCommand lCommand1 = new SQLiteCommand("Update ExchangeTx SET ID = @Id, Market = @Market, Quantity = @Quantity, OpenTime = @Opentime, Rate = @Rate, Stop = @Stop, Completed = @Completed, Cancelled = @Cancelled, Status = @Status, CoinTXID = @CoinTxID, CurrencyID = @CurrencyId, CurrencyTicker = @CurrencyTicker,Name = @Name, ProfileID = @ProfileID WHERE InternalID = @InternalID", lConnection); lCommand1.Parameters.Add(new SQLiteParameter("@InternalID", aMarketTransaction.InternalID)); lCommand1.Parameters.Add(new SQLiteParameter("@Id", aMarketTransaction.ID)); lCommand1.Parameters.Add(new SQLiteParameter("@Market", aMarketTransaction.Market.MarketID)); lCommand1.Parameters.Add(new SQLiteParameter("@Quantity", aMarketTransaction.SentQuantity)); lCommand1.Parameters.Add(new SQLiteParameter("@Opentime", aMarketTransaction.OpenTime)); lCommand1.Parameters.Add(new SQLiteParameter("@Rate", aMarketTransaction.Rate)); lCommand1.Parameters.Add(new SQLiteParameter("@Stop", aMarketTransaction.StopPrice)); lCommand1.Parameters.Add(new SQLiteParameter("@Completed", aMarketTransaction.Completed)); lCommand1.Parameters.Add(new SQLiteParameter("@Cancelled", aMarketTransaction.Cancelled)); lCommand1.Parameters.Add(new SQLiteParameter("@Status", (int)aStatus)); lCommand1.Parameters.Add(new SQLiteParameter("@CoinTxID", aMarketTransaction.CoinTxID)); lCommand1.Parameters.Add(new SQLiteParameter("@CurrencyId", aMarketTransaction.Market.SellingCurrencyInfo.Id)); lCommand1.Parameters.Add(new SQLiteParameter("@CurrencyTicker", aMarketTransaction.Market.SellingCurrencyInfo.Ticker)); lCommand1.Parameters.Add(new SQLiteParameter("@Name", aMarketTransaction.Name)); lCommand1.Parameters.Add(new SQLiteParameter("@ProfileID", aMarketTransaction.ProfileID)); SQLiteCommand lCommand2 = new SQLiteCommand("Update Relationship_ExchangeID_OrderID SET ExchangeID = @ExchangeID WHERE InternalOrderID = @InternalID", lConnection); lCommand2.Parameters.Add(new SQLiteParameter("@InternalID", aMarketTransaction.InternalID)); lCommand2.Parameters.Add(new SQLiteParameter("@ExchangeID", aMarketTransaction.Market.ExchangeID)); try { lCommand1.ExecuteNonQuery(); lCommand2.ExecuteNonQuery(); lTransaction.Commit(); return(true); } catch (Exception ex) { lTransaction.Rollback(); Universal.Log.Write(Universal.LogLevel.Error, $"Error updating exchange order from db. Exception {ex}"); return(false); } finally { lConnection.Close(); } } }
private void TryRefundOrder(UserTradeOrder aOrderToWithdraw) { try { FExchangeOrderManager.WriteTransactionLogEntry(aOrderToWithdraw, OrderMessage.OrderMessageLevel.Info, "Trying to refund coins from exchange."); FExchanger.RefundOrder(aOrderToWithdraw, FPandorasWalletConnection.GetCoinAddress(aOrderToWithdraw.Market.SellingCurrencyInfo.Id)); FExchangeOrderManager.WriteTransactionLogEntry(aOrderToWithdraw, OrderMessage.OrderMessageLevel.Info, "Coins successfully withdrawn. Please wait some minutes to be shown in wallet"); } catch (Exception ex) { Universal.Log.Write(Universal.LogLevel.Error, string.Format("Order: {0}. Exception: {1}", aOrderToWithdraw.InternalID, ex.ToString())); FExchangeOrderManager.WriteTransactionLogEntry(aOrderToWithdraw, OrderMessage.OrderMessageLevel.Error, $"Error on refund process in order: {ex.Message}. Please try to manually withdraw your coins from exchange"); } }
public bool PlaceOrder(UserTradeOrder aOrder, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder == null || aOrder.Market == null) { throw new ArgumentNullException(aOrder == null ? nameof(aOrder) : nameof(aOrder.Market), "Invalid argument: " + aOrder == null ? nameof(aOrder) : nameof(aOrder.Market)); } if (aOrder.Status != OrderStatus.Waiting) { return(false); } BitfinexClientOptions lBitfinexClientOptions = new BitfinexClientOptions() { Proxy = PandoraProxy.GetApiProxy(), ApiCredentials = new ApiCredentials(FUserCredentials.Item1, FUserCredentials.Item2) }; using (BitfinexClient lClient = aUseProxy ? new BitfinexClient(lBitfinexClientOptions) : new BitfinexClient()) { if (!aOrder.Market.TryCastToLocalMarket(out ExchangeMarket lExchangeMarket)) { throw new ArgumentException(nameof(aOrder.Market), "Invalid Market"); } var lResponse = lClient.PlaceOrderAsync(lExchangeMarket.MarketPairID, lExchangeMarket.MarketDirection == MarketDirection.Sell ? OrderSide.Sell : OrderSide.Buy, OrderType.ExchangeLimit, lExchangeMarket.MarketDirection == MarketDirection.Sell ? aOrder.SentQuantity : aOrder.SentQuantity / aOrder.Rate, aOrder.Rate).Result; if (!lResponse.Success) { throw new Exception($"Bitfinex Error. Message: {lResponse.Error.Message}"); } long lUuid = lResponse.Data.Id; var lVerifyResponse = lClient.GetOrderAsync(lUuid).Result; if (!lResponse.Success) { throw new Exception("Failed to verify order with exchange server"); } aOrder.ID = lUuid.ToString(); aOrder.OpenTime = lVerifyResponse.Data.Timestamp; aOrder.Cancelled = lVerifyResponse.Data.Canceled; aOrder.Completed = lVerifyResponse.Data.RemainingAmount == 0; } return(true); }
private void SetOrderInCache(UserTradeOrder aOrder, int aExchangeID = -1) { var lExchangeId = aOrder.Market?.ExchangeID ?? aExchangeID; if (lExchangeId < 0) { return; } FOrders.AddOrUpdate(aOrder.InternalID, aOrder, (key, oldvalue) => aOrder); if (!FOrdersByExchange.TryGetValue(lExchangeId, out ConcurrentBag <UserTradeOrder> lIds)) { lIds = new ConcurrentBag <UserTradeOrder>(); FOrdersByExchange.TryAdd(lExchangeId, lIds); } lIds.Add(aOrder); }
private void TryToWithdrawOrder(UserTradeOrder aOrder) { if (aOrder.Status != OrderStatus.Completed) { return; } if (aOrder.ErrorCounter % 60 == 0) { try { if (aOrder.Market.BuyingCurrencyInfo.Id == 0) { throw new Exception($"Failed to withdraw order id {aOrder.ID}. No currency data."); } if (FExchanger.WithdrawOrder(aOrder, FPandorasWalletConnection.GetCoinAddress(aOrder.Market.BuyingCurrencyInfo.Id), FExchanger.GetTransactionsFee(aOrder.Market.BuyingCurrencyInfo))) { FExchangeOrderManager.UpdateOrder(aOrder, OrderStatus.Withdrawn); } FExchangeOrderManager.WriteTransactionLogEntry(aOrder); aOrder.ErrorCounter = 0; } catch (Exception ex) { int lNumberofretrys = aOrder.ErrorCounter / 60; if (lNumberofretrys >= 9) { aOrder.Cancelled = true; FExchangeOrderManager.UpdateOrder(aOrder, OrderStatus.Interrupted); FExchangeOrderManager.WriteTransactionLogEntry(aOrder); } aOrder.ErrorCounter += 1; Universal.Log.Write(Universal.LogLevel.Error, string.Format("Order: {0}. Exception: {1}", aOrder.InternalID, ex.ToString())); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Error, "Error on Withdraw Order: " + ex.Message); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Info, string.Format("Retrying in 5 minute. Attempt: {0}/10", (lNumberofretrys + 1))); } } else { aOrder.ErrorCounter++; } }
public void WriteTransactionLogEntry(UserTradeOrder aOrder, OrderMessage.OrderMessageLevel aLevel = OrderMessage.OrderMessageLevel.Info, string aMessage = null) { if (string.IsNullOrEmpty(aMessage)) { switch (aOrder.Status) { case OrderStatus.Initial: FSaveManager.WriteOrderLog(aOrder.InternalID, "Starting transaction process.", OrderMessage.OrderMessageLevel.Info); FSaveManager.WriteOrderLog(aOrder.InternalID, "Waiting for market stop price to place order.", OrderMessage.OrderMessageLevel.StageChange); break; case OrderStatus.Waiting: FSaveManager.WriteOrderLog(aOrder.InternalID, "Price reached specified stop price.", OrderMessage.OrderMessageLevel.Info); FSaveManager.WriteOrderLog(aOrder.InternalID, string.Format("{0} coins sent to exchange account. Tx ID: {1}.", aOrder.SentQuantity, aOrder.CoinTxID), OrderMessage.OrderMessageLevel.Info); FSaveManager.WriteOrderLog(aOrder.InternalID, "Waiting for confirmations to place the order.", OrderMessage.OrderMessageLevel.StageChange); break; case OrderStatus.Placed: FSaveManager.WriteOrderLog(aOrder.InternalID, string.Format("Transaction id {0} has enough confirmations to place the order.", aOrder.CoinTxID), OrderMessage.OrderMessageLevel.Info); FSaveManager.WriteOrderLog(aOrder.InternalID, string.Format("Placed order in exchange. Uuid: {0}. Waiting for order to fulfill.", aOrder.ID.ToString()), OrderMessage.OrderMessageLevel.StageChange); break; case OrderStatus.Interrupted: FSaveManager.WriteOrderLog(aOrder.InternalID, "Transaction cancelled or not found on the exchange.", OrderMessage.OrderMessageLevel.FatalError); break; case OrderStatus.Completed: FSaveManager.WriteOrderLog(aOrder.InternalID, "Transaction completed. Waiting for withdrawal.", OrderMessage.OrderMessageLevel.StageChange); break; case OrderStatus.Withdrawn: FSaveManager.WriteOrderLog(aOrder.InternalID, "Cryptocurrencies succesfully withdrawn to Pandora's Wallet.", OrderMessage.OrderMessageLevel.Finisher); break; } } else { FSaveManager.WriteOrderLog(aOrder.InternalID, aMessage, aLevel); } if (FSaveManager.ReadOrderLogs(aOrder.InternalID, out List <OrderMessage> lOrderMessages)) { OnNewOrderLogsAdded?.BeginInvoke(aOrder.InternalID, lOrderMessages, null, null); } }
public bool PlaceOrder(UserTradeOrder aOrder, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder == null) { throw new ArgumentNullException(nameof(aOrder), $"Invalid order with id {aOrder}"); } if (aOrder.Status != OrderStatus.Waiting) { return(false); } using (var lClient = new PoloniexClient()) { WebCallResult <PoloniexOrderPlaceResult> lResponse = null; if (!aOrder.Market.TryCastToLocalMarket(out ExchangeMarket lExchangeMarket)) { throw new ArgumentException(nameof(aOrder.Market), "Invalid Market"); } if (lExchangeMarket.MarketDirection == MarketDirection.Sell) { lResponse = lClient.PlaceSellOrder(lExchangeMarket.MarketPairID, aOrder.Rate, aOrder.SentQuantity); } else if (lExchangeMarket.MarketDirection == MarketDirection.Buy) { lResponse = lClient.PlaceBuyOrder(lExchangeMarket.MarketPairID, aOrder.Rate, aOrder.SentQuantity / aOrder.Rate); } if (lResponse == null || !lResponse.Success) { throw new Exception($"Unable to place trade order at exchange. Error: {lResponse?.Error.Message ?? "Failed to get response from server" }"); } aOrder.ID = lResponse.Data.orderNumber.ToString(); aOrder.OpenTime = DateTime.UtcNow; } return(true); }
private void TryToPlaceOrder(UserTradeOrder aOrder) { if (aOrder.ErrorCounter % 60 == 0) { try { FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Info, "Attempting to place order in exchange."); if (FExchanger.PlaceOrder(aOrder)) { FExchangeOrderManager.UpdateOrder(aOrder, OrderStatus.Placed); } FExchangeOrderManager.WriteTransactionLogEntry(aOrder); aOrder.ErrorCounter = 0; } catch (Exception ex) { int lNumberofretrys = aOrder.ErrorCounter / 60; if (lNumberofretrys >= 9) { aOrder.Cancelled = true; FExchangeOrderManager.UpdateOrder(aOrder, OrderStatus.Interrupted); FExchangeOrderManager.WriteTransactionLogEntry(aOrder); } aOrder.ErrorCounter += 1; Universal.Log.Write(Universal.LogLevel.Error, string.Format("Order: {0}. Exception: {1}", aOrder.InternalID, ex.ToString())); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Error, "Error while placing Order: " + ex.Message); FExchangeOrderManager.WriteTransactionLogEntry(aOrder, OrderMessage.OrderMessageLevel.Info, string.Format("Retrying in 1 minute. Attempt: {0}/10", (lNumberofretrys + 1))); } } else { aOrder.ErrorCounter++; } }
public bool PlaceOrder(UserTradeOrder aOrder, bool aUseProxy = true) { if (!IsCredentialsSet) { throw new Exception("No Credentials were set"); } if (aOrder == null) { throw new ArgumentNullException(nameof(aOrder), $"Invalid order{aOrder.ID}"); } if (aOrder.Status != OrderStatus.Waiting) { return(false); } BittrexClientOptions lBittrexClientOptions = new BittrexClientOptions() { Proxy = PandoraProxy.GetApiProxy(), ApiCredentials = new ApiCredentials(FUserCredentials.Item1, FUserCredentials.Item2) }; using (BittrexClient lClient = aUseProxy ? new BittrexClient(lBittrexClientOptions) : new BittrexClient()) { if (!aOrder.Market.TryCastToLocalMarket(out ExchangeMarket lExchangeMarket)) { throw new ArgumentException(nameof(aOrder.Market), "Invalid Market"); } CallResult <BittrexOrder> lResponse; if (aOrder.Market.MarketDirection == MarketDirection.Sell) { lResponse = lClient.PlaceOrderAsync(lExchangeMarket.MarketPairID, OrderSide.Sell, OrderType.Limit, TimeInForce.GoodTillCancelled, aOrder.SentQuantity, limit: aOrder.Rate).Result; } else { lResponse = lClient.PlaceOrderAsync(lExchangeMarket.MarketPairID, OrderSide.Buy, OrderType.Limit, TimeInForce.GoodTillCancelled, aOrder.SentQuantity / aOrder.Rate, limit: aOrder.Rate).Result; } if (!lResponse.Success) { throw new Exception("Bittrex Error. Message: " + lResponse.Error.Message); } string lUuid = lResponse.Data.Id; CallResult <BittrexOrder> lResponse2 = lClient.GetOrderAsync(lUuid).Result; if (!lResponse.Success) { throw new Exception("Failed to verify order with server"); } BittrexOrder lReceivedOrder = lResponse2.Data; aOrder.ID = lUuid; aOrder.OpenTime = lReceivedOrder.CreatedAt; aOrder.Cancelled = lReceivedOrder.OrderToCancel != null; aOrder.Completed = lReceivedOrder.ClosedAt.HasValue; return(true); } }
/// <summary> /// Loads currency exchange orders from disk. This should only be called once or to reload orders. /// </summary> /// <param name="aCurrencyTicker"></param> /// <param name="aCurrencyID"></param> /// <returns></returns> public IEnumerable <UserTradeOrder> LoadOrders(ICurrencyIdentity aCurrency, IPandoraExchangeFactory lExchangeFactory, GetWalletIDDelegate aGetWalletIDFunction) { var lResult = new List <UserTradeOrder>(); var lDBOrders = FSaveManager.ReadOrders(aCurrency); if (lDBOrders != null && lDBOrders.Any()) { int lErrorCounter; var lMarketCache = new Dictionary <int, IEnumerable <IExchangeMarket> >(); foreach (var lDBOrder in lDBOrders) { bool lOrdersLogs = FSaveManager.ReadOrderLogs(lDBOrder.InternalID, out List <OrderMessage> lMessages); lMessages = lMessages.OrderBy(lMessage => lMessage.Time).ToList(); lErrorCounter = 0; for (int it2 = 0; it2 < lMessages.Count; it2++) { OrderMessage lIndividualMessage = lMessages[it2]; switch (lIndividualMessage.Level) { case OrderMessage.OrderMessageLevel.Error: lErrorCounter += 60; break; case OrderMessage.OrderMessageLevel.StageChange: lErrorCounter = 0; break; case OrderMessage.OrderMessageLevel.FatalError: lErrorCounter = -1; break; } if (lErrorCounter == -1) { break; } } var lExchanger = lExchangeFactory.GetPandoraExchange((AvailableExchangesList)lDBOrder.ExchangeID); if (!lMarketCache.TryGetValue(lDBOrder.ExchangeID, out IEnumerable <IExchangeMarket> lMarkets)) { lMarkets = lExchanger.GetMarketCoins(aCurrency, aGetWalletIDFunction); lMarketCache.Add(lDBOrder.ExchangeID, lMarkets); } var lUserOrder = new UserTradeOrder { InternalID = lDBOrder.InternalID, ID = lDBOrder.ID, Name = lDBOrder.Name, SentQuantity = lDBOrder.SentQuantity, Status = lDBOrder.Status, CoinTxID = lDBOrder.CoinTxID, StopPrice = lDBOrder.StopPrice, OpenTime = lDBOrder.OpenTime, Rate = lDBOrder.Rate, ProfileID = lDBOrder.ProfileID, ErrorCounter = lErrorCounter, Completed = lDBOrder.Completed, Cancelled = lDBOrder.Cancelled, Market = lMarkets.FindByMarketID(lDBOrder.MarketID) }; if (lUserOrder.Market == null) { Log.Write(LogLevel.Warning, $"Exchange: Unable to find market for order of id {lUserOrder.InternalID} of exchange {lExchanger.Name}"); continue; } lResult.Add(lUserOrder); SetOrderInCache(lUserOrder, lDBOrder.ExchangeID); } } return(lResult); }