private static unsafe void Copy(Quotation *destination, IList <Quotation> source, int i) { destination[i].DateTime = source[i].DateTime; destination[i].Price = source[i].Price; destination[i].Open = source[i].Open; destination[i].High = source[i].High; destination[i].Low = source[i].Low; destination[i].Volume = source[i].Volume; destination[i].OpenInterest = source[i].OpenInterest; destination[i].AuxData1 = source[i].AuxData1; destination[i].AuxData2 = source[i].AuxData2; }
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); }
public static unsafe int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation *quotes, GQEContext *context) { // Статус - в ожидании данных Status = StatusCode.Wait; // при запуске из базы if (refrashTime == -1) { refrashTime = (int)periodicity; } // ticker - наименование пары // periodicity - период опроса (day, mminute, ...) string baseURL; // Если не фьючерсы Okex if (ticker.IndexOf("Future Contracts") < 0) { baseURL = "https://min-api.cryptocompare.com/data/"; // Вроде как ограничение за последние 30 дней = 30 записей по умолчанию (макс 2000) if (periodicity == Periodicity.EndOfDay) { baseURL += "histoday?"; } // Вроде как ограничение за последние 7 дней = 168 записей по умолчанию (макс 2000) if (periodicity == Periodicity.OneHour) { baseURL += "histohour?"; } // Вроде как ограничение за последние 24 часа = 1440 записей по умолчанию (макс 2000) if (periodicity == Periodicity.OneMinute) { baseURL += "histominute?aggregate=1&"; } // 5 минутная агрегация if (periodicity == Periodicity.FiveMinutes) { baseURL += "histominute?aggregate=5&"; } // 15 минутная агрегация if (periodicity == Periodicity.FifteenMinutes) { baseURL += "histominute?aggregate=15&"; } } else { // https://www.okex.com/api/v1/future_kline.do?symbol=btc_usd&contract_type=this_week&type=5min baseURL = "https://www.okex.com/api/v1/future_kline.do?type="; // Вроде как ограничение за последние 30 дней = 30 записей по умолчанию (макс 2000) if (periodicity == Periodicity.EndOfDay) { baseURL += "1day"; } // Вроде как ограничение за последние 7 дней = 168 записей по умолчанию (макс 2000) if (periodicity == Periodicity.OneHour) { baseURL += "1hour"; } // Вроде как ограничение за последние 24 часа = 1440 записей по умолчанию (макс 2000) if (periodicity == Periodicity.OneMinute) { baseURL += "1min"; } // 5 минутная агрегация if (periodicity == Periodicity.FiveMinutes) { baseURL += "5min"; } // 15 минутная агрегация if (periodicity == Periodicity.FifteenMinutes) { baseURL += "15min"; } } // 2. Выбираем маркет и пару // Разбор вида [1]/[2] - [3] // [1] - 1й символ // [2] - 2й символ // [3] - маркет try { string s1 = ticker.Substring(0, ticker.IndexOf("/")); string s2 = ticker.Substring(ticker.IndexOf("/") + 1, ticker.IndexOf(" ") - ticker.IndexOf("/")); string market = ticker.Substring(ticker.IndexOf(" - ") + 3); // Коррекция CryptoCompare if (market.IndexOf("CryptoCompare") > -1) { market = "CCCAGG"; } if (ticker.IndexOf("Future Contracts") < 0) { // Добавим пары и маркет в URL baseURL += "fsym=" + s1.Trim() + "&tsym=" + s2.Trim() + "&e=" + market.Trim() + "&allData=true"; } else { //symbol=btc_usd baseURL += "&symbol=" + s1.Trim().ToLower() + "_" + s2.Trim().ToLower() + "&contract_type=" + RightClickMenu.contractType + "&size=" + size; } } catch (Exception e) { Status = StatusCode.Error; Log.Write("The symbol translate error!"); return(lastValid + 1); } string jsonResponse = MarketData.getMarketData(baseURL); // Если ошибка if (String.IsNullOrEmpty(jsonResponse)) { Status = StatusCode.Error; Log.Write("Error: " + MarketData.getLastError()); return(lastValid + 1); } MarketData.hasData = false; // В jsonResponse имеем файл ответа сервера // Парсим List <Quotation> newQuotes = null; if (ticker.IndexOf("Future Contracts") < 0) { HistoryData data = null; try { data = JsonConvert.DeserializeObject <HistoryData>(jsonResponse); } catch (Exception e) { Log.Write("Json deserialize error: " + e.Message); return(lastValid + 1); } // В итоге имеем данные newQuotes = data.GetQuotesList(); } else { IList <IList <string> > data = null; try { data = JsonConvert.DeserializeObject <IList <IList <string> > >(jsonResponse); } catch (Exception e) { Log.Write("Json deserialize error: " + e.Message); return(lastValid + 1); } foreach (IList <string> item in data) { Quotation qt = new Quotation(); AmiDate tickerDate = new AmiDate(HistoryData.UnixTimeStampToDateTime(ulong.Parse(item[0]) / 1000)); try { qt.Open = float.Parse(item[1].Replace(".", ",")); qt.High = float.Parse(item[2].Replace(".", ",")); qt.Low = float.Parse(item[3].Replace(".", ",")); qt.Price = float.Parse(item[4].Replace(".", ",")); qt.Volume = float.Parse(item[5].Replace(".", ",")); } catch (Exception e) { Log.Write(e.Message); } qt.DateTime = tickerDate.ToUInt64(); newQuotes.Add(qt); } } // Запись данных в БД #region Пишем с нуля - БД не заполнена if (lastValid < 0) { lastValid = 0; // Что меньше: длинна полученных данных или Limit? int count = Math.Min(size, newQuotes.Count); int i = 0, j = 0; for (i = 0; i < count; i++) { j = newQuotes.Count - count + i; // Date quotes[i].DateTime = newQuotes[j].DateTime; // ticker quotes[i].Open = newQuotes[j].Open; quotes[i].High = newQuotes[j].High; quotes[i].Low = newQuotes[j].Low; quotes[i].Price = newQuotes[j].Price; quotes[i].Volume = newQuotes[j].Volume; // Extra data quotes[i].OpenInterest = 0; quotes[i].AuxData1 = 0; quotes[i].AuxData2 = 0; lastValid++; } // Меняем статус на ОК if (!isUpdateAvailable) { Status = StatusCode.OK; } else { Status = StatusCode.Update; } return(lastValid); } #endregion #region Кастрация данных до последнего тайминга for (var i = 0; i < newQuotes.Count; i++) { // Сейчас у нас в массиве только свежак if (newQuotes[i].DateTime < quotes[lastValid].DateTime) { newQuotes.RemoveAt(i); i--; } } #endregion // Если нечего показывать - выход if (newQuotes.Count == 0) { return(lastValid + 1); } #region Данные уже есть в БД - в корридор входим if (newQuotes.Count <= (size - lastValid - 1)) { foreach (Quotation item in newQuotes) { // Date quotes[lastValid].DateTime = item.DateTime; // ticker quotes[lastValid].Open = item.Open; quotes[lastValid].High = item.High; quotes[lastValid].Low = item.Low; quotes[lastValid].Price = item.Price; quotes[lastValid].Volume = item.Volume; // Extra data quotes[lastValid].OpenInterest = 0; quotes[lastValid].AuxData1 = 0; quotes[lastValid].AuxData2 = 0; lastValid++; } // Меняем статус на ОК if (!isUpdateAvailable) { Status = StatusCode.OK; } else { Status = StatusCode.Update; } return(lastValid); } #endregion #region Данные уже есть в БД - в корридор не входим - сдвиг массива lastValid = 0; // Смещение первой части while (lastValid < (size - newQuotes.Count)) { quotes[lastValid].DateTime = quotes[lastValid + newQuotes.Count].DateTime; quotes[lastValid].Open = quotes[lastValid + newQuotes.Count].Open; quotes[lastValid].High = quotes[lastValid + newQuotes.Count].High; quotes[lastValid].Low = quotes[lastValid + newQuotes.Count].Low; quotes[lastValid].Price = quotes[lastValid + newQuotes.Count].Price; quotes[lastValid].Volume = quotes[lastValid + newQuotes.Count].Volume; lastValid++; } // КОпируем остатки foreach (Quotation item in newQuotes) { quotes[lastValid].DateTime = item.DateTime; quotes[lastValid].Open = item.Open; quotes[lastValid].High = item.High; quotes[lastValid].Low = item.Low; quotes[lastValid].Price = item.Price; quotes[lastValid].Volume = item.Volume; lastValid++; } // Меняем статус на ОК if (!isUpdateAvailable) { Status = StatusCode.OK; } else { Status = StatusCode.Update; } return(lastValid); #endregion }
public static unsafe int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation *quotes, GQEContext *context) { Debug.WriteLine("GetQuotesEx(ticker: " + ticker + ", periodicity: " + periodicity + ", lastValid: " + lastValid + ", size: " + size + ", ...)"); var existingQuotes = new Quotation[0]; if (lastValid > 2) { Array.Resize <Quotation>(ref existingQuotes, lastValid + 1); for (var i = 0; i <= lastValid; i++) { existingQuotes[i] = new Quotation { DateTime = quotes[i].DateTime, Open = quotes[i].Open, High = quotes[i].High, Low = quotes[i].Low, Price = quotes[i].Price, Volume = quotes[i].Volume, OpenInterest = quotes[i].OpenInterest, AuxData1 = quotes[i].AuxData1, AuxData2 = quotes[i].AuxData2 }; } Array.Sort <Quotation>(existingQuotes, new Comparison <Quotation>((q1, q2) => q1.DateTime.CompareTo(q2.DateTime))); } var newQuotes = DataSource.GetQuotes(ticker, periodicity, size, existingQuotes); if (newQuotes.Any()) { lastValid = 0; for (var i = 0; i < newQuotes.Length; i++) { quotes[i].DateTime = newQuotes[i].DateTime; quotes[i].Price = newQuotes[i].Price; quotes[i].Open = newQuotes[i].Open; quotes[i].High = newQuotes[i].High; quotes[i].Low = newQuotes[i].Low; quotes[i].Volume = newQuotes[i].Volume; quotes[i].OpenInterest = newQuotes[i].OpenInterest; quotes[i].AuxData1 = newQuotes[i].AuxData1; quotes[i].AuxData2 = newQuotes[i].AuxData2; lastValid++; } return(lastValid); } // return 'lastValid + 1' if no updates are found and you want to keep all existing records return(lastValid + 1); }
public static unsafe int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation *quotes, GQEContext *context) { try { Debug.WriteLine( $"GetQuotesEx(ticker: {ticker}, periodicity: {periodicity}, lastValid: {lastValid}, size: {size} ..." ); Quotation[] newQuotes = { }; try { newQuotes = DataSource.GetQuotes(ticker, periodicity, size); } catch (Exception) { if (DataSource.Mode == Mode.Online) { Status = StatusCode.Offline; DataSource.Mode = Mode.Offline; newQuotes = DataSource.GetQuotes(ticker, periodicity, size); } else { throw; } } // return 'lastValid + 1' if no updates are found and you want to keep all existing records if (!newQuotes.Any()) { return(lastValid + 1); } for (var i = 0; i < newQuotes.Length; i++) { Copy(quotes, newQuotes, i); } return(newQuotes.Length); } catch (Exception e) { MessageBox.Show(e.Message + Environment.NewLine + e); Debug.WriteLine(e.Message + Environment.NewLine + e); } return(-1); }
unsafe public static int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation *quotes, GQEContext *context) { // TODO: Add logic here. Take a look at the demo below: int i = 0; string chktmp = ConfigurationManager.AppSettings["txtTargetFolderforami"]; string timerflag = ConfigurationManager.AppSettings["timerflag"]; if (timerflag == "1") { Status = StatusCode.OK; } if (timerflag == "2") { Status = StatusCode.Unknown; } try { string tempfilepath = chktmp + "\\ShubhaRT.txt"; int flag = 0; string datatostore = ticker; string Openinterest1 = ConfigurationManager.AppSettings["Openinterest"]; string Open1 = ConfigurationManager.AppSettings["Open"]; string High1 = ConfigurationManager.AppSettings["High"]; string Low1 = ConfigurationManager.AppSettings["Low"]; string Volume1 = ConfigurationManager.AppSettings["Volume"]; string Ask1 = ConfigurationManager.AppSettings["Ask"]; string Bid1 = ConfigurationManager.AppSettings["Bid"]; string Preset1 = ConfigurationManager.AppSettings["preset"]; string servername1 = ConfigurationManager.AppSettings["servername"]; string refreshtime1 = ConfigurationManager.AppSettings["interval"]; int volumecount = 0; int openinterestcount = 0; int opencount = 0; int highcount = 0; int lowcount = 0; int askcount = 0; int bidcount = 0; int count = 2; //first 2 position of file is for 1.LTT,2.LTP,3.Volume if (Volume1 != "") { //if user want openint it come at position 4 in file count++; volumecount = count; } if (Openinterest1 != "") { //if user want openint it come at position 4 in file count++; openinterestcount = count; } if (Open1 != "") { count++; opencount = count; } if (High1 != "") { count++; highcount = count; } if (Low1 != "") { count++; lowcount = count; } if (Ask1 != "") { count++; askcount = count; } if (Bid1 != "") { count++; bidcount = count; } //////////////////////////////// string[] wordsdata1 = ticker.Split('|'); if (wordsdata1[1].Contains("-")) { wordsdata1[1] = wordsdata1[1].Substring(0, wordsdata1[1].Length - 3); } if (!File.Exists(chktmp + "\\" + wordsdata1[1] + ".csv")) { return(0); } ////////////////////////////////imp using (var reader = new StreamReader(chktmp + "\\" + wordsdata1[1] + ".csv")) { string line = null; while ((line = reader.ReadLine()) != null) { string[] wordsdata = line.Split(','); DateTime date = Convert.ToDateTime(wordsdata[0]); TimeSpan time = TimeSpan.Parse(wordsdata[1]); DateTime dateTime = date.Add(time); quotes[i].DateTime = PackDate(dateTime.AddDays(0)); quotes[i].Price = float.Parse(wordsdata[2], CultureInfo.InvariantCulture.NumberFormat);// Convert.ToInt32(wordsdata[3]); if (volumecount == 0) { quotes[i].Volume = 0; } else { quotes[i].Volume = float.Parse(wordsdata[volumecount], CultureInfo.InvariantCulture.NumberFormat);//Convert.ToInt32(wordsdata[4]); } if (opencount == 0) { quotes[i].Open = float.Parse(wordsdata[2], CultureInfo.InvariantCulture.NumberFormat);// Convert.ToInt32(wordsdata[3]);; } else { quotes[i].Open = float.Parse(wordsdata[opencount], CultureInfo.InvariantCulture.NumberFormat);//Convert.ToInt32(wordsdata[3]); } if (highcount == 0) { quotes[i].High = float.Parse(wordsdata[2], CultureInfo.InvariantCulture.NumberFormat);// Convert.ToInt32(wordsdata[3]);; } else { quotes[i].High = float.Parse(wordsdata[highcount], CultureInfo.InvariantCulture.NumberFormat);//Convert.ToInt32(wordsdata[3]); } if (lowcount == 0) { quotes[i].Low = float.Parse(wordsdata[2], CultureInfo.InvariantCulture.NumberFormat);// Convert.ToInt32(wordsdata[3]);; } else { quotes[i].Low = float.Parse(wordsdata[lowcount], CultureInfo.InvariantCulture.NumberFormat);// Convert.ToInt32(wordsdata[3]); } if (openinterestcount == 0) { quotes[i].OpenInterest = 0; } else { quotes[i].OpenInterest = float.Parse(wordsdata[openinterestcount], CultureInfo.InvariantCulture.NumberFormat);; } if (askcount == 0) { quotes[i].AuxData1 = 0; } else { quotes[i].AuxData1 = float.Parse(wordsdata[askcount], CultureInfo.InvariantCulture.NumberFormat);; } if (bidcount == 0) { quotes[i].AuxData2 = 0; } else { quotes[i].AuxData2 = float.Parse(wordsdata[bidcount], CultureInfo.InvariantCulture.NumberFormat); } i++; } } } catch { } return(i); }