/// <summary> /// Update account balances and total USD value /// </summary> private void UpdateAccounts(object sender, EventArgs e) { try { var assets = 0.0M; var balances = GeminiClient.GetBalances(); foreach (var balance in balances) { switch (balance.Currency) { case "BTC": textboxBtcBalance.Text = balance.Amount.ToString(); assets += balance.Amount * LastTrades["btcusd"].Price; break; case "ETH": textboxEthBalance.Text = balance.Amount.ToString(); assets += balance.Amount * LastTrades["ethusd"].Price; break; case "USD": textboxUsdBalance.Text = balance.Amount.ToString(); assets += balance.Amount; break; } } labelAssetValue.Text = String.Format("Total Value: ${0}", Math.Round(assets, 2)); } catch (Exception ex) { Logger.WriteException(Logger.Level.Error, ex); } }
public LibraMain() { InitializeComponent(); AppDomain.CurrentDomain.ProcessExit += Exit; /* Callback for API errors */ GeminiClient.InstallErrorHandler(ErrorHandler); /* Update runtime clock every second */ runtime.Tick += UpdateRuntime; runtime.Interval = 1000; runtime.Start(); /* Also update account balance whenever API Keys are loaded */ GeminiClient.Wallet.OnChange += UpdateAccounts; GeminiClient.Wallet.OnChange += OrderEventStart; GeminiClient.Wallet.OnChange += delegate(object sender, EventArgs e) { labelAddress.Text = GeminiClient.Wallet.Key(); }; /* Initialize Websockets */ InitialPrices(); MarketDataStart(); /* Websocket PriceChanged event handles ticker data and pending Stop orders */ PriceChanged += UpdateTicker; PriceChanged += OrderTracker.CheckPendingOrders; /* Websocket OrderChanged event */ OrderChanged += UpdateOrders; }
/// <summary> /// Check all orders in the pending queue, and execute if price condition is met. /// This is called by the OrderEvents websocket /// </summary> /// <param name="currency"></param> /// <param name="data"></param> public static void CheckPendingOrders(string currency, MarketDataEvent data) { Parallel.ForEach(Pending, order => { var price = decimal.Parse(order.Price); if (order.Symbol == currency) { if (order.Side == "buy") { /* If currenct price is above the stop-buy price, execute */ if (price <= data.Price) { order.Price = (data.Price + 0.01M).ToString(); order.ClientOrderID += "STOP"; order.Options = new string[] { "immediate-or-cancel" }; GeminiClient.PlaceOrder(order); Pending.Remove(order); } } else { /* if curenct price is below the stop-loss price, execute */ if (price >= data.Price) { /* Decrease by 10, since this is still viewed as a limit order * by the server, and this increases our chances of getting filled */ order.Price = (data.Price - 0.01M).ToString(); order.ClientOrderID += "STOP"; GeminiClient.PlaceOrder(order); Pending.Remove(order); } } } }); }
private void bNewAddress_Click(object sender, EventArgs e) { try { tbNewAddress.Text = GeminiClient.GetDepositAddress(cbAddress.Text, "LIBRA" + Time.Timestamp().ToString()); } catch { } }
private void bWithdraw_Click(object sender, EventArgs e) { try { GeminiClient.Withdraw(cbWithdraw.Text, tbWithdrawAddress.Text, tbWithdrawAmount.Text); UpdateAccounts(null, null); } catch { } }
private void bMaxWithdraw_Click(object sender, EventArgs e) { try { tbWithdrawAmount.Text = GeminiClient.GetBalances() .First((x) => x.Currency == cbWithdraw.Text) .AvailableForWithdrawal.ToString(); } catch { } }
public DataClient() { Binance = new BinanceClient(); Bitfinex = new BitfinexClient(); Poloniex = new PoloniexClient(); Bitstamp = new BitstampClient(); Gdax = new GdaxClient(); Gemini = new GeminiClient(); Kraken = new KrakenClient(); Okex = new OkexClient(); }
public void LoadPastOrders(object sender, DoWorkEventArgs e) { string[] symbols = { "btcusd", "ethusd", "ethbtc" }; foreach (var symbol in symbols) { foreach (var trade in GeminiClient.GetPastTrades(symbol, 50, 0)) { (sender as BackgroundWorker).ReportProgress(0, trade); } } ; }
/// <summary> /// Seed the last trade dictionary /// </summary> public void InitialPrices() { Parallel.ForEach(Symbols, s => { var t = GeminiClient.GetTicker(s); LastTrades[s] = new MarketDataEvent() { Price = t.Last, }; PV[s] = t.Volume.Currency2; V[s] = t.Volume.Currency1; }); UpdateTicker(null, null); }
/// <summary> /// Cancel the order selected in the tree view object /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void bCancelSelect_Click(object sender, EventArgs e) { if (treeOrders.SelectedNode == null) { return; } if (treeOrders.SelectedNode?.Level == 0) { return; } var node = treeOrders.SelectedNode.Name; var selected = treeOrders.SelectedNode; /* This isn't really a *real* order yet */ if (selected.Parent.Name == "Pending") { if ((bool)Properties.Settings.Default["RequireConfirmations"]) { if (MessageBox.Show("Confirm cancellation of order " + node, "Cancel Order", MessageBoxButtons.YesNo) == DialogResult.No) { return; } } OrderTracker.Pending.Remove(OrderTracker.Pending.Find((x) => x.ClientOrderID == node)); selected.Remove(); } /* Order is on the books */ if (selected.Parent.Name == "Active") { if ((bool)Properties.Settings.Default["RequireConfirmations"]) { if (MessageBox.Show("Confirm cancellation of order " + node, "Cancel Order", MessageBoxButtons.YesNo) == DialogResult.No) { return; } } try { var res = GeminiClient.CancelOrder(int.Parse(selected.Text)); } catch (Exception ex) { MessageBox.Show(ex.Message); Logger.WriteException(Logger.Level.Error, ex); } } }
private void bCancelSession_Click(object sender, EventArgs e) { if ((bool)Properties.Settings.Default["RequireConfirmations"]) { if (MessageBox.Show("Confirm cancellation of session orders", "Cancel Order", MessageBoxButtons.YesNo) == DialogResult.No) { return; } } try { GeminiClient.CancelSession(); } catch (Exception ex) { MessageBox.Show(ex.Message); Logger.WriteException(Logger.Level.Error, ex); } }
/// <summary> /// Callback for when an order is placed, or status has changed /// </summary> /// <param name="state"></param> /// <param name="e"></param> private void UpdateOrders(string type, object data) { TreeNode[] found; // Handle "fake" order call, sent by application during refresh to check for pending orders, // per issue #2. data will be null if (type == "PENDING") { foreach (var n in OrderTracker.Pending) { if ((found = treeOrders.Nodes["Pending"].Nodes.Find(n.ClientOrderID, false)).Count() == 0) { treeOrders.Nodes["Pending"].Nodes.Add(n.ClientOrderID, n.ClientOrderID); } } return; } var order = (OrderEvent)data; if (type == "closed") { if ((found = treeOrders.Nodes.Find(order.OrderID, true)).Count() > 0) { found.First().Remove(); } OrderTracker.Orders[order.OrderID] = order; if (order.IsCancelled) { if (order.ClientOrderID == null) { treeOrders.Nodes["Cancelled"].Nodes.Add(order.OrderID, order.OrderID); } else if (!order.ClientOrderID.Contains("STOP")) { treeOrders.Nodes["Cancelled"].Nodes.Add(order.OrderID, order.OrderID); } } else if (order.ExecutedAmount == order.OriginalAmount) { treeOrders.Nodes["Filled"].Nodes.Add(order.OrderID, order.OrderID); } } else if (type == "cancelled") { var cancel = (OrderEventCancelled)data; /* * Our stop orders are placed as immediate or cancel. * We will resubmit it at a slightly worse price, and try again until it succeeds */ if (cancel.RemainingAmount > 0 && cancel.ClientOrderID != null) { if (cancel.ClientOrderID.Contains("STOP")) { var request = new NewOrderRequest() { Side = order.Side, Price = Math.Round((cancel.Side == "buy" ? cancel.Price + .01M : cancel.Price - 0.01M), 2).ToString(), Options = new string[] { "immediate-or-cancel" }, Symbol = cancel.Symbol, Amount = Math.Round(cancel.RemainingAmount, 8).ToString(), ClientOrderID = String.Format("LIBRA_{0}STOP", DateTime.Now.ToTimestampMs()), Type = "exchange limit", }; GeminiClient.PlaceOrder(request); } } } else if (type == "booked" || type == "initial") { // Remove existing node from Pending, move it to Active if ((found = treeOrders.Nodes["Pending"].Nodes.Find(order.ClientOrderID, false)).Count() > 0) { found.First().Remove(); } treeOrders.Nodes["Active"].Nodes.Add(order.OrderID, order.OrderID); OrderTracker.Orders[order.OrderID] = order; } else if (type == "filled") { order = (OrderEventFilled)data; OrderTracker.Orders[order.OrderID] = order; } UpdateAccounts(null, null); }