private void bbBuy_ItemClick(object sender, ItemClickEventArgs e)
        {
            SelectedCollection = (TickerCollection)this.bbTryArbitrage.Tag;
            if (SelectedCollection == null)
            {
                return;
            }

            ArbitrageInfo info   = SelectedCollection.Arbitrage;
            Ticker        lowest = info.LowestAskTicker;

            if (!lowest.UpdateBalance(lowest.BaseCurrency))
            {
                LogManager.Default.Error("Cant update balance.", lowest.HostName + "-" + lowest.BaseCurrency);
                SelectedCollection = null;
                LogManager.Default.ShowLogForm();
                return;
            }

            double percent   = Convert.ToDouble(this.beBuyLowestAsk.EditValue) / 100;
            double buyAmount = lowest.BaseCurrencyBalance * percent;

            LogManager.Default.Log("Lowest Ask Base Currency Amount = " + buyAmount.ToString("0.00000000"));
            double amount = buyAmount / info.LowestAsk;

            if (info.LowestAskTicker.Buy(info.LowestAsk, amount) == null)
            {
                LogManager.Default.Error("Cant buy currency.", "At " + lowest.HostName + "-" + lowest.BaseCurrency + "(" + amount.ToString("0.00000000") + ")" + " for " + lowest.MarketCurrency);
            }

            SelectedCollection = null;
            LogManager.Default.ShowLogForm();
            return;
        }
        private void bbSell_ItemClick(object sender, ItemClickEventArgs e)
        {
            SelectedCollection = (TickerCollection)this.bbTryArbitrage.Tag;
            if (SelectedCollection == null)
            {
                return;
            }
            ArbitrageInfo info = SelectedCollection.Arbitrage;

            Ticker highest = info.HighestBidTicker;

            if (!highest.UpdateBalance(highest.MarketCurrency))
            {
                LogManager.Default.Error("Cant update balance.", highest.HostName + "-" + highest.MarketCurrency);
                SelectedCollection = null;
                LogManager.Default.ShowLogForm();
                return;
            }

            double percent = Convert.ToDouble(this.beHighestBidSell.EditValue) / 100;
            double amount  = highest.MarketCurrencyBalance * percent;

            LogManager.Default.Log("Highest Bid Market Currency Amount = " + amount.ToString("0.00000000"));

            if (info.HighestBidTicker.Sell(info.HighestBid, amount) == null)
            {
                LogManager.Default.Error("Cant sell currency.", "At " + highest.HostName + "-" + highest.MarketCurrency + "(" + amount.ToString("0.00000000") + ")" + " for " + highest.BaseCurrency);
            }

            SelectedCollection = null;
        }
        void ShowDesktopNotification(TickerCollection collection, double prev)
        {
            ArbitrageInfo info = collection.Arbitrage;

            if (MdiParent.WindowState != FormWindowState.Minimized)
            {
                return;
            }
            double delta   = info.MaxProfitUSD - prev;
            double percent = delta / prev * 100;

            string            changed = string.Empty;
            TrendNotification trend   = TrendNotification.New;

            if (prev > 0)
            {
                changed = "Arbitrage changed: <b>" + percent.ToString("+0.###;-0.###;0.###%%") + "</b>";
                trend   = delta > 0 ? TrendNotification.TrendUp : TrendNotification.TrendDown;
            }
            else
            {
                changed = "New Arbitrage possibilities. Up to <b>" + info.MaxProfitUSD.ToString("USD 0.###") + "</b>";
            }
            GetReadyNotificationForm().ShowInfo(this, trend, collection.ShortName, changed, 10000);
        }
        void SendTelegramNotification(TickerCollection collection, double prev)
        {
            ArbitrageInfo info = collection.Arbitrage;

            if (/*!info.Ready || */ collection.Disabled)
            {
                return;
            }
            if (prev <= 0 && info.MaxProfit <= 0)
            {
                return;
            }
            string text      = string.Empty;
            string eventText = string.Empty;

            if (prev <= 0)
            {
                eventText = prev <= 0 ? "<b>new</b> " : "<b>changed</b> ";
            }
            text  = eventText + collection.ShortName;
            text += "<pre> buy:        " + info.LowestAsk.ToString("0.00000000") + "</pre>";
            text += "<pre> sell:       " + info.HighestBid.ToString("0.00000000") + "</pre>";
            text += "<pre> spread:     " + info.Spread.ToString("0.00000000") + "</pre>";
            text += "<pre> amount:     " + info.Amount.ToString("0.00000000") + "</pre>";
            text += "<pre> max profit: " + info.MaxProfitUSD.ToString("0.###") + "</pre>";
            text += "<pre> spend:      " + info.BuyTotal.ToString("0.00000000") + "</pre>";
            text += "<pre></pre>";
            text += "buy on: <a href=\"" + info.LowestAskTicker.WebPageAddress + "\">" + info.LowestAskHost + "</a>";
            text += "<pre></pre>";
            text += "sell on: <a href=\"" + info.HighestBidTicker.WebPageAddress + "\">" + info.HighestBidHost + "</a>";
            TelegramBot.Default.SendNotification(text);
        }
        private bool HasPositiveArbitrage(ArbitrageInfo arbitrage)
        {
            if (arbitrage.History.Count < 5)
            {
                return(false);
            }
            int start = arbitrage.History.Count - 1;

            for (int i = start; i > start - 5; i--)
            {
                if (arbitrage.History[i].MaxProfitUSD < 1)
                {
                    return(false);
                }
                if (arbitrage.History[i].LowestAskHost != "Poloniex")
                {
                    return(false);
                }
            }
            DateTime startTime = arbitrage.History[start - 5].Time;
            DateTime endTime   = arbitrage.History[start].Time;

            if ((endTime - startTime).TotalMinutes > 1)
            {
                return(false);
            }
            if (arbitrage.History[start].HighestBid < arbitrage.History[start - 5].LowestAsk)
            {
                return(false);
            }
            return(true);
        }
        public bool CheckCurrentPrice(Observation observation, ArbitrageInfo info)
        {
            if (info.SpreadVolume < observation.MinimumVolume)
            {
                return(false);
            }
            var canArbitrage = false;

            if (observation.SpreadType == SpreadType.Percentage)
            {
                if ((info.SpreadValue / info.FromPrice) > observation.SpreadPercentage)
                {
                    canArbitrage = true;
                }
            }
            else
            {
                if (info.SpreadValue > observation.SpreadValue)
                {
                    canArbitrage = true;
                }
            }

            return(canArbitrage);
        }
        void ITickerCollectionUpdateListener.OnUpdateTickerCollection(TickerCollection collection, bool useInvokeForUI)
        {
            ArbitrageInfo info = collection.Arbitrage;

            double prevProfits = info.MaxProfitUSD;
            double prevSpread  = info.Spread;

            collection.IsUpdating = true;
            info.Calculate();
            info.SaveExpectedProfitUSD();
            collection.IsUpdating = false;
            bool checkMaxProfits = true;

            if (info.AvailableProfitUSD > 20)
            {
                SelectedCollection     = collection;
                ShouldProcessArbitrage = true;
                checkMaxProfits        = false;
            }
            var action = new Action(() => {
                if (this.bbAllCurrencies.Checked && prevSpread * info.Spread < 0)
                {
                    RefreshGrid();
                }
                else
                {
                    RefreshGridRow(collection);
                }
                if (checkMaxProfits && info.MaxProfitUSD - prevProfits > 20)
                {
                    ShowNotification(collection, prevProfits);
                }
                for (int i = 0; i < collection.Count; i++)
                {
                    Ticker ticker = collection.Tickers[i];
                    if (ticker.OrderBook.BidHipeStarted || ticker.OrderBook.AskHipeStarted)
                    {
                        SendBoostNotification(ticker);
                    }
                    else if (ticker.OrderBook.BidHipeStopped || ticker.OrderBook.AskHipeStopped)
                    {
                        SendBoostStopNotification(ticker);
                    }
                }
            });

            if (useInvokeForUI && IsHandleCreated)
            {
                BeginInvoke(action);
            }
            else
            {
                action();
            }
        }
        private void bbMinimalProfitSpread_ItemClick(object sender, ItemClickEventArgs e)
        {
            TickerCollection collection = (TickerCollection)this.bbTryArbitrage.Tag;
            ArbitrageInfo    info       = collection.Arbitrage;
            CalculatorForm   form       = new CalculatorForm();

            if (info != null && info.LowestAskTicker != null)
            {
                form.Text      = info.LowestAskTicker.Name;
                form.Amount    = Convert.ToDouble(info.LowestAskTicker.MarketCurrencyBalance);
                form.BuyPrice  = Convert.ToDouble(info.LowestAskTicker.LowestAsk);
                form.SellPrice = Convert.ToDouble(info.LowestAskTicker.HighestBid);
                form.UsdRate   = Convert.ToDouble(info.UsdTicker.Last);
            }
            form.Show();
        }
        void ITickerCollectionUpdateListener.OnUpdateTickerCollection(TickerCollection collection, bool useInvokeForUI)
        {
            collection.RequestOverdue = false;

            ArbitrageInfo info = collection.Arbitrage;

            double prevProfits = info.MaxProfitUSD;
            double prevSpread  = info.Spread;

            collection.IsUpdating = true;
            info.Calculate();
            info.SaveExpectedProfitUSD();
            RaiseArbitrageChanged(collection);
            collection.IsUpdating = false;


            //for(int i = 0; i < collection.Count; i++) {
            //    Ticker ticker = collection.Tickers[i];
            //    if(ticker.OrderBook.BidHipeStarted || ticker.OrderBook.AskHipeStarted)
            //        SendBoostNotification(ticker);
            //    else if(ticker.OrderBook.BidHipeStopped || ticker.OrderBook.AskHipeStopped)
            //        SendBoostStopNotification(ticker);
            //}
        }
 public TickerCollection()
 {
     Arbitrage = new ArbitrageInfo(this);
 }
        void ProcessSelectedArbitrageInfo()
        {
            ShouldProcessArbitrage = false;
            if (SelectedCollection == null)
            {
                LogManager.Default.Warning("There is no selected arbitrage info. Quit.");
                Invoke(new MethodInvoker(ShowLog));
                return;
            }
            ArbitrageInfo info = SelectedCollection.Arbitrage;

            LogManager.Default.Log("Update buy on market balance info.", info.LowestAskHost + " - " + info.LowestAskTicker.BaseCurrency);
            if (!info.LowestAskTicker.UpdateBalance(info.LowestAskTicker.BaseCurrency))
            {
                LogManager.Default.Error("Failed update buy on market currency balance. Quit.", SelectedCollection.Arbitrage.LowestAskTicker.BaseCurrency);
                Invoke(new MethodInvoker(ShowLog));
                return;
            }

            LogManager.Default.Log("Update buy on market balance info.", info.HighestBidHost + " - " + info.HighestBidTicker.MarketCurrency);
            if (!info.HighestBidTicker.UpdateBalance(info.HighestBidTicker.MarketCurrency))
            {
                LogManager.Default.Error("Failed update sell on market currency balance. Quit.", info.HighestBidTicker.MarketCurrency);
                Invoke(new MethodInvoker(ShowLog));
                return;
            }

            LogManager.Default.Log("Update arbitrage info values.", SelectedCollection.Name);
            if (!UpdateArbitrageInfoTask(SelectedCollection).Wait(5000))
            {
                LogManager.Default.Error("Failed arbitrage update info values. Timeout.", SelectedCollection.Name);
                Invoke(new MethodInvoker(ShowLog));
                return;
            }
            SelectedCollection.IsActual = true;

            info.Calculate();
            info.UpateAmountByBalance();
            if (info.ExpectedProfitUSD - info.MaxProfitUSD > 10)
            {
                LogManager.Default.Warning("Arbitrage amount reduced because of balance not enough.", "New Amount = " + info.Amount.ToString("0.00000000") + ", ProfitUSD = " + info.MaxProfitUSD);
            }

            if (info.AvailableProfitUSD <= 20)
            {
                LogManager.Default.Warning("Arbitrage Profit reduced since last time. Skip trading.", SelectedCollection.Name + " expected " + info.ExpectedProfitUSD + " but after update" + info.MaxProfitUSD);
                Invoke(new MethodInvoker(ShowLog));
                return;
            }

            if (!info.Buy())
            {
                LogManager.Default.Error("FATAL ERROR! Could not buy!", SelectedCollection.Name);
                return;
            }
            if (!info.Sell())
            {
                LogManager.Default.Error("FATAL ERROR! Could not sell!", SelectedCollection.Name);
                return;
            }

            string successText = "Arbitrage completed!!! Please check your balances." + SelectedCollection.Name + " earned <b>" + info.AvailableProfitUSD + "</b>";

            LogManager.Default.Success(successText);
            TelegramBot.Default.SendNotification(successText);
            UpdateBalanceNotification = true;
            Invoke(new MethodInvoker(ShowLog));
            return;
        }