public static int Configure(string path, IntPtr infoSitePtr)
        {
            Status = StatusCode.Wait;

            // 32 bit
            // GetStockQty = (GetStockQtyDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 4))), typeof(GetStockQtyDelegate));

            // 64 bit
            //GetStockQty = (GetStockQtyDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 8))), typeof(GetStockQtyDelegate));

            #if (_WIN64)
            // 64 bit
            SetCategoryName = (SetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt64(new IntPtr(infoSitePtr.ToInt64() + 24))), typeof(SetCategoryNameDelegate));
            #else
            // 32 bit
            SetCategoryName = (SetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 12))), typeof(SetCategoryNameDelegate));
            #endif

            //GetCategoryName = (GetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 30))), typeof(GetCategoryNameDelegate));
            //SetIndustrySector = (SetIndustrySectorDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 16))), typeof(SetIndustrySectorDelegate));
            //GetIndustrySector = (GetIndustrySectorDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 20))), typeof(GetIndustrySectorDelegate));

            #if (_WIN64)
            // 64 bit
            AddStockNew = (AddStockNewDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt64(new IntPtr(infoSitePtr.ToInt64() + 56))), typeof(AddStockNewDelegate));
            #else
            // 32 bit
            AddStockNew = (AddStockNewDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 28))), typeof(AddStockNewDelegate));
            #endif

            SetCategoryName(0, 0, "Binance");


            List <SymbolInfo> Symbols = BinanceHelper.getAllPairs();

            // Данных нет
            if (Symbols.Count < 0)
            {
                MessageBox.Show("No configuration data!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Status = StatusCode.OK;
                return(0);
            }

            foreach (SymbolInfo symbol in Symbols)
            {
                addStock(symbol.pairName, 0, symbol.description);
            }

            Status = StatusCode.OK;

            MessageBox.Show("Configure is completed!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);

            return(1);
        }
        public static unsafe int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation *quotes, GQEContext *context)
        {
            // Статус - в ожидании данных
            Status = StatusCode.Wait;

            #region Данных не было - БД пуста
            if (lastValid < 0)
            {
                List <Ticker> last24hBars = BinanceHelper.getLast24hBars(ticker);

                // Проверка что не пусто
                if (last24hBars == null || last24hBars.Count == 0)
                {
                    return(lastValid + 1);
                }

                lastValid = 0;

                // Если влазим в окно - то i = 0; иначе last24hBars.Count - size

                for (var i = (last24hBars.Count < size) ? 0 : last24hBars.Count - size; i < last24hBars.Count; i++)
                {
                    quotes[lastValid].DateTime = last24hBars[i].time;
                    quotes[lastValid].Open     = last24hBars[i].open;
                    quotes[lastValid].High     = last24hBars[i].high;
                    quotes[lastValid].Low      = last24hBars[i].low;
                    quotes[lastValid].Price    = last24hBars[i].close;
                    quotes[lastValid].Volume   = last24hBars[i].volume;

                    lastValid++;
                }

                // Сохраняем значение символьной пары
                lastTicker = ticker;

                return(lastValid);
            }
            #endregion

            Log.Write("isConn: " + isSocketConnected + " lastT: " + lastTicker + " TC: " + ticker);

            // Проверка на то что не переключили символы + первый запуск
            if (String.IsNullOrEmpty(lastTicker) || !lastTicker.Equals(ticker))
            {
                isFirstRun = true;

                /*
                 * if (wss != null)
                 *  wss.Close();
                 *
                 * // Запуск сокета
                 * wss = new WebSocket(String.Format("wss://stream.binance.com:9443/ws/{0}@kline_{1}",ticker.ToLower(),"1m"));
                 * wss.Opened += new EventHandler(WebSockedOpened);
                 * wss.MessageReceived += Wss_MessageReceived;
                 * // wss.Closed += Wss_Closed;
                 * wss.Error += Wss_Error;
                 * wss.Open();
                 */
                if (!BinanceHelper.CreateWSS(ticker, periodicity))
                {
                    Log.Write("Create WSS failed!");
                    isSocketConnected = false;
                    return(lastValid + 1);
                }
                // BinanceHelper.onWSSMessage = Wss_MessageReceived;
                // isSocketConnected = true;
            }
            else
            {
                isFirstRun = false;
            }

            // Обозначаем тикер
            lastTicker = ticker;

            #region Данные есть и это первый запуск
            if (isFirstRun && lastValid > 0)
            {
                // Получаем данные
                List <Ticker> last24hBars = BinanceHelper.getLast24hBars(ticker);

                // Проверка что не пусто
                if (last24hBars == null || last24hBars.Count == 0)
                {
                    return(lastValid + 1);
                }

                // Кастрируем массив
                for (var i = 0; i < last24hBars.Count; i++)
                {
                    AmiDate lastDate      = new AmiDate(quotes[lastValid].DateTime);
                    AmiDate requestedDate = new AmiDate(last24hBars[i].time);

                    if (requestedDate.CompareTo(lastDate) <= 0)
                    {
                        last24hBars.RemoveAt(0);
                        i--;
                    }
                    else
                    {
                        // Вываливаемся из цикла так как последний элемент явно старше
                        break;
                    }
                }

                // Вариант 1 - Count > size - переносим данные
                if (last24hBars.Count > size)
                {
                    lastValid = 0;

                    // Перенос последних = size данных
                    for (var i = last24hBars.Count - size; i < last24hBars.Count; i++)
                    {
                        quotes[lastValid].DateTime = last24hBars[i].time;
                        quotes[lastValid].Open     = last24hBars[i].open;
                        quotes[lastValid].High     = last24hBars[i].high;
                        quotes[lastValid].Low      = last24hBars[i].low;
                        quotes[lastValid].Price    = last24hBars[i].close;
                        quotes[lastValid].Volume   = last24hBars[i].volume;

                        lastValid++;
                    }

                    return(lastValid);
                }

                // Вариант 2 - Count < size и входит в окно - добавить в список
                if ((last24hBars.Count < size) && (last24hBars.Count < (size - lastValid)))
                {
                    // Перенос всех из массива
                    for (var i = 0; i < last24hBars.Count; i++)
                    {
                        quotes[lastValid].DateTime = last24hBars[i].time;
                        quotes[lastValid].Open     = last24hBars[i].open;
                        quotes[lastValid].High     = last24hBars[i].high;
                        quotes[lastValid].Low      = last24hBars[i].low;
                        quotes[lastValid].Price    = last24hBars[i].close;
                        quotes[lastValid].Volume   = last24hBars[i].volume;

                        lastValid++;
                    }

                    return(lastValid);
                }
                else
                if ((last24hBars.Count < size) && (last24hBars.Count > (size - lastValid)))
                {
                    // Вариант 3 - данные в окно не входят - нужно сдвигать массив

                    lastValid = 0;

                    // Сколько элементов останется
                    var j = size - last24hBars.Count;
                    // Индекс начала копирования
                    var index = lastValid - j;

                    // Смещение первой части
                    while (lastValid < j)
                    {
                        Log.Write("I: " + lastValid + " HIGH: " + quotes[index].High + " VOL: " + quotes[index].Volume, "3.txt");

                        quotes[lastValid].DateTime = quotes[index].DateTime;
                        quotes[lastValid].Open     = quotes[index].Open;
                        quotes[lastValid].High     = quotes[index].High;
                        quotes[lastValid].Low      = quotes[index].Low;
                        quotes[lastValid].Price    = quotes[index].Price;
                        quotes[lastValid].Volume   = quotes[index].Volume;

                        lastValid++;
                        index++;
                    }

                    // КОпируем остатки
                    foreach (Ticker item in last24hBars)
                    {
                        Log.Write("I: " + lastValid + " HIGH: " + item.high + " VOL: " + item.volume, "4.txt");

                        quotes[lastValid].DateTime = item.time;
                        quotes[lastValid].Open     = item.open;
                        quotes[lastValid].High     = item.high;
                        quotes[lastValid].Low      = item.low;
                        quotes[lastValid].Price    = item.close;
                        quotes[lastValid].Volume   = item.volume;

                        lastValid++;
                    }

                    return(lastValid);
                }
            }

            #endregion

            // не первый запуск - просто обновляем

            // Если не подключились - нечего разбирать
            if (!isSocketConnected)
            {
                return(lastValid + 1);
            }

            // Показывает что данные тикера устарели
            //bool isTooOld = false;
            BinanceData data = null;

            if (!String.IsNullOrEmpty(jsonAnswer))
            {
                // Парсинг
                try
                {
                    data = JsonConvert.DeserializeObject <BinanceData>(jsonAnswer);
                }
                catch (Exception e)
                {
                    Log.Write("Parse Error: " + e.Message);
                    return(lastValid + 1);
                }
            }

            // В БД есть какие-то данные
            if (lastValid >= 0)
            {
                ulong lastDate   = quotes[lastValid].DateTime;
                ulong tickerDate = (new AmiDate(Utils.UnixTimeStampToDateTime(data.k.t / 1000))).ToUInt64();

                /*
                 * if (tickerDate < lastDate)
                 *  isTooOld = true;
                 */

                if (tickerDate > lastDate)
                {
                    lastValid++;
                }
            }
            else
            {
                // Если пусто в БД - начинаем писать с 0го  индекса
                lastValid = 0;
            }


            // Поправка на лимит
            if (size > 0 && lastValid == size)
            {
                // Сдвигание массива влево
                for (int i = 0; i < size - 1; i++)
                {
                    quotes[i].DateTime = quotes[i + 1].DateTime;
                    quotes[i].Open     = quotes[i + 1].Open;
                    quotes[i].High     = quotes[i + 1].High;
                    quotes[i].Low      = quotes[i + 1].Low;
                    quotes[i].Price    = quotes[i + 1].Price;
                    quotes[i].Volume   = quotes[i + 1].Volume;
                }

                lastValid--;
            }

            // Правим
            //if (!isTooOld)
            {
                AmiDate tickerDate = new AmiDate(Utils.UnixTimeStampToDateTime(data.k.t / 1000));

                quotes[lastValid].DateTime = tickerDate.ToUInt64();
                quotes[lastValid].Open     = float.Parse(data.k.o.Replace(".", ","));
                quotes[lastValid].High     = float.Parse(data.k.h.Replace(".", ","));
                quotes[lastValid].Low      = float.Parse(data.k.l.Replace(".", ","));
                quotes[lastValid].Price    = float.Parse(data.k.c.Replace(".", ","));
                quotes[lastValid].Volume   = float.Parse(data.k.v.Replace(".", ","));
                quotes[lastValid].AuxData1 = 0;
                quotes[lastValid].AuxData2 = 0;
            }

            Status = StatusCode.OK;
            return(lastValid + 1);
        }