public async Task <DepthModel> GetDepth(string tradingPair) { using (var client = GetClient()) { using (var response = await client.GetAsync($"/api/v1/depth?symbol={tradingPair}")) { if (!response.IsSuccessStatusCode) { throw new Exception($"Response code: {response.StatusCode}, body: {response.Content.ReadAsStringAsync().Result}"); } var depthModel = new DepthModel { Bids = new List <PriceRateModel>(), Asks = new List <PriceRateModel>() }; var responseContent = await response.Content.ReadAsStringAsync(); var obj = (JObject)JsonConvert.DeserializeObject(responseContent); var bidArray = obj["bids"].ToArray(); foreach (var bid in bidArray) { var bidPriceAndRate = bid.ToArray(); depthModel.Bids.Add(new PriceRateModel { Price = (decimal)bidPriceAndRate[0], Quantity = (decimal)bidPriceAndRate[1] }); } var askArray = obj["asks"].ToArray(); foreach (var ask in askArray) { var askPriceAndRate = ask.ToArray(); depthModel.Asks.Add(new PriceRateModel { Price = (decimal)askPriceAndRate[0], Quantity = (decimal)askPriceAndRate[1] }); } return(depthModel); } } }
private decimal CheckProfitPrecentageAsync(DepthModel depth, decimal closePrice) { //var bidsWall = depth.Bids.First(f => f.Quantity == depth.Bids.Max(b => b.Quantity)); var asksWall = depth.Asks.First(f => f.Quantity == depth.Asks.Max(b => b.Quantity)); var bidsSum = depth.Bids.Sum(s => s.Quantity); var asksSum = depth.Asks.Sum(s => s.Quantity); var profitEstimation = (asksWall.Price / closePrice - 1) * 100; Console.WriteLine($"Profit estimation: {Math.Round(profitEstimation, 4)}%"); if (profitEstimation > _options.ProfitEstimationRate && bidsSum > asksSum) { return(Math.Round(profitEstimation, 4)); } return(-1); }
/// <summary> /// Parses the data from source to datapoints. /// </summary> /// <param name="data">The data.</param> /// <param name="ticker">Associated ticker</param> /// <returns></returns> public DataPointImpl[] ParseData(string data, string ticker = "") { //Initial items DepthModel depthupdate = null; TradeModel treadeupdate = null; OrderBookModel orderbookupdate = null; var toreturn = new List <DataPointImpl>(); data = data.Replace(",[]", ""); //Convert models if (data.Contains("depthUpdate")) { depthupdate = JSON.Deserialize <DepthModel>(data); } else if (data.Contains("aggTrade")) { treadeupdate = JSON.Deserialize <TradeModel>(data); } else if (data.Contains("lastUpdateId")) { //Check if this contains additional data if (data.Contains("|")) { var splitted = data.Split('|'); ticker = splitted[0]; data = splitted[1]; } //Parse data orderbookupdate = JSON.Deserialize <OrderBookModel>(data); } //Full update order book if (orderbookupdate != null && !string.IsNullOrWhiteSpace(ticker)) { //Check data if (!_orderbook.TryGetValue(ticker, out var orderbook)) { //Set order book instance orderbook = new OrderBook(ticker); _orderbook[ticker] = orderbook; } //Helper function void UpdateBook(bool isBid, PriceModel x) => orderbook.AddQuote(isBid, x.DoubleValue, x.DoubleSize); //Clear and refresh orderbook.Clear(); orderbookupdate.Asks.ForEach(u => UpdateBook(false, u)); orderbookupdate.Bids.ForEach(u => UpdateBook(true, u)); } //Update order book else if (depthupdate != null) { //Check data if (!_orderbook.TryGetValue(ticker, out var orderbook)) { //Set order book instance orderbook = new OrderBook(ticker); _orderbook[ticker] = orderbook; } //DateTime occured DateTime occuredutc = Time.FromUnixTime(depthupdate.EventTime, true); //Check for quote updates in the order book (size == 0 = remove from order book) bool update = depthupdate.AskPricesModel.Count(x => orderbook.AddQuote(false, x.DoubleValue, x.DoubleSize)) > 0; update = depthupdate.BidPricesModel.Count(x => orderbook.AddQuote(true, x.DoubleValue, x.DoubleSize)) > 0 | update; //Check for full quote update if (update) { toreturn.Add(new Tick(GetQuantlerTicker(depthupdate.Symbol), DataSource) { AskSize = Convert.ToDecimal(orderbook.AskSize), AskPrice = Convert.ToDecimal(orderbook.BestAsk), BidPrice = Convert.ToDecimal(orderbook.BestBid), BidSize = Convert.ToDecimal(orderbook.BidSize), Depth = 0, Occured = occuredutc, TimeZone = TimeZone.Utc }); } } //Send trade else if (treadeupdate != null) { //DateTime occured DateTime occuredutc = Time.FromUnixTime(treadeupdate.EventTime, true); toreturn.Add(new Tick(GetQuantlerTicker(treadeupdate.Symbol), DataSource) { TradePrice = decimal.Parse(treadeupdate.Price, NumberStyles.Any, new CultureInfo("en-US")), Size = decimal.Parse(treadeupdate.Quantity, NumberStyles.Any, new CultureInfo("en-US")), Occured = occuredutc, TimeZone = TimeZone.Utc }); } //Return what we have return(toreturn.ToArray()); }
public async Task <TrendDirection> CheckTrendAsync(string tradingPair, CandleModel currentCandle) { var shortEmaValue = _shortEmaIndicator.GetIndicatorValue(currentCandle).IndicatorValue; var longEmaValue = _longEmaIndicator.GetIndicatorValue(currentCandle).IndicatorValue; var macdValue = Math.Round(shortEmaValue - longEmaValue, 4); var signalEmaValue = Math.Round(_signalEmaIndicator.GetIndicatorValue(macdValue).IndicatorValue, 4); var histogramValue = Math.Round(macdValue - signalEmaValue, 4); var ichimokuCloudValue = _ichimokuCloudIndicator.GetIndicatorValue(currentCandle); var ssa = ichimokuCloudValue.IchimokuCloud?.SenkouSpanAValue; var ssb = ichimokuCloudValue.IchimokuCloud?.SenkouSpanBValue; DepthModel depth = null; if (ichimokuCloudValue.IchimokuCloud != null) { depth = await _exchangeProvider.GetDepth(tradingPair); } var bid = depth?.Bids.First(f => f.Quantity == depth.Bids.Max(b => b.Quantity)); var ask = depth?.Asks.First(f => f.Quantity == depth.Asks.Max(b => b.Quantity)); var bidPrice = bid?.Price ?? Math.Round(currentCandle.ClosePrice, 4); var askPrice = ask?.Price ?? Math.Round(currentCandle.ClosePrice, 4); var bidPercentage = Math.Round((currentCandle.ClosePrice / bidPrice) * (decimal)100.0 - (decimal)100.0, 2); var askPercentage = Math.Round((currentCandle.ClosePrice / askPrice) * (decimal)100.0 - (decimal)100.0, 2); Console.WriteLine($"DateTs: {currentCandle.StartDateTime:s}; " + $"MACD Value: {macdValue}; " + $"SSA/SSB: {ssa}/{ssb}; " + $"Bids price/qty/%: {bid}/{bidPercentage}%; " + $"Asks price/qty/%: {ask}/{askPercentage}%; " + $"Close price: {Math.Round(currentCandle.ClosePrice, 4)};"); _volumenQueue.Enqueue(currentCandle.Volume); if (!_lastMacd.HasValue || _lastMacd == 0) { _lastMacd = macdValue; _lastClosePrice = currentCandle.ClosePrice; _macdDirection = macdValue < 0 ? MacdDirection.LessThanZero : MacdDirection.GreaterThanZero; return(await Task.FromResult(TrendDirection.None)); } if (_lastMacd < 0 && macdValue >= 0) { if (_macdSwitch) { _maxMacd = 0; } else { _macdSwitch = true; } } if (_lastMacd > 0 && macdValue <= 0) { if (_macdSwitch) { _minMacd = 0; } else { _macdSwitch = true; } } if (macdValue < 0 && macdValue < _minMacd) { _minMacd = macdValue; _minMacdClosePrice = currentCandle.ClosePrice; } if (macdValue > 0 && macdValue > _maxMacd) { _maxMacd = macdValue; _maxMacdClosePrice = currentCandle.ClosePrice; } // wait 0.5 hour if (_candleCount <= 30) { _candleCount++; if (macdValue < 0 && macdValue < _minWarmupMacd) { _minWarmupMacd = macdValue; } Console.WriteLine($"Min warmup Macd: {_minWarmupMacd}"); return(await Task.FromResult(TrendDirection.None)); } if (_lastTrend == TrendDirection.Short) { if (macdValue > 0 && _stopTrading) { _stopTrading = false; } if (macdValue < 0 && macdValue < _lastMacd) { _maxOrMinMacd = macdValue; } //var diffPreviousMacd = _maxOrMinMacd - macdValue; if (_stopTrading == false && macdValue < _options.BuyThreshold && currentCandle.ClosePrice > ssa && currentCandle.ClosePrice > ssb && currentCandle.CandleType == CandleType.Green //&& diffPreviousMacd < -(decimal)0.2 && macdValue > _lastMacd && currentCandle.ClosePrice > _lastClosePrice) { _lastMacd = macdValue; _lastClosePrice = currentCandle.ClosePrice; _profitEstimationRate = CheckProfitPrecentageAsync(depth, currentCandle.ClosePrice); if (_profitEstimationRate < 0) { return(await Task.FromResult(TrendDirection.None)); } _lastTrend = TrendDirection.Long; _maxOrMinMacd = 0; _lastBuyPrice = currentCandle.ClosePrice; } else { _lastMacd = macdValue; _lastClosePrice = currentCandle.ClosePrice; return(await Task.FromResult(TrendDirection.None)); } } else if (_lastTrend == TrendDirection.Long) { if (macdValue > 0 && macdValue > _lastMacd) { _maxOrMinMacd = macdValue; } if (macdValue < 0) { _maxOrMinMacd = 0; } var stopPercentage = 1 - _profitEstimationRate / (decimal)100.0; //1 - (_macdRate - (decimal)0.4) / 100; //(decimal) 0.97; var profitPercentage = 1 + (_profitEstimationRate + (decimal)0.4) / (decimal)100.0; //1 + (_macdRate + (decimal)0.4) / 100; //(decimal) 1.038; //var diffPreviousMacd = _maxOrMinMacd - macdValue; if (_lastMacd > macdValue //&& diffPreviousMacd > (decimal)1.0 && currentCandle.ClosePrice > _lastBuyPrice * profitPercentage || currentCandle.ClosePrice < _lastBuyPrice * stopPercentage) { Console.WriteLine($"Stop percentage: {stopPercentage}; Profit percentage: {profitPercentage}"); _lastTrend = TrendDirection.Short; _maxOrMinMacd = 0; _stopTrading = true; _lastMacd = macdValue; _lastClosePrice = currentCandle.ClosePrice; } else { _lastMacd = macdValue; _lastClosePrice = currentCandle.ClosePrice; return(await Task.FromResult(TrendDirection.None)); } } return(await Task.FromResult(_lastTrend)); }
public void Init(DepthModel model) { ChangeDepthPanel(model.depth); }