public Task <ExchangeTrade> MarketTrade(MarketTradeRequest request) { if (!Prices.TryGetValue(request.Market, out var price)) { throw new Exception($"Cannot found MOCK price for {request.Market}"); } var oppVol = double.Parse(((decimal)price * (decimal)request.Volume * -1m).ToString(CultureInfo.InvariantCulture)); var trade = new ExchangeTrade() { Id = Guid.NewGuid().ToString("N"), Price = price, Side = request.Side, Volume = request.Volume, Market = request.Market, OppositeVolume = oppVol, Timestamp = DateTime.UtcNow, ReferenceId = request.ReferenceId, Source = Name, }; Trades[Name].Add(trade); return(Task.FromResult(trade)); }
public async Task <ExchangeTrade> MarketTrade(MarketTradeRequest request) { try { using var action = MyTelemetry.StartActivity("FTX Market Trade"); request.AddToActivityAsJsonTag("request"); var refId = request.ReferenceId ?? Guid.NewGuid().ToString("N"); refId.AddToActivityAsTag("reference-id"); var size = (decimal)Math.Abs(request.Volume); var resp = await _restApi.PlaceOrderAsync(request.Market, request.Side == OrderSide.Buy?SideType.buy : SideType.sell, 0, OrderType.market, size, refId, true); resp.AddToActivityAsJsonTag("marketOrder-response"); if (!resp.Success && resp.Error != "Duplicate client order ID") { throw new Exception( $"Cannot place marketOrder. Error: {resp.Error}. Request: {JsonConvert.SerializeObject(request)}. Reference: {refId}"); } action?.AddTag("is-duplicate", resp.Error == "Duplicate client order ID"); var tradeData = await _restApi.GetOrderStatusByClientIdAsync(refId); if (!tradeData.Success) { throw new Exception( $"Cannot get order state. Error: {resp.Error}. Request: {JsonConvert.SerializeObject(request)}. Reference: {refId}"); } if (tradeData.Result.Status != "closed") { await _restApi.CancelOrderByClientIdAsync(refId); } tradeData = await _restApi.GetOrderStatusByClientIdAsync(refId); tradeData.AddToActivityAsJsonTag("order-status-response"); if (!tradeData.Success) { throw new Exception( $"Cannot get second order state. Error: {resp.Error}. Request: {JsonConvert.SerializeObject(request)}. Reference: {refId}"); } size = tradeData.Result.FilledSize ?? 0; if (tradeData.Result.Side == "sell") { size = size * -1; } var trade = new ExchangeTrade() { Id = (tradeData.Result.Id ?? 0).ToString(CultureInfo.InvariantCulture), Market = tradeData.Result.Market, Side = tradeData.Result.Side == "buy" ? OrderSide.Buy : OrderSide.Sell, Price = (double)(tradeData.Result.AvgFillPrice ?? 0), ReferenceId = tradeData.Result.ClientId, Source = FtxConst.Name, Volume = (double)size, Timestamp = tradeData.Result.CreatedAt }; trade.AddToActivityAsJsonTag("response"); if (resp.Error == "Duplicate client order ID") { _logger.LogInformation("Ftx trade is Duplicate. Request: {requestJson}. Trade: {tradeJson}", JsonConvert.SerializeObject(request), JsonConvert.SerializeObject(trade)); } else { _logger.LogInformation("Ftx trade is done. Request: {requestJson}. Trade: {tradeJson}", JsonConvert.SerializeObject(request), JsonConvert.SerializeObject(trade)); } return(trade); } catch (Exception ex) { _logger.LogError(ex, "Cannot execute trade. Request: {requestJson}", JsonConvert.SerializeObject(request)); throw; } }